1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <OpenGl_Texture.hxx>
17 #include <OpenGl_ArbFBO.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_GlCore32.hxx>
20 #include <OpenGl_Sampler.hxx>
21 #include <Graphic3d_TextureParams.hxx>
22 #include <TCollection_ExtendedString.hxx>
23 #include <Standard_Assert.hxx>
24 #include <Image_PixMap.hxx>
26 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
28 //! Simple class to reset unpack alignment settings
29 struct OpenGl_UnpackAlignmentSentry
32 //! Reset unpack alignment settings to safe values
35 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
36 #if !defined(GL_ES_VERSION_2_0)
37 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
41 OpenGl_UnpackAlignmentSentry() {}
43 ~OpenGl_UnpackAlignmentSentry()
50 // =======================================================================
51 // function : OpenGl_Texture
53 // =======================================================================
54 OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
55 const Handle(Graphic3d_TextureParams)& theParams)
56 : OpenGl_NamedResource (theResourceId),
57 mySampler (new OpenGl_Sampler (theParams)),
59 myTextureId (NO_TEXTURE),
60 myTarget (GL_TEXTURE_2D),
64 myTextFormat (GL_RGBA),
65 mySizedFormat(GL_RGBA8),
67 myHasMipmaps (Standard_False),
73 // =======================================================================
74 // function : ~OpenGl_Texture
76 // =======================================================================
77 OpenGl_Texture::~OpenGl_Texture()
82 // =======================================================================
85 // =======================================================================
86 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
88 if (myTextureId != NO_TEXTURE)
93 theCtx->core11fwd->glGenTextures (1, &myTextureId);
94 if (myTextureId == NO_TEXTURE)
99 //mySampler->Create (theCtx); // do not create sampler object by default
103 // =======================================================================
104 // function : Release
106 // =======================================================================
107 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
109 mySampler->Release (theGlCtx);
110 if (myTextureId == NO_TEXTURE)
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...",);
119 if (theGlCtx->IsValid())
121 glDeleteTextures (1, &myTextureId);
123 myTextureId = NO_TEXTURE;
124 mySizeX = mySizeY = mySizeZ = 0;
127 // =======================================================================
128 // function : applyDefaultSamplerParams
130 // =======================================================================
131 void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
133 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myHasMipmaps);
134 if (mySampler->IsValid() && !mySampler->IsImmutable())
136 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myHasMipmaps);
140 // =======================================================================
143 // =======================================================================
144 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
145 const Graphic3d_TextureUnit theTextureUnit) const
147 if (theCtx->core15fwd != NULL)
149 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
151 mySampler->Bind (theCtx, theTextureUnit);
152 glBindTexture (myTarget, myTextureId);
155 // =======================================================================
158 // =======================================================================
159 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
160 const Graphic3d_TextureUnit theTextureUnit) const
162 if (theCtx->core15fwd != NULL)
164 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
166 mySampler->Unbind (theCtx, theTextureUnit);
167 glBindTexture (myTarget, NO_TEXTURE);
170 //=======================================================================
171 //function : InitSamplerObject
173 //=======================================================================
174 bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
176 return myTextureId != NO_TEXTURE
177 && mySampler->Init (theCtx, *this);
180 // =======================================================================
183 // =======================================================================
184 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
185 const OpenGl_TextureFormat& theFormat,
186 const Graphic3d_Vec2i& theSizeXY,
187 const Graphic3d_TypeOfTexture theType,
188 const Image_PixMap* theImage)
190 if (theSizeXY.x() < 1
191 || theSizeXY.y() < 1)
193 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
194 "Error: texture of 0 size cannot be created.");
195 Release (theCtx.get());
199 #if !defined(GL_ES_VERSION_2_0)
200 const GLenum aTarget = theType == Graphic3d_TOT_1D
204 const GLenum aTarget = GL_TEXTURE_2D;
206 const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP);
207 const bool toPatchExisting = IsValid()
208 && myTextFormat == theFormat.PixelFormat()
209 && myTarget == aTarget
210 && myHasMipmaps == toCreateMipMaps
211 && mySizeX == theSizeXY.x()
212 && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
213 if (!Create (theCtx))
215 Release (theCtx.get());
219 if (theImage != NULL)
221 myIsAlpha = theImage->Format() == Image_Format_Alpha
222 || theImage->Format() == Image_Format_AlphaF;
226 myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
229 myHasMipmaps = toCreateMipMaps;
230 myTextFormat = theFormat.PixelFormat();
231 mySizedFormat = theFormat.InternalFormat();
233 #if !defined(GL_ES_VERSION_2_0)
234 const GLint anIntFormat = theFormat.InternalFormat();
236 // ES 2.0 does not support sized formats and format conversions - them detected from data type
237 const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? theFormat.InternalFormat() : theFormat.PixelFormat();
240 if (theFormat.DataType() == GL_FLOAT
241 && !theCtx->arbTexFloat)
243 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
244 "Error: floating-point textures are not supported by hardware.");
245 Release (theCtx.get());
249 const GLsizei aMaxSize = theCtx->MaxTextureSize();
250 if (theSizeXY.x() > aMaxSize
251 || theSizeXY.y() > aMaxSize)
253 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
254 TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y()
255 + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")");
256 Release (theCtx.get());
259 #if !defined(GL_ES_VERSION_2_0)
260 else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
262 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
263 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
264 // Trying to create NPOT textures on such hardware will not fail
265 // but driver will fall back into software rendering,
266 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
267 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
268 if (theSizeXY.x() != aWidthP2
269 || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2))
271 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
272 TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
273 " are not supported by hardware.");
274 Release (theCtx.get());
279 else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
281 // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
282 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
283 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
284 if (theSizeXY.x() != aWidthP2
285 || theSizeXY.y() != aHeightP2)
287 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
288 TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
289 " are not supported by OpenGL ES 2.0");
290 Release (theCtx.get());
296 #if !defined(GL_ES_VERSION_2_0)
297 GLint aTestWidth = 0;
298 GLint aTestHeight = 0;
300 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
302 // setup the alignment
303 OpenGl_UnpackAlignmentSentry anUnpackSentry;
304 (void)anUnpackSentry; // avoid compiler warning
306 if (aDataPtr != NULL)
308 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
309 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
311 #if !defined(GL_ES_VERSION_2_0)
312 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
313 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
314 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
315 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
322 case Graphic3d_TOT_1D:
324 #if !defined(GL_ES_VERSION_2_0)
326 applyDefaultSamplerParams (theCtx);
329 glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
330 theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
335 // use proxy to check texture could be created or not
336 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
338 theFormat.PixelFormat(), theFormat.DataType(), NULL);
339 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
340 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
343 // no memory or broken input parameters
345 Release (theCtx.operator->());
349 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
351 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
352 if (glGetError() != GL_NO_ERROR)
355 Release (theCtx.get());
359 mySizeX = theSizeXY.x();
365 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
366 "Error: 1D textures are not supported by hardware.");
367 Release (theCtx.get());
371 case Graphic3d_TOT_2D:
374 applyDefaultSamplerParams (theCtx);
377 glTexSubImage2D (GL_TEXTURE_2D, 0,
379 theSizeXY.x(), theSizeXY.y(),
380 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
385 #if !defined(GL_ES_VERSION_2_0)
386 // use proxy to check texture could be created or not
387 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
388 theSizeXY.x(), theSizeXY.y(), 0,
389 theFormat.PixelFormat(), theFormat.DataType(), NULL);
390 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
391 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
392 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
393 if (aTestWidth == 0 || aTestHeight == 0)
395 // no memory or broken input parameters
397 Release (theCtx.get());
402 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
403 theSizeXY.x(), theSizeXY.y(), 0,
404 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
405 const GLenum anErr = glGetError();
406 if (anErr != GL_NO_ERROR)
408 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
409 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
410 + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
411 + " DT: " + int(theFormat.DataType())
412 + " can not be created with error " + int(anErr) + ".");
414 Release (theCtx.get());
418 mySizeX = theSizeXY.x();
419 mySizeY = theSizeXY.y();
424 case Graphic3d_TOT_2D_MIPMAP:
427 applyDefaultSamplerParams (theCtx);
430 glTexSubImage2D (GL_TEXTURE_2D, 0,
432 theSizeXY.x(), theSizeXY.y(),
433 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
434 if (theCtx->arbFBO != NULL)
437 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
438 if (glGetError() != GL_NO_ERROR)
441 Release (theCtx.get());
450 #if !defined(GL_ES_VERSION_2_0)
451 // use proxy to check texture could be created or not
452 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
453 theSizeXY.x(), theSizeXY.y(), 0,
454 theFormat.PixelFormat(), theFormat.DataType(), NULL);
455 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
456 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
457 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
458 if (aTestWidth == 0 || aTestHeight == 0)
460 // no memory or broken input parameters
462 Release (theCtx.get());
467 // upload main picture
468 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
469 theSizeXY.x(), theSizeXY.y(), 0,
470 theFormat.PixelFormat(), theFormat.DataType(), theImage->Data());
471 const GLenum aTexImgErr = glGetError();
472 if (aTexImgErr != GL_NO_ERROR)
474 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
475 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
476 + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
477 + " DT: " + int(theFormat.DataType())
478 + " can not be created with error " + int(aTexImgErr) + ".");
480 Release (theCtx.get());
484 mySizeX = theSizeXY.x();
485 mySizeY = theSizeXY.y();
487 if (theCtx->arbFBO != NULL)
490 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
491 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
493 if (glGetError() != GL_NO_ERROR)
496 Release (theCtx.get());
502 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
503 "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
505 Release (theCtx.get());
512 case Graphic3d_TOT_CUBEMAP:
515 Release (theCtx.get());
520 Release (theCtx.get());
524 // =======================================================================
527 // =======================================================================
528 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
529 const Image_PixMap& theImage,
530 const Graphic3d_TypeOfTexture theType,
531 const Standard_Boolean theIsColorMap)
533 if (theImage.IsEmpty())
535 Release (theCtx.get());
539 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap);
540 if (!aFormat.IsValid())
542 Release (theCtx.get());
546 return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()),
550 // =======================================================================
553 // =======================================================================
554 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
555 const Handle(Graphic3d_TextureMap)& theTextureMap)
557 if (theTextureMap.IsNull())
562 switch (theTextureMap->Type())
564 case Graphic3d_TOT_CUBEMAP:
566 return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap),
567 0, Image_Format_RGB, false, theTextureMap->IsColorMap());
571 Handle(Image_PixMap) anImage = theTextureMap->GetImage();
572 if (anImage.IsNull())
576 return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap());
581 // =======================================================================
582 // function : Init2DMultisample
584 // =======================================================================
585 bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
586 const GLsizei theNbSamples,
587 const GLint theTextFormat,
588 const GLsizei theSizeX,
589 const GLsizei theSizeY)
592 || theNbSamples > theCtx->MaxMsaaSamples()
598 myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
599 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
600 myHasMipmaps = false;
601 if(theSizeX > theCtx->MaxTextureSize()
602 || theSizeY > theCtx->MaxTextureSize())
608 //myTextFormat = theTextFormat;
609 mySizedFormat = theTextFormat;
610 #if !defined(GL_ES_VERSION_2_0)
611 if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
613 theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
617 theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
620 theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
622 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
635 // =======================================================================
636 // function : InitRectangle
638 // =======================================================================
639 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
640 const Standard_Integer theSizeX,
641 const Standard_Integer theSizeY,
642 const OpenGl_TextureFormat& theFormat)
644 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
649 #if !defined(GL_ES_VERSION_2_0)
650 myTarget = GL_TEXTURE_RECTANGLE;
652 myHasMipmaps = false;
654 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
655 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
658 applyDefaultSamplerParams (theCtx);
660 myTextFormat = theFormat.Format();
661 mySizedFormat = theFormat.Internal();
663 // setup the alignment
664 OpenGl_UnpackAlignmentSentry::Reset();
666 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
668 myTextFormat, GL_FLOAT, NULL);
670 GLint aTestSizeX = 0;
671 GLint aTestSizeY = 0;
673 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
674 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
675 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
677 if (aTestSizeX == 0 || aTestSizeY == 0)
683 glTexImage2D (myTarget, 0, mySizedFormat,
685 myTextFormat, GL_FLOAT, NULL);
687 if (glGetError() != GL_NO_ERROR)
706 // =======================================================================
709 // =======================================================================
710 bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
711 const OpenGl_TextureFormat& theFormat,
712 const Graphic3d_Vec3i& theSizeXYZ,
713 const void* thePixels)
715 if (theCtx->Functions()->glTexImage3D == NULL)
717 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
718 "Error: three-dimensional textures are not supported by hardware.");
727 myTarget = GL_TEXTURE_3D;
729 myHasMipmaps = false;
731 const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
732 if (aSizeXYZ != theSizeXYZ)
734 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
735 "Error: 3D texture dimensions exceed hardware limits.");
736 Release (theCtx.get());
742 if (theFormat.DataType() == GL_FLOAT
743 && !theCtx->arbTexFloat)
745 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
746 "Error: floating-point textures are not supported by hardware.");
747 Release (theCtx.get());
752 mySizedFormat = theFormat.InternalFormat();
754 // setup the alignment
755 OpenGl_UnpackAlignmentSentry::Reset();
757 #if !defined (GL_ES_VERSION_2_0)
758 theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
759 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
760 theFormat.PixelFormat(), theFormat.DataType(), NULL);
762 NCollection_Vec3<GLint> aTestSizeXYZ;
763 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x());
764 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y());
765 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z());
766 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
767 if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0)
770 Release (theCtx.get());
775 applyDefaultSamplerParams (theCtx);
776 theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
777 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
778 theFormat.PixelFormat(), theFormat.DataType(), thePixels);
780 if (glGetError() != GL_NO_ERROR)
783 Release (theCtx.get());
787 mySizeX = aSizeXYZ.x();
788 mySizeY = aSizeXYZ.y();
789 mySizeZ = aSizeXYZ.z();
795 // =======================================================================
796 // function : InitCubeMap
798 // =======================================================================
799 bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx,
800 const Handle(Graphic3d_CubeMap)& theCubeMap,
801 Standard_Size theSize,
802 Image_Format theFormat,
803 Standard_Boolean theToGenMipmap,
804 Standard_Boolean theIsColorMap)
806 if (!Create (theCtx))
808 Release (theCtx.get());
812 if (!theCubeMap.IsNull())
814 theToGenMipmap = theCubeMap->HasMipmaps();
815 if (Handle(Image_PixMap) anImage = theCubeMap->Reset().Value())
817 theSize = anImage->SizeX();
818 theFormat = anImage->Format();
822 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
823 "Unable to get the first side of cubemap");
824 Release(theCtx.get());
829 OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
830 if (!aFormat.IsValid())
833 Release(theCtx.get());
837 myTarget = GL_TEXTURE_CUBE_MAP;
838 myHasMipmaps = theToGenMipmap;
840 mySizeX = (GLsizei )theSize;
841 mySizeY = (GLsizei )theSize;
843 applyDefaultSamplerParams (theCtx);
845 for (Standard_Integer i = 0; i < 6; ++i)
847 const void* aData = NULL;
848 Handle(Image_PixMap) anImage;
850 if (!theCubeMap.IsNull())
852 anImage = theCubeMap->Value();
853 if (!anImage.IsNull())
855 #if !defined(GL_ES_VERSION_2_0)
856 const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
857 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
859 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
860 const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
861 const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
862 const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
863 glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
865 Handle(Image_PixMap) aCopyImage = new Image_PixMap();
866 aCopyImage->InitTrash (theFormat, theSize, theSize);
867 for (unsigned int y = 0; y < theSize; ++y)
869 for (unsigned int x = 0; x < theSize; ++x)
871 for (unsigned int aByte = 0; aByte < anImage->SizePixelBytes(); ++aByte)
873 aCopyImage->ChangeRawValue (y, x)[aByte] = anImage->RawValue (y, x)[aByte];
877 anImage = aCopyImage;
878 const GLint anAligment = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
879 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
881 aData = anImage->Data();
885 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
886 TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap");
888 Release (theCtx.get());
894 glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
895 aFormat.InternalFormat(),
896 GLsizei(theSize), GLsizei(theSize),
897 0, aFormat.PixelFormat(), aFormat.DataType(),
900 OpenGl_UnpackAlignmentSentry::Reset();
902 const GLenum anErr = glGetError();
903 if (anErr != GL_NO_ERROR)
905 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
906 TCollection_AsciiString ("Unable to initialize side of cubemap. Error #") + int(anErr));
908 Release (theCtx.get());
913 if (theToGenMipmap && theCtx->arbFBO != NULL)
915 theCtx->arbFBO->glGenerateMipmap (myTarget);
916 const GLenum anErr = glGetError();
917 if (anErr != GL_NO_ERROR)
919 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
920 TCollection_AsciiString ("Unable to generate mipmap of cubemap. Error #") + int(anErr));
922 Release (theCtx.get());
927 Unbind (theCtx.get());
931 // =======================================================================
932 // function : PixelSizeOfPixelFormat
934 // =======================================================================
935 Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
937 switch(theInternalFormat)
939 // RED variations (GL_RED, OpenGL 3.0+)
941 case GL_R8: return 1;
942 case GL_R16: return 2;
943 case GL_R16F: return 2;
944 case GL_R32F: return 4;
946 case GL_RGB: return 3;
947 case GL_RGB8: return 3;
948 case GL_RGB16: return 6;
949 case GL_RGB16F: return 6;
950 case GL_RGB32F: return 12;
952 case GL_RGBA: return 4;
953 case GL_RGBA8: return 4;
954 case GL_RGB10_A2: return 4;
955 case GL_RGBA12: return 6;
956 case GL_RGBA16: return 8;
957 case GL_RGBA16F: return 8;
958 case GL_RGBA32F: return 16;
960 case GL_BGRA_EXT: return 4;
961 // ALPHA variations (deprecated)
963 case GL_ALPHA8: return 1;
964 case GL_ALPHA16: return 2;
965 case GL_LUMINANCE: return 1;
966 case GL_LUMINANCE_ALPHA: return 2;
968 case GL_DEPTH24_STENCIL8: return 4;
969 case GL_DEPTH32F_STENCIL8: return 8;
970 case GL_DEPTH_COMPONENT16: return 2;
971 case GL_DEPTH_COMPONENT24: return 3;
972 case GL_DEPTH_COMPONENT32F: return 4;
977 // =======================================================================
978 // function : EstimatedDataSize
980 // =======================================================================
981 Standard_Size OpenGl_Texture::EstimatedDataSize() const
988 Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
991 aSize *= Standard_Size(mySizeY);
995 aSize *= Standard_Size(mySizeZ);
997 if (myTarget == GL_TEXTURE_CUBE_MAP)
999 aSize *= 6; // cube sides
1003 aSize = aSize + aSize / 3;