1 unit uglcFrameBufferObject;
4 Prefix: glc - OpenGL Core
5 Beschreibung: diese Unit enthält eine Klassen-Kapselung der OpenGL FrameBufferObjekte }
12 Classes, SysUtils, fgl, dglOpenGl, uglcTypes;
15 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 TglcBufferType = (btRenderBuffer, btTextureBuffer);
17 TglcBuffer = class(TObject)
19 fBufferType: TglcBufferType;
23 procedure SetWidth(const aValue: Integer);
24 procedure SetHeight(const aValue: Integer);
26 property Width : Integer read fWidth write SetWidth;
27 property Height: Integer read fHeight write SetHeight;
28 property BufferType: TglcBufferType read fBufferType;
30 procedure SetSize(const aWidth, aHeight: Integer); virtual;
33 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
34 EglcRenderBuffer = class(Exception);
35 TglcRenderBuffer = class(TglcBuffer)
38 fFormat: TglcInternalFormat;
40 procedure UpdateRenderBufferStorage;
41 procedure SetFormat(const aValue: TglcInternalFormat);
43 property ID: gluInt read fID;
44 property Format: TglcInternalFormat read fFormat write SetFormat;
46 procedure SetSize(const aWidth, aHeight: Integer); override;
50 constructor Create(const aFormat: TglcInternalFormat);
51 destructor Destroy; override;
54 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
55 EglcTextureBuffer = class(exception);
56 TglcTextureBuffer = class(TglcBuffer)
60 fInternalFormat: TglcInternalFormat;
63 procedure UpdateTexImage;
64 procedure SetFormat(const aValue: TglcFormat);
65 procedure SetInternalFormat(const aValue: TglcInternalFormat);
66 procedure SetBorder(const aValue: Boolean);
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;
73 procedure SetSize(const aWidth, aHeight: Integer); override;
74 procedure Bind(const aEnableTextureUnit: Boolean = true);
75 procedure Unbind(const aDisableTextureUnit: Boolean = true);
77 constructor Create(const aFormat: TglcFormat; const aInternalFormat: TglcInternalFormat);
78 destructor Destroy; override;
81 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
82 EglcFrameBufferObject = class(Exception);
83 TglcFrameBufferObject = class(TObject)
85 TglcAttachmentContainer = class(TObject)
87 Attachment: TglcAttachment;
89 constructor Create(const aBuffer: TglcBuffer; const aAttachment: TglcAttachment; const aOwnsObject: Boolean = true);
90 destructor Destroy; override;
92 TglcAttachmentContainerList = specialize TFPGObjectList<TglcAttachmentContainer>;
95 fOwnsObjects: Boolean;
98 fBuffers: TglcAttachmentContainerList;
100 function GetBuffer(const aIndex: Integer): TglcBuffer;
101 procedure SetBuffer(const aIndex: Integer; const aValue: TglcBuffer);
103 function GetAttachment(const aIndex: Integer): TglcAttachment;
104 procedure SetAttachment(const aIndex: Integer; const aValue: TglcAttachment);
106 function GetBufferCount: Integer;
108 procedure Attach(const aIndex: Integer);
109 procedure Detach(const aIndex: Integer);
111 procedure SetWidth(const aValue: Integer);
112 procedure SetHeight(const aValue: Integer);
113 procedure CheckFrameBufferStatus;
114 procedure UpdateAndCheckFBO;
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;
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;
129 procedure SetSize(const aWidth, aHeight: Integer);
130 function CheckAttachment(const aAttachment: TglcAttachment): Boolean;
132 procedure Bind(const aSetViewport: Boolean = true);
133 procedure Unbind(const aResetViewport: Boolean = true);
135 constructor Create(const aOwnBuffers: Boolean = true);
136 destructor Destroy; override;
141 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
142 //TglcBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
143 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
144 procedure TglcBuffer.SetWidth(const aValue: Integer);
146 SetSize(aValue, fHeight);
149 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
150 procedure TglcBuffer.SetHeight(const aValue: Integer);
152 SetSize(fWidth, aValue);
155 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
156 procedure TglcBuffer.SetSize(const aWidth, aHeight: Integer);
162 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
163 //TglcRenderBuffer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
164 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
165 procedure TglcRenderBuffer.UpdateRenderBufferStorage;
167 glGetError; //clear Erroros
169 glRenderbufferStorage(GL_RENDERBUFFER, GLenum(fFormat), fWidth, fHeight);
171 glcCheckAndRaiseError;
174 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
175 procedure TglcRenderBuffer.SetFormat(const aValue: TglcInternalFormat);
178 UpdateRenderBufferStorage;
181 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
182 procedure TglcRenderBuffer.SetSize(const aWidth, aHeight: Integer);
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;
192 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
193 procedure TglcRenderBuffer.Bind;
195 glBindRenderbuffer(GL_RENDERBUFFER, fID);
198 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
199 procedure TglcRenderBuffer.Unbind;
201 glBindRenderbuffer(GL_RENDERBUFFER, 0);
204 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205 constructor TglcRenderBuffer.Create(const aFormat: TglcInternalFormat);
208 fBufferType := btRenderBuffer;
209 glGenRenderbuffers(1, @fID);
214 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
215 destructor TglcRenderBuffer.Destroy;
217 glDeleteRenderbuffers(1, @fID);
221 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
222 //TglcTextureBuffer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
223 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
224 procedure TglcTextureBuffer.UpdateTexImage;
226 glGetError; //clear errors
228 glTexImage2D(GL_TEXTURE_2D, 0, GLenum(fInternalFormat), fWidth, fHeight, GLint(Byte(fBorder) and Byte(1)), GLenum(fFormat), GL_UNSIGNED_BYTE, nil);
230 glcCheckAndRaiseError;
233 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
234 procedure TglcTextureBuffer.SetFormat(const aValue: TglcFormat);
236 if (fFormat <> aValue) then begin
242 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
243 procedure TglcTextureBuffer.SetInternalFormat(const aValue: TglcInternalFormat);
245 if (fInternalFormat <> aValue) then begin
246 fInternalFormat := aValue;
251 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
252 procedure TglcTextureBuffer.SetBorder(const aValue: Boolean);
254 if (fBorder <> aValue) then begin
260 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
261 procedure TglcTextureBuffer.SetSize(const aWidth, aHeight: Integer);
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);
271 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272 procedure TglcTextureBuffer.Bind(const aEnableTextureUnit: Boolean = true);
274 if aEnableTextureUnit then
275 glEnable(GL_TEXTURE_2D);
276 glBindTexture(GL_TEXTURE_2D, fID);
279 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
280 procedure TglcTextureBuffer.Unbind(const aDisableTextureUnit: Boolean = true);
282 if aDisableTextureUnit then
283 glDisable(GL_TEXTURE_2D);
284 glBindTexture(GL_TEXTURE_2D, 0);
287 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
288 constructor TglcTextureBuffer.Create(const aFormat: TglcFormat; const aInternalFormat: TglcInternalFormat);
291 fBufferType := btTextureBuffer;
293 glGenTextures(1, @fID);
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);
302 fInternalFormat := aInternalFormat;
306 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
307 destructor TglcTextureBuffer.Destroy;
309 glDeleteTextures(1, @fID);
313 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
314 //TglcAttachment////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
315 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
316 constructor TglcFrameBufferObject.TglcAttachmentContainer.Create(const aBuffer: TglcBuffer;
317 const aAttachment: TglcAttachment; const aOwnsObject: Boolean);
321 Attachment := aAttachment;
322 OwnsObject := aOwnsObject;
325 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
326 destructor TglcFrameBufferObject.TglcAttachmentContainer.Destroy;
333 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
334 //TglcFrameBufferObject/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
335 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
336 function TglcFrameBufferObject.GetBuffer(const aIndex: Integer): TglcBuffer;
338 if (aIndex >= 0) and (aIndex < fBuffers.Count) then
339 result := fBuffers[aIndex].Buffer
341 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
344 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
345 procedure TglcFrameBufferObject.SetBuffer(const aIndex: Integer; const aValue: TglcBuffer);
347 if (aIndex < 0) or (aIndex >= fBuffers.Count) then
348 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
350 if not Assigned(aValue) then
351 raise EglcFrameBufferObject.Create('invalid buffer');
354 fBuffers[aIndex].Buffer := aValue;
359 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
360 function TglcFrameBufferObject.GetAttachment(const aIndex: Integer): TglcAttachment;
362 if (aIndex >= 0) and (aIndex < fBuffers.Count) then
363 result := fBuffers[aIndex].Attachment
365 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
368 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
369 procedure TglcFrameBufferObject.SetAttachment(const aIndex: Integer; const aValue: TglcAttachment);
371 if (aIndex < 0) or (aIndex >= fBuffers.Count) then
372 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
374 if not CheckAttachment(aValue) then
375 raise EglcFrameBufferObject.Create('Attachment already assigned');
378 fBuffers[aIndex].Attachment := aValue;
383 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
384 procedure TglcFrameBufferObject.Attach(const aIndex: Integer);
389 a := Attachments[aIndex];
390 b := Buffers[aIndex];
392 if (b.BufferType = btRenderBuffer) then
393 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GLenum(a), GL_RENDERBUFFER, (b as TglcRenderBuffer).ID)
395 glFramebufferTexture2D(GL_FRAMEBUFFER, GLenum(a), GL_TEXTURE_2D, (b as TglcTextureBuffer).ID, 0);
399 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
400 procedure TglcFrameBufferObject.Detach(const aIndex: Integer);
405 a := Attachments[aIndex];
406 b := Buffers[aIndex];
408 if (b.BufferType = btRenderBuffer) then
409 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GLenum(a), GL_RENDERBUFFER, 0)
411 glFramebufferTexture2D(GL_FRAMEBUFFER, GLenum(a), GL_TEXTURE_2D, 0, 0);
415 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
416 //legt die neue Breite fest
418 procedure TglcFrameBufferObject.SetWidth(const aValue: Integer);
420 SetSize(aValue, fHeight);
423 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
424 //legt die neue Höhe fest
426 procedure TglcFrameBufferObject.SetHeight(const aValue: Integer);
428 SetSize(fWidth, aValue);
431 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
432 procedure TglcFrameBufferObject.CheckFrameBufferStatus;
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');
452 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
453 //prüft das FrameBufferObjekt auf Fehler
454 procedure TglcFrameBufferObject.UpdateAndCheckFBO;
456 function IsColorAttachment(const a: TglcAttachment): Boolean;
458 result := (GLenum(a) >= GL_COLOR_ATTACHMENT0) and (GLenum(a) <= GL_COLOR_ATTACHMENT15);
462 buff: array of GLenum;
466 if (fBuffers.Count = 0) then
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);
478 //set Read and Draw Buffer
479 if (Length(buff) = 0) then begin
480 glReadBuffer(GL_NONE);
481 glDrawBuffer(GL_NONE);
483 glDrawBuffers(Length(buff), @buff[0]);
484 glGetBooleanv(GL_DOUBLEBUFFER, @b);
486 glReadBuffer(GL_BACK)
488 glReadBuffer(GL_FRONT);
493 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
494 function TglcFrameBufferObject.GetBufferCount: Integer;
496 result := fBuffers.Count;
499 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
500 procedure TglcFrameBufferObject.AddBuffer(const aBuffer: TglcBuffer;
501 const aAttachment: TglcAttachment; const aOwnsBuffer: Boolean);
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');
508 fBuffers.Add(TglcAttachmentContainer.Create(aBuffer, aAttachment, fOwnsObjects and aOwnsBuffer));
510 aBuffer.SetSize(fWidth, fHeight);
511 Attach(fBuffers.Count-1);
516 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
517 procedure TglcFrameBufferObject.DelBuffer(const aIndex: Integer);
519 if (aIndex >= 0) and (aIndex < fBuffers.Count) then begin
521 fBuffers.Delete(aIndex);
524 raise EglcFrameBufferObject.Create('Index out of Bounds: ' + IntToStr(aIndex));
527 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
528 function TglcFrameBufferObject.RemBuffer(const aBuffer: TglcBuffer): Integer;
530 result := IndexOfBuffer(aBuffer);
531 if (result >= 0) then
535 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
536 function TglcFrameBufferObject.IndexOfBuffer(const aBuffer: TglcBuffer): Integer;
540 for i := 0 to fBuffers.Count-1 do
541 if (fBuffers[i].Buffer = aBuffer) then begin
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);
554 c: TglcAttachmentContainer;
556 if (aWidth <= 0) or (aHeight <= 0) then
557 raise EglcFrameBufferObject.Create('invalid width or height');
564 c.Buffer.SetSize(fWidth, fHeight);
567 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
568 function TglcFrameBufferObject.CheckAttachment(const aAttachment: TglcAttachment): Boolean;
573 for i := 0 to fBuffers.Count-1 do
574 if (fBuffers[i].Attachment = aAttachment) then
579 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
580 //Bindet das FrameBufferObjekt
581 procedure TglcFrameBufferObject.Bind(const aSetViewport: Boolean = true);
583 glBindFramebuffer(GL_FRAMEBUFFER, fID);
584 if aSetViewport then begin
585 glPushAttrib(GL_VIEWPORT_BIT);
586 glViewPort(0, 0, fWidth, fHeight);
590 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
591 //Entbindet das FrameBufferObjekt
592 procedure TglcFrameBufferObject.Unbind(const aResetViewport: Boolean = true);
594 if aResetViewport then
596 glBindFramebuffer(GL_FRAMEBUFFER, 0);
599 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
601 constructor TglcFrameBufferObject.Create(const aOwnBuffers: Boolean = true);
605 glGenFramebuffers(1, @fID);
608 fOwnsObjects := aOwnBuffers;
609 fBuffers := TglcAttachmentContainerList.Create(true); //containers are always owned by this object!
612 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
613 //gibt das Objekt frei
614 destructor TglcFrameBufferObject.Destroy;
617 glDeleteFramebuffers(1, @fID);