1 unit uglcFrameBufferObject;
4 Prefix: glc - OpenGL Core
5 Beschreibung: diese Unit enthält eine Klassen-Kapselung der OpenGL FrameBufferObjekte
8 fbo: TglcFrameBufferObject;
9 tex: TglcTextureBuffer;
10 buf: TglcRenderBuffer;
12 fbo := TglcFrameBufferObject;
14 ffbo.SetSize(800, 600);
16 // creating texture buffer as color buffer
17 tex := TglcTextureBuffer.Create(TglcFormat.fmRGBA, TglcInternalFormat.ifRGBA16F);
18 fbo.AddBuffer(tex, TglcAttachment.atColor0, true);
20 // creating render buffer as depth buffer
21 buf := TglcRenderBuffer.Create(TglcInternalFormat.ifDepthComponent);
22 fbo.AddBuffer(buf, TglcAttachment.atDepth, true);
24 // render to frame buffer object
26 // do normal rendering
31 // do normal rendering
42 Classes, SysUtils, fgl, dglOpenGl, uglcTypes;
45 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
46 TglcBufferType = (btRenderBuffer, btTextureBuffer);
47 TglcBuffer = class(TObject)
49 fBufferType: TglcBufferType;
53 procedure SetWidth(const aValue: Integer);
54 procedure SetHeight(const aValue: Integer);
56 property Width : Integer read fWidth write SetWidth;
57 property Height: Integer read fHeight write SetHeight;
58 property BufferType: TglcBufferType read fBufferType;
60 procedure SetSize(const aWidth, aHeight: Integer); virtual;
63 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
64 EglcRenderBuffer = class(Exception);
65 TglcRenderBuffer = class(TglcBuffer)
68 fFormat: TglcInternalFormat;
70 procedure UpdateRenderBufferStorage;
71 procedure SetFormat(const aValue: TglcInternalFormat);
73 property ID: gluInt read fID;
74 property Format: TglcInternalFormat read fFormat write SetFormat;
76 procedure SetSize(const aWidth, aHeight: Integer); override;
80 constructor Create(const aFormat: TglcInternalFormat);
81 destructor Destroy; override;
84 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
85 EglcTextureBuffer = class(exception);
86 TglcTextureBuffer = class(TglcBuffer)
90 fInternalFormat: TglcInternalFormat;
93 procedure UpdateTexImage;
94 procedure SetFormat(const aValue: TglcFormat);
95 procedure SetInternalFormat(const aValue: TglcInternalFormat);
96 procedure SetBorder(const aValue: Boolean);
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;
103 procedure SetSize(const aWidth, aHeight: Integer); override;
104 procedure Bind(const aEnableTextureUnit: Boolean = true);
105 procedure Unbind(const aDisableTextureUnit: Boolean = true);
107 constructor Create(const aFormat: TglcFormat; const aInternalFormat: TglcInternalFormat);
108 destructor Destroy; override;
111 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
112 EglcFrameBufferObject = class(Exception);
113 TglcFrameBufferObject = class(TObject)
115 TglcAttachmentContainer = class(TObject)
117 Attachment: TglcAttachment;
119 constructor Create(const aBuffer: TglcBuffer; const aAttachment: TglcAttachment; const aOwnsObject: Boolean = true);
120 destructor Destroy; override;
122 TglcAttachmentContainerList = specialize TFPGObjectList<TglcAttachmentContainer>;
125 fOwnsObjects: Boolean;
128 fBuffers: TglcAttachmentContainerList;
130 function GetBuffer(const aIndex: Integer): TglcBuffer;
131 procedure SetBuffer(const aIndex: Integer; const aValue: TglcBuffer);
133 function GetAttachment(const aIndex: Integer): TglcAttachment;
134 procedure SetAttachment(const aIndex: Integer; const aValue: TglcAttachment);
136 function GetBufferCount: Integer;
138 procedure Attach(const aIndex: Integer);
139 procedure Detach(const aIndex: Integer);
141 procedure SetWidth(const aValue: Integer);
142 procedure SetHeight(const aValue: Integer);
143 procedure CheckFrameBufferStatus;
144 procedure UpdateAndCheckFBO;
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;
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;
159 procedure SetSize(const aWidth, aHeight: Integer);
160 function CheckAttachment(const aAttachment: TglcAttachment): Boolean;
162 procedure Bind(const aSetViewport: Boolean = true);
163 procedure Unbind(const aResetViewport: Boolean = true);
165 constructor Create(const aOwnBuffers: Boolean = true);
166 destructor Destroy; override;
171 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
172 //TglcBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
173 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
174 procedure TglcBuffer.SetWidth(const aValue: Integer);
176 SetSize(aValue, fHeight);
179 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
180 procedure TglcBuffer.SetHeight(const aValue: Integer);
182 SetSize(fWidth, aValue);
185 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
186 procedure TglcBuffer.SetSize(const aWidth, aHeight: Integer);
192 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
193 //TglcRenderBuffer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
194 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
195 procedure TglcRenderBuffer.UpdateRenderBufferStorage;
197 glGetError; //clear Erroros
199 glRenderbufferStorage(GL_RENDERBUFFER, GLenum(fFormat), fWidth, fHeight);
201 glcCheckAndRaiseError;
204 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205 procedure TglcRenderBuffer.SetFormat(const aValue: TglcInternalFormat);
208 UpdateRenderBufferStorage;
211 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
212 procedure TglcRenderBuffer.SetSize(const aWidth, aHeight: Integer);
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;
222 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
223 procedure TglcRenderBuffer.Bind;
225 glBindRenderbuffer(GL_RENDERBUFFER, fID);
228 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
229 procedure TglcRenderBuffer.Unbind;
231 glBindRenderbuffer(GL_RENDERBUFFER, 0);
234 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
235 constructor TglcRenderBuffer.Create(const aFormat: TglcInternalFormat);
238 fBufferType := btRenderBuffer;
239 glGenRenderbuffers(1, @fID);
244 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
245 destructor TglcRenderBuffer.Destroy;
247 glDeleteRenderbuffers(1, @fID);
251 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
252 //TglcTextureBuffer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
253 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
254 procedure TglcTextureBuffer.UpdateTexImage;
256 glGetError; //clear errors
258 glTexImage2D(GL_TEXTURE_2D, 0, GLenum(fInternalFormat), fWidth, fHeight, GLint(Byte(fBorder) and Byte(1)), GLenum(fFormat), GL_UNSIGNED_BYTE, nil);
260 glcCheckAndRaiseError;
263 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
264 procedure TglcTextureBuffer.SetFormat(const aValue: TglcFormat);
266 if (fFormat <> aValue) then begin
272 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
273 procedure TglcTextureBuffer.SetInternalFormat(const aValue: TglcInternalFormat);
275 if (fInternalFormat <> aValue) then begin
276 fInternalFormat := aValue;
281 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
282 procedure TglcTextureBuffer.SetBorder(const aValue: Boolean);
284 if (fBorder <> aValue) then begin
290 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
291 procedure TglcTextureBuffer.SetSize(const aWidth, aHeight: Integer);
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);
301 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
302 procedure TglcTextureBuffer.Bind(const aEnableTextureUnit: Boolean = true);
304 if aEnableTextureUnit then
305 glEnable(GL_TEXTURE_2D);
306 glBindTexture(GL_TEXTURE_2D, fID);
309 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
310 procedure TglcTextureBuffer.Unbind(const aDisableTextureUnit: Boolean = true);
312 if aDisableTextureUnit then
313 glDisable(GL_TEXTURE_2D);
314 glBindTexture(GL_TEXTURE_2D, 0);
317 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
318 constructor TglcTextureBuffer.Create(const aFormat: TglcFormat; const aInternalFormat: TglcInternalFormat);
321 fBufferType := btTextureBuffer;
323 glGenTextures(1, @fID);
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);
332 fInternalFormat := aInternalFormat;
336 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
337 destructor TglcTextureBuffer.Destroy;
339 glDeleteTextures(1, @fID);
343 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
344 //TglcAttachment////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
345 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
346 constructor TglcFrameBufferObject.TglcAttachmentContainer.Create(const aBuffer: TglcBuffer;
347 const aAttachment: TglcAttachment; const aOwnsObject: Boolean);
351 Attachment := aAttachment;
352 OwnsObject := aOwnsObject;
355 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
356 destructor TglcFrameBufferObject.TglcAttachmentContainer.Destroy;
363 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
364 //TglcFrameBufferObject/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
365 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
366 function TglcFrameBufferObject.GetBuffer(const aIndex: Integer): TglcBuffer;
368 if (aIndex >= 0) and (aIndex < fBuffers.Count) then
369 result := fBuffers[aIndex].Buffer
371 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
374 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
375 procedure TglcFrameBufferObject.SetBuffer(const aIndex: Integer; const aValue: TglcBuffer);
377 if (aIndex < 0) or (aIndex >= fBuffers.Count) then
378 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
380 if not Assigned(aValue) then
381 raise EglcFrameBufferObject.Create('invalid buffer');
384 fBuffers[aIndex].Buffer := aValue;
389 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
390 function TglcFrameBufferObject.GetAttachment(const aIndex: Integer): TglcAttachment;
392 if (aIndex >= 0) and (aIndex < fBuffers.Count) then
393 result := fBuffers[aIndex].Attachment
395 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
398 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
399 procedure TglcFrameBufferObject.SetAttachment(const aIndex: Integer; const aValue: TglcAttachment);
401 if (aIndex < 0) or (aIndex >= fBuffers.Count) then
402 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
404 if not CheckAttachment(aValue) then
405 raise EglcFrameBufferObject.Create('Attachment already assigned');
408 fBuffers[aIndex].Attachment := aValue;
413 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
414 procedure TglcFrameBufferObject.Attach(const aIndex: Integer);
419 a := Attachments[aIndex];
420 b := Buffers[aIndex];
422 if (b.BufferType = btRenderBuffer) then
423 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GLenum(a), GL_RENDERBUFFER, (b as TglcRenderBuffer).ID)
425 glFramebufferTexture2D(GL_FRAMEBUFFER, GLenum(a), GL_TEXTURE_2D, (b as TglcTextureBuffer).ID, 0);
429 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
430 procedure TglcFrameBufferObject.Detach(const aIndex: Integer);
435 a := Attachments[aIndex];
436 b := Buffers[aIndex];
438 if (b.BufferType = btRenderBuffer) then
439 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GLenum(a), GL_RENDERBUFFER, 0)
441 glFramebufferTexture2D(GL_FRAMEBUFFER, GLenum(a), GL_TEXTURE_2D, 0, 0);
445 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
446 //legt die neue Breite fest
448 procedure TglcFrameBufferObject.SetWidth(const aValue: Integer);
450 SetSize(aValue, fHeight);
453 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
454 //legt die neue Höhe fest
456 procedure TglcFrameBufferObject.SetHeight(const aValue: Integer);
458 SetSize(fWidth, aValue);
461 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
462 procedure TglcFrameBufferObject.CheckFrameBufferStatus;
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');
482 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
483 //prüft das FrameBufferObjekt auf Fehler
484 procedure TglcFrameBufferObject.UpdateAndCheckFBO;
486 function IsColorAttachment(const a: TglcAttachment): Boolean;
488 result := (GLenum(a) >= GL_COLOR_ATTACHMENT0) and (GLenum(a) <= GL_COLOR_ATTACHMENT15);
492 buff: array of GLenum;
496 if (fBuffers.Count = 0) then
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);
508 //set Read and Draw Buffer
509 if (Length(buff) = 0) then begin
510 glReadBuffer(GL_NONE);
511 glDrawBuffer(GL_NONE);
513 glDrawBuffers(Length(buff), @buff[0]);
514 glGetBooleanv(GL_DOUBLEBUFFER, @b);
516 glReadBuffer(GL_BACK)
518 glReadBuffer(GL_FRONT);
523 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
524 function TglcFrameBufferObject.GetBufferCount: Integer;
526 result := fBuffers.Count;
529 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
530 procedure TglcFrameBufferObject.AddBuffer(const aBuffer: TglcBuffer;
531 const aAttachment: TglcAttachment; const aOwnsBuffer: Boolean);
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');
538 fBuffers.Add(TglcAttachmentContainer.Create(aBuffer, aAttachment, fOwnsObjects and aOwnsBuffer));
540 aBuffer.SetSize(fWidth, fHeight);
541 Attach(fBuffers.Count-1);
546 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
547 procedure TglcFrameBufferObject.DelBuffer(const aIndex: Integer);
549 if (aIndex >= 0) and (aIndex < fBuffers.Count) then begin
551 fBuffers.Delete(aIndex);
554 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
557 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
558 function TglcFrameBufferObject.RemBuffer(const aBuffer: TglcBuffer): Integer;
560 result := IndexOfBuffer(aBuffer);
561 if (result >= 0) then
565 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
566 function TglcFrameBufferObject.IndexOfBuffer(const aBuffer: TglcBuffer): Integer;
570 for i := 0 to fBuffers.Count-1 do
571 if (fBuffers[i].Buffer = aBuffer) then begin
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);
584 c: TglcAttachmentContainer;
586 if (aWidth <= 0) or (aHeight <= 0) then
587 raise EglcFrameBufferObject.Create('invalid width or height');
594 c.Buffer.SetSize(fWidth, fHeight);
597 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
598 function TglcFrameBufferObject.CheckAttachment(const aAttachment: TglcAttachment): Boolean;
603 for i := 0 to fBuffers.Count-1 do
604 if (fBuffers[i].Attachment = aAttachment) then
609 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
610 //Bindet das FrameBufferObjekt
611 procedure TglcFrameBufferObject.Bind(const aSetViewport: Boolean = true);
613 glBindFramebuffer(GL_FRAMEBUFFER, fID);
614 if aSetViewport then begin
615 glPushAttrib(GL_VIEWPORT_BIT);
616 glViewPort(0, 0, fWidth, fHeight);
620 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
621 //Entbindet das FrameBufferObjekt
622 procedure TglcFrameBufferObject.Unbind(const aResetViewport: Boolean = true);
624 if aResetViewport then
626 glBindFramebuffer(GL_FRAMEBUFFER, 0);
629 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
631 constructor TglcFrameBufferObject.Create(const aOwnBuffers: Boolean = true);
635 glGenFramebuffers(1, @fID);
638 fOwnsObjects := aOwnBuffers;
639 fBuffers := TglcAttachmentContainerList.Create(true); //containers are always owned by this object!
642 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
643 //gibt das Objekt frei
644 destructor TglcFrameBufferObject.Destroy;
647 glDeleteFramebuffers(1, @fID);