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