Back to index

nux  3.0.0
IOpenGLFrameBufferObject.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 
00023 #include "GLResource.h"
00024 #include "GraphicsDisplay.h"
00025 #include "GpuDevice.h"
00026 #include "GLDeviceObjects.h"
00027 #include "IOpenGLFrameBufferObject.h"
00028 #include "GraphicsEngine.h"
00029 
00030 namespace nux
00031 {
00032 
00033   NUX_IMPLEMENT_OBJECT_TYPE(IOpenGLFrameBufferObject);
00034 
00035   IOpenGLFrameBufferObject::IOpenGLFrameBufferObject(NUX_FILE_LINE_DECL)
00036     :   IOpenGLResource(RTFRAMEBUFFEROBJECT, NUX_FILE_LINE_PARAM)
00037   {
00038     _Width = 1;
00039     _Height = 1;
00040     _PixelFormat = BITFMT_R8G8B8A8;
00041     _IsActive = false;
00042 
00043     for (int i = 0; i < 1 /*GetGraphicsDisplay()->GetGpuDevice()->GetGpuInfo().GetMaxFboAttachment()*/; i++)
00044     {
00045       _Color_AttachmentArray.push_back(ObjectPtr<IOpenGLSurface> (0));
00046     }
00047 
00048     FormatFrameBufferObject(_Width, _Height, _PixelFormat);
00049     GRunTimeStats.Register(this);
00050   }
00051 
00052   IOpenGLFrameBufferObject::~IOpenGLFrameBufferObject()
00053   {
00054     // IOpenGLFrameBufferObject is an abstraction. Is does not have an opengl id.
00055     // _Fbo has an opengl id that is destroyed when the destructor is called.
00056     _OpenGLID = 0;
00057     GRunTimeStats.UnRegister(this);
00058   }
00059 
00060   int IOpenGLFrameBufferObject::FormatFrameBufferObject(int Width, int Height, BitmapFormat PixelFormat)
00061   {
00062     Deactivate();
00063 
00064     for (int i = 0; i < 1 /*GetGraphicsDisplay()->GetGpuDevice()->GetGpuInfo().GetMaxFboAttachment()*/; i++)
00065     {
00066       _Color_AttachmentArray[i] = ObjectPtr<IOpenGLSurface> (0);
00067     }
00068 
00069     _Depth_Attachment = ObjectPtr<IOpenGLSurface> (0);
00070     _Stencil_Attachment = ObjectPtr<IOpenGLSurface> (0);
00071 
00072     if ((_Width == Width) && (_Height == Height) && (_PixelFormat == PixelFormat))
00073       return 1;
00074 
00075 // #ifndef NUX_OPENGLES_20
00076 //     _Rbo.Set(GL_DEPTH_COMPONENT, Width, Height);
00077 // #endif
00078 
00079     // Clear clipping region stack
00080     _Width  = Width;
00081     _Height = Height;
00082     _PixelFormat = PixelFormat;
00083     EmptyClippingRegion();
00084     
00085     return 1;
00086   }
00087 
00088   int IOpenGLFrameBufferObject::SetRenderTarget(int ColorAttachmentIndex, ObjectPtr<IOpenGLSurface> pRenderTargetSurface)
00089   {
00090     nuxAssert(ColorAttachmentIndex < 1 /*GetGraphicsDisplay()->GetGpuDevice()->GetGpuInfo().GetMaxFboAttachment()*/);
00091 
00092     if (pRenderTargetSurface.IsNull())
00093     {
00094       _Color_AttachmentArray[ColorAttachmentIndex] = ObjectPtr<IOpenGLSurface> (0);
00095       return 1;
00096     }
00097 
00098     if (_Color_AttachmentArray[ColorAttachmentIndex] == pRenderTargetSurface)
00099     {
00100       return 1;
00101     }
00102 
00103     if (! (_Width == pRenderTargetSurface->GetWidth() && _Height == pRenderTargetSurface->GetHeight()))
00104     {
00105       nuxAssertMsg(0, "[IOpenGLFrameBufferObject::SetRenderTarget] Invalid surface size.");
00106       return 0;
00107     }
00108 
00109     _Color_AttachmentArray[ColorAttachmentIndex] = pRenderTargetSurface;
00110 
00111     if (_IsActive)
00112     {
00113       Activate();
00114     }
00115 
00116     return 1;
00117   }
00118 
00119   int IOpenGLFrameBufferObject::SetDepthSurface(ObjectPtr<IOpenGLSurface> pDepthSurface)
00120   {
00121     //nuxAssert(pDepthSurface.IsValid());
00122 
00123     if (pDepthSurface.IsNull())
00124     {
00125       _Depth_Attachment = ObjectPtr<IOpenGLSurface> (0);
00126       _Stencil_Attachment = ObjectPtr<IOpenGLSurface> (0);
00127       return 1;
00128     }
00129 
00130     if (! (_Width == pDepthSurface->GetWidth() && _Height == pDepthSurface->GetHeight()))
00131     {
00132       nuxAssertMsg(0, "The depth surface size is not compatible with the frame buffer size.");
00133       return 0;
00134     }
00135 
00136     if (_Depth_Attachment == pDepthSurface)
00137       return 1;
00138 
00139     // We rely on the fact that the depth texture is actually a D24_S8 texture.
00140     // That is, the surface for the depth and stencil attachment is the same. When we bound, the surface,
00141     // we explicitly bind the depth attachment and the stencil attachment with the same surface.
00142     _Depth_Attachment = pDepthSurface;
00143     _Stencil_Attachment = pDepthSurface;
00144 
00145     if (_IsActive)
00146     {
00147       Activate();
00148     }
00149 
00150     return 1;
00151   }
00152 
00153   ObjectPtr<IOpenGLSurface> IOpenGLFrameBufferObject::GetRenderTarget(int ColorAttachmentIndex)
00154   {
00155     nuxAssert(ColorAttachmentIndex < 1 /*GetGraphicsDisplay()->GetGpuDevice()->GetGpuInfo().GetMaxFboAttachment()*/);
00156     return _Color_AttachmentArray[ColorAttachmentIndex];
00157   }
00158 
00159   ObjectPtr<IOpenGLSurface> IOpenGLFrameBufferObject::GetDepthRenderTarget()
00160   {
00161     return _Depth_Attachment;
00162   }
00163 
00164   int IOpenGLFrameBufferObject::Activate(bool WithClippingStack)
00165   {
00166     GLuint NumBuffers = 0;
00167     _Fbo.Bind();
00168 
00169     if (GetGraphicsDisplay()->GetGpuDevice())
00170       GetGraphicsDisplay()->GetGpuDevice()->SetCurrentFrameBufferObject(ObjectPtr<IOpenGLFrameBufferObject> (this));
00171 
00172     for (int i = 0; i < 1 /*GetGraphicsDisplay()->GetGpuDevice()->GetGpuInfo().GetMaxFboAttachment()*/; i++)
00173     {
00174       if (_Color_AttachmentArray[i].IsValid())
00175       {
00176         GLenum target   = _Color_AttachmentArray[i]->GetSurfaceTarget();
00177         GLenum glID     = _Color_AttachmentArray[i]->GetOpenGLID();
00178         GLint level     = _Color_AttachmentArray[i]->GetMipLevel();
00179         CHECKGL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, target, glID, level));
00180 
00181 #ifndef NUX_OPENGLES_20
00182         CHECKGL(glDrawBuffer(GL_COLOR_ATTACHMENT0 + i));
00183 #endif
00184         NumBuffers++;
00185       }
00186       else
00187       {
00188         CHECKGL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, 0, 0));
00189       }
00190     }
00191 
00192     if (_Depth_Attachment.IsValid())
00193     {
00194         GLenum target   = _Depth_Attachment->GetSurfaceTarget();
00195         GLenum glID     = _Depth_Attachment->GetOpenGLID();
00196         GLint level     = _Depth_Attachment->GetMipLevel();
00197         CHECKGL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, target, glID, level));
00198     }
00199     else
00200     {
00201         CHECKGL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
00202         // On the PC you need to bing the same D24S8 surface to the depth and the stencil attachment.
00203     }
00204 
00205 // #ifndef NUX_OPENGLES_20
00206 //     _Rbo.Set(GL_DEPTH_COMPONENT, _Width, _Height);
00207 //     CHECKGL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
00208 //                                             GL_DEPTH_ATTACHMENT_EXT,
00209 //                                             GL_RENDERBUFFER_EXT,
00210 //                                             _Rbo.GetId()));
00211 // #endif
00212 
00213     nuxAssert( _Fbo.IsValid() == true );
00214 
00215     if (GetGraphicsDisplay()->GetGraphicsEngine())
00216       GetGraphicsDisplay()->GetGraphicsEngine()->SetViewport(0, 0, _Width, _Height);
00217 
00218     if (WithClippingStack)
00219       ApplyClippingRegion();
00220 
00221     _IsActive = true;
00222     return 1;
00223   }
00224 
00225 // Restore the original opengl back buffer as defined when creating the opengl context(color + depth + stencil).
00226   int IOpenGLFrameBufferObject::Deactivate()
00227   {
00228     CHECKGL(glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ));
00229 
00230 #ifndef NUX_OPENGLES_20
00231     CHECKGL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
00232 #endif
00233 
00234     if (GetGraphicsDisplay()->GetGpuDevice())
00235       GetGraphicsDisplay()->GetGpuDevice()->SetCurrentFrameBufferObject(ObjectPtr<IOpenGLFrameBufferObject> (0));
00236 
00237     if (GetGraphicsDisplay()->GetGraphicsEngine())
00238       GetGraphicsDisplay()->GetGraphicsEngine()->SetScissor(0, 0, _Width, _Height);
00239 
00240     _IsActive = false;
00241     return 1;
00242   }
00243 
00244   void IOpenGLFrameBufferObject::PushClippingRegion(Rect rect)
00245   {
00246     Rect r0;
00247     if (GetGraphicsDisplay()->GetGraphicsEngine())
00248     {
00249       r0 = GetGraphicsDisplay()->GetGraphicsEngine()->ModelViewXFormRect(rect);
00250     }
00251 
00252     Rect current_clip_rect;
00253     unsigned int stacksize = (unsigned int) _ClippingRegionStack.size();
00254 
00255     if (stacksize == 0)
00256     {
00257       current_clip_rect = Rect(0, 0, _Width, _Height);
00258     }
00259     else
00260     {
00261       current_clip_rect = _ClippingRegionStack[stacksize-1];
00262     }
00263 
00264     Rect r1;
00265 
00266     if (GetGraphicsDisplay()->GetGraphicsEngine())
00267       r1 = GetGraphicsDisplay()->GetGraphicsEngine()->GetViewportRect();
00268 
00269     r0.OffsetPosition(r1.x, _Height - (r1.y + r1.GetHeight()));
00270 
00271     Rect Intersection = current_clip_rect.Intersect(r0);
00272 
00273     if (!Intersection.IsNull())
00274     {
00275       _clipping_rect = Intersection;
00276       _ClippingRegionStack.push_back(Intersection);
00277 
00278       SetOpenGLClippingRectangle(Intersection.x + GetGraphicsDisplay()->GetGraphicsEngine()->GetViewportX(),
00279                          _Height - Intersection.y - Intersection.GetHeight() - GetGraphicsDisplay()->GetGraphicsEngine()->GetViewportY(),
00280                          Intersection.GetWidth(), Intersection.GetHeight());
00281     }
00282     else
00283     {
00284       _clipping_rect = Rect(0, 0, 0, 0);
00285       _ClippingRegionStack.push_back(Rect(0, 0, 0, 0));
00286       SetOpenGLClippingRectangle(0, 0, 0, 0);
00287     }
00288   }
00289 
00290   void IOpenGLFrameBufferObject::PopClippingRegion()
00291   {
00292     _ClippingRegionStack.pop_back();
00293     int stacksize = (int) _ClippingRegionStack.size();
00294 
00295     if (stacksize == 0)
00296     {
00297       _clipping_rect = Rect(0, 0, _Width, _Height);
00298       SetOpenGLClippingRectangle(0, 0, _Width, _Height);
00299     }
00300     else
00301     {
00302       _clipping_rect = _ClippingRegionStack [stacksize-1];
00303       Rect current_clip_rect = _ClippingRegionStack [stacksize-1];
00304       SetOpenGLClippingRectangle(current_clip_rect.x, _Height - current_clip_rect.y - current_clip_rect.GetHeight(), current_clip_rect.GetWidth(), current_clip_rect.GetHeight());
00305     }
00306   }
00307 
00308   void IOpenGLFrameBufferObject::EmptyClippingRegion()
00309   {
00310     _ClippingRegionStack.clear();
00311     {
00312       _clipping_rect = Rect(0, 0, _Width, _Height);
00313       SetOpenGLClippingRectangle(0, 0, _Width, _Height);
00314     }
00315   }
00316 
00317   void IOpenGLFrameBufferObject::ApplyClippingRegion()
00318   {
00319     int stacksize = (int) _ClippingRegionStack.size();
00320 
00321     if (stacksize == 0)
00322     {
00323       _clipping_rect = Rect(0, 0, _Width, _Height);
00324       SetOpenGLClippingRectangle(0, 0, _Width, _Height);
00325     }
00326     else
00327     {
00328       _clipping_rect = _ClippingRegionStack [stacksize-1];
00329       Rect current_clip_rect = _ClippingRegionStack [stacksize-1];
00330       SetOpenGLClippingRectangle(current_clip_rect.x, _Height - current_clip_rect.y - current_clip_rect.GetHeight(), current_clip_rect.GetWidth(), current_clip_rect.GetHeight());
00331     }
00332   }
00333 
00334   void IOpenGLFrameBufferObject::SetClippingRectangle(const Rect &rect)
00335   {
00336     if (GetGraphicsDisplay()->GetGraphicsEngine())
00337     {
00338       _clipping_rect = rect;
00339       GetGraphicsDisplay()->GetGraphicsEngine()->SetScissor(rect.x, _Height - rect.y - rect.height, rect.width, rect.height);
00340     }
00341   }
00342 
00343   void IOpenGLFrameBufferObject::SetOpenGLClippingRectangle(int x, int y, int width, int height)
00344   {
00345     if (GetGraphicsDisplay()->GetGraphicsEngine())
00346     {
00347       _clipping_rect = Rect(x, y, width, height);
00348       GetGraphicsDisplay()->GetGraphicsEngine()->SetScissor(x, y, width, height);
00349     }
00350   }
00351 
00352   Rect IOpenGLFrameBufferObject::GetClippingRegion()
00353   {
00354     return _clipping_rect;
00355 
00356 //     unsigned int stacksize = (unsigned int) _ClippingRegionStack.size();
00357 // 
00358 //     if (stacksize == 0)
00359 //     {
00360 //       return Rect(0, 0, _Width, _Height);
00361 //     }
00362 //     else
00363 //     {
00364 //       Rect r = _ClippingRegionStack [stacksize-1];
00365 //       return r;
00366 //     }
00367   }
00368 
00369   int IOpenGLFrameBufferObject::GetNumberOfClippingRegions() const
00370   {
00371     return _ClippingRegionStack.size();
00372   }
00373 }
00374