fba0cb768916ed6f5920d851675cf148c8ec8b67
[occt.git] / src / OpenGl / OpenGl_FrameBuffer.cxx
1 #include <OpenGl_FrameBuffer.hxx>
2
3 #ifdef DEB
4   #include <iostream>
5 #endif
6
7 #ifndef WNT
8   #define glGetProcAddress( x )  glXGetProcAddress( (const GLubyte*) x )
9 #else
10   #define glGetProcAddress( x )  wglGetProcAddress( x )
11 #endif
12
13 static inline bool isOddNumber (const GLsizei theNumber)
14 {
15   return theNumber & 0x01;
16 }
17
18 static inline GLsizei getEvenNumber (const GLsizei theNumber)
19 {
20   return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
21 }
22
23 //! Notice - 0 is not power of two here
24 static inline bool isPowerOfTwo (const GLsizei theNumber)
25 {
26         return !(theNumber & (theNumber - 1));
27 }
28
29 static inline GLsizei getPowerOfTwo (const GLsizei theNumber,
30                                      const GLsizei theThreshold)
31 {
32   for (GLsizei p2 = 2; p2 <= theThreshold; p2 <<= 1)
33   {
34     if (theNumber <= p2)
35     {
36       return p2;
37     }
38   }
39   return theThreshold;
40 }
41
42 Standard_Boolean OpenGl_FrameBuffer::AreFBOFunctionsValid()
43 {
44   return glGenFramebuffersEXT != NULL
45       && glDeleteFramebuffersEXT != NULL
46       && glBindFramebufferEXT != NULL
47       && glFramebufferTexture2DEXT != NULL
48       && glCheckFramebufferStatusEXT != NULL
49       && glGenRenderbuffersEXT != NULL
50       && glBindRenderbufferEXT != NULL
51       && glDeleteRenderbuffersEXT != NULL
52       && glRenderbufferStorageEXT != NULL
53       && glFramebufferRenderbufferEXT != NULL;
54 }
55
56 Standard_Boolean OpenGl_FrameBuffer::InitFBOFunctions()
57 {
58   if (AreFBOFunctionsValid())
59   {
60     return Standard_True;
61   }
62   if (CheckExtension ((char *)"GL_EXT_framebuffer_object", (const char *)glGetString (GL_EXTENSIONS)))
63   {
64     glGenFramebuffersEXT         = (glGenFramebuffersEXT_t)        glGetProcAddress ("glGenFramebuffersEXT");
65     glDeleteFramebuffersEXT      = (glDeleteFramebuffersEXT_t)     glGetProcAddress ("glDeleteFramebuffersEXT");
66     glBindFramebufferEXT         = (glBindFramebufferEXT_t)        glGetProcAddress ("glBindFramebufferEXT");
67     glFramebufferTexture2DEXT    = (glFramebufferTexture2DEXT_t)   glGetProcAddress ("glFramebufferTexture2DEXT");
68     glCheckFramebufferStatusEXT  = (glCheckFramebufferStatusEXT_t) glGetProcAddress ("glCheckFramebufferStatusEXT");
69     glGenRenderbuffersEXT        = (glGenRenderbuffersEXT_t)       glGetProcAddress ("glGenRenderbuffersEXT");
70     glDeleteRenderbuffersEXT     = (glDeleteRenderbuffersEXT_t)    glGetProcAddress ("glDeleteRenderbuffersEXT");
71     glBindRenderbufferEXT        = (glBindRenderbufferEXT_t)       glGetProcAddress ("glBindRenderbufferEXT");
72     glRenderbufferStorageEXT     = (glRenderbufferStorageEXT_t)    glGetProcAddress ("glRenderbufferStorageEXT");
73     glFramebufferRenderbufferEXT = (glFramebufferRenderbufferEXT_t)glGetProcAddress ("glFramebufferRenderbufferEXT");
74     return AreFBOFunctionsValid();
75   }
76   return Standard_False;
77 }
78
79 OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
80 : mySizeX (0),
81   mySizeY (0),
82   myVPSizeX (0),
83   myVPSizeY (0),
84   myTextFormat (theTextureFormat),
85   myGlTextureId (NO_TEXTURE),
86   myGlFBufferId (NO_FRAMEBUFFER),
87   myGlDepthRBId (NO_RENDERBUFFER),
88   glGenFramebuffersEXT (NULL),
89   glDeleteFramebuffersEXT (NULL),
90   glBindFramebufferEXT (NULL),
91   glFramebufferTexture2DEXT (NULL),
92   glCheckFramebufferStatusEXT (NULL),
93   glGenRenderbuffersEXT (NULL),
94   glDeleteRenderbuffersEXT (NULL),
95   glBindRenderbufferEXT (NULL),
96   glRenderbufferStorageEXT (NULL),
97   glFramebufferRenderbufferEXT (NULL)
98 {
99   //
100 }
101
102 Standard_Boolean OpenGl_FrameBuffer::Init (GLsizei theViewportSizeX,
103                                            GLsizei theViewportSizeY,
104                                            GLboolean toForcePowerOfTwo)
105 {
106   if (!InitFBOFunctions())
107   {
108   #ifdef DEB
109     std::cerr << "OpenGl_FrameBuffer, FBO extension not supported!\n";
110   #endif
111     return Standard_False;
112   }
113
114   // clean up previous state
115   Release();
116
117   // upscale width/height if numbers are odd
118   if (toForcePowerOfTwo)
119   {
120     GLint aMaxTexDim = 2048;
121     glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
122     mySizeX = getPowerOfTwo (theViewportSizeX, aMaxTexDim);
123     mySizeY = getPowerOfTwo (theViewportSizeY, aMaxTexDim);
124   }
125   else
126   {
127     mySizeX = getEvenNumber (theViewportSizeX);
128     mySizeY = getEvenNumber (theViewportSizeY);
129   }
130
131   // setup viewport sizes as is
132   myVPSizeX = theViewportSizeX;
133   myVPSizeY = theViewportSizeY;
134
135   // Create the texture (will be used as color buffer)
136   if (!InitTrashTexture())
137   {
138     if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
139     {
140       return Init (theViewportSizeX, theViewportSizeY, GL_TRUE);
141     }
142     Release();
143     return Standard_False;
144   }
145
146   // Create RenderBuffer (will be used as depth buffer)
147   glGenRenderbuffersEXT (1, &myGlDepthRBId);
148   glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
149   glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
150
151   // Build FBO and setup it as texture
152   glGenFramebuffersEXT (1, &myGlFBufferId);
153   glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
154   glEnable (GL_TEXTURE_2D);
155   glBindTexture (GL_TEXTURE_2D, myGlTextureId);
156   glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
157   glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlFBufferId);
158   if (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
159   {
160     if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
161     {
162       return Init (theViewportSizeX, theViewportSizeY, GL_TRUE);
163     }
164     Release();
165     return Standard_False;
166   }
167
168   UnbindBuffer();
169   UnbindTexture();
170   glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
171
172   #ifdef DEB
173     std::cerr << "OpenGl_FrameBuffer, created FBO " << mySizeX << "x" << mySizeY
174               << " for viewport " << theViewportSizeX << "x" << theViewportSizeY << "\n";
175   #endif
176   return Standard_True;
177 }
178
179 void OpenGl_FrameBuffer::Release()
180 {
181   if (IsValidDepthBuffer())
182   {
183     glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
184     myGlDepthRBId = NO_RENDERBUFFER;
185   }
186   if (IsValidTexture())
187   {
188     glDeleteTextures (1, &myGlTextureId);
189     myGlTextureId = NO_TEXTURE;
190   }
191   mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
192   if (IsValidFrameBuffer())
193   {
194     glDeleteFramebuffersEXT (1, &myGlFBufferId);
195     myGlFBufferId = NO_FRAMEBUFFER;
196   }
197 }
198
199 Standard_Boolean OpenGl_FrameBuffer::IsProxySuccess() const
200 {
201   // use proxy to check texture could be created or not
202   glTexImage2D (GL_PROXY_TEXTURE_2D,
203                 0,                // LOD number: 0 - base image level; n is the nth mipmap reduction image
204                 myTextFormat,     // internalformat
205                 mySizeX, mySizeY, 0,
206                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
207   GLint aTestParamX (0), aTestParamY (0);
208   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
209   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
210   return aTestParamX != 0 && aTestParamY != 0;
211 }
212
213 Standard_Boolean OpenGl_FrameBuffer::InitTrashTexture()
214 {
215   // Check texture size is fit dimension maximum
216   GLint aMaxTexDim = 2048;
217   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
218   if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
219   {
220     return Standard_False;
221   }
222
223   // generate new id
224   glEnable (GL_TEXTURE_2D);
225   if (!IsValidTexture())
226   {
227     glGenTextures (1, &myGlTextureId); // Create The Texture
228   }
229   glBindTexture (GL_TEXTURE_2D, myGlTextureId);
230
231   // texture interpolation parameters - could be overridden later
232   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
233   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
234
235   if (!IsProxySuccess())
236   {
237     Release();
238     return Standard_False;
239   }
240
241   glTexImage2D (GL_TEXTURE_2D,
242                 0,                // LOD number: 0 - base image level; n is the nth mipmap reduction image
243                 myTextFormat,     // internalformat
244                 mySizeX, mySizeY, 0,
245                 GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
246   return Standard_True;
247 }