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.

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