0024225: TKOpenGL, OpenGl_FrameBuffer - Wrong ID is used for attachement of depth...
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2011-2012 OPEN CASCADE SAS
3 //
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
8 //
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11 //
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
18
19
20 #include <OpenGl_FrameBuffer.hxx>
21
22 #ifdef DEB
23   #include <iostream>
24 #endif
25
26 static inline bool isOddNumber (const GLsizei theNumber)
27 {
28   return theNumber & 0x01;
29 }
30
31 static inline GLsizei getEvenNumber (const GLsizei theNumber)
32 {
33   return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
34 }
35
36 //! Notice - 0 is not power of two here
37 static inline bool isPowerOfTwo (const GLsizei theNumber)
38 {
39         return !(theNumber & (theNumber - 1));
40 }
41
42 OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
43 : mySizeX (0),
44   mySizeY (0),
45   myVPSizeX (0),
46   myVPSizeY (0),
47   myTextFormat (theTextureFormat),
48   myGlTextureId (NO_TEXTURE),
49   myGlFBufferId (NO_FRAMEBUFFER),
50   myGlDepthRBId (NO_RENDERBUFFER)
51 {
52   //
53 }
54
55 Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
56                                            GLsizei theViewportSizeX,
57                                            GLsizei theViewportSizeY,
58                                            GLboolean toForcePowerOfTwo)
59 {
60   if (theGlContext->extFBO == NULL)
61   {
62   #ifdef DEB
63     std::cerr << "OpenGl_FrameBuffer, FBO extension not supported!\n";
64   #endif
65     return Standard_False;
66   }
67
68   // clean up previous state
69   Release (theGlContext);
70
71   // upscale width/height if numbers are odd
72   if (toForcePowerOfTwo)
73   {
74     mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize());
75     mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize());
76   }
77   else
78   {
79     mySizeX = getEvenNumber (theViewportSizeX);
80     mySizeY = getEvenNumber (theViewportSizeY);
81   }
82
83   // setup viewport sizes as is
84   myVPSizeX = theViewportSizeX;
85   myVPSizeY = theViewportSizeY;
86
87   // Create the texture (will be used as color buffer)
88   if (!InitTrashTexture (theGlContext))
89   {
90     if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
91     {
92       return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
93     }
94     Release (theGlContext);
95     return Standard_False;
96   }
97
98   // Create RenderBuffer (will be used as depth buffer)
99   theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
100   theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
101   theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
102
103   // Build FBO and setup it as texture
104   theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
105   theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
106   glEnable (GL_TEXTURE_2D);
107   glBindTexture (GL_TEXTURE_2D, myGlTextureId);
108   theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
109   theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId);
110   if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
111   {
112     if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
113     {
114       return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
115     }
116     Release (theGlContext);
117     return Standard_False;
118   }
119
120   UnbindBuffer (theGlContext);
121   UnbindTexture();
122   theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
123
124   #ifdef DEB
125     std::cerr << "OpenGl_FrameBuffer, created FBO " << mySizeX << "x" << mySizeY
126               << " for viewport " << theViewportSizeX << "x" << theViewportSizeY << "\n";
127   #endif
128   return Standard_True;
129 }
130
131 void OpenGl_FrameBuffer::Release (const Handle(OpenGl_Context)& theGlContext)
132 {
133   if (IsValidDepthBuffer())
134   {
135     if (!theGlContext.IsNull() && theGlContext->extFBO != NULL)
136     {
137       theGlContext->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
138       myGlDepthRBId = NO_RENDERBUFFER;
139     }
140     else
141     {
142       std::cerr << "OpenGl_FrameBuffer::Release() called with invalid OpenGl_Context!\n";
143     }
144   }
145   if (IsValidTexture())
146   {
147     glDeleteTextures (1, &myGlTextureId);
148     myGlTextureId = NO_TEXTURE;
149   }
150   mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
151   if (IsValidFrameBuffer())
152   {
153     if (!theGlContext.IsNull() && theGlContext->extFBO != NULL)
154     {
155       theGlContext->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
156       myGlFBufferId = NO_FRAMEBUFFER;
157     }
158     else
159     {
160       std::cerr << "OpenGl_FrameBuffer::Release() called with invalid OpenGl_Context!\n";
161     }
162   }
163 }
164
165 Standard_Boolean OpenGl_FrameBuffer::IsProxySuccess() const
166 {
167   // use proxy to check texture could be created or not
168   glTexImage2D (GL_PROXY_TEXTURE_2D,
169                 0,                // LOD number: 0 - base image level; n is the nth mipmap reduction image
170                 myTextFormat,     // internalformat
171                 mySizeX, mySizeY, 0,
172                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
173   GLint aTestParamX (0), aTestParamY (0);
174   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
175   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
176   return aTestParamX != 0 && aTestParamY != 0;
177 }
178
179 Standard_Boolean OpenGl_FrameBuffer::InitTrashTexture (const Handle(OpenGl_Context)& theGlContext)
180 {
181   // Check texture size is fit dimension maximum
182   GLint aMaxTexDim = 2048;
183   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
184   if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
185   {
186     return Standard_False;
187   }
188
189   // generate new id
190   glEnable (GL_TEXTURE_2D);
191   if (!IsValidTexture())
192   {
193     glGenTextures (1, &myGlTextureId); // Create The Texture
194   }
195   glBindTexture (GL_TEXTURE_2D, myGlTextureId);
196
197   // texture interpolation parameters - could be overridden later
198   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
199   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
200
201   if (!IsProxySuccess())
202   {
203     Release (theGlContext);
204     return Standard_False;
205   }
206
207   glTexImage2D (GL_TEXTURE_2D,
208                 0,                // LOD number: 0 - base image level; n is the nth mipmap reduction image
209                 myTextFormat,     // internalformat
210                 mySizeX, mySizeY, 0,
211                 GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
212   return Standard_True;
213 }