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.

675 lines
26 KiB

  1. unit uglcFrameBufferObject;
  2. { Package: OpenGLCore
  3. Prefix: glc - OpenGL Core
  4. Beschreibung: diese Unit enthält eine Klassen-Kapselung der OpenGL FrameBufferObjekte
  5. Beispiel:
  6. var
  7. fbo: TglcFrameBufferObject;
  8. tex: TglcTextureBuffer;
  9. buf: TglcRenderBuffer;
  10. fbo := TglcFrameBufferObject.Create;
  11. try
  12. ffbo.SetSize(800, 600);
  13. // creating texture buffer as color buffer
  14. tex := TglcTextureBuffer.Create(TglcFormat.fmRGBA, TglcInternalFormat.ifRGBA16F);
  15. fbo.AddBuffer(tex, TglcAttachment.atColor0, true);
  16. // creating render buffer as depth buffer
  17. buf := TglcRenderBuffer.Create(TglcInternalFormat.ifDepthComponent);
  18. fbo.AddBuffer(buf, TglcAttachment.atDepth, true);
  19. // render to frame buffer object
  20. fbo.Bind;
  21. // do normal rendering
  22. fbo.Unbind;
  23. // use texture buffer
  24. tex.Bind;
  25. // do normal rendering
  26. tex.Unbind;
  27. finally
  28. FreeAndNil(fbo);
  29. end; }
  30. {$mode objfpc}{$H+}
  31. interface
  32. uses
  33. Classes, SysUtils, fgl, {$IFNDEF OPENGL_ES}dglOpenGl{$ELSE}dglOpenGLES{$ENDIF}, uglcTypes;
  34. type
  35. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36. TglcBufferType = (btRenderBuffer, btTextureBuffer);
  37. TglcBuffer = class(TObject)
  38. private
  39. fBufferType: TglcBufferType;
  40. fWidth: Integer;
  41. fHeight: Integer;
  42. procedure SetWidth(const aValue: Integer);
  43. procedure SetHeight(const aValue: Integer);
  44. public
  45. property Width : Integer read fWidth write SetWidth;
  46. property Height: Integer read fHeight write SetHeight;
  47. property BufferType: TglcBufferType read fBufferType;
  48. procedure SetSize(const aWidth, aHeight: Integer); virtual;
  49. end;
  50. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  51. EglcRenderBuffer = class(Exception);
  52. TglcRenderBuffer = class(TglcBuffer)
  53. private
  54. fID: gluInt;
  55. fFormat: TglcInternalFormat;
  56. procedure UpdateRenderBufferStorage;
  57. procedure SetFormat(const aValue: TglcInternalFormat);
  58. public
  59. property ID: gluInt read fID;
  60. property Format: TglcInternalFormat read fFormat write SetFormat;
  61. procedure SetSize(const aWidth, aHeight: Integer); override;
  62. procedure Bind;
  63. procedure Unbind;
  64. constructor Create(const aFormat: TglcInternalFormat);
  65. destructor Destroy; override;
  66. end;
  67. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  68. EglcTextureBuffer = class(exception);
  69. TglcTextureBuffer = class(TglcBuffer)
  70. private
  71. fID: GLuint;
  72. fFormat: TglcFormat;
  73. fInternalFormat: TglcInternalFormat;
  74. fBorder: Boolean;
  75. procedure UpdateTexImage;
  76. procedure SetFormat(const aValue: TglcFormat);
  77. procedure SetInternalFormat(const aValue: TglcInternalFormat);
  78. procedure SetBorder(const aValue: Boolean);
  79. public
  80. property ID : GLuint read fID;
  81. property Border : Boolean read fBorder write SetBorder;
  82. property Format : TglcFormat read fFormat write SetFormat;
  83. property InternalFormat: TglcInternalFormat read fInternalFormat write SetInternalFormat;
  84. procedure SetSize(const aWidth, aHeight: Integer); override;
  85. procedure Bind(const aEnableTextureUnit: Boolean = true);
  86. procedure Unbind(const aDisableTextureUnit: Boolean = true);
  87. constructor Create(const aFormat: TglcFormat; const aInternalFormat: TglcInternalFormat);
  88. destructor Destroy; override;
  89. end;
  90. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  91. EglcFrameBufferObject = class(Exception);
  92. TglcFrameBufferObject = class(TObject)
  93. private type
  94. TglcAttachmentContainer = class(TObject)
  95. Buffer: TglcBuffer;
  96. Attachment: TglcAttachment;
  97. OwnsObject: Boolean;
  98. constructor Create(const aBuffer: TglcBuffer; const aAttachment: TglcAttachment; const aOwnsObject: Boolean = true);
  99. destructor Destroy; override;
  100. end;
  101. TglcAttachmentContainerList = specialize TFPGObjectList<TglcAttachmentContainer>;
  102. private
  103. fID: GLuint;
  104. fOwnsObjects: Boolean;
  105. fWidth: Integer;
  106. fHeight: Integer;
  107. fBuffers: TglcAttachmentContainerList;
  108. {$IFDEF OPENGL_ES}
  109. fOldViewport: array[0..3] of GLint;
  110. {$ENDIF}
  111. function GetBuffer(const aIndex: Integer): TglcBuffer;
  112. procedure SetBuffer(const aIndex: Integer; const aValue: TglcBuffer);
  113. function GetAttachment(const aIndex: Integer): TglcAttachment;
  114. procedure SetAttachment(const aIndex: Integer; const aValue: TglcAttachment);
  115. function GetBufferCount: Integer;
  116. procedure Attach(const aIndex: Integer);
  117. procedure Detach(const aIndex: Integer);
  118. procedure SetWidth(const aValue: Integer);
  119. procedure SetHeight(const aValue: Integer);
  120. procedure CheckFrameBufferStatus;
  121. procedure UpdateAndCheckFBO;
  122. public
  123. property ID : GLuint read fID;
  124. property Count : Integer read GetBufferCount;
  125. property OwnsObjects: Boolean read fOwnsObjects;
  126. property Width : Integer read fWidth write SetWidth;
  127. property Height : Integer read fHeight write SetHeight;
  128. property Attachments[const aIndex: Integer]: TglcAttachment read GetAttachment write SetAttachment;
  129. property Buffers [const aIndex: Integer]: TglcBuffer read GetBuffer write SetBuffer;
  130. procedure AddBuffer(const aBuffer: TglcBuffer; const aAttachment: TglcAttachment; const aOwnsBuffer: Boolean = true);
  131. procedure DelBuffer(const aIndex: Integer);
  132. function RemBuffer(const aBuffer: TglcBuffer): Integer;
  133. function IndexOfBuffer(const aBuffer: TglcBuffer): Integer;
  134. procedure SetSize(const aWidth, aHeight: Integer);
  135. function CheckAttachment(const aAttachment: TglcAttachment): Boolean;
  136. procedure Bind(const aSetViewport: Boolean = true);
  137. procedure Unbind(const aResetViewport: Boolean = true);
  138. constructor Create(const aOwnBuffers: Boolean = true);
  139. destructor Destroy; override;
  140. end;
  141. implementation
  142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. //TglcBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. procedure TglcBuffer.SetWidth(const aValue: Integer);
  146. begin
  147. SetSize(aValue, fHeight);
  148. end;
  149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. procedure TglcBuffer.SetHeight(const aValue: Integer);
  151. begin
  152. SetSize(fWidth, aValue);
  153. end;
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. procedure TglcBuffer.SetSize(const aWidth, aHeight: Integer);
  156. begin
  157. fWidth := aWidth;
  158. fHeight := aHeight;
  159. end;
  160. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. //TglcRenderBuffer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  163. procedure TglcRenderBuffer.UpdateRenderBufferStorage;
  164. begin
  165. glGetError; //clear Erroros
  166. Bind;
  167. glRenderbufferStorage(GL_RENDERBUFFER, GLenum(fFormat), fWidth, fHeight);
  168. Unbind;
  169. glcCheckAndRaiseError;
  170. end;
  171. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  172. procedure TglcRenderBuffer.SetFormat(const aValue: TglcInternalFormat);
  173. begin
  174. fFormat := aValue;
  175. UpdateRenderBufferStorage;
  176. end;
  177. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  178. procedure TglcRenderBuffer.SetSize(const aWidth, aHeight: Integer);
  179. begin
  180. if (aWidth <= 0) or (aHeight <= 0) then
  181. raise EglcRenderBuffer.Create('invalid width or height');
  182. if (aWidth <> fWidth) or (aHeight <> fHeight) then begin
  183. inherited SetSize(aWidth, aHeight);
  184. UpdateRenderBufferStorage;
  185. end;
  186. end;
  187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. procedure TglcRenderBuffer.Bind;
  189. begin
  190. glBindRenderbuffer(GL_RENDERBUFFER, fID);
  191. end;
  192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  193. procedure TglcRenderBuffer.Unbind;
  194. begin
  195. glBindRenderbuffer(GL_RENDERBUFFER, 0);
  196. end;
  197. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  198. constructor TglcRenderBuffer.Create(const aFormat: TglcInternalFormat);
  199. begin
  200. inherited Create;
  201. fBufferType := btRenderBuffer;
  202. glGenRenderbuffers(1, @fID);
  203. fFormat := aFormat;
  204. SetSize(64, 64);
  205. end;
  206. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. destructor TglcRenderBuffer.Destroy;
  208. begin
  209. glDeleteRenderbuffers(1, @fID);
  210. inherited Destroy;
  211. end;
  212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. //TglcTextureBuffer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  214. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  215. procedure TglcTextureBuffer.UpdateTexImage;
  216. begin
  217. glGetError; //clear errors
  218. Bind(false);
  219. glTexImage2D(GL_TEXTURE_2D, 0, GLenum(fInternalFormat), fWidth, fHeight, GLint(Byte(fBorder) and Byte(1)), GLenum(fFormat), GL_UNSIGNED_BYTE, nil);
  220. Unbind(false);
  221. glcCheckAndRaiseError;
  222. end;
  223. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  224. procedure TglcTextureBuffer.SetFormat(const aValue: TglcFormat);
  225. begin
  226. if (fFormat <> aValue) then begin
  227. fFormat := aValue;
  228. UpdateTexImage;
  229. end;
  230. end;
  231. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  232. procedure TglcTextureBuffer.SetInternalFormat(const aValue: TglcInternalFormat);
  233. begin
  234. if (fInternalFormat <> aValue) then begin
  235. fInternalFormat := aValue;
  236. UpdateTexImage;
  237. end;
  238. end;
  239. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  240. procedure TglcTextureBuffer.SetBorder(const aValue: Boolean);
  241. begin
  242. if (fBorder <> aValue) then begin
  243. fBorder := aValue;
  244. UpdateTexImage;
  245. end;
  246. end;
  247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. procedure TglcTextureBuffer.SetSize(const aWidth, aHeight: Integer);
  249. begin
  250. if (aWidth <= 0) or (aHeight <= 0) then
  251. raise EglcTextureBuffer.Create('invalid width or height');
  252. if (aWidth <> fWidth) or (aHeight <> fHeight) then begin
  253. inherited SetSize(aWidth, aHeight);
  254. UpdateTexImage;
  255. end;
  256. end;
  257. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  258. procedure TglcTextureBuffer.Bind(const aEnableTextureUnit: Boolean = true);
  259. begin
  260. if aEnableTextureUnit then
  261. glEnable(GL_TEXTURE_2D);
  262. glBindTexture(GL_TEXTURE_2D, fID);
  263. end;
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. procedure TglcTextureBuffer.Unbind(const aDisableTextureUnit: Boolean = true);
  266. begin
  267. if aDisableTextureUnit then
  268. glDisable(GL_TEXTURE_2D);
  269. glBindTexture(GL_TEXTURE_2D, 0);
  270. end;
  271. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. constructor TglcTextureBuffer.Create(const aFormat: TglcFormat; const aInternalFormat: TglcInternalFormat);
  273. begin
  274. inherited Create;
  275. fBufferType := btTextureBuffer;
  276. glGenTextures(1, @fID);
  277. Bind(false);
  278. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, {$IFNDEF OPENGL_ES}GL_CLAMP{$ELSE}GL_CLAMP_TO_EDGE{$ENDIF});
  279. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, {$IFNDEF OPENGL_ES}GL_CLAMP{$ELSE}GL_CLAMP_TO_EDGE{$ENDIF});
  280. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  281. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  282. Unbind(false);
  283. fFormat := aFormat;
  284. fInternalFormat := aInternalFormat;
  285. SetSize(64, 64);
  286. end;
  287. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  288. destructor TglcTextureBuffer.Destroy;
  289. begin
  290. glDeleteTextures(1, @fID);
  291. inherited Destroy;
  292. end;
  293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  294. //TglcAttachment////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  296. constructor TglcFrameBufferObject.TglcAttachmentContainer.Create(const aBuffer: TglcBuffer;
  297. const aAttachment: TglcAttachment; const aOwnsObject: Boolean);
  298. begin
  299. inherited Create;
  300. Buffer := aBuffer;
  301. Attachment := aAttachment;
  302. OwnsObject := aOwnsObject;
  303. end;
  304. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  305. destructor TglcFrameBufferObject.TglcAttachmentContainer.Destroy;
  306. begin
  307. if OwnsObject then
  308. Buffer.Free;
  309. inherited Destroy;
  310. end;
  311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. //TglcFrameBufferObject/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  313. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  314. function TglcFrameBufferObject.GetBuffer(const aIndex: Integer): TglcBuffer;
  315. begin
  316. if (aIndex >= 0) and (aIndex < fBuffers.Count) then
  317. result := fBuffers[aIndex].Buffer
  318. else
  319. raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
  320. end;
  321. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  322. procedure TglcFrameBufferObject.SetBuffer(const aIndex: Integer; const aValue: TglcBuffer);
  323. begin
  324. if (aIndex < 0) or (aIndex >= fBuffers.Count) then
  325. raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
  326. if not Assigned(aValue) then
  327. raise EglcFrameBufferObject.Create('invalid buffer');
  328. Detach(aIndex);
  329. fBuffers[aIndex].Buffer := aValue;
  330. Attach(aIndex);
  331. UpdateAndCheckFBO;
  332. end;
  333. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  334. function TglcFrameBufferObject.GetAttachment(const aIndex: Integer): TglcAttachment;
  335. begin
  336. if (aIndex >= 0) and (aIndex < fBuffers.Count) then
  337. result := fBuffers[aIndex].Attachment
  338. else
  339. raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
  340. end;
  341. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  342. procedure TglcFrameBufferObject.SetAttachment(const aIndex: Integer; const aValue: TglcAttachment);
  343. begin
  344. if (aIndex < 0) or (aIndex >= fBuffers.Count) then
  345. raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
  346. if not CheckAttachment(aValue) then
  347. raise EglcFrameBufferObject.Create('Attachment already assigned');
  348. Detach(aIndex);
  349. fBuffers[aIndex].Attachment := aValue;
  350. Attach(aIndex);
  351. UpdateAndCheckFBO;
  352. end;
  353. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  354. procedure TglcFrameBufferObject.Attach(const aIndex: Integer);
  355. var
  356. a: TglcAttachment;
  357. b: TglcBuffer;
  358. begin
  359. a := Attachments[aIndex];
  360. b := Buffers[aIndex];
  361. Bind(false);
  362. if (b.BufferType = btRenderBuffer) then
  363. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GLenum(a), GL_RENDERBUFFER, (b as TglcRenderBuffer).ID)
  364. else
  365. glFramebufferTexture2D(GL_FRAMEBUFFER, GLenum(a), GL_TEXTURE_2D, (b as TglcTextureBuffer).ID, 0);
  366. Unbind(false);
  367. end;
  368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  369. procedure TglcFrameBufferObject.Detach(const aIndex: Integer);
  370. var
  371. a: TglcAttachment;
  372. b: TglcBuffer;
  373. begin
  374. a := Attachments[aIndex];
  375. b := Buffers[aIndex];
  376. Bind(false);
  377. if (b.BufferType = btRenderBuffer) then
  378. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GLenum(a), GL_RENDERBUFFER, 0)
  379. else
  380. glFramebufferTexture2D(GL_FRAMEBUFFER, GLenum(a), GL_TEXTURE_2D, 0, 0);
  381. Unbind(false);
  382. end;
  383. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  384. //legt die neue Breite fest
  385. //@Value: Breite;
  386. procedure TglcFrameBufferObject.SetWidth(const aValue: Integer);
  387. begin
  388. SetSize(aValue, fHeight);
  389. end;
  390. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  391. //legt die neue Höhe fest
  392. //@Value: neue Höhe;
  393. procedure TglcFrameBufferObject.SetHeight(const aValue: Integer);
  394. begin
  395. SetSize(fWidth, aValue);
  396. end;
  397. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  398. procedure TglcFrameBufferObject.CheckFrameBufferStatus;
  399. begin
  400. case glCheckFramebufferStatus(GL_FRAMEBUFFER) of
  401. GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
  402. raise EglcFrameBufferObject.Create('Incomplete attachment');
  403. GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
  404. raise EglcFrameBufferObject.Create('Missing attachment');
  405. {$IFNDEF OPENGL_ES}
  406. GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
  407. raise EglcFrameBufferObject.Create('Incomplete dimensions');
  408. GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
  409. raise EglcFrameBufferObject.Create('Incomplete formats');
  410. GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
  411. raise EglcFrameBufferObject.Create('Incomplete draw buffer');
  412. GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
  413. raise EglcFrameBufferObject.Create('Incomplete read buffer');
  414. {$ENDIF}
  415. GL_FRAMEBUFFER_UNSUPPORTED:
  416. raise EglcFrameBufferObject.Create('Framebufferobjects unsupported');
  417. end;
  418. end;
  419. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  420. //prüft das FrameBufferObjekt auf Fehler
  421. procedure TglcFrameBufferObject.UpdateAndCheckFBO;
  422. function IsColorAttachment(const a: TglcAttachment): Boolean;
  423. begin
  424. result := (GLenum(a) >= GL_COLOR_ATTACHMENT0) and (GLenum(a) <= GL_COLOR_ATTACHMENT15);
  425. end;
  426. var
  427. buff: array of GLenum;
  428. i: Integer;
  429. {$IFNDEF OPENGL_ES}DoubleBuffered: GLboolean;{$ENDIF}
  430. begin
  431. {$IFNDEF OPENGL_ES}glGetBooleanv(GL_DOUBLEBUFFER, @DoubleBuffered);{$ENDIF}
  432. if (fBuffers.Count = 0) then
  433. exit;
  434. Bind(false);
  435. //find ColorBuffers
  436. SetLength(buff, 0);
  437. for i := 0 to fBuffers.Count-1 do
  438. if IsColorAttachment(fBuffers[i].Attachment) then begin
  439. SetLength(buff, Length(buff) + 1);
  440. buff[High(buff)] := GLenum(fBuffers[i].Attachment);
  441. end;
  442. //set Read and Draw Buffer
  443. if (Length(buff) = 0) then begin
  444. glReadBuffer(GL_NONE);
  445. {$IFNDEF OPENGL_ES}
  446. glDrawBuffer(GL_NONE);
  447. {$ELSE}
  448. SetLength(buff, 1);
  449. buff[0] := GL_NONE;
  450. glDrawBuffers(1, @buff[0]);
  451. {$ENDIF}
  452. end else begin
  453. glDrawBuffers(Length(buff), @buff[0]);
  454. {$IFNDEF OPENGL_ES}
  455. if DoubleBuffered then
  456. glReadBuffer(GL_BACK)
  457. else
  458. glReadBuffer(GL_FRONT);
  459. {$ELSE}
  460. glReadBuffer(GL_FRONT);
  461. {$ENDIF}
  462. end;
  463. Unbind(false);
  464. end;
  465. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  466. function TglcFrameBufferObject.GetBufferCount: Integer;
  467. begin
  468. result := fBuffers.Count;
  469. end;
  470. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  471. procedure TglcFrameBufferObject.AddBuffer(const aBuffer: TglcBuffer;
  472. const aAttachment: TglcAttachment; const aOwnsBuffer: Boolean);
  473. begin
  474. if not Assigned(aBuffer) then
  475. raise EglcFrameBufferObject.Create('invalid buffer');
  476. if not CheckAttachment(aAttachment) then
  477. raise EglcFrameBufferObject.Create('attachment already assigned');
  478. fBuffers.Add(TglcAttachmentContainer.Create(aBuffer, aAttachment, fOwnsObjects and aOwnsBuffer));
  479. if OwnsObjects then
  480. aBuffer.SetSize(fWidth, fHeight);
  481. Attach(fBuffers.Count-1);
  482. UpdateAndCheckFBO;
  483. end;
  484. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485. procedure TglcFrameBufferObject.DelBuffer(const aIndex: Integer);
  486. begin
  487. if (aIndex >= 0) and (aIndex < fBuffers.Count) then begin
  488. Detach(aIndex);
  489. fBuffers.Delete(aIndex);
  490. UpdateAndCheckFBO;
  491. end else
  492. raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
  493. end;
  494. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  495. function TglcFrameBufferObject.RemBuffer(const aBuffer: TglcBuffer): Integer;
  496. begin
  497. result := IndexOfBuffer(aBuffer);
  498. if (result >= 0) then
  499. DelBuffer(result);
  500. end;
  501. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  502. function TglcFrameBufferObject.IndexOfBuffer(const aBuffer: TglcBuffer): Integer;
  503. var
  504. i: Integer;
  505. begin
  506. for i := 0 to fBuffers.Count-1 do
  507. if (fBuffers[i].Buffer = aBuffer) then begin
  508. result := i;
  509. exit;
  510. end;
  511. result := -1;
  512. end;
  513. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  514. //legt die Größe neu fest
  515. //@Width: neue Breite;
  516. //@Height: neue Höhe;
  517. procedure TglcFrameBufferObject.SetSize(const aWidth, aHeight: Integer);
  518. var
  519. c: TglcAttachmentContainer;
  520. begin
  521. if (aWidth <= 0) or (aHeight <= 0) then
  522. raise EglcFrameBufferObject.Create('invalid width or height');
  523. fWidth := aWidth;
  524. fHeight := aHeight;
  525. if OwnsObjects then
  526. for c in fBuffers do
  527. if c.OwnsObject then
  528. c.Buffer.SetSize(fWidth, fHeight);
  529. end;
  530. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  531. function TglcFrameBufferObject.CheckAttachment(const aAttachment: TglcAttachment): Boolean;
  532. var
  533. i: Integer;
  534. begin
  535. result := false;
  536. for i := 0 to fBuffers.Count-1 do
  537. if (fBuffers[i].Attachment = aAttachment) then
  538. exit;
  539. result := true;
  540. end;
  541. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  542. //Bindet das FrameBufferObjekt
  543. procedure TglcFrameBufferObject.Bind(const aSetViewport: Boolean = true);
  544. begin
  545. glBindFramebuffer(GL_FRAMEBUFFER, fID);
  546. if aSetViewport then begin
  547. {$IFNDEF OPENGL_ES}
  548. glPushAttrib(GL_VIEWPORT_BIT);
  549. {$ELSE}
  550. glGetIntegerv(GL_VIEWPORT, @fOldViewport[0]);
  551. {$ENDIF}
  552. glViewPort(0, 0, fWidth, fHeight);
  553. end;
  554. end;
  555. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  556. //Entbindet das FrameBufferObjekt
  557. procedure TglcFrameBufferObject.Unbind(const aResetViewport: Boolean = true);
  558. begin
  559. if aResetViewport then
  560. {$IFNDEF OPENGL_ES}
  561. glPopAttrib;
  562. {$ELSE}
  563. glViewport(fOldViewport[0], fOldViewport[1], fOldViewport[2], fOldViewport[3]);
  564. {$ENDIF}
  565. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  566. end;
  567. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  568. //erzeugt das Objekt
  569. constructor TglcFrameBufferObject.Create(const aOwnBuffers: Boolean = true);
  570. begin
  571. inherited Create;
  572. glGenFramebuffers(1, @fID);
  573. fWidth := 64;
  574. fHeight := 64;
  575. fOwnsObjects := aOwnBuffers;
  576. fBuffers := TglcAttachmentContainerList.Create(true); //containers are always owned by this object!
  577. end;
  578. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  579. //gibt das Objekt frei
  580. destructor TglcFrameBufferObject.Destroy;
  581. begin
  582. fBuffers.Free;
  583. glDeleteFramebuffers(1, @fID);
  584. inherited Destroy;
  585. end;
  586. end.