25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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