7fd59977 |
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 | } |