bf75be98 |
1 | // Created by: Kirill GAVRILOV |
d5f74e42 |
2 | // Copyright (c) 2013-2014 OPEN CASCADE SAS |
bf75be98 |
3 | // |
973c2be1 |
4 | // This file is part of Open CASCADE Technology software library. |
bf75be98 |
5 | // |
d5f74e42 |
6 | // This library is free software; you can redistribute it and/or modify it under |
7 | // the terms of the GNU Lesser General Public License version 2.1 as published |
973c2be1 |
8 | // by the Free Software Foundation, with special exception defined in the file |
9 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
10 | // distribution for complete text of the license and disclaimer of any warranty. |
bf75be98 |
11 | // |
973c2be1 |
12 | // Alternatively, this file may be used under the terms of Open CASCADE |
13 | // commercial license or contractual agreement. |
bf75be98 |
14 | |
15 | #include <OpenGl_Texture.hxx> |
16 | |
01ca42b2 |
17 | #include <OpenGl_ArbFBO.hxx> |
bf75be98 |
18 | #include <OpenGl_Context.hxx> |
3c4b62a4 |
19 | #include <OpenGl_GlCore32.hxx> |
bf75be98 |
20 | #include <Graphic3d_TextureParams.hxx> |
fa4dcbe0 |
21 | #include <TCollection_ExtendedString.hxx> |
bf75be98 |
22 | #include <Standard_Assert.hxx> |
23 | #include <Image_PixMap.hxx> |
24 | |
bf75be98 |
25 | |
92efcf78 |
26 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture,OpenGl_Resource) |
27 | |
74706083 |
28 | //! Simple class to reset unpack alignment settings |
29 | struct OpenGl_UnpackAlignmentSentry |
30 | { |
31 | |
32 | //! Reset unpack alignment settings to safe values |
33 | void Reset() |
34 | { |
35 | glPixelStorei (GL_UNPACK_ALIGNMENT, 1); |
ca3c13d1 |
36 | #if !defined(GL_ES_VERSION_2_0) |
74706083 |
37 | glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); |
ca3c13d1 |
38 | #endif |
74706083 |
39 | } |
40 | |
41 | ~OpenGl_UnpackAlignmentSentry() |
42 | { |
43 | Reset(); |
44 | } |
45 | |
46 | }; |
47 | |
bf75be98 |
48 | // ======================================================================= |
49 | // function : OpenGl_Texture |
50 | // purpose : |
51 | // ======================================================================= |
52 | OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams) |
53 | : OpenGl_Resource(), |
54 | myTextureId (NO_TEXTURE), |
55 | myTarget (GL_TEXTURE_2D), |
56 | mySizeX (0), |
57 | mySizeY (0), |
74fb257d |
58 | mySizeZ (0), |
8625ef7e |
59 | myTextFormat (GL_RGBA), |
bf75be98 |
60 | myHasMipmaps (Standard_False), |
4e1523ef |
61 | myIsAlpha (false), |
bf75be98 |
62 | myParams (theParams) |
63 | { |
64 | if (myParams.IsNull()) |
65 | { |
66 | myParams = new Graphic3d_TextureParams(); |
67 | } |
68 | } |
69 | |
70 | // ======================================================================= |
71 | // function : ~OpenGl_Texture |
72 | // purpose : |
73 | // ======================================================================= |
74 | OpenGl_Texture::~OpenGl_Texture() |
75 | { |
76 | Release (NULL); |
77 | } |
78 | |
79 | // ======================================================================= |
80 | // function : HasMipmaps |
81 | // purpose : |
82 | // ======================================================================= |
487bf1ce |
83 | Standard_Boolean OpenGl_Texture::HasMipmaps() const |
bf75be98 |
84 | { |
85 | return myHasMipmaps; |
86 | } |
87 | |
88 | // ======================================================================= |
89 | // function : GetParams |
90 | // purpose : |
91 | // ======================================================================= |
92 | const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const |
93 | { |
94 | return myParams; |
95 | } |
96 | |
97 | // ======================================================================= |
98 | // function : SetParams |
99 | // purpose : |
100 | // ======================================================================= |
101 | void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams) |
102 | { |
103 | myParams = theParams; |
104 | } |
105 | |
106 | // ======================================================================= |
107 | // function : Create |
108 | // purpose : |
109 | // ======================================================================= |
110 | bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& ) |
111 | { |
112 | if (myTextureId == NO_TEXTURE) |
113 | { |
114 | glGenTextures (1, &myTextureId); |
115 | } |
116 | return myTextureId != NO_TEXTURE; |
117 | } |
118 | |
119 | // ======================================================================= |
120 | // function : Release |
121 | // purpose : |
122 | // ======================================================================= |
10b9c7df |
123 | void OpenGl_Texture::Release (OpenGl_Context* theGlCtx) |
bf75be98 |
124 | { |
125 | if (myTextureId == NO_TEXTURE) |
126 | { |
127 | return; |
128 | } |
129 | |
130 | // application can not handle this case by exception - this is bug in code |
131 | Standard_ASSERT_RETURN (theGlCtx != NULL, |
132 | "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",); |
133 | |
ec2eeb2d |
134 | if (theGlCtx->IsValid()) |
135 | { |
136 | glDeleteTextures (1, &myTextureId); |
137 | } |
bf75be98 |
138 | myTextureId = NO_TEXTURE; |
139 | mySizeX = mySizeY = 0; |
140 | } |
141 | |
142 | // ======================================================================= |
143 | // function : Bind |
144 | // purpose : |
145 | // ======================================================================= |
146 | void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx, |
147 | const GLenum theTextureUnit) const |
148 | { |
4e1523ef |
149 | if (theCtx->core15fwd != NULL) |
bf75be98 |
150 | { |
01ca42b2 |
151 | theCtx->core15fwd->glActiveTexture (theTextureUnit); |
bf75be98 |
152 | } |
153 | glBindTexture (myTarget, myTextureId); |
154 | } |
155 | |
156 | // ======================================================================= |
157 | // function : Unbind |
158 | // purpose : |
159 | // ======================================================================= |
160 | void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx, |
161 | const GLenum theTextureUnit) const |
162 | { |
4e1523ef |
163 | if (theCtx->core15fwd != NULL) |
bf75be98 |
164 | { |
01ca42b2 |
165 | theCtx->core15fwd->glActiveTexture (theTextureUnit); |
bf75be98 |
166 | } |
167 | glBindTexture (myTarget, NO_TEXTURE); |
168 | } |
169 | |
18f4e8e2 |
170 | //======================================================================= |
171 | //function : GetDataFormat |
172 | //purpose : |
173 | //======================================================================= |
174 | bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx, |
175 | const Image_PixMap& theData, |
176 | GLint& theTextFormat, |
177 | GLenum& thePixelFormat, |
178 | GLenum& theDataType) |
bf75be98 |
179 | { |
18f4e8e2 |
180 | theTextFormat = GL_RGBA8; |
181 | thePixelFormat = 0; |
182 | theDataType = 0; |
183 | switch (theData.Format()) |
bf75be98 |
184 | { |
185 | case Image_PixMap::ImgGrayF: |
186 | { |
076ca35c |
187 | if (theCtx->core11 == NULL) |
188 | { |
189 | theTextFormat = GL_R8; // GL_R32F |
190 | thePixelFormat = GL_RED; |
191 | } |
192 | else |
193 | { |
194 | theTextFormat = GL_LUMINANCE8; |
195 | thePixelFormat = GL_LUMINANCE; |
196 | } |
197 | theDataType = GL_FLOAT; |
198 | return true; |
199 | } |
200 | case Image_PixMap::ImgAlphaF: |
201 | { |
202 | if (theCtx->core11 == NULL) |
203 | { |
204 | theTextFormat = GL_R8; // GL_R32F |
205 | thePixelFormat = GL_RED; |
206 | } |
207 | else |
208 | { |
209 | theTextFormat = GL_ALPHA8; |
210 | thePixelFormat = GL_ALPHA; |
211 | } |
212 | theDataType = GL_FLOAT; |
18f4e8e2 |
213 | return true; |
bf75be98 |
214 | } |
215 | case Image_PixMap::ImgRGBAF: |
216 | { |
076ca35c |
217 | theTextFormat = GL_RGBA8; // GL_RGBA32F |
18f4e8e2 |
218 | thePixelFormat = GL_RGBA; |
219 | theDataType = GL_FLOAT; |
220 | return true; |
bf75be98 |
221 | } |
222 | case Image_PixMap::ImgBGRAF: |
223 | { |
224 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
225 | { |
226 | return false; |
227 | } |
ca3c13d1 |
228 | theTextFormat = GL_RGBA8; // GL_RGBA32F |
229 | thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA |
18f4e8e2 |
230 | theDataType = GL_FLOAT; |
231 | return true; |
bf75be98 |
232 | } |
233 | case Image_PixMap::ImgRGBF: |
234 | { |
076ca35c |
235 | theTextFormat = GL_RGB8; // GL_RGB32F |
18f4e8e2 |
236 | thePixelFormat = GL_RGB; |
237 | theDataType = GL_FLOAT; |
238 | return true; |
bf75be98 |
239 | } |
240 | case Image_PixMap::ImgBGRF: |
241 | { |
ca3c13d1 |
242 | #if !defined(GL_ES_VERSION_2_0) |
243 | theTextFormat = GL_RGB8; // GL_RGB32F |
18f4e8e2 |
244 | thePixelFormat = GL_BGR; // equals to GL_BGR_EXT |
245 | theDataType = GL_FLOAT; |
246 | return true; |
ca3c13d1 |
247 | #else |
248 | return false; |
249 | #endif |
bf75be98 |
250 | } |
251 | case Image_PixMap::ImgRGBA: |
252 | { |
18f4e8e2 |
253 | theTextFormat = GL_RGBA8; |
254 | thePixelFormat = GL_RGBA; |
255 | theDataType = GL_UNSIGNED_BYTE; |
256 | return true; |
bf75be98 |
257 | } |
258 | case Image_PixMap::ImgBGRA: |
259 | { |
260 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
261 | { |
262 | return false; |
263 | } |
ca3c13d1 |
264 | theTextFormat = GL_RGBA8; |
265 | thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA |
18f4e8e2 |
266 | theDataType = GL_UNSIGNED_BYTE; |
267 | return true; |
bf75be98 |
268 | } |
269 | case Image_PixMap::ImgRGB32: |
270 | { |
18f4e8e2 |
271 | theTextFormat = GL_RGB8; |
272 | thePixelFormat = GL_RGBA; |
273 | theDataType = GL_UNSIGNED_BYTE; |
274 | return true; |
bf75be98 |
275 | } |
276 | case Image_PixMap::ImgBGR32: |
277 | { |
278 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
279 | { |
280 | return false; |
281 | } |
ca3c13d1 |
282 | theTextFormat = GL_RGB8; |
283 | thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA |
18f4e8e2 |
284 | theDataType = GL_UNSIGNED_BYTE; |
285 | return true; |
bf75be98 |
286 | } |
287 | case Image_PixMap::ImgRGB: |
288 | { |
18f4e8e2 |
289 | theTextFormat = GL_RGB8; |
290 | thePixelFormat = GL_RGB; |
291 | theDataType = GL_UNSIGNED_BYTE; |
292 | return true; |
bf75be98 |
293 | } |
294 | case Image_PixMap::ImgBGR: |
295 | { |
ca3c13d1 |
296 | #if !defined(GL_ES_VERSION_2_0) |
bf75be98 |
297 | if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra) |
298 | { |
299 | return false; |
300 | } |
18f4e8e2 |
301 | theTextFormat = GL_RGB8; |
302 | thePixelFormat = GL_BGR; // equals to GL_BGR_EXT |
303 | theDataType = GL_UNSIGNED_BYTE; |
304 | return true; |
ca3c13d1 |
305 | #else |
306 | return false; |
307 | #endif |
bf75be98 |
308 | } |
309 | case Image_PixMap::ImgGray: |
310 | { |
076ca35c |
311 | if (theCtx->core11 == NULL) |
312 | { |
313 | theTextFormat = GL_R8; |
314 | thePixelFormat = GL_RED; |
315 | } |
316 | else |
317 | { |
318 | theTextFormat = GL_LUMINANCE8; |
319 | thePixelFormat = GL_LUMINANCE; |
320 | } |
321 | theDataType = GL_UNSIGNED_BYTE; |
322 | return true; |
323 | } |
324 | case Image_PixMap::ImgAlpha: |
325 | { |
326 | if (theCtx->core11 == NULL) |
327 | { |
328 | theTextFormat = GL_R8; |
329 | thePixelFormat = GL_RED; |
330 | } |
331 | else |
332 | { |
333 | theTextFormat = GL_ALPHA8; |
334 | thePixelFormat = GL_ALPHA; |
335 | } |
336 | theDataType = GL_UNSIGNED_BYTE; |
18f4e8e2 |
337 | return true; |
bf75be98 |
338 | } |
076ca35c |
339 | case Image_PixMap::ImgUNKNOWN: |
bf75be98 |
340 | { |
341 | return false; |
342 | } |
343 | } |
076ca35c |
344 | return false; |
18f4e8e2 |
345 | } |
bf75be98 |
346 | |
18f4e8e2 |
347 | // ======================================================================= |
348 | // function : Init |
349 | // purpose : |
350 | // ======================================================================= |
351 | bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, |
352 | const Standard_Integer theTextFormat, |
353 | const GLenum thePixelFormat, |
354 | const GLenum theDataType, |
355 | const Standard_Integer theSizeX, |
356 | const Standard_Integer theSizeY, |
357 | const Graphic3d_TypeOfTexture theType, |
358 | const Image_PixMap* theImage) |
359 | { |
360 | if (!Create (theCtx)) |
361 | { |
362 | Release (theCtx.operator->()); |
363 | return false; |
364 | } |
4e1523ef |
365 | |
366 | if (theImage != NULL) |
367 | { |
368 | myIsAlpha = theImage->Format() == Image_PixMap::ImgAlpha |
369 | || theImage->Format() == Image_PixMap::ImgAlphaF; |
370 | } |
371 | else |
372 | { |
373 | myIsAlpha = thePixelFormat == GL_ALPHA; |
374 | } |
375 | |
18f4e8e2 |
376 | myHasMipmaps = Standard_False; |
8625ef7e |
377 | myTextFormat = thePixelFormat; |
378 | #if !defined(GL_ES_VERSION_2_0) |
379 | const GLint anIntFormat = theTextFormat; |
380 | #else |
381 | // ES does not support sized formats and format conversions - them detected from data type |
382 | const GLint anIntFormat = thePixelFormat; |
74fb257d |
383 | (void) theTextFormat; |
8625ef7e |
384 | #endif |
18f4e8e2 |
385 | const GLsizei aWidth = theSizeX; |
386 | const GLsizei aHeight = theSizeY; |
bf75be98 |
387 | const GLsizei aMaxSize = theCtx->MaxTextureSize(); |
bf75be98 |
388 | |
fa4dcbe0 |
389 | if (aWidth > aMaxSize || aHeight > aMaxSize) |
390 | { |
391 | TCollection_ExtendedString aWarnMessage = TCollection_ExtendedString ("Error: Texture dimension - ") |
392 | + aWidth + "x" + aHeight + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")"; |
393 | |
394 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage); |
395 | Release (theCtx.operator->()); |
396 | return false; |
397 | } |
398 | #if !defined(GL_ES_VERSION_2_0) |
399 | else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW) |
400 | { |
401 | // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications |
402 | // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT! |
403 | // Trying to create NPOT textures on such hardware will not fail |
404 | // but driver will fall back into software rendering, |
405 | const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize); |
406 | const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize); |
407 | |
408 | if (aWidth != aWidthP2 || (theType != Graphic3d_TOT_1D && aHeight != aHeightP2)) |
409 | { |
410 | TCollection_ExtendedString aWarnMessage = |
411 | TCollection_ExtendedString ("Error: NPOT Textures (") + aWidth + "x" + aHeight + ") are not supported by hardware."; |
412 | |
413 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage); |
414 | |
415 | Release (theCtx.operator->()); |
416 | return false; |
417 | } |
418 | } |
419 | #else |
420 | else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP) |
421 | { |
422 | // Mipmap NPOT textures are not supported by OpenGL ES 2.0. |
423 | const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize); |
424 | const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize); |
425 | |
426 | if (aWidth != aWidthP2 || aHeight != aHeightP2) |
427 | { |
428 | TCollection_ExtendedString aWarnMessage = |
429 | TCollection_ExtendedString ("Error: Mipmap NPOT Textures (") + aWidth + "x" + aHeight + ") are not supported by OpenGL ES 2.0"; |
430 | |
431 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage); |
432 | |
433 | Release (theCtx.operator->()); |
434 | return false; |
435 | } |
436 | } |
437 | #endif |
438 | |
439 | const GLenum aFilter = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR; |
440 | const GLenum aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp(); |
bf75be98 |
441 | |
ca3c13d1 |
442 | #if !defined(GL_ES_VERSION_2_0) |
bf75be98 |
443 | GLint aTestWidth = 0; |
444 | GLint aTestHeight = 0; |
ca3c13d1 |
445 | #endif |
18f4e8e2 |
446 | GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL; |
bf75be98 |
447 | |
74706083 |
448 | // setup the alignment |
449 | OpenGl_UnpackAlignmentSentry anUnpackSentry; |
fa4dcbe0 |
450 | (void)anUnpackSentry; // avoid compiler warning |
451 | |
18f4e8e2 |
452 | if (aDataPtr != NULL) |
453 | { |
454 | const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes |
455 | glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment); |
74706083 |
456 | |
ca3c13d1 |
457 | #if !defined(GL_ES_VERSION_2_0) |
18f4e8e2 |
458 | // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension |
459 | const GLint anExtraBytes = GLint(theImage->RowExtraBytes()); |
460 | const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes()); |
461 | glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0); |
ca3c13d1 |
462 | #endif |
18f4e8e2 |
463 | } |
74706083 |
464 | |
bf75be98 |
465 | switch (theType) |
466 | { |
467 | case Graphic3d_TOT_1D: |
468 | { |
ca3c13d1 |
469 | #if !defined(GL_ES_VERSION_2_0) |
bf75be98 |
470 | myTarget = GL_TEXTURE_1D; |
471 | Bind (theCtx); |
fe3a29bc |
472 | glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, aFilter); |
473 | glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, aFilter); |
474 | glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, aWrapMode); |
bf75be98 |
475 | |
bf75be98 |
476 | // use proxy to check texture could be created or not |
8625ef7e |
477 | glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat, |
fa4dcbe0 |
478 | aWidth, 0, |
18f4e8e2 |
479 | thePixelFormat, theDataType, NULL); |
bf75be98 |
480 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
481 | if (aTestWidth == 0) |
482 | { |
483 | // no memory or broken input parameters |
484 | Unbind (theCtx); |
18f4e8e2 |
485 | Release (theCtx.operator->()); |
bf75be98 |
486 | return false; |
487 | } |
488 | |
8625ef7e |
489 | glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat, |
fa4dcbe0 |
490 | aWidth, 0, |
18f4e8e2 |
491 | thePixelFormat, theDataType, aDataPtr); |
a174a3c5 |
492 | if (glGetError() != GL_NO_ERROR) |
493 | { |
494 | Unbind (theCtx); |
18f4e8e2 |
495 | Release (theCtx.operator->()); |
a174a3c5 |
496 | return false; |
497 | } |
498 | |
fa4dcbe0 |
499 | mySizeX = aWidth; |
a174a3c5 |
500 | mySizeY = 1; |
bf75be98 |
501 | |
502 | Unbind (theCtx); |
503 | return true; |
ca3c13d1 |
504 | #else |
fa4dcbe0 |
505 | Release (theCtx.operator->()); |
ca3c13d1 |
506 | return false; |
507 | #endif |
bf75be98 |
508 | } |
509 | case Graphic3d_TOT_2D: |
510 | { |
511 | myTarget = GL_TEXTURE_2D; |
512 | Bind (theCtx); |
fe3a29bc |
513 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilter); |
514 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter); |
515 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, aWrapMode); |
516 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, aWrapMode); |
bf75be98 |
517 | |
ca3c13d1 |
518 | #if !defined(GL_ES_VERSION_2_0) |
bf75be98 |
519 | // use proxy to check texture could be created or not |
8625ef7e |
520 | glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat, |
fa4dcbe0 |
521 | aWidth, aHeight, 0, |
18f4e8e2 |
522 | thePixelFormat, theDataType, NULL); |
bf75be98 |
523 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
524 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight); |
525 | if (aTestWidth == 0 || aTestHeight == 0) |
526 | { |
527 | // no memory or broken input parameters |
528 | Unbind (theCtx); |
18f4e8e2 |
529 | Release (theCtx.operator->()); |
bf75be98 |
530 | return false; |
531 | } |
ca3c13d1 |
532 | #endif |
bf75be98 |
533 | |
8625ef7e |
534 | glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat, |
fa4dcbe0 |
535 | aWidth, aHeight, 0, |
18f4e8e2 |
536 | thePixelFormat, theDataType, aDataPtr); |
a174a3c5 |
537 | if (glGetError() != GL_NO_ERROR) |
538 | { |
539 | Unbind (theCtx); |
18f4e8e2 |
540 | Release (theCtx.operator->()); |
a174a3c5 |
541 | return false; |
542 | } |
543 | |
fa4dcbe0 |
544 | mySizeX = aWidth; |
545 | mySizeY = aHeight; |
bf75be98 |
546 | |
547 | Unbind (theCtx); |
548 | return true; |
549 | } |
550 | case Graphic3d_TOT_2D_MIPMAP: |
551 | { |
552 | myTarget = GL_TEXTURE_2D; |
553 | myHasMipmaps = Standard_True; |
fe3a29bc |
554 | |
555 | GLenum aFilterMin = aFilter; |
556 | aFilterMin = GL_NEAREST_MIPMAP_NEAREST; |
557 | if (myParams->Filter() == Graphic3d_TOTF_BILINEAR) |
558 | { |
559 | aFilterMin = GL_LINEAR_MIPMAP_NEAREST; |
560 | } |
561 | else if (myParams->Filter() == Graphic3d_TOTF_TRILINEAR) |
562 | { |
563 | aFilterMin = GL_LINEAR_MIPMAP_LINEAR; |
564 | } |
565 | |
bf75be98 |
566 | Bind (theCtx); |
fe3a29bc |
567 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterMin); |
568 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter); |
569 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, aWrapMode); |
570 | glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, aWrapMode); |
bf75be98 |
571 | |
fa4dcbe0 |
572 | #if !defined(GL_ES_VERSION_2_0) |
573 | // use proxy to check texture could be created or not |
574 | glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat, |
575 | aWidth, aHeight, 0, |
576 | thePixelFormat, theDataType, NULL); |
577 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
578 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight); |
579 | if (aTestWidth == 0 || aTestHeight == 0) |
580 | { |
581 | // no memory or broken input parameters |
582 | Unbind (theCtx); |
583 | Release (theCtx.operator->()); |
584 | return false; |
585 | } |
586 | #endif |
587 | |
588 | // upload main picture |
589 | glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat, |
590 | aWidth, aHeight, 0, |
591 | thePixelFormat, theDataType, theImage->Data()); |
592 | if (glGetError() != GL_NO_ERROR) |
1a7dfdb7 |
593 | { |
fa4dcbe0 |
594 | Unbind (theCtx); |
595 | Release (theCtx.operator->()); |
596 | return false; |
597 | } |
598 | |
599 | mySizeX = aWidth; |
600 | mySizeY = aHeight; |
601 | |
602 | if (theCtx->arbFBO != NULL) |
603 | { |
604 | // generate mipmaps |
605 | //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST); |
606 | theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D); |
1a7dfdb7 |
607 | |
a174a3c5 |
608 | if (glGetError() != GL_NO_ERROR) |
609 | { |
610 | Unbind (theCtx); |
18f4e8e2 |
611 | Release (theCtx.operator->()); |
a174a3c5 |
612 | return false; |
613 | } |
1a7dfdb7 |
614 | } |
615 | else |
616 | { |
fa4dcbe0 |
617 | const TCollection_ExtendedString aWarnMessage ("Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing."); |
618 | |
3b523c4c |
619 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage); |
a174a3c5 |
620 | |
1a7dfdb7 |
621 | Unbind (theCtx); |
fa4dcbe0 |
622 | Release (theCtx.operator->()); |
ca3c13d1 |
623 | return false; |
1a7dfdb7 |
624 | } |
fa4dcbe0 |
625 | |
626 | Unbind (theCtx); |
627 | return true; |
bf75be98 |
628 | } |
629 | default: |
630 | { |
18f4e8e2 |
631 | Release (theCtx.operator->()); |
bf75be98 |
632 | return false; |
633 | } |
634 | } |
635 | } |
68333c8f |
636 | |
18f4e8e2 |
637 | // ======================================================================= |
638 | // function : Init |
639 | // purpose : |
640 | // ======================================================================= |
641 | bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, |
642 | const Image_PixMap& theImage, |
643 | const Graphic3d_TypeOfTexture theType) |
644 | { |
645 | if (theImage.IsEmpty()) |
646 | { |
647 | Release (theCtx.operator->()); |
648 | return false; |
649 | } |
650 | |
651 | GLenum aPixelFormat; |
652 | GLenum aDataType; |
653 | GLint aTextFormat; |
654 | if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType)) |
655 | { |
656 | Release (theCtx.operator->()); |
657 | return false; |
658 | } |
659 | |
660 | return Init (theCtx, |
661 | aTextFormat, aPixelFormat, aDataType, |
662 | (Standard_Integer)theImage.SizeX(), |
663 | (Standard_Integer)theImage.SizeY(), |
664 | theType, &theImage); |
665 | } |
666 | |
3c4b62a4 |
667 | // ======================================================================= |
668 | // function : Init2DMultisample |
669 | // purpose : |
670 | // ======================================================================= |
671 | bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx, |
672 | const GLsizei theNbSamples, |
673 | const GLint theTextFormat, |
674 | const GLsizei theSizeX, |
675 | const GLsizei theSizeY) |
676 | { |
677 | if (!Create (theCtx) |
678 | || theNbSamples > theCtx->MaxMsaaSamples() |
679 | || theNbSamples < 1) |
680 | { |
681 | return false; |
682 | } |
683 | |
684 | const GLsizei aNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples()); |
685 | myTarget = GL_TEXTURE_2D_MULTISAMPLE; |
686 | if(theSizeX > theCtx->MaxTextureSize() |
687 | || theSizeY > theCtx->MaxTextureSize()) |
688 | { |
689 | return false; |
690 | } |
691 | |
692 | Bind (theCtx); |
693 | //myTextFormat = theTextFormat; |
694 | #if !defined(GL_ES_VERSION_2_0) |
695 | if (theCtx->Functions()->glTexStorage2DMultisample != NULL) |
696 | { |
697 | theCtx->Functions()->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE); |
698 | } |
699 | else |
700 | { |
701 | theCtx->Functions()->glTexImage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE); |
702 | } |
703 | #else |
704 | theCtx->Functions() ->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE); |
705 | #endif |
706 | if (theCtx->core11fwd->glGetError() != GL_NO_ERROR) |
707 | { |
708 | Unbind (theCtx); |
709 | return false; |
710 | } |
711 | |
712 | mySizeX = theSizeX; |
713 | mySizeY = theSizeY; |
714 | |
715 | Unbind (theCtx); |
716 | return true; |
717 | } |
718 | |
68333c8f |
719 | // ======================================================================= |
720 | // function : InitRectangle |
721 | // purpose : |
722 | // ======================================================================= |
723 | bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx, |
724 | const Standard_Integer theSizeX, |
725 | const Standard_Integer theSizeY, |
726 | const OpenGl_TextureFormat& theFormat) |
727 | { |
728 | if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0)) |
729 | { |
730 | return false; |
731 | } |
ca3c13d1 |
732 | |
733 | #if !defined(GL_ES_VERSION_2_0) |
68333c8f |
734 | myTarget = GL_TEXTURE_RECTANGLE; |
735 | |
fe3a29bc |
736 | const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX); |
737 | const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY); |
738 | const GLenum aFilter = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR; |
739 | const GLenum aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp(); |
ca3c13d1 |
740 | |
68333c8f |
741 | Bind (theCtx); |
fe3a29bc |
742 | glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, aFilter); |
743 | glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, aFilter); |
744 | glTexParameteri (myTarget, GL_TEXTURE_WRAP_S, aWrapMode); |
745 | glTexParameteri (myTarget, GL_TEXTURE_WRAP_T, aWrapMode); |
68333c8f |
746 | |
8625ef7e |
747 | const GLint anIntFormat = theFormat.Internal(); |
748 | myTextFormat = theFormat.Format(); |
68333c8f |
749 | |
750 | glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, |
751 | 0, |
8625ef7e |
752 | anIntFormat, |
68333c8f |
753 | aSizeX, |
754 | aSizeY, |
755 | 0, |
756 | theFormat.Format(), |
757 | GL_FLOAT, |
758 | NULL); |
759 | |
760 | GLint aTestSizeX = 0; |
761 | GLint aTestSizeY = 0; |
762 | |
763 | glGetTexLevelParameteriv ( |
764 | GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX); |
765 | glGetTexLevelParameteriv ( |
766 | GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY); |
767 | |
768 | if (aTestSizeX == 0 || aTestSizeY == 0) |
769 | { |
770 | Unbind (theCtx); |
771 | return false; |
772 | } |
773 | |
774 | glTexImage2D (myTarget, |
775 | 0, |
8625ef7e |
776 | anIntFormat, |
68333c8f |
777 | aSizeX, |
778 | aSizeY, |
779 | 0, |
780 | theFormat.Format(), |
781 | GL_FLOAT, |
782 | NULL); |
783 | |
784 | if (glGetError() != GL_NO_ERROR) |
785 | { |
786 | Unbind (theCtx); |
787 | return false; |
788 | } |
789 | |
790 | mySizeX = aSizeX; |
791 | mySizeY = aSizeY; |
792 | |
793 | Unbind (theCtx); |
794 | return true; |
ca3c13d1 |
795 | #else |
20aeeb7b |
796 | (void )theSizeX; |
797 | (void )theSizeY; |
798 | (void )theFormat; |
ca3c13d1 |
799 | return false; |
800 | #endif |
68333c8f |
801 | } |
74fb257d |
802 | |
803 | // ======================================================================= |
804 | // function : Init3D |
805 | // purpose : |
806 | // ======================================================================= |
807 | bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx, |
808 | const GLint theTextFormat, |
809 | const GLenum thePixelFormat, |
810 | const GLenum theDataType, |
811 | const Standard_Integer theSizeX, |
812 | const Standard_Integer theSizeY, |
813 | const Standard_Integer theSizeZ, |
814 | const void* thePixels) |
815 | { |
816 | if (theCtx->Functions()->glTexImage3D == NULL) |
817 | { |
818 | TCollection_ExtendedString aMsg ("Error: three-dimensional textures are not supported by hardware."); |
819 | |
820 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, |
821 | GL_DEBUG_TYPE_ERROR, |
822 | 0, |
823 | GL_DEBUG_SEVERITY_HIGH, |
824 | aMsg); |
825 | |
826 | return false; |
827 | } |
828 | |
829 | if (!Create(theCtx)) |
830 | { |
831 | return false; |
832 | } |
833 | |
834 | myTarget = GL_TEXTURE_3D; |
835 | |
836 | const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX); |
837 | const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY); |
838 | const GLsizei aSizeZ = Min (theCtx->MaxTextureSize(), theSizeZ); |
839 | |
840 | Bind (theCtx); |
841 | |
842 | if (theDataType == GL_FLOAT && !theCtx->arbTexFloat) |
843 | { |
844 | TCollection_ExtendedString aMsg ("Error: floating-point textures are not supported by hardware."); |
845 | |
846 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, |
847 | GL_DEBUG_TYPE_ERROR, |
848 | 0, |
849 | GL_DEBUG_SEVERITY_HIGH, |
850 | aMsg); |
851 | |
852 | Release (theCtx.operator->()); |
853 | Unbind (theCtx); |
854 | return false; |
855 | } |
856 | |
857 | const GLint anIntFormat = theTextFormat; |
858 | |
859 | #if !defined (GL_ES_VERSION_2_0) |
860 | theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, |
861 | 0, |
862 | anIntFormat, |
863 | aSizeX, |
864 | aSizeY, |
865 | aSizeZ, |
866 | 0, |
867 | thePixelFormat, |
868 | theDataType, |
869 | NULL); |
870 | |
871 | GLint aTestSizeX = 0; |
872 | GLint aTestSizeY = 0; |
873 | GLint aTestSizeZ = 0; |
874 | |
875 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeX); |
876 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeY); |
877 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeZ); |
878 | |
879 | if (aTestSizeX == 0 || aTestSizeY == 0 || aTestSizeZ == 0) |
880 | { |
881 | Unbind (theCtx); |
882 | Release (theCtx.operator->()); |
883 | return false; |
884 | } |
885 | #endif |
886 | |
887 | const GLenum aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp(); |
888 | const GLenum aFilter = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR; |
889 | |
890 | glTexParameteri (myTarget, GL_TEXTURE_WRAP_S, aWrapMode); |
891 | glTexParameteri (myTarget, GL_TEXTURE_WRAP_T, aWrapMode); |
892 | glTexParameteri (myTarget, GL_TEXTURE_WRAP_R, aWrapMode); |
893 | |
894 | glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, aFilter); |
895 | glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, aFilter); |
896 | |
897 | theCtx->Functions()->glTexImage3D (myTarget, |
898 | 0, |
899 | anIntFormat, |
900 | aSizeX, |
901 | aSizeY, |
902 | aSizeZ, |
903 | 0, |
904 | thePixelFormat, |
905 | theDataType, |
906 | thePixels); |
907 | |
908 | if (glGetError() != GL_NO_ERROR) |
909 | { |
910 | Unbind (theCtx); |
911 | Release (theCtx.operator->()); |
912 | return false; |
913 | } |
914 | |
915 | mySizeX = aSizeX; |
916 | mySizeY = aSizeY; |
917 | mySizeZ = aSizeZ; |
918 | |
919 | Unbind (theCtx); |
920 | return true; |
921 | } |