Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

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