You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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