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