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

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