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.

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