No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

976 líneas
39 KiB

  1. unit uglcShader;
  2. { Package: OpenGLCore
  3. Prefix: glc - OpenGL Core
  4. Beschreibung: diese Unit enthält eine Klassen-Kapselung der OpenGL Shader Objekte
  5. Beispiel:
  6. var
  7. shader: TglcShaderProgram;
  8. //write log message to console
  9. // @param aSender: object that send the message
  10. // @param aMsg: message to write to console
  11. procedure LogMessage(aSender: TObject; const aMsg: String);
  12. begin
  13. writeln(Format('[%p]: %s', [aSender, aMsg]);
  14. end;
  15. //load shader object from file and add it to 'shader'
  16. // @param aFilename: name of file to load shader code from
  17. // @param aType: type of shader object to create
  18. procedure LoadShaderObject(const aFilename: String; const aType: TglcShaderType);
  19. var
  20. sl: TStringList;
  21. so: TglcShaderObject;
  22. begin
  23. sl := TStringList.Create;
  24. try
  25. sl.LoadFromFile(aFileName);
  26. so := TglcShaderObject.Create(aType);
  27. shader.add(so);
  28. finally
  29. FreeAndNil(sl, @LogMessage);
  30. end;
  31. end;
  32. shader := TglcShaderProgram.Create(@LogMessage);
  33. try
  34. // load shader objects
  35. LoadShaderObject('./test_shader.vert', TglcShaderType.stVertex);
  36. LoadShaderObject('./test_shader.frag', TglcShaderType.stFragment);
  37. // compile shader
  38. shader.Compile;
  39. // use shader
  40. shader.Enable;
  41. shader.Uniform1f('uTest', 0.1234);
  42. // do normal rendering
  43. shader.Disable;
  44. finally
  45. FreeAndNil(shader);
  46. end; }
  47. {$mode objfpc}{$H+}
  48. interface
  49. uses
  50. Classes, SysUtils, fgl, dglOpenGL, uglcTypes, ugluMatrix;
  51. type
  52. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  53. EglcShader = class(Exception);
  54. TglcShaderProgram = class;
  55. TglcShaderLogEvent = procedure(aSender: TObject; const aMsg: String) of Object;
  56. TglcShaderObject = class(TObject)
  57. private
  58. fAtachedTo: TglcShaderProgram;
  59. fShaderObj: GLHandle;
  60. fShaderType: TglcShaderType;
  61. fCode: String;
  62. fOnLog: TglcShaderLogEvent;
  63. fAttachedTo: TglcShaderProgram;
  64. function GetInfoLog(aObj: GLHandle): String;
  65. function GetCompiled: Boolean;
  66. procedure Log(const aMsg: String);
  67. procedure CreateShaderObj;
  68. procedure AttachTo(const aProgram: TglcShaderProgram);
  69. public
  70. property ShaderObj : GLHandle read fShaderObj;
  71. property ShaderType: TglcShaderType read fShaderType;
  72. property Compiled: Boolean read GetCompiled;
  73. property AtachedTo: TglcShaderProgram read fAtachedTo;
  74. property Code: String read fCode write fCode;
  75. property OnLog: TglcShaderLogEvent read fOnLog write fOnLog;
  76. procedure Compile;
  77. constructor Create(const aShaderType: TglcShaderType; const aLogEvent: TglcShaderLogEvent = nil);
  78. destructor Destroy; override;
  79. end;
  80. TglcShaderObjectList = specialize TFPGObjectList<TglcShaderObject>;
  81. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. TglcShaderProgram = class(TglcShaderObjectList)
  83. private
  84. fProgramObj: GLHandle;
  85. fOnLog: TglcShaderLogEvent;
  86. fFilename: String;
  87. function GetUniformLocation(const aName: String; out aPos: glInt): Boolean;
  88. function GetInfoLog(Obj: GLHandle): String;
  89. function GetCompiled: Boolean;
  90. function GetLinked: Boolean;
  91. procedure CreateProgramObj;
  92. procedure Log(const msg: String);
  93. procedure AttachShaderObj(const aShaderObj: TglcShaderObject);
  94. public
  95. property ProgramObj: glHandle read fProgramObj;
  96. property Filename: String read fFilename;
  97. property Compiled: Boolean read GetCompiled;
  98. property Linked: Boolean read GetLinked;
  99. property OnLog: TglcShaderLogEvent read fOnLog write fOnLog;
  100. procedure Compile;
  101. procedure Enable;
  102. procedure Disable;
  103. procedure Add(aShaderObj: TglcShaderObject);
  104. procedure Delete(aID: Integer; aFreeOwnedObj: Boolean = True);
  105. procedure Clear;
  106. function Uniform1f(const aName: String; aP1: GLFloat): Boolean;
  107. function Uniform2f(const aName: String; aP1, aP2: GLFloat): Boolean;
  108. function Uniform3f(const aName: String; aP1, aP2, aP3: GLFloat): Boolean;
  109. function Uniform4f(const aName: String; aP1, aP2, aP3, aP4: GLFloat): Boolean;
  110. function Uniform1i(const aName: String; aP1: GLint): Boolean;
  111. function Uniform2i(const aName: String; aP1, aP2: GLint): Boolean;
  112. function Uniform3i(const aName: String; aP1, aP2, aP3: GLint): Boolean;
  113. function Uniform4i(const aName: String; aP1, aP2, aP3, aP4: GLint): Boolean;
  114. function Uniform1fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  115. function Uniform2fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  116. function Uniform3fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  117. function Uniform4fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  118. function Uniform1iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  119. function Uniform2iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  120. function Uniform3iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  121. function Uniform4iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  122. function UniformMatrix2fv(const aName: String; aTranspose: Boolean; aCount: GLint; aP1: PgluMatrix2f): Boolean;
  123. function UniformMatrix3fv(const aName: String; aTranspose: Boolean; aCount: GLint; aP1: PgluMatrix3f): Boolean;
  124. function UniformMatrix4fv(const aName: String; aTranspose: Boolean; aCount: GLint; aP1: PgluMatrix4f): Boolean;
  125. function GetUniformfv(const aName: String; aP: PGLfloat): Boolean;
  126. function GetUniformfi(const aName: String; aP: PGLint): Boolean;
  127. function HasUniform(const aName: String): Boolean;
  128. procedure LoadFromFile(const aFilename: String);
  129. procedure LoadFromStream(const aStream: TStream);
  130. procedure SaveToFile(const aFilename: String);
  131. procedure SaveToStream(const aStream: TStream);
  132. constructor Create(const aLogEvent: TglcShaderLogEvent = nil);
  133. destructor Destroy; override;
  134. end;
  135. implementation
  136. uses
  137. RegExpr;
  138. const
  139. ERROR_STR_VAR_NAME: String = 'can''t find the variable ''%s'' in the program';
  140. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  141. //glShaderObject////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. //PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRI//
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. //ließt das Log eines OpenGL-Objekts aus
  146. //@Obj: Handle des Objekts, dessen Log ausgelesen werden soll;
  147. //@result: Log des Objekts;
  148. function TglcShaderObject.GetInfoLog(aObj: GLHandle): String;
  149. var
  150. Msg: PChar;
  151. bLen: GLint;
  152. sLen: GLsizei;
  153. begin
  154. bLen := 0;
  155. glGetShaderiv(aObj, GL_INFO_LOG_LENGTH, @bLen);
  156. if bLen > 1 then begin
  157. GetMem(Msg, bLen * SizeOf(Char));
  158. glGetShaderInfoLog(aObj, bLen, @sLen, Msg);
  159. result := PChar(Msg);
  160. Dispose(Msg);
  161. end;
  162. end;
  163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  164. //ließt aus, ob der Shader ohne Fehler kompiliert wurde
  165. //@result: TRUE wenn ohne Fehler kompiliert, sonst FALSE;
  166. function TglcShaderObject.GetCompiled: Boolean;
  167. var
  168. value: glInt;
  169. begin
  170. glGetShaderiv(fShaderObj, GL_COMPILE_STATUS, @value);
  171. result := (value = GL_TRUE);
  172. end;
  173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. //ruft das Log-Event auf, wenn es gesetzt ist
  175. //@msg: Nachricht die geloggt werden soll;
  176. procedure TglcShaderObject.Log(const aMsg: String);
  177. begin
  178. if Assigned(fOnLog) then begin
  179. fOnLog(self, aMsg);
  180. end;
  181. end;
  182. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  183. procedure TglcShaderObject.CreateShaderObj;
  184. begin
  185. if (fShaderObj <> 0) then
  186. exit;
  187. fShaderObj := glCreateShader(GLenum(fShaderType));
  188. if fShaderObj = 0 then
  189. raise EglcShader.Create('can''t create ShaderObject');
  190. Log('shader object created: #'+IntToHex(fShaderObj, 4));
  191. end;
  192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193. procedure TglcShaderObject.AttachTo(const aProgram: TglcShaderProgram);
  194. begin
  195. if (aProgram <> fAtachedTo) then begin
  196. CreateShaderObj;
  197. glAttachShader(aProgram.ProgramObj, fShaderObj);
  198. fAttachedTo := aProgram;
  199. end;
  200. end;
  201. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  202. //PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBL//
  203. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  204. //kompiliert das Shader-Objekt
  205. procedure TglcShaderObject.Compile;
  206. var
  207. len, i: GLint;
  208. List: TStringList;
  209. c: PAnsiChar;
  210. begin
  211. CreateShaderObj;
  212. len := Length(fCode);
  213. if len > 0 then begin
  214. c := PAnsiChar(fCode);
  215. glShaderSource(fShaderObj, 1, @c, @len);
  216. glCompileShader(fShaderObj);
  217. List := TStringList.Create;
  218. List.Text := GetInfoLog(fShaderObj);
  219. for i := 0 to List.Count-1 do
  220. Log(List[i]);
  221. List.Free;
  222. end else Log('error while compiling: no bound shader code');
  223. end;
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. //erzeugt das Objekt
  226. //@ShaderType: Typ des Shader-Objekts;
  227. //@LogEvent: Event zum loggen von Fehlern und Ereignissen;
  228. //@raise: EglcShader wenn der Shadertyp unbekannt oder ungültig ist;
  229. constructor TglcShaderObject.Create(const aShaderType: TglcShaderType; const aLogEvent: TglcShaderLogEvent);
  230. begin
  231. inherited Create;
  232. fCode := '';
  233. fOnLog := aLogEvent;
  234. fShaderType := aShaderType;
  235. end;
  236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. //gibt das Objekt frei
  238. destructor TglcShaderObject.Destroy;
  239. begin
  240. if (fShaderObj <> 0) then
  241. glDeleteShader(fShaderObj);
  242. inherited Destroy;
  243. end;
  244. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  245. //glShaderProgram///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  247. //PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRIVATE//PRI//
  248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  249. function TglcShaderProgram.GetUniformLocation(const aName: String; out aPos: glInt): Boolean;
  250. begin
  251. aPos := glGetUniformLocation(fProgramObj, PChar(aName));
  252. result := (aPos <> -1);
  253. if not result then
  254. Log(StringReplace(ERROR_STR_VAR_NAME, '%s', aName, [rfIgnoreCase, rfReplaceAll]));
  255. end;
  256. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  257. //ließt das Log eines OpenGL-Objekts aus
  258. //@Obj: Handle des Objekts, dessen Log ausgelesen werden soll;
  259. //@result: Log des Objekts;
  260. function TglcShaderProgram.GetInfoLog(Obj: GLHandle): String;
  261. var
  262. Msg: PChar;
  263. bLen: GLint;
  264. sLen: GLsizei;
  265. begin
  266. bLen := 0;
  267. glGetProgramiv(Obj, GL_INFO_LOG_LENGTH, @bLen);
  268. if bLen > 1 then begin
  269. GetMem(Msg, bLen * SizeOf(Char));
  270. glGetProgramInfoLog(Obj, bLen, @sLen, Msg);
  271. result := PChar(Msg);
  272. Dispose(Msg);
  273. end;
  274. end;
  275. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. //prüft ob alle Shader ohne Fehler compiliert wurden
  277. //@result: TRUE wenn alle erfolgreich compiliert, sonst FALSE;
  278. function TglcShaderProgram.GetCompiled: Boolean;
  279. var
  280. i: Integer;
  281. begin
  282. result := (Count > 0);
  283. for i := 0 to Count-1 do
  284. result := result and Items[i].Compiled;
  285. end;
  286. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  287. //prüft ob das Programm ohne Fehler gelinkt wurde
  288. //@result: TRUE wenn linken erfolgreich, sonst FASLE;
  289. function TglcShaderProgram.GetLinked: Boolean;
  290. var
  291. value: glInt;
  292. begin
  293. glGetProgramiv(fProgramObj, GL_LINK_STATUS, @value);
  294. result := (value = GL_TRUE);
  295. end;
  296. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  297. procedure TglcShaderProgram.CreateProgramObj;
  298. begin
  299. if (fProgramObj = 0) then begin
  300. if GL_LibHandle = nil then
  301. raise EglcShader.Create('TglShaderProgram.Create - OpenGL not initialized');
  302. if (wglGetCurrentContext() = 0) or (wglGetCurrentDC() = 0) then
  303. raise EglcShader.Create('TglShaderProgram.Create - no valid render context');
  304. fProgramObj := glCreateProgram();
  305. Log('shader program created: #'+IntToHex(fProgramObj, 4));
  306. end;
  307. end;
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. //ruft das Log-Event auf, wenn es gesetzt ist
  310. //@msg: Nachricht die geloggt werden soll;
  311. procedure TglcShaderProgram.Log(const msg: String);
  312. begin
  313. if Assigned(fOnLog) then begin
  314. fOnLog(self, msg);
  315. end;
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  318. procedure TglcShaderProgram.AttachShaderObj(const aShaderObj: TglcShaderObject);
  319. begin
  320. CreateProgramObj;
  321. aShaderObj.AttachTo(self);
  322. end;
  323. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  324. //PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBLIC//PUBL//
  325. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  326. //Kompiliert den Shader-Code
  327. procedure TglcShaderProgram.Compile;
  328. var
  329. i: Integer;
  330. l: TStringList;
  331. begin
  332. CreateProgramObj;
  333. for i := 0 to Count-1 do begin
  334. AttachShaderObj(Items[i]);
  335. Items[i].Compile;
  336. end;
  337. glLinkProgram(fProgramObj);
  338. l := TStringList.Create;
  339. l.Text := GetInfoLog(fProgramObj);
  340. for i := 0 to l.Count-1 do
  341. Log(l[i]);
  342. l.Free;
  343. end;
  344. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  345. //aktiviert den Shader
  346. procedure TglcShaderProgram.Enable;
  347. begin
  348. glUseProgram(fProgramObj);
  349. end;
  350. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  351. //deaktiviert den Shader
  352. procedure TglcShaderProgram.Disable;
  353. begin
  354. glUseProgram(0);
  355. end;
  356. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  357. //fügt der Liste einen Shader hinzu
  358. //@ShaderObj: Objekt, das hinzugefügt werden soll;
  359. procedure TglcShaderProgram.Add(aShaderObj: TglcShaderObject);
  360. begin
  361. inherited Add(aShaderObj);
  362. if (fProgramObj <> 0) then
  363. AttachShaderObj(aShaderObj);
  364. end;
  365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. //löscht ein ShaderObjekt aus der Liste
  367. //@ID: Index des Objekts, das gelöscht werden soll;
  368. //@FreeOwnedObj: wenn TRUE wird das gelöschte Objekt freigegeben;
  369. procedure TglcShaderProgram.Delete(aID: Integer; aFreeOwnedObj: Boolean);
  370. var
  371. b: Boolean;
  372. begin
  373. if (aID >= 0) and (aID < Count) and (fProgramObj <> 0) then begin
  374. glDetachShader(fProgramObj, Items[aID].fShaderObj);
  375. Items[aID].fAttachedTo := nil;
  376. end;
  377. b := FreeObjects;
  378. FreeObjects := aFreeOwnedObj;
  379. inherited Delete(aID);
  380. FreeObjects := b;
  381. end;
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. procedure TglcShaderProgram.Clear;
  384. begin
  385. while (Count > 0) do
  386. Delete(0);
  387. end;
  388. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  389. //übergibt einen 1-Komponenten Float-Vektoren an den Shader
  390. //!!!Der Shader muss dazu aktiviert sein!!!
  391. //@Name: Name der Variablen die gesetzt werden soll;
  392. //@p1: Wert der Variable, der gesetzt werden soll;
  393. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  394. function TglcShaderProgram.Uniform1f(const aName: String; aP1: GLFloat): Boolean;
  395. var
  396. pos: GLint;
  397. begin
  398. result := GetUniformLocation(aName, pos);
  399. if result then
  400. glUniform1f(pos, aP1);
  401. end;
  402. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  403. //übergibt einen 2-Komponenten Float-Vektoren an den Shader
  404. //!!!Der Shader muss dazu aktiviert sein!!!
  405. //@Name: Name der Variablen die gesetzt werden soll;
  406. //@p1: Wert der Variable, der gesetzt werden soll;
  407. //@p2: Wert der Variable, der gesetzt werden soll;
  408. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  409. function TglcShaderProgram.Uniform2f(const aName: String; aP1, aP2: GLFloat): Boolean;
  410. var
  411. pos: GLint;
  412. begin
  413. result := GetUniformLocation(aName, pos);
  414. if result then
  415. glUniform2f(pos, aP1, aP2);
  416. end;
  417. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  418. //übergibt einen 3-Komponenten Float-Vektoren an den Shader
  419. //!!!Der Shader muss dazu aktiviert sein!!!
  420. //@Name: Name der Variablen die gesetzt werden soll;
  421. //@p1: Wert der Variable, der gesetzt werden soll;
  422. //@p2: Wert der Variable, der gesetzt werden soll;
  423. //@p3: Wert der Variable, der gesetzt werden soll;
  424. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  425. function TglcShaderProgram.Uniform3f(const aName: String; aP1, aP2, aP3: GLFloat): Boolean;
  426. var
  427. pos: GLint;
  428. begin
  429. result := GetUniformLocation(aName, pos);
  430. if result then
  431. glUniform3f(pos, aP1, aP2, aP3);
  432. end;
  433. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  434. //übergibt einen 4-Komponenten Float-Vektoren an den Shader
  435. //!!!Der Shader muss dazu aktiviert sein!!!
  436. //@Name: Name der Variablen die gesetzt werden soll;
  437. //@p1: Wert der Variable, der gesetzt werden soll;
  438. //@p2: Wert der Variable, der gesetzt werden soll;
  439. //@p3: Wert der Variable, der gesetzt werden soll;
  440. //@p4: Wert der Variable, der gesetzt werden soll;
  441. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  442. function TglcShaderProgram.Uniform4f(const aName: String; aP1, aP2, aP3, aP4: GLFloat): Boolean;
  443. var
  444. pos: GLint;
  445. begin
  446. result := GetUniformLocation(aName, pos);
  447. if result then
  448. glUniform4f(pos, aP1, aP2, aP3, aP4);
  449. end;
  450. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  451. //übergibt einen 1-Komponenten Integer-Vektoren an den Shader
  452. //!!!Der Shader muss dazu aktiviert sein!!!
  453. //@Name: Name der Variablen die gesetzt werden soll;
  454. //@p1: Wert der Variable, der gesetzt werden soll;
  455. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  456. function TglcShaderProgram.Uniform1i(const aName: String; aP1: GLint): Boolean;
  457. var
  458. pos: GLint;
  459. begin
  460. result := GetUniformLocation(aName, pos);
  461. if result then
  462. glUniform1i(pos, aP1);
  463. end;
  464. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  465. //übergibt einen 2-Komponenten Integer-Vektoren an den Shader
  466. //!!!Der Shader muss dazu aktiviert sein!!!
  467. //@Name: Name der Variablen die gesetzt werden soll;
  468. //@p1: Wert der Variable, der gesetzt werden soll;
  469. //@p1: Wert der Variable, der gesetzt werden soll;
  470. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  471. function TglcShaderProgram.Uniform2i(const aName: String; aP1, aP2: GLint): Boolean;
  472. var
  473. pos: GLint;
  474. begin
  475. result := GetUniformLocation(aName, pos);
  476. if result then
  477. glUniform2i(pos, aP1, aP2);
  478. end;
  479. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  480. //übergibt einen 3-Komponenten Integer-Vektoren an den Shader
  481. //!!!Der Shader muss dazu aktiviert sein!!!
  482. //@Name: Name der Variablen die gesetzt werden soll;
  483. //@p1: Wert der Variable, der gesetzt werden soll;
  484. //@p2: Wert der Variable, der gesetzt werden soll;
  485. //@p3: Wert der Variable, der gesetzt werden soll;
  486. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  487. function TglcShaderProgram.Uniform3i(const aName: String; aP1, aP2, aP3: GLint): Boolean;
  488. var
  489. pos: GLint;
  490. begin
  491. result := GetUniformLocation(aName, pos);
  492. if result then
  493. glUniform3i(pos, aP1, aP2, aP3);
  494. end;
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. //übergibt einen 4-Komponenten Integer-Vektoren an den Shader
  497. //!!!Der Shader muss dazu aktiviert sein!!!
  498. //@Name: Name der Variablen die gesetzt werden soll;
  499. //@p1: Wert der Variable, der gesetzt werden soll;
  500. //@p2: Wert der Variable, der gesetzt werden soll;
  501. //@p3: Wert der Variable, der gesetzt werden soll;
  502. //@p4: Wert der Variable, der gesetzt werden soll;
  503. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  504. function TglcShaderProgram.Uniform4i(const aName: String; aP1, aP2, aP3, aP4: GLint): Boolean;
  505. var
  506. pos: GLint;
  507. begin
  508. result := GetUniformLocation(aName, pos);
  509. if result then
  510. glUniform4i(pos, aP1, aP2, aP3, aP4);
  511. end;
  512. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  513. //übergibt einen oder mehrere 1-Komponenten Float-Vektoren an den Shader
  514. //!!!Der Shader muss dazu aktiviert sein!!!
  515. //@Name: Name der Variablen die gesetzt werden soll;
  516. //@count: Anzahl an Parametern auf die p1 zeigt;
  517. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  518. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  519. function TglcShaderProgram.Uniform1fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  520. var
  521. pos: GLint;
  522. begin
  523. result := GetUniformLocation(aName, pos);
  524. if result then
  525. glUniform1fv(pos, aCount, aP1);
  526. end;
  527. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  528. //übergibt einen oder mehrere 2-Komponenten Float-Vektoren an den Shader
  529. //!!!Der Shader muss dazu aktiviert sein!!!
  530. //@Name: Name der Variablen die gesetzt werden soll;
  531. //@count: Anzahl an Parametern auf die p1 zeigt;
  532. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  533. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  534. function TglcShaderProgram.Uniform2fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  535. var
  536. pos: GLint;
  537. begin
  538. result := GetUniformLocation(aName, pos);
  539. if result then
  540. glUniform2fv(pos, aCount, aP1);
  541. end;
  542. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  543. //übergibt einen oder mehrere 3-Komponenten Float-Vektoren an den Shader
  544. //!!!Der Shader muss dazu aktiviert sein!!!
  545. //@Name: Name der Variablen die gesetzt werden soll;
  546. //@count: Anzahl an Parametern auf die p1 zeigt;
  547. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  548. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  549. function TglcShaderProgram.Uniform3fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  550. var
  551. pos: GLint;
  552. begin
  553. result := GetUniformLocation(aName, pos);
  554. if result then
  555. glUniform3fv(pos, aCount, aP1);
  556. end;
  557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  558. //übergibt einen oder mehrere 4-Komponenten Float-Vektoren an den Shader
  559. //!!!Der Shader muss dazu aktiviert sein!!!
  560. //@Name: Name der Variablen die gesetzt werden soll;
  561. //@count: Anzahl an Parametern auf die p1 zeigt;
  562. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  563. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  564. function TglcShaderProgram.Uniform4fv(const aName: String; aCount: GLint; aP1: PGLFloat): Boolean;
  565. var
  566. pos: GLint;
  567. begin
  568. result := GetUniformLocation(aName, pos);
  569. if result then
  570. glUniform4fv(pos, aCount, aP1);
  571. end;
  572. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  573. //übergibt einen oder mehrere 1-Komponenten Integer-Vektoren an den Shader
  574. //!!!Der Shader muss dazu aktiviert sein!!!
  575. //@Name: Name der Variablen die gesetzt werden soll;
  576. //@count: Anzahl an Parametern auf die p1 zeigt;
  577. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  578. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  579. function TglcShaderProgram.Uniform1iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  580. var
  581. pos: GLint;
  582. begin
  583. result := GetUniformLocation(aName, pos);
  584. if result then
  585. glUniform1iv(pos, aCount, aP1);
  586. end;
  587. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  588. //übergibt einen oder mehrere 2-Komponenten Integer-Vektoren an den Shader
  589. //!!!Der Shader muss dazu aktiviert sein!!!
  590. //@Name: Name der Variablen die gesetzt werden soll;
  591. //@count: Anzahl an Parametern auf die p1 zeigt;
  592. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  593. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  594. function TglcShaderProgram.Uniform2iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  595. var
  596. pos: GLint;
  597. begin
  598. result := GetUniformLocation(aName, pos);
  599. if result then
  600. glUniform2iv(pos, aCount, aP1);
  601. end;
  602. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  603. //übergibt einen oder mehrere 3-Komponenten Integer-Vektoren an den Shader
  604. //!!!Der Shader muss dazu aktiviert sein!!!
  605. //@Name: Name der Variablen die gesetzt werden soll;
  606. //@count: Anzahl an Parametern auf die p1 zeigt;
  607. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  608. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  609. function TglcShaderProgram.Uniform3iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  610. var
  611. pos: GLint;
  612. begin
  613. result := GetUniformLocation(aName, pos);
  614. if result then
  615. glUniform3iv(pos, aCount, aP1);
  616. end;
  617. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  618. //übergibt einen oder mehrere 4-Komponenten Integer-Vektoren an den Shader
  619. //!!!Der Shader muss dazu aktiviert sein!!!
  620. //@Name: Name der Variablen die gesetzt werden soll;
  621. //@count: Anzahl an Parametern auf die p1 zeigt;
  622. //@p1: Zeiger auf den ersten Wert der gesetzt werden soll;
  623. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  624. function TglcShaderProgram.Uniform4iv(const aName: String; aCount: GLint; aP1: PGLInt): Boolean;
  625. var
  626. pos: GLint;
  627. begin
  628. result := GetUniformLocation(aName, pos);
  629. if result then
  630. glUniform4iv(pos, aCount, aP1) ;
  631. end;
  632. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  633. //übergibt eine oder mehrere 2x2-Matrizen an den Shader
  634. //!!!Der Shader muss dazu aktiviert sein!!!
  635. //@Name: Name der Variablen die gesetzt werden soll;
  636. //@Transpose: wenn TRUe wird die matrix vor der Übergabe transponiert;
  637. //@Count: Anzahl der zu übergebenden Elemente;
  638. //@p1: Wert der Variable, der gesetzt werden soll;
  639. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  640. function TglcShaderProgram.UniformMatrix2fv(const aName: String; aTranspose: Boolean; aCount: GLint; aP1: PgluMatrix2f): Boolean;
  641. var
  642. pos: GLint;
  643. begin
  644. result := GetUniformLocation(aName, pos);
  645. if result then
  646. glUniformMatrix2fv(pos, aCount, aTranspose, PGLfloat(aP1));
  647. end;
  648. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  649. //übergibt eine oder mehrere 3x3-Matrizen an den Shader
  650. //!!!Der Shader muss dazu aktiviert sein!!!
  651. //@Name: Name der Variablen die gesetzt werden soll;
  652. //@Transpose: wenn TRUe wird die matrix vor der Übergabe transponiert;
  653. //@Count: Anzahl der zu übergebenden Elemente;
  654. //@p1: Wert der Variable, der gesetzt werden soll;
  655. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  656. function TglcShaderProgram.UniformMatrix3fv(const aName: String; aTranspose: Boolean; aCount: GLint; aP1: PgluMatrix3f): Boolean;
  657. var
  658. pos: GLint;
  659. begin
  660. result := GetUniformLocation(aName, pos);
  661. if result then
  662. glUniformMatrix3fv(pos, aCount, aTranspose, PGLfloat(aP1));
  663. end;
  664. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  665. //übergibt eine oder mehrere 4x4-Matrizen an den Shader
  666. //!!!Der Shader muss dazu aktiviert sein!!!
  667. //@Name: Name der Variablen die gesetzt werden soll;
  668. //@Transpose: wenn TRUe wird die matrix vor der Übergabe transponiert;
  669. //@Count: Anzahl der zu übergebenden Elemente;
  670. //@p1: Wert der Variable, der gesetzt werden soll;
  671. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  672. function TglcShaderProgram.UniformMatrix4fv(const aName: String; aTranspose: Boolean; aCount: GLint; aP1: PgluMatrix4f): Boolean;
  673. var
  674. pos: GLint;
  675. begin
  676. result := GetUniformLocation(aName, pos);
  677. if result then
  678. glUniformMatrix4fv(pos, aCount, aTranspose, PGLfloat(aP1));
  679. end;
  680. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  681. //holt den Wert einer Float-Uniform-Variable aus dem Shader
  682. //!!!Der Shader muss dazu aktiviert sein!!!
  683. //@Name: Name der Variablen die gelesen werden soll;
  684. //@p: Zeiger auf die Variable, in die der gelesene Wert geschrieben werden soll;
  685. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  686. function TglcShaderProgram.GetUniformfv(const aName: String; aP: PGLfloat): Boolean;
  687. var
  688. pos: GLint;
  689. begin
  690. result := GetUniformLocation(aName, pos);
  691. if result then
  692. glGetUniformfv(fProgramObj, pos, aP);
  693. end;
  694. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  695. //holt den Wert einer Integer-Uniform-Variable aus dem Shader
  696. //!!!Der Shader muss dazu aktiviert sein!!!
  697. //@Name: Name der Variablen die gelesen werden soll;
  698. //@p: Zeiger auf die Variable, in die der gelesene Wert geschrieben werden soll;
  699. //@result: TRUE wenn erfolgreich, sonst FALSE (Variablenname konnte nicht aufgelöst werden);
  700. function TglcShaderProgram.GetUniformfi(const aName: String; aP: PGLint): Boolean;
  701. var
  702. pos: GLint;
  703. begin
  704. result := GetUniformLocation(aName, pos);
  705. if result then
  706. glGetUniformiv(fProgramObj, pos, aP);
  707. end;
  708. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  709. function TglcShaderProgram.HasUniform(const aName: String): Boolean;
  710. var
  711. pos: GLint;
  712. begin
  713. result := GetUniformLocation(aName, pos);
  714. end;
  715. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  716. //läd den Shader aus einer Datei
  717. //@Filename: Datei aus der gelesen werden soll;
  718. //@raise: EglcShader, wenn Datei nicht vorhanden ist;
  719. procedure TglcShaderProgram.LoadFromFile(const aFilename: String);
  720. var
  721. Stream: TFileStream;
  722. begin
  723. if FileExists(aFilename) then begin
  724. Stream := TFileStream.Create(aFilename, fmOpenRead);
  725. try
  726. LoadFromStream(Stream);
  727. fFilename := aFilename;
  728. finally
  729. Stream.Free;
  730. end;
  731. end else raise EglcShader.Create('TglShaderProgram.LoadFromFile - file not found: '+Filename);
  732. end;
  733. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  734. //läd den Shader aus einem Stream
  735. //@Stream: Stream aus dem gelesen werden soll;
  736. //@raise: EglcShader wenn kein Stream-Objekt übergeben wurde;
  737. procedure TglcShaderProgram.LoadFromStream(const aStream: TStream);
  738. function GetShaderType(const aStr: String): TglcShaderType;
  739. begin
  740. if (aStr = 'GL_VERTEX_SHADER') then
  741. result := TglcShaderType.stVertex
  742. else if (aStr = 'GL_FRAGMENT_SHADER') then
  743. result := TglcShaderType.stFragment
  744. else if (aStr = 'GL_GEOMETRY_SHADER') then
  745. result := TglcShaderType.stGeometry
  746. else if (aStr = 'GL_TESS_CONTROL_SHADER') then
  747. result := TglcShaderType.stTessControl
  748. else if (aStr = 'GL_TESS_EVALUATION_SHADER') then
  749. result := TglcShaderType.stTessEvaluation
  750. else
  751. raise Exception.Create('invalid shader type: ' + aStr);
  752. end;
  753. var
  754. sl: TStringList;
  755. s: String;
  756. rx: TRegExpr;
  757. LastMatchPos: PtrInt;
  758. st: TglcShaderType;
  759. o: TglcShaderObject;
  760. procedure AddObj(const aPos: Integer);
  761. begin
  762. if (LastMatchPos > 0) then begin
  763. o := TglcShaderObject.Create(st, fOnLog);
  764. o.Code := Trim(Copy(s, LastMatchPos, aPos - LastMatchPos));
  765. Add(o);
  766. end;
  767. end;
  768. begin
  769. if not Assigned(aStream) then
  770. raise EglcShader.Create('TglShaderProgram.SaveToStream - stream is nil');
  771. Clear;
  772. sl := TStringList.Create;
  773. rx := TRegExpr.Create;
  774. try
  775. sl.LoadFromStream(aStream);
  776. s := sl.Text;
  777. LastMatchPos := 0;
  778. rx.Expression := '/\*\s*ShaderObject\s*:\s*(GL_[A-Z_]+)\s*\*/\s*$?';
  779. rx.InputString := s;
  780. while rx.Exec(LastMatchPos+1) do begin
  781. AddObj(rx.MatchPos[0]);
  782. LastMatchPos := rx.MatchPos[0] + rx.MatchLen[0];
  783. st := GetShaderType(rx.Match[1]);
  784. end;
  785. AddObj(Length(s));
  786. finally
  787. rx.Free;
  788. sl.Free;
  789. end;
  790. {
  791. if Assigned(aStream) then begin
  792. Clear;
  793. fFilename := '';
  794. reader := TutlStreamReader.Create(aStream);
  795. try
  796. if reader.ReadAnsiString <> GLSL_FILE_HEADER then
  797. raise EglcShader.Create('TglShaderProgram.SaveToStream - incompatible file');
  798. v := reader.ReadInteger;
  799. if v >= 100 then begin //version 1.00
  800. c := reader.ReadInteger;
  801. for i := 0 to c-1 do begin
  802. Add(TglcShaderObject.Create(Cardinal(reader.ReadInteger), fOnLog));
  803. Last.fCode := reader.ReadAnsiString;
  804. end;
  805. end;
  806. finally
  807. reader.Free;
  808. end;
  809. end else
  810. }
  811. end;
  812. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  813. //speichert den Shader in einer Datei
  814. //@Filename: Datei in die geschrieben werden soll;
  815. procedure TglcShaderProgram.SaveToFile(const aFilename: String);
  816. var
  817. Stream: TFileStream;
  818. begin
  819. Stream := TFileStream.Create(aFilename, fmCreate);
  820. try
  821. SaveToStream(Stream);
  822. fFilename := aFilename;
  823. finally
  824. Stream.Free;
  825. end;
  826. end;
  827. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  828. //speichert den Shader in einen Stream
  829. //@Stream: Stream in den geschrieben werden soll;
  830. //@raise: EglcShader wenn kein Stream-Objekt übergeben wurde;
  831. //@raise: EglcShader wenn ungültige Datei;
  832. procedure TglcShaderProgram.SaveToStream(const aStream: TStream);
  833. var
  834. i: Integer;
  835. sl: TStringList;
  836. sObj: TglcShaderObject;
  837. function GetShaderTypeStr(const aShaderType: TglcShaderType): String;
  838. begin
  839. case aShaderType of
  840. TglcShaderType.stVertex: result := 'GL_VERTEX_SHADER';
  841. TglcShaderType.stFragment: result := 'GL_FRAGMENT_SHADER';
  842. TglcShaderType.stGeometry: result := 'GL_GEOMETRY_SHADER';
  843. TglcShaderType.stTessControl: result := 'GL_TESS_CONTROL_SHADER';
  844. TglcShaderType.stTessEvaluation: result := 'GL_TESS_EVALUATION_SHADER';
  845. else
  846. result := 'UNKNOWN';
  847. end;
  848. end;
  849. begin
  850. if not Assigned(aStream) then
  851. raise EglcShader.Create('TglShaderProgram.LoadFromStream - stream is nil');
  852. fFilename := '';
  853. sl := TStringList.Create;
  854. try
  855. for i := 0 to Count-1 do begin
  856. sObj := Items[i];
  857. sl.Add('/* ShaderObject: ' + GetShaderTypeStr(sObj.ShaderType) + ' */');
  858. sl.Add(sObj.Code);
  859. end;
  860. sl.SaveToStream(aStream);
  861. finally
  862. sl.Free;
  863. end;
  864. end;
  865. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  866. //erzeugt das Objekt
  867. //@LogEvent: Event zum loggen von Fehlern und Ereignissen;
  868. //@raise: EglcShader wenn OpenGL nicht initialisiert werden konnte;
  869. //@raise:
  870. constructor TglcShaderProgram.Create(const aLogEvent: TglcShaderLogEvent);
  871. begin
  872. inherited Create;
  873. fOnLog := aLogEvent;
  874. fFilename := '';
  875. fProgramObj := 0;
  876. end;
  877. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  878. //gibt das Objekt frei
  879. destructor TglcShaderProgram.Destroy;
  880. begin
  881. if (fProgramObj <> 0) then
  882. glDeleteProgram(fProgramObj);
  883. inherited Destroy;
  884. end;
  885. end.