Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

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