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