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.

678 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. {$IFNDEF OPENGL_ES}
  429. b: GLboolean;
  430. {$ENDIF}
  431. i: Integer;
  432. begin
  433. if (fBuffers.Count = 0) then
  434. exit;
  435. Bind(false);
  436. //find ColorBuffers
  437. SetLength(buff, 0);
  438. for i := 0 to fBuffers.Count-1 do
  439. if IsColorAttachment(fBuffers[i].Attachment) then begin
  440. SetLength(buff, Length(buff) + 1);
  441. buff[High(buff)] := GLenum(fBuffers[i].Attachment);
  442. end;
  443. //set Read and Draw Buffer
  444. if (Length(buff) = 0) then begin
  445. glReadBuffer(GL_NONE);
  446. {$IFNDEF OPENGL_ES}
  447. glDrawBuffer(GL_NONE);
  448. {$ELSE}
  449. SetLength(buff, 1);
  450. buff[0] := GL_NONE;
  451. glDrawBuffers(1, @buff[0]);
  452. {$ENDIF}
  453. end else begin
  454. glDrawBuffers(Length(buff), @buff[0]);
  455. {$IFNDEF OPENGL_ES}
  456. glGetBooleanv(GL_DOUBLEBUFFER, @b);
  457. if b then
  458. glReadBuffer(GL_BACK)
  459. else
  460. glReadBuffer(GL_FRONT);
  461. {$ELSE}
  462. glReadBuffer(GL_FRONT);
  463. {$ENDIF}
  464. end;
  465. Unbind(false);
  466. end;
  467. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  468. function TglcFrameBufferObject.GetBufferCount: Integer;
  469. begin
  470. result := fBuffers.Count;
  471. end;
  472. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  473. procedure TglcFrameBufferObject.AddBuffer(const aBuffer: TglcBuffer;
  474. const aAttachment: TglcAttachment; const aOwnsBuffer: Boolean);
  475. begin
  476. if not Assigned(aBuffer) then
  477. raise EglcFrameBufferObject.Create('invalid buffer');
  478. if not CheckAttachment(aAttachment) then
  479. raise EglcFrameBufferObject.Create('attachment already assigned');
  480. fBuffers.Add(TglcAttachmentContainer.Create(aBuffer, aAttachment, fOwnsObjects and aOwnsBuffer));
  481. if OwnsObjects then
  482. aBuffer.SetSize(fWidth, fHeight);
  483. Attach(fBuffers.Count-1);
  484. UpdateAndCheckFBO;
  485. end;
  486. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  487. procedure TglcFrameBufferObject.DelBuffer(const aIndex: Integer);
  488. begin
  489. if (aIndex >= 0) and (aIndex < fBuffers.Count) then begin
  490. Detach(aIndex);
  491. fBuffers.Delete(aIndex);
  492. UpdateAndCheckFBO;
  493. end else
  494. raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
  495. end;
  496. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  497. function TglcFrameBufferObject.RemBuffer(const aBuffer: TglcBuffer): Integer;
  498. begin
  499. result := IndexOfBuffer(aBuffer);
  500. if (result >= 0) then
  501. DelBuffer(result);
  502. end;
  503. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  504. function TglcFrameBufferObject.IndexOfBuffer(const aBuffer: TglcBuffer): Integer;
  505. var
  506. i: Integer;
  507. begin
  508. for i := 0 to fBuffers.Count-1 do
  509. if (fBuffers[i].Buffer = aBuffer) then begin
  510. result := i;
  511. exit;
  512. end;
  513. result := -1;
  514. end;
  515. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  516. //legt die Größe neu fest
  517. //@Width: neue Breite;
  518. //@Height: neue Höhe;
  519. procedure TglcFrameBufferObject.SetSize(const aWidth, aHeight: Integer);
  520. var
  521. c: TglcAttachmentContainer;
  522. begin
  523. if (aWidth <= 0) or (aHeight <= 0) then
  524. raise EglcFrameBufferObject.Create('invalid width or height');
  525. fWidth := aWidth;
  526. fHeight := aHeight;
  527. if OwnsObjects then
  528. for c in fBuffers do
  529. if c.OwnsObject then
  530. c.Buffer.SetSize(fWidth, fHeight);
  531. end;
  532. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  533. function TglcFrameBufferObject.CheckAttachment(const aAttachment: TglcAttachment): Boolean;
  534. var
  535. i: Integer;
  536. begin
  537. result := false;
  538. for i := 0 to fBuffers.Count-1 do
  539. if (fBuffers[i].Attachment = aAttachment) then
  540. exit;
  541. result := true;
  542. end;
  543. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  544. //Bindet das FrameBufferObjekt
  545. procedure TglcFrameBufferObject.Bind(const aSetViewport: Boolean = true);
  546. begin
  547. glBindFramebuffer(GL_FRAMEBUFFER, fID);
  548. if aSetViewport then begin
  549. {$IFNDEF OPENGL_ES}
  550. glPushAttrib(GL_VIEWPORT_BIT);
  551. {$ELSE}
  552. glGetIntegerv(GL_VIEWPORT, @fOldViewport[0]);
  553. {$ENDIF}
  554. glViewPort(0, 0, fWidth, fHeight);
  555. end;
  556. end;
  557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  558. //Entbindet das FrameBufferObjekt
  559. procedure TglcFrameBufferObject.Unbind(const aResetViewport: Boolean = true);
  560. begin
  561. if aResetViewport then
  562. {$IFNDEF OPENGL_ES}
  563. glPopAttrib;
  564. {$ELSE}
  565. glViewport(fOldViewport[0], fOldViewport[1], fOldViewport[2], fOldViewport[3]);
  566. {$ENDIF}
  567. glBindFramebuffer(GL_FRAMEBUFFER, 0);
  568. end;
  569. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  570. //erzeugt das Objekt
  571. constructor TglcFrameBufferObject.Create(const aOwnBuffers: Boolean = true);
  572. begin
  573. inherited Create;
  574. glGenFramebuffers(1, @fID);
  575. fWidth := 64;
  576. fHeight := 64;
  577. fOwnsObjects := aOwnBuffers;
  578. fBuffers := TglcAttachmentContainerList.Create(true); //containers are always owned by this object!
  579. end;
  580. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  581. //gibt das Objekt frei
  582. destructor TglcFrameBufferObject.Destroy;
  583. begin
  584. fBuffers.Free;
  585. glDeleteFramebuffers(1, @fID);
  586. inherited Destroy;
  587. end;
  588. end.