bf75be98 |
1 | // Created by: Kirill GAVRILOV |
2 | // Copyright (c) 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 | #include <OpenGl_Texture.hxx> |
20 | |
1a7dfdb7 |
21 | #include <OpenGl_ExtFBO.hxx> |
bf75be98 |
22 | #include <OpenGl_Context.hxx> |
23 | #include <Graphic3d_TextureParams.hxx> |
24 | #include <Standard_Assert.hxx> |
25 | #include <Image_PixMap.hxx> |
26 | |
27 | IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource) |
28 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource) |
29 | |
bf75be98 |
30 | // ======================================================================= |
31 | // function : OpenGl_Texture |
32 | // purpose : |
33 | // ======================================================================= |
34 | OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams) |
35 | : OpenGl_Resource(), |
36 | myTextureId (NO_TEXTURE), |
37 | myTarget (GL_TEXTURE_2D), |
38 | mySizeX (0), |
39 | mySizeY (0), |
40 | myTextFormat (GL_FLOAT), |
41 | myHasMipmaps (Standard_False), |
42 | myParams (theParams) |
43 | { |
44 | if (myParams.IsNull()) |
45 | { |
46 | myParams = new Graphic3d_TextureParams(); |
47 | } |
48 | } |
49 | |
50 | // ======================================================================= |
51 | // function : ~OpenGl_Texture |
52 | // purpose : |
53 | // ======================================================================= |
54 | OpenGl_Texture::~OpenGl_Texture() |
55 | { |
56 | Release (NULL); |
57 | } |
58 | |
59 | // ======================================================================= |
60 | // function : HasMipmaps |
61 | // purpose : |
62 | // ======================================================================= |
63 | const Standard_Boolean OpenGl_Texture::HasMipmaps() const |
64 | { |
65 | return myHasMipmaps; |
66 | } |
67 | |
68 | // ======================================================================= |
69 | // function : GetParams |
70 | // purpose : |
71 | // ======================================================================= |
72 | const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const |
73 | { |
74 | return myParams; |
75 | } |
76 | |
77 | // ======================================================================= |
78 | // function : SetParams |
79 | // purpose : |
80 | // ======================================================================= |
81 | void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams) |
82 | { |
83 | myParams = theParams; |
84 | } |
85 | |
86 | // ======================================================================= |
87 | // function : Create |
88 | // purpose : |
89 | // ======================================================================= |
90 | bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& ) |
91 | { |
92 | if (myTextureId == NO_TEXTURE) |
93 | { |
94 | glGenTextures (1, &myTextureId); |
95 | } |
96 | return myTextureId != NO_TEXTURE; |
97 | } |
98 | |
99 | // ======================================================================= |
100 | // function : Release |
101 | // purpose : |
102 | // ======================================================================= |
103 | void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx) |
104 | { |
105 | if (myTextureId == NO_TEXTURE) |
106 | { |
107 | return; |
108 | } |
109 | |
110 | // application can not handle this case by exception - this is bug in code |
111 | Standard_ASSERT_RETURN (theGlCtx != NULL, |
112 | "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",); |
113 | |
ec2eeb2d |
114 | if (theGlCtx->IsValid()) |
115 | { |
116 | glDeleteTextures (1, &myTextureId); |
117 | } |
bf75be98 |
118 | myTextureId = NO_TEXTURE; |
119 | mySizeX = mySizeY = 0; |
120 | } |
121 | |
122 | // ======================================================================= |
123 | // function : Bind |
124 | // purpose : |
125 | // ======================================================================= |
126 | void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx, |
127 | const GLenum theTextureUnit) const |
128 | { |
129 | if (theCtx->IsGlGreaterEqual (1, 3)) |
130 | { |
131 | theCtx->core13->glActiveTexture (theTextureUnit); |
132 | } |
133 | glBindTexture (myTarget, myTextureId); |
134 | } |
135 | |
136 | // ======================================================================= |
137 | // function : Unbind |
138 | // purpose : |
139 | // ======================================================================= |
140 | void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx, |
141 | const GLenum theTextureUnit) const |
142 | { |
143 | if (theCtx->IsGlGreaterEqual (1, 3)) |
144 | { |
145 | theCtx->core13->glActiveTexture (theTextureUnit); |
146 | } |
147 | glBindTexture (myTarget, NO_TEXTURE); |
148 | } |
149 | |
150 | // ======================================================================= |
151 | // function : Init |
152 | // purpose : |
153 | // ======================================================================= |
154 | bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, |
155 | const Image_PixMap& theImage, |
156 | const Graphic3d_TypeOfTexture theType) |
157 | { |
158 | myHasMipmaps = Standard_False; |
159 | if (theImage.IsEmpty() || !Create (theCtx)) |
160 | { |
161 | return false; |
162 | } |
163 | |
a577aaab |
164 | myTextFormat = GL_RGBA8; |
165 | GLenum aPixelFormat = 0; |
166 | GLenum aDataType = 0; |
bf75be98 |
167 | switch (theImage.Format()) |
168 | { |
169 | case Image_PixMap::ImgGrayF: |
170 | { |
a577aaab |
171 | myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F |
172 | aPixelFormat = GL_ALPHA; // GL_RED |
173 | aDataType = GL_FLOAT; |
bf75be98 |
174 | break; |
175 | } |
176 | case Image_PixMap::ImgRGBAF: |
177 | { |
a577aaab |
178 | myTextFormat = GL_RGBA8; // GL_RGBA32F |
179 | aPixelFormat = GL_RGBA; |
180 | aDataType = GL_FLOAT; |
bf75be98 |
181 | break; |
182 | } |
183 | case Image_PixMap::ImgBGRAF: |
184 | { |
185 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
186 | { |
187 | return false; |
188 | } |
a577aaab |
189 | myTextFormat = GL_RGBA8; // GL_RGBA32F |
190 | aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT |
191 | aDataType = GL_FLOAT; |
bf75be98 |
192 | break; |
193 | } |
194 | case Image_PixMap::ImgRGBF: |
195 | { |
a577aaab |
196 | myTextFormat = GL_RGB8; // GL_RGB32F |
197 | aPixelFormat = GL_RGB; |
198 | aDataType = GL_FLOAT; |
bf75be98 |
199 | break; |
200 | } |
201 | case Image_PixMap::ImgBGRF: |
202 | { |
a577aaab |
203 | myTextFormat = GL_RGB8; // GL_RGB32F |
204 | aPixelFormat = GL_BGR; // equals to GL_BGR_EXT |
205 | aDataType = GL_FLOAT; |
bf75be98 |
206 | break; |
207 | } |
208 | case Image_PixMap::ImgRGBA: |
209 | { |
a577aaab |
210 | myTextFormat = GL_RGBA8; |
211 | aPixelFormat = GL_RGBA; |
212 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
213 | break; |
214 | } |
215 | case Image_PixMap::ImgBGRA: |
216 | { |
217 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
218 | { |
219 | return false; |
220 | } |
a577aaab |
221 | myTextFormat = GL_RGBA8; |
222 | aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT |
223 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
224 | break; |
225 | } |
226 | case Image_PixMap::ImgRGB32: |
227 | { |
a577aaab |
228 | myTextFormat = GL_RGB8; |
229 | aPixelFormat = GL_RGBA; |
230 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
231 | break; |
232 | } |
233 | case Image_PixMap::ImgBGR32: |
234 | { |
235 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
236 | { |
237 | return false; |
238 | } |
a577aaab |
239 | myTextFormat = GL_RGB8; |
240 | aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT |
241 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
242 | break; |
243 | } |
244 | case Image_PixMap::ImgRGB: |
245 | { |
a577aaab |
246 | myTextFormat = GL_RGB8; |
247 | aPixelFormat = GL_RGB; |
248 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
249 | break; |
250 | } |
251 | case Image_PixMap::ImgBGR: |
252 | { |
253 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
254 | { |
255 | return false; |
256 | } |
a577aaab |
257 | myTextFormat = GL_RGB8; |
258 | aPixelFormat = GL_BGR; // equals to GL_BGR_EXT |
259 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
260 | break; |
261 | } |
262 | case Image_PixMap::ImgGray: |
263 | { |
a577aaab |
264 | myTextFormat = GL_ALPHA8; // GL_R8 |
265 | aPixelFormat = GL_ALPHA; // GL_RED |
266 | aDataType = GL_UNSIGNED_BYTE; |
bf75be98 |
267 | break; |
268 | } |
269 | default: |
270 | { |
271 | return false; |
272 | } |
273 | } |
274 | |
275 | const GLsizei aMaxSize = theCtx->MaxTextureSize(); |
276 | const GLsizei aWidth = (GLsizei )theImage.SizeX(); |
277 | const GLsizei aHeight = (GLsizei )theImage.SizeY(); |
278 | |
279 | // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications |
280 | // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT! |
281 | // Trying to create NPOT rextures on such hardware will not fail |
282 | // but driver will fall back into software rendering, |
283 | const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW; |
a174a3c5 |
284 | const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize); |
285 | const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize); |
bf75be98 |
286 | |
287 | GLint aTestWidth = 0; |
288 | GLint aTestHeight = 0; |
289 | |
290 | glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // ensure alignment will not screw up the party |
291 | switch (theType) |
292 | { |
293 | case Graphic3d_TOT_1D: |
294 | { |
295 | myTarget = GL_TEXTURE_1D; |
296 | Bind (theCtx); |
297 | glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
298 | glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
299 | |
300 | Image_PixMap aCopy; |
301 | GLvoid* aDataPtr = (GLvoid* )theImage.Data(); |
302 | if (aWidth != aWidthOut) |
303 | { |
304 | if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1) |
305 | || gluScaleImage (aPixelFormat, |
306 | aWidth, 1, aDataType, theImage.Data(), |
307 | aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0) |
308 | { |
309 | Unbind (theCtx); |
310 | return false; |
311 | } |
312 | |
313 | aDataPtr = (GLvoid* )aCopy.Data(); |
314 | } |
315 | |
316 | // use proxy to check texture could be created or not |
a577aaab |
317 | glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat, |
bf75be98 |
318 | aWidthOut, 0, |
319 | aPixelFormat, aDataType, NULL); |
320 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
321 | if (aTestWidth == 0) |
322 | { |
323 | // no memory or broken input parameters |
324 | Unbind (theCtx); |
325 | return false; |
326 | } |
327 | |
a577aaab |
328 | glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat, |
bf75be98 |
329 | aWidthOut, 0, |
330 | aPixelFormat, aDataType, aDataPtr); |
a174a3c5 |
331 | if (glGetError() != GL_NO_ERROR) |
332 | { |
333 | Unbind (theCtx); |
334 | return false; |
335 | } |
336 | |
337 | mySizeX = aWidthOut; |
338 | mySizeY = 1; |
bf75be98 |
339 | |
340 | Unbind (theCtx); |
341 | return true; |
342 | } |
343 | case Graphic3d_TOT_2D: |
344 | { |
345 | myTarget = GL_TEXTURE_2D; |
346 | Bind (theCtx); |
347 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
348 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
349 | |
350 | Image_PixMap aCopy; |
351 | GLvoid* aDataPtr = (GLvoid* )theImage.Data(); |
352 | if (aWidth != aWidthOut || aHeight != aHeightOut) |
353 | { |
354 | // scale texture |
bf75be98 |
355 | if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut)) |
356 | || gluScaleImage (aPixelFormat, |
357 | aWidth, aHeight, aDataType, theImage.Data(), |
358 | aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0) |
359 | { |
360 | Unbind (theCtx); |
361 | return false; |
362 | } |
363 | |
364 | aDataPtr = (GLvoid* )aCopy.Data(); |
365 | } |
366 | |
367 | // use proxy to check texture could be created or not |
a577aaab |
368 | glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat, |
bf75be98 |
369 | aWidthOut, aHeightOut, 0, |
370 | aPixelFormat, aDataType, NULL); |
371 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
372 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight); |
373 | if (aTestWidth == 0 || aTestHeight == 0) |
374 | { |
375 | // no memory or broken input parameters |
376 | Unbind (theCtx); |
377 | return false; |
378 | } |
379 | |
a577aaab |
380 | glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat, |
bf75be98 |
381 | aWidthOut, aHeightOut, 0, |
382 | aPixelFormat, aDataType, aDataPtr); |
a174a3c5 |
383 | if (glGetError() != GL_NO_ERROR) |
384 | { |
385 | Unbind (theCtx); |
386 | return false; |
387 | } |
388 | |
389 | mySizeX = aWidthOut; |
390 | mySizeY = aHeightOut; |
bf75be98 |
391 | |
392 | Unbind (theCtx); |
393 | return true; |
394 | } |
395 | case Graphic3d_TOT_2D_MIPMAP: |
396 | { |
397 | myTarget = GL_TEXTURE_2D; |
398 | myHasMipmaps = Standard_True; |
399 | Bind (theCtx); |
400 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
401 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
402 | |
1a7dfdb7 |
403 | if (theCtx->extFBO != NULL |
404 | && aWidth == aWidthOut && aHeight == aHeightOut) |
405 | { |
406 | // use proxy to check texture could be created or not |
a577aaab |
407 | glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat, |
1a7dfdb7 |
408 | aWidthOut, aHeightOut, 0, |
409 | aPixelFormat, aDataType, NULL); |
410 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
411 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight); |
412 | if (aTestWidth == 0 || aTestHeight == 0) |
413 | { |
414 | // no memory or broken input parameters |
415 | Unbind (theCtx); |
416 | return false; |
417 | } |
418 | |
419 | // upload main picture |
a577aaab |
420 | glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat, |
1a7dfdb7 |
421 | aWidthOut, aHeightOut, 0, |
422 | aPixelFormat, aDataType, theImage.Data()); |
a174a3c5 |
423 | if (glGetError() != GL_NO_ERROR) |
424 | { |
425 | Unbind (theCtx); |
426 | return false; |
427 | } |
428 | |
429 | mySizeX = aWidthOut; |
430 | mySizeY = aHeightOut; |
1a7dfdb7 |
431 | |
432 | // generate mipmaps |
433 | //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST); |
434 | theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D); |
435 | |
436 | Unbind (theCtx); |
437 | return true; |
438 | } |
439 | else |
440 | { |
a577aaab |
441 | bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat, |
1a7dfdb7 |
442 | aWidth, aHeight, |
443 | aPixelFormat, aDataType, theImage.Data()) == 0; |
a174a3c5 |
444 | if (isCreated) |
445 | { |
446 | glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX); |
447 | glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY); |
448 | } |
449 | |
1a7dfdb7 |
450 | Unbind (theCtx); |
451 | return isCreated; |
452 | } |
bf75be98 |
453 | } |
454 | default: |
455 | { |
456 | return false; |
457 | } |
458 | } |
459 | } |