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