0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[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>
faff3767 24#include <Image_CompressedPixMap.hxx>
bf75be98 25#include <Image_PixMap.hxx>
faff3767 26#include <Image_SupportedFormats.hxx>
bf75be98 27
cc8cbabe 28IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
92efcf78 29
faff3767 30namespace
31{
32
74706083 33//! Simple class to reset unpack alignment settings
34struct OpenGl_UnpackAlignmentSentry
35{
36
37 //! Reset unpack alignment settings to safe values
90fd6145 38 static void Reset()
74706083 39 {
40 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
ca3c13d1 41 #if !defined(GL_ES_VERSION_2_0)
74706083 42 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
ca3c13d1 43 #endif
74706083 44 }
45
90fd6145 46 OpenGl_UnpackAlignmentSentry() {}
47
74706083 48 ~OpenGl_UnpackAlignmentSentry()
49 {
50 Reset();
51 }
52
53};
54
faff3767 55//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
56static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize)
57{
58 for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2)
59 {
60 if (theSize <= 1)
61 {
62 return aMipIter;
63 }
64 }
65}
66
67//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
68static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSizeX, Standard_Integer theSizeY)
69{
70 return computeUpperMipMapLevel (Max (theSizeX, theSizeY));
71}
72
73//! Compute size of the smallest defined mipmap level (for verbose messages).
74static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel)
75{
76 Graphic3d_Vec2i aMipSizeXY = theBaseSize;
77 for (Standard_Integer aMipIter = 0;; ++aMipIter)
78 {
79 if (aMipIter > theMaxLevel)
80 {
81 return aMipSizeXY;
82 }
83
84 aMipSizeXY /= 2;
85 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
86 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
87 }
88}
89
90}
91
bf75be98 92// =======================================================================
93// function : OpenGl_Texture
94// purpose :
95// =======================================================================
cc8cbabe 96OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
97 const Handle(Graphic3d_TextureParams)& theParams)
98: OpenGl_NamedResource (theResourceId),
99 mySampler (new OpenGl_Sampler (theParams)),
d2edda76 100 myRevision (0),
bf75be98 101 myTextureId (NO_TEXTURE),
102 myTarget (GL_TEXTURE_2D),
103 mySizeX (0),
104 mySizeY (0),
74fb257d 105 mySizeZ (0),
8625ef7e 106 myTextFormat (GL_RGBA),
15669413 107 mySizedFormat(GL_RGBA8),
108 myNbSamples (1),
faff3767 109 myMaxMipLevel(0),
110 myIsAlpha (false),
111 myIsTopDown (true)
bf75be98 112{
cc8cbabe 113 //
bf75be98 114}
115
116// =======================================================================
117// function : ~OpenGl_Texture
118// purpose :
119// =======================================================================
120OpenGl_Texture::~OpenGl_Texture()
121{
122 Release (NULL);
123}
124
bf75be98 125// =======================================================================
126// function : Create
127// purpose :
128// =======================================================================
cc8cbabe 129bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
bf75be98 130{
cc8cbabe 131 if (myTextureId != NO_TEXTURE)
132 {
133 return true;
134 }
135
136 theCtx->core11fwd->glGenTextures (1, &myTextureId);
bf75be98 137 if (myTextureId == NO_TEXTURE)
138 {
cc8cbabe 139 return false;
bf75be98 140 }
cc8cbabe 141
142 //mySampler->Create (theCtx); // do not create sampler object by default
143 return true;
bf75be98 144}
145
146// =======================================================================
147// function : Release
148// purpose :
149// =======================================================================
10b9c7df 150void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
bf75be98 151{
cc8cbabe 152 mySampler->Release (theGlCtx);
bf75be98 153 if (myTextureId == NO_TEXTURE)
154 {
155 return;
156 }
157
158 // application can not handle this case by exception - this is bug in code
159 Standard_ASSERT_RETURN (theGlCtx != NULL,
160 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
161
ec2eeb2d 162 if (theGlCtx->IsValid())
163 {
164 glDeleteTextures (1, &myTextureId);
165 }
bf75be98 166 myTextureId = NO_TEXTURE;
d2edda76 167 mySizeX = mySizeY = mySizeZ = 0;
bf75be98 168}
169
cc8cbabe 170// =======================================================================
171// function : applyDefaultSamplerParams
172// purpose :
173// =======================================================================
174void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
175{
faff3767 176 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel);
cc8cbabe 177 if (mySampler->IsValid() && !mySampler->IsImmutable())
178 {
faff3767 179 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel);
cc8cbabe 180 }
181}
182
bf75be98 183// =======================================================================
184// function : Bind
185// purpose :
186// =======================================================================
187void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 188 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 189{
4e1523ef 190 if (theCtx->core15fwd != NULL)
bf75be98 191 {
cc8cbabe 192 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 193 }
cc8cbabe 194 mySampler->Bind (theCtx, theTextureUnit);
bf75be98 195 glBindTexture (myTarget, myTextureId);
196}
197
198// =======================================================================
199// function : Unbind
200// purpose :
201// =======================================================================
202void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 203 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 204{
4e1523ef 205 if (theCtx->core15fwd != NULL)
bf75be98 206 {
cc8cbabe 207 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 208 }
cc8cbabe 209 mySampler->Unbind (theCtx, theTextureUnit);
bf75be98 210 glBindTexture (myTarget, NO_TEXTURE);
211}
212
cc8cbabe 213//=======================================================================
214//function : InitSamplerObject
215//purpose :
216//=======================================================================
217bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
218{
219 return myTextureId != NO_TEXTURE
220 && mySampler->Init (theCtx, *this);
221}
222
18f4e8e2 223// =======================================================================
224// function : Init
225// purpose :
226// =======================================================================
227bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
ba00aab7 228 const OpenGl_TextureFormat& theFormat,
229 const Graphic3d_Vec2i& theSizeXY,
18f4e8e2 230 const Graphic3d_TypeOfTexture theType,
231 const Image_PixMap* theImage)
232{
ba00aab7 233 if (theSizeXY.x() < 1
234 || theSizeXY.y() < 1)
66d1cdc6 235 {
236 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
237 "Error: texture of 0 size cannot be created.");
ba00aab7 238 Release (theCtx.get());
66d1cdc6 239 return false;
240 }
241
d2edda76 242#if !defined(GL_ES_VERSION_2_0)
243 const GLenum aTarget = theType == Graphic3d_TOT_1D
244 ? GL_TEXTURE_1D
245 : GL_TEXTURE_2D;
246#else
247 const GLenum aTarget = GL_TEXTURE_2D;
248#endif
d2edda76 249 const bool toPatchExisting = IsValid()
ba00aab7 250 && myTextFormat == theFormat.PixelFormat()
d2edda76 251 && myTarget == aTarget
faff3767 252 && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP)
ba00aab7 253 && mySizeX == theSizeXY.x()
254 && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
18f4e8e2 255 if (!Create (theCtx))
256 {
ba00aab7 257 Release (theCtx.get());
18f4e8e2 258 return false;
259 }
4e1523ef 260
261 if (theImage != NULL)
262 {
dc858f4c 263 myIsAlpha = theImage->Format() == Image_Format_Alpha
264 || theImage->Format() == Image_Format_AlphaF;
faff3767 265 myIsTopDown = theImage->IsTopDown();
4e1523ef 266 }
267 else
268 {
ba00aab7 269 myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
4e1523ef 270 }
271
faff3767 272 myMaxMipLevel = theType == Graphic3d_TOT_2D_MIPMAP && theCtx->arbFBO != NULL
273 ? computeUpperMipMapLevel (theSizeXY.x(), theSizeXY.y())
274 : 0;
275 myTextFormat = theFormat.PixelFormat();
276 mySizedFormat = theFormat.InternalFormat();
277 myNbSamples = 1;
8625ef7e 278#if !defined(GL_ES_VERSION_2_0)
ba00aab7 279 const GLint anIntFormat = theFormat.InternalFormat();
8625ef7e 280#else
a1073ae2 281 // ES 2.0 does not support sized formats and format conversions - them detected from data type
ba00aab7 282 const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? theFormat.InternalFormat() : theFormat.PixelFormat();
8625ef7e 283#endif
bf75be98 284
ba00aab7 285 if (theFormat.DataType() == GL_FLOAT
286 && !theCtx->arbTexFloat)
ff6665dc 287 {
288 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
289 "Error: floating-point textures are not supported by hardware.");
ba00aab7 290 Release (theCtx.get());
ff6665dc 291 return false;
292 }
293
d2edda76 294 const GLsizei aMaxSize = theCtx->MaxTextureSize();
ba00aab7 295 if (theSizeXY.x() > aMaxSize
296 || theSizeXY.y() > aMaxSize)
fa4dcbe0 297 {
ba00aab7 298 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
299 TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y()
300 + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")");
301 Release (theCtx.get());
fa4dcbe0 302 return false;
303 }
304#if !defined(GL_ES_VERSION_2_0)
305 else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
306 {
307 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
308 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
309 // Trying to create NPOT textures on such hardware will not fail
310 // but driver will fall back into software rendering,
ba00aab7 311 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
312 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
313 if (theSizeXY.x() != aWidthP2
314 || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2))
fa4dcbe0 315 {
ba00aab7 316 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
317 TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
318 " are not supported by hardware.");
319 Release (theCtx.get());
fa4dcbe0 320 return false;
321 }
322 }
323#else
324 else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
325 {
326 // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
ba00aab7 327 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
328 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
329 if (theSizeXY.x() != aWidthP2
330 || theSizeXY.y() != aHeightP2)
fa4dcbe0 331 {
ba00aab7 332 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
333 TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
334 " are not supported by OpenGL ES 2.0");
335 Release (theCtx.get());
fa4dcbe0 336 return false;
337 }
338 }
339#endif
340
ca3c13d1 341#if !defined(GL_ES_VERSION_2_0)
faff3767 342 GLint aTestWidth = 0, aTestHeight = 0;
ca3c13d1 343#endif
18f4e8e2 344 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
bf75be98 345
74706083 346 // setup the alignment
347 OpenGl_UnpackAlignmentSentry anUnpackSentry;
fa4dcbe0 348 (void)anUnpackSentry; // avoid compiler warning
349
18f4e8e2 350 if (aDataPtr != NULL)
351 {
352 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
353 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
74706083 354
ca3c13d1 355 #if !defined(GL_ES_VERSION_2_0)
18f4e8e2 356 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
357 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
358 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
359 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
ca3c13d1 360 #endif
18f4e8e2 361 }
74706083 362
d2edda76 363 myTarget = aTarget;
bf75be98 364 switch (theType)
365 {
366 case Graphic3d_TOT_1D:
367 {
ca3c13d1 368 #if !defined(GL_ES_VERSION_2_0)
bf75be98 369 Bind (theCtx);
cc8cbabe 370 applyDefaultSamplerParams (theCtx);
d2edda76 371 if (toPatchExisting)
372 {
373 glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
ba00aab7 374 theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
d2edda76 375 Unbind (theCtx);
376 return true;
377 }
bf75be98 378
bf75be98 379 // use proxy to check texture could be created or not
8625ef7e 380 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
ba00aab7 381 theSizeXY.x(), 0,
382 theFormat.PixelFormat(), theFormat.DataType(), NULL);
ff6665dc 383 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
15669413 384 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
bf75be98 385 if (aTestWidth == 0)
386 {
387 // no memory or broken input parameters
388 Unbind (theCtx);
18f4e8e2 389 Release (theCtx.operator->());
bf75be98 390 return false;
391 }
392
8625ef7e 393 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
ba00aab7 394 theSizeXY.x(), 0,
395 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
a174a3c5 396 if (glGetError() != GL_NO_ERROR)
397 {
398 Unbind (theCtx);
ba00aab7 399 Release (theCtx.get());
a174a3c5 400 return false;
401 }
402
ba00aab7 403 mySizeX = theSizeXY.x();
a174a3c5 404 mySizeY = 1;
bf75be98 405
406 Unbind (theCtx);
407 return true;
ca3c13d1 408 #else
ff6665dc 409 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
410 "Error: 1D textures are not supported by hardware.");
ba00aab7 411 Release (theCtx.get());
ca3c13d1 412 return false;
413 #endif
bf75be98 414 }
415 case Graphic3d_TOT_2D:
bf75be98 416 case Graphic3d_TOT_2D_MIPMAP:
417 {
bf75be98 418 Bind (theCtx);
cc8cbabe 419 applyDefaultSamplerParams (theCtx);
d2edda76 420 if (toPatchExisting)
421 {
422 glTexSubImage2D (GL_TEXTURE_2D, 0,
423 0, 0,
ba00aab7 424 theSizeXY.x(), theSizeXY.y(),
425 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
faff3767 426
427 if (myMaxMipLevel > 0)
d2edda76 428 {
429 // generate mipmaps
430 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
431 if (glGetError() != GL_NO_ERROR)
432 {
faff3767 433 myMaxMipLevel = 0;
d2edda76 434 }
435 }
436
437 Unbind (theCtx);
438 return true;
439 }
bf75be98 440
fa4dcbe0 441 #if !defined(GL_ES_VERSION_2_0)
442 // use proxy to check texture could be created or not
443 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
ba00aab7 444 theSizeXY.x(), theSizeXY.y(), 0,
445 theFormat.PixelFormat(), theFormat.DataType(), NULL);
fa4dcbe0 446 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
447 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
15669413 448 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
fa4dcbe0 449 if (aTestWidth == 0 || aTestHeight == 0)
450 {
451 // no memory or broken input parameters
452 Unbind (theCtx);
ba00aab7 453 Release (theCtx.get());
fa4dcbe0 454 return false;
455 }
456 #endif
457
fa4dcbe0 458 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
ba00aab7 459 theSizeXY.x(), theSizeXY.y(), 0,
faff3767 460 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
461 GLenum anErr = glGetError();
462 if (anErr != GL_NO_ERROR)
1a7dfdb7 463 {
177781da 464 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 465 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
faff3767 466 + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
467 + " DT: " + int(theFormat.DataType())
468 + " can not be created with error " + int(anErr) + ".");
fa4dcbe0 469 Unbind (theCtx);
ba00aab7 470 Release (theCtx.get());
fa4dcbe0 471 return false;
472 }
473
ba00aab7 474 mySizeX = theSizeXY.x();
475 mySizeY = theSizeXY.y();
fa4dcbe0 476
faff3767 477 if (myMaxMipLevel > 0)
fa4dcbe0 478 {
479 // generate mipmaps
480 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
481 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
faff3767 482 anErr = glGetError();
483 if (anErr != GL_NO_ERROR)
a174a3c5 484 {
faff3767 485 myMaxMipLevel = 0;
486 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
487 "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
a174a3c5 488 }
1a7dfdb7 489 }
fa4dcbe0 490
491 Unbind (theCtx);
492 return true;
bf75be98 493 }
077a220c 494 case Graphic3d_TOT_CUBEMAP:
495 {
496 Unbind (theCtx);
497 Release (theCtx.get());
498 return false;
499 }
bf75be98 500 }
d2edda76 501
ba00aab7 502 Release (theCtx.get());
d2edda76 503 return false;
bf75be98 504}
68333c8f 505
18f4e8e2 506// =======================================================================
507// function : Init
508// purpose :
509// =======================================================================
510bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
511 const Image_PixMap& theImage,
ba00aab7 512 const Graphic3d_TypeOfTexture theType,
513 const Standard_Boolean theIsColorMap)
18f4e8e2 514{
515 if (theImage.IsEmpty())
516 {
ba00aab7 517 Release (theCtx.get());
18f4e8e2 518 return false;
519 }
520
ba00aab7 521 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap);
522 if (!aFormat.IsValid())
18f4e8e2 523 {
ba00aab7 524 Release (theCtx.get());
18f4e8e2 525 return false;
526 }
527
ba00aab7 528 return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()),
18f4e8e2 529 theType, &theImage);
530}
531
077a220c 532// =======================================================================
533// function : Init
534// purpose :
535// =======================================================================
536bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
537 const Handle(Graphic3d_TextureMap)& theTextureMap)
538{
539 if (theTextureMap.IsNull())
540 {
541 return false;
542 }
543
544 switch (theTextureMap->Type())
545 {
546 case Graphic3d_TOT_CUBEMAP:
547 {
67312b79 548 return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap),
ba00aab7 549 0, Image_Format_RGB, false, theTextureMap->IsColorMap());
077a220c 550 }
551 default:
552 {
faff3767 553 if (theCtx->SupportedTextureFormats()->HasCompressed()
554 && !theCtx->caps->compressedTexturesDisable)
555 {
556 if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats()))
557 {
558 return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap());
559 }
560 }
561
562 Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats());
077a220c 563 if (anImage.IsNull())
564 {
565 return false;
566 }
ba00aab7 567 return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap());
077a220c 568 }
569 }
570}
571
faff3767 572// =======================================================================
573// function : InitCompressed
574// purpose :
575// =======================================================================
576bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
577 const Image_CompressedPixMap& theImage,
578 const Standard_Boolean theIsColorMap)
579{
580 if (theImage.SizeX() < 1
581 || theImage.SizeY() < 1
582 || theImage.FaceData().IsNull())
583 {
584 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
585 "Error: texture of 0 size cannot be created.");
586 Release (theCtx.get());
587 return false;
588 }
589 if (theImage.SizeX() > theCtx->MaxTextureSize()
590 || theImage.SizeY() > theCtx->MaxTextureSize())
591 {
592 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
593 TCollection_AsciiString ("Error: Texture dimension - ") + theImage.SizeX() + "x" + theImage.SizeY()
594 + " exceeds hardware limits (" + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ")");
595 Release (theCtx.get());
596 return false;
597 }
598
599 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap);
600 if (!aFormat.IsValid())
601 {
602 Release (theCtx.get());
603 return false;
604 }
605
606 if (!Create (theCtx))
607 {
608 return false;
609 }
610
611 myTarget = GL_TEXTURE_2D;
612 myNbSamples = 1;
613 myTextFormat = aFormat.Format();
614 mySizedFormat = aFormat.Internal();
615 myIsTopDown = theImage.IsTopDown();
616 mySizeX = theImage.SizeX();
617 mySizeY = theImage.SizeY();
618 myMaxMipLevel = Max (theImage.MipMaps().Size() - 1, 0);
619 if (myMaxMipLevel > 0
620 && !theImage.IsCompleteMipMapSet())
621 {
622 const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (mySizeX, mySizeY), myMaxMipLevel);
623 if (!theCtx->HasTextureBaseLevel())
624 {
625 myMaxMipLevel = 0;
626 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
627 TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
628 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
629 }
630 else
631 {
632 Message::SendTrace (TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
633 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
634 }
635 }
636
637 Bind (theCtx);
638 applyDefaultSamplerParams (theCtx);
639
640 // setup the alignment
641 OpenGl_UnpackAlignmentSentry::Reset();
642
643 Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY());
644 const Standard_Byte* aData = theImage.FaceData()->Data();
645 for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
646 {
647 const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter);
648 theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
649 const GLenum aTexImgErr = glGetError();
650 if (aTexImgErr != GL_NO_ERROR)
651 {
652 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
653 TCollection_AsciiString ("Error: 2D compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
654 + " IF: " + int(aFormat.Internal()) + " PF: " + int(aFormat.PixelFormat())
655 + " DT: " + int(aFormat.DataType())
656 + " can not be created with error " + int(aTexImgErr) + ".");
657 Unbind (theCtx);
658 Release (theCtx.get());
659 return false;
660 }
661
662 aData += aMipLength;
663 aMipSizeXY /= 2;
664 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
665 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
666 }
667
668 Unbind (theCtx);
669 return true;
670}
671
3c4b62a4 672// =======================================================================
673// function : Init2DMultisample
674// purpose :
675// =======================================================================
676bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
677 const GLsizei theNbSamples,
678 const GLint theTextFormat,
679 const GLsizei theSizeX,
680 const GLsizei theSizeY)
681{
682 if (!Create (theCtx)
683 || theNbSamples > theCtx->MaxMsaaSamples()
684 || theNbSamples < 1)
685 {
686 return false;
687 }
688
15669413 689 myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
3c4b62a4 690 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
faff3767 691 myMaxMipLevel = 0;
3c4b62a4 692 if(theSizeX > theCtx->MaxTextureSize()
693 || theSizeY > theCtx->MaxTextureSize())
694 {
695 return false;
696 }
697
698 Bind (theCtx);
699 //myTextFormat = theTextFormat;
15669413 700 mySizedFormat = theTextFormat;
3c4b62a4 701#if !defined(GL_ES_VERSION_2_0)
702 if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
703 {
15669413 704 theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 705 }
706 else
707 {
15669413 708 theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 709 }
710#else
15669413 711 theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 712#endif
713 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
714 {
715 Unbind (theCtx);
716 return false;
717 }
718
719 mySizeX = theSizeX;
720 mySizeY = theSizeY;
721
722 Unbind (theCtx);
723 return true;
724}
725
68333c8f 726// =======================================================================
727// function : InitRectangle
728// purpose :
729// =======================================================================
730bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
731 const Standard_Integer theSizeX,
732 const Standard_Integer theSizeY,
733 const OpenGl_TextureFormat& theFormat)
734{
735 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
736 {
737 return false;
738 }
ca3c13d1 739
740#if !defined(GL_ES_VERSION_2_0)
68333c8f 741 myTarget = GL_TEXTURE_RECTANGLE;
15669413 742 myNbSamples = 1;
faff3767 743 myMaxMipLevel = 0;
68333c8f 744
fe3a29bc 745 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
746 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
ca3c13d1 747
68333c8f 748 Bind (theCtx);
cc8cbabe 749 applyDefaultSamplerParams (theCtx);
68333c8f 750
15669413 751 myTextFormat = theFormat.Format();
752 mySizedFormat = theFormat.Internal();
68333c8f 753
90fd6145 754 // setup the alignment
755 OpenGl_UnpackAlignmentSentry::Reset();
756
15669413 757 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
758 aSizeX, aSizeY, 0,
759 myTextFormat, GL_FLOAT, NULL);
68333c8f 760
761 GLint aTestSizeX = 0;
762 GLint aTestSizeY = 0;
763
15669413 764 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
765 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
766 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
68333c8f 767
768 if (aTestSizeX == 0 || aTestSizeY == 0)
769 {
770 Unbind (theCtx);
771 return false;
772 }
773
15669413 774 glTexImage2D (myTarget, 0, mySizedFormat,
775 aSizeX, aSizeY, 0,
776 myTextFormat, GL_FLOAT, NULL);
68333c8f 777
778 if (glGetError() != GL_NO_ERROR)
779 {
780 Unbind (theCtx);
781 return false;
782 }
783
784 mySizeX = aSizeX;
785 mySizeY = aSizeY;
786
787 Unbind (theCtx);
788 return true;
ca3c13d1 789#else
20aeeb7b 790 (void )theSizeX;
791 (void )theSizeY;
792 (void )theFormat;
ca3c13d1 793 return false;
794#endif
68333c8f 795}
74fb257d 796
797// =======================================================================
798// function : Init3D
799// purpose :
800// =======================================================================
801bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
ba00aab7 802 const OpenGl_TextureFormat& theFormat,
803 const Graphic3d_Vec3i& theSizeXYZ,
74fb257d 804 const void* thePixels)
805{
806 if (theCtx->Functions()->glTexImage3D == NULL)
807 {
ba00aab7 808 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
809 "Error: three-dimensional textures are not supported by hardware.");
74fb257d 810 return false;
811 }
812
813 if (!Create(theCtx))
814 {
815 return false;
816 }
817
818 myTarget = GL_TEXTURE_3D;
15669413 819 myNbSamples = 1;
faff3767 820 myMaxMipLevel = 0;
74fb257d 821
ba00aab7 822 const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
823 if (aSizeXYZ != theSizeXYZ)
824 {
825 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
826 "Error: 3D texture dimensions exceed hardware limits.");
827 Release (theCtx.get());
828 Unbind (theCtx);
829 return false;
830 }
74fb257d 831 Bind (theCtx);
832
ba00aab7 833 if (theFormat.DataType() == GL_FLOAT
834 && !theCtx->arbTexFloat)
74fb257d 835 {
ba00aab7 836 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
837 "Error: floating-point textures are not supported by hardware.");
838 Release (theCtx.get());
74fb257d 839 Unbind (theCtx);
840 return false;
841 }
842
ba00aab7 843 mySizedFormat = theFormat.InternalFormat();
74fb257d 844
90fd6145 845 // setup the alignment
846 OpenGl_UnpackAlignmentSentry::Reset();
847
74fb257d 848#if !defined (GL_ES_VERSION_2_0)
15669413 849 theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
ba00aab7 850 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
851 theFormat.PixelFormat(), theFormat.DataType(), NULL);
74fb257d 852
ba00aab7 853 NCollection_Vec3<GLint> aTestSizeXYZ;
854 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x());
855 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y());
856 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z());
15669413 857 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
ba00aab7 858 if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0)
74fb257d 859 {
860 Unbind (theCtx);
ba00aab7 861 Release (theCtx.get());
74fb257d 862 return false;
863 }
864#endif
865
cc8cbabe 866 applyDefaultSamplerParams (theCtx);
15669413 867 theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
ba00aab7 868 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
869 theFormat.PixelFormat(), theFormat.DataType(), thePixels);
74fb257d 870
871 if (glGetError() != GL_NO_ERROR)
872 {
873 Unbind (theCtx);
ba00aab7 874 Release (theCtx.get());
74fb257d 875 return false;
876 }
877
ba00aab7 878 mySizeX = aSizeXYZ.x();
879 mySizeY = aSizeXYZ.y();
880 mySizeZ = aSizeXYZ.z();
74fb257d 881
882 Unbind (theCtx);
883 return true;
884}
15669413 885
077a220c 886// =======================================================================
67312b79 887// function : InitCubeMap
077a220c 888// purpose :
889// =======================================================================
67312b79 890bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx,
077a220c 891 const Handle(Graphic3d_CubeMap)& theCubeMap,
ba00aab7 892 Standard_Size theSize,
893 Image_Format theFormat,
894 Standard_Boolean theToGenMipmap,
895 Standard_Boolean theIsColorMap)
077a220c 896{
897 if (!Create (theCtx))
898 {
899 Release (theCtx.get());
900 return false;
901 }
902
faff3767 903 Handle(Image_PixMap) anImage;
904 Handle(Image_CompressedPixMap) aCompImage;
905 OpenGl_TextureFormat aFormat;
077a220c 906 if (!theCubeMap.IsNull())
907 {
faff3767 908 theCubeMap->Reset();
909 if (theCtx->SupportedTextureFormats()->HasCompressed()
910 && !theCtx->caps->compressedTexturesDisable)
077a220c 911 {
faff3767 912 aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
077a220c 913 }
faff3767 914 if (!aCompImage.IsNull())
077a220c 915 {
faff3767 916 aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, aCompImage->CompressedFormat(), theIsColorMap);
917 if (aFormat.IsValid())
918 {
919 theToGenMipmap = false;
920 theSize = aCompImage->SizeX();
921 theFormat = aCompImage->BaseFormat();
922 myMaxMipLevel = Max (aCompImage->MipMaps().Size() - 1, 0);
923 if (myMaxMipLevel > 0
924 && !aCompImage->IsCompleteMipMapSet())
925 {
926 const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (aCompImage->SizeX(), aCompImage->SizeY()), myMaxMipLevel);
927 if (!theCtx->HasTextureBaseLevel())
928 {
929 myMaxMipLevel = 0;
930 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
931 TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
932 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
933 }
934 else
935 {
936 Message::SendTrace (TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
937 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
938 }
939 }
940
941 OpenGl_UnpackAlignmentSentry::Reset();
942 }
943 else
944 {
945 aCompImage.Nullify();
946 }
947 }
948
949 if (!aFormat.IsValid())
950 {
951 anImage = theCubeMap->Reset().Value (theCtx->SupportedTextureFormats());
952 if (anImage.IsNull())
953 {
954 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
955 "Unable to get the first side of cubemap");
956 Release(theCtx.get());
957 return false;
958 }
959
960 theSize = anImage->SizeX();
961 theFormat = anImage->Format();
962 theToGenMipmap = theCubeMap->HasMipmaps();
963 myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
077a220c 964 }
faff3767 965
966 myIsTopDown = theCubeMap->IsTopDown();
967 }
968 else
969 {
970 myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
077a220c 971 }
972
faff3767 973 if (!aFormat.IsValid())
974 {
975 aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
976 }
ba00aab7 977 if (!aFormat.IsValid())
077a220c 978 {
979 Unbind(theCtx);
980 Release(theCtx.get());
981 return false;
982 }
983
984 myTarget = GL_TEXTURE_CUBE_MAP;
077a220c 985 myNbSamples = 1;
67312b79 986 mySizeX = (GLsizei )theSize;
987 mySizeY = (GLsizei )theSize;
faff3767 988 myTextFormat = aFormat.Format();
989 mySizedFormat = aFormat.Internal();
e4e3254a 990#if !defined(GL_ES_VERSION_2_0)
991 const GLint anIntFormat = aFormat.InternalFormat();
992#else
993 // ES 2.0 does not support sized formats and format conversions - them detected from data type
994 const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? aFormat.InternalFormat() : aFormat.PixelFormat();
995#endif
996
077a220c 997 Bind (theCtx);
998 applyDefaultSamplerParams (theCtx);
999
1000 for (Standard_Integer i = 0; i < 6; ++i)
1001 {
faff3767 1002 const Standard_Byte* aData = NULL;
077a220c 1003
1004 if (!theCubeMap.IsNull())
1005 {
faff3767 1006 if (i != 0)
1007 {
1008 if (!aCompImage.IsNull())
1009 {
1010 aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
1011 }
1012 else
1013 {
1014 anImage = theCubeMap->Value (theCtx->SupportedTextureFormats());
1015 }
1016 }
1017 if (!aCompImage.IsNull())
1018 {
1019 Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY);
1020 aData = aCompImage->FaceData()->Data();
1021 for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
1022 {
1023 const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter);
1024 theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
1025 const GLenum aTexImgErr = glGetError();
1026 if (aTexImgErr != GL_NO_ERROR)
1027 {
1028 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1029 TCollection_AsciiString ("Error: cubemap compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
1030 + " IF: " + int(aFormat.Internal()) + " PF: " + int(aFormat.PixelFormat())
1031 + " DT: " + int(aFormat.DataType())
1032 + " can not be created with error " + int(aTexImgErr) + ".");
1033 Unbind (theCtx);
1034 Release (theCtx.get());
1035 return false;
1036 }
1037
1038 aData += aMipLength;
1039 aMipSizeXY /= 2;
1040 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
1041 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
1042 }
1043
1044 theCubeMap->Next();
1045 continue;
1046 }
1047
077a220c 1048 if (!anImage.IsNull())
1049 {
1050#if !defined(GL_ES_VERSION_2_0)
1051 const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
1052 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
1053
1054 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
1055 const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
1056 const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
1057 const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
1058 glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
1059#else
1060 Handle(Image_PixMap) aCopyImage = new Image_PixMap();
1061 aCopyImage->InitTrash (theFormat, theSize, theSize);
1062 for (unsigned int y = 0; y < theSize; ++y)
1063 {
1064 for (unsigned int x = 0; x < theSize; ++x)
1065 {
1066 for (unsigned int aByte = 0; aByte < anImage->SizePixelBytes(); ++aByte)
1067 {
1068 aCopyImage->ChangeRawValue (y, x)[aByte] = anImage->RawValue (y, x)[aByte];
1069 }
1070 }
1071 }
1072 anImage = aCopyImage;
1073 const GLint anAligment = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
1074 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
1075#endif
1076 aData = anImage->Data();
1077 }
1078 else
1079 {
ba00aab7 1080 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1081 TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap");
077a220c 1082 Unbind (theCtx);
1083 Release (theCtx.get());
1084 return false;
1085 }
1086 theCubeMap->Next();
1087 }
1088
1089 glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
e4e3254a 1090 anIntFormat,
077a220c 1091 GLsizei(theSize), GLsizei(theSize),
ba00aab7 1092 0, aFormat.PixelFormat(), aFormat.DataType(),
077a220c 1093 aData);
1094
1095 OpenGl_UnpackAlignmentSentry::Reset();
1096
ba00aab7 1097 const GLenum anErr = glGetError();
1098 if (anErr != GL_NO_ERROR)
077a220c 1099 {
1100 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 1101 TCollection_AsciiString ("Unable to initialize side of cubemap. Error #") + int(anErr));
077a220c 1102 Unbind (theCtx);
1103 Release (theCtx.get());
1104 return false;
1105 }
1106 }
1107
1108 if (theToGenMipmap && theCtx->arbFBO != NULL)
1109 {
ba00aab7 1110 theCtx->arbFBO->glGenerateMipmap (myTarget);
1111 const GLenum anErr = glGetError();
1112 if (anErr != GL_NO_ERROR)
1113 {
1114 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1115 TCollection_AsciiString ("Unable to generate mipmap of cubemap. Error #") + int(anErr));
1116 Unbind (theCtx);
1117 Release (theCtx.get());
1118 return false;
1119 }
077a220c 1120 }
1121
1122 Unbind (theCtx.get());
1123 return true;
1124}
1125
15669413 1126// =======================================================================
1127// function : PixelSizeOfPixelFormat
1128// purpose :
1129// =======================================================================
1130Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
1131{
1132 switch(theInternalFormat)
1133 {
1134 // RED variations (GL_RED, OpenGL 3.0+)
1135 case GL_RED:
1136 case GL_R8: return 1;
1137 case GL_R16: return 2;
1138 case GL_R16F: return 2;
1139 case GL_R32F: return 4;
1140 // RGB variations
1141 case GL_RGB: return 3;
1142 case GL_RGB8: return 3;
1143 case GL_RGB16: return 6;
1144 case GL_RGB16F: return 6;
1145 case GL_RGB32F: return 12;
1146 // RGBA variations
1147 case GL_RGBA: return 4;
1148 case GL_RGBA8: return 4;
1149 case GL_RGB10_A2: return 4;
1150 case GL_RGBA12: return 6;
1151 case GL_RGBA16: return 8;
1152 case GL_RGBA16F: return 8;
1153 case GL_RGBA32F: return 16;
1154 //
1155 case GL_BGRA_EXT: return 4;
1156 // ALPHA variations (deprecated)
1157 case GL_ALPHA:
1158 case GL_ALPHA8: return 1;
1159 case GL_ALPHA16: return 2;
1160 case GL_LUMINANCE: return 1;
1161 case GL_LUMINANCE_ALPHA: return 2;
1162 // depth-stencil
1163 case GL_DEPTH24_STENCIL8: return 4;
1164 case GL_DEPTH32F_STENCIL8: return 8;
1165 case GL_DEPTH_COMPONENT16: return 2;
1166 case GL_DEPTH_COMPONENT24: return 3;
1167 case GL_DEPTH_COMPONENT32F: return 4;
faff3767 1168 // compressed
1169 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block)
1170 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
1171 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1172 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
1173 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block)
1174 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
1175 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1176 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
1177 return 1;
15669413 1178 }
faff3767 1179 return 1;
15669413 1180}
1181
1182// =======================================================================
1183// function : EstimatedDataSize
1184// purpose :
1185// =======================================================================
1186Standard_Size OpenGl_Texture::EstimatedDataSize() const
1187{
1188 if (!IsValid())
1189 {
1190 return 0;
1191 }
1192
1193 Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
1194 if (mySizeY != 0)
1195 {
1196 aSize *= Standard_Size(mySizeY);
1197 }
1198 if (mySizeZ != 0)
1199 {
1200 aSize *= Standard_Size(mySizeZ);
1201 }
67312b79 1202 if (myTarget == GL_TEXTURE_CUBE_MAP)
1203 {
1204 aSize *= 6; // cube sides
1205 }
faff3767 1206 if (myMaxMipLevel > 0)
15669413 1207 {
1208 aSize = aSize + aSize / 3;
1209 }
1210 return aSize;
1211}