// Created by: Kirill GAVRILOV
-// Copyright (c) 2012 OPEN CASCADE SAS
+// Copyright (c) 2013-2014 OPEN CASCADE SAS
//
-// The content of this file is subject to the Open CASCADE Technology Public
-// License Version 6.5 (the "License"). You may not use the content of this file
-// except in compliance with the License. Please obtain a copy of the License
-// at http://www.opencascade.org and read it completely before using this file.
+// This file is part of Open CASCADE Technology software library.
//
-// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
-// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
//
-// The Original Code and all software distributed under the License is
-// distributed on an "AS IS" basis, without warranty of any kind, and the
-// Initial Developer hereby disclaims all such warranties, including without
-// limitation, any warranties of merchantability, fitness for a particular
-// purpose or non-infringement. Please see the License for the specific terms
-// and conditions governing the rights and limitations under the License.
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
#include <OpenGl_Texture.hxx>
-#include <OpenGl_ExtFBO.hxx>
+#include <OpenGl_ArbFBO.hxx>
#include <OpenGl_Context.hxx>
+#include <OpenGl_GlCore32.hxx>
+#include <OpenGl_Sampler.hxx>
#include <Graphic3d_TextureParams.hxx>
+#include <TCollection_ExtendedString.hxx>
#include <Standard_Assert.hxx>
+#include <Image_CompressedPixMap.hxx>
#include <Image_PixMap.hxx>
+#include <Image_SupportedFormats.hxx>
-IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
+
+namespace
+{
//! Simple class to reset unpack alignment settings
struct OpenGl_UnpackAlignmentSentry
{
//! Reset unpack alignment settings to safe values
- void Reset()
+ static void Reset()
{
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+ #if !defined(GL_ES_VERSION_2_0)
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
+ #endif
}
+ OpenGl_UnpackAlignmentSentry() {}
+
~OpenGl_UnpackAlignmentSentry()
{
Reset();
};
-// =======================================================================
-// function : OpenGl_Texture
-// purpose :
-// =======================================================================
-OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
-: OpenGl_Resource(),
- myTextureId (NO_TEXTURE),
- myTarget (GL_TEXTURE_2D),
- mySizeX (0),
- mySizeY (0),
- myTextFormat (GL_FLOAT),
- myHasMipmaps (Standard_False),
- myParams (theParams)
+//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
+static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize)
{
- if (myParams.IsNull())
+ for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2)
{
- myParams = new Graphic3d_TextureParams();
+ if (theSize <= 1)
+ {
+ return aMipIter;
+ }
}
}
-// =======================================================================
-// function : ~OpenGl_Texture
-// purpose :
-// =======================================================================
-OpenGl_Texture::~OpenGl_Texture()
+//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
+static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSizeX, Standard_Integer theSizeY)
{
- Release (NULL);
+ return computeUpperMipMapLevel (Max (theSizeX, theSizeY));
}
-// =======================================================================
-// function : HasMipmaps
-// purpose :
-// =======================================================================
-const Standard_Boolean OpenGl_Texture::HasMipmaps() const
+//! Compute size of the smallest defined mipmap level (for verbose messages).
+static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel)
{
- return myHasMipmaps;
+ Graphic3d_Vec2i aMipSizeXY = theBaseSize;
+ for (Standard_Integer aMipIter = 0;; ++aMipIter)
+ {
+ if (aMipIter > theMaxLevel)
+ {
+ return aMipSizeXY;
+ }
+
+ aMipSizeXY /= 2;
+ if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+ if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
+ }
+}
+
}
// =======================================================================
-// function : GetParams
+// function : OpenGl_Texture
// purpose :
// =======================================================================
-const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
+OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
+ const Handle(Graphic3d_TextureParams)& theParams)
+: OpenGl_NamedResource (theResourceId),
+ mySampler (new OpenGl_Sampler (theParams)),
+ myRevision (0),
+ myTextureId (NO_TEXTURE),
+ myTarget (GL_TEXTURE_2D),
+ mySizeX (0),
+ mySizeY (0),
+ mySizeZ (0),
+ myTextFormat (GL_RGBA),
+ mySizedFormat(GL_RGBA8),
+ myNbSamples (1),
+ myMaxMipLevel(0),
+ myIsAlpha (false),
+ myIsTopDown (true)
{
- return myParams;
+ //
}
// =======================================================================
-// function : SetParams
+// function : ~OpenGl_Texture
// purpose :
// =======================================================================
-void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
+OpenGl_Texture::~OpenGl_Texture()
{
- myParams = theParams;
+ Release (NULL);
}
// =======================================================================
// function : Create
// purpose :
// =======================================================================
-bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
+bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
{
+ if (myTextureId != NO_TEXTURE)
+ {
+ return true;
+ }
+
+ theCtx->core11fwd->glGenTextures (1, &myTextureId);
if (myTextureId == NO_TEXTURE)
{
- glGenTextures (1, &myTextureId);
+ return false;
}
- return myTextureId != NO_TEXTURE;
+
+ //mySampler->Create (theCtx); // do not create sampler object by default
+ return true;
}
// =======================================================================
// function : Release
// purpose :
// =======================================================================
-void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
+void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
{
+ mySampler->Release (theGlCtx);
if (myTextureId == NO_TEXTURE)
{
return;
glDeleteTextures (1, &myTextureId);
}
myTextureId = NO_TEXTURE;
- mySizeX = mySizeY = 0;
+ mySizeX = mySizeY = mySizeZ = 0;
+}
+
+// =======================================================================
+// function : applyDefaultSamplerParams
+// purpose :
+// =======================================================================
+void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
+{
+ OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel);
+ if (mySampler->IsValid() && !mySampler->IsImmutable())
+ {
+ OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel);
+ }
}
// =======================================================================
// purpose :
// =======================================================================
void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
- const GLenum theTextureUnit) const
+ const Graphic3d_TextureUnit theTextureUnit) const
{
- if (theCtx->IsGlGreaterEqual (1, 3))
+ if (theCtx->core15fwd != NULL)
{
- theCtx->core13->glActiveTexture (theTextureUnit);
+ theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
}
+ mySampler->Bind (theCtx, theTextureUnit);
glBindTexture (myTarget, myTextureId);
}
// purpose :
// =======================================================================
void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
- const GLenum theTextureUnit) const
+ const Graphic3d_TextureUnit theTextureUnit) const
{
- if (theCtx->IsGlGreaterEqual (1, 3))
+ if (theCtx->core15fwd != NULL)
{
- theCtx->core13->glActiveTexture (theTextureUnit);
+ theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
}
+ mySampler->Unbind (theCtx, theTextureUnit);
glBindTexture (myTarget, NO_TEXTURE);
}
+//=======================================================================
+//function : InitSamplerObject
+//purpose :
+//=======================================================================
+bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
+{
+ return myTextureId != NO_TEXTURE
+ && mySampler->Init (theCtx, *this);
+}
+
// =======================================================================
// function : Init
// purpose :
// =======================================================================
bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
- const Image_PixMap& theImage,
- const Graphic3d_TypeOfTexture theType)
+ const OpenGl_TextureFormat& theFormat,
+ const Graphic3d_Vec2i& theSizeXY,
+ const Graphic3d_TypeOfTexture theType,
+ const Image_PixMap* theImage)
{
- myHasMipmaps = Standard_False;
- if (theImage.IsEmpty() || !Create (theCtx))
+ if (theSizeXY.x() < 1
+ || theSizeXY.y() < 1)
{
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: texture of 0 size cannot be created.");
+ Release (theCtx.get());
return false;
}
- myTextFormat = GL_RGBA8;
- GLenum aPixelFormat = 0;
- GLenum aDataType = 0;
- switch (theImage.Format())
+#if !defined(GL_ES_VERSION_2_0)
+ const GLenum aTarget = theType == Graphic3d_TOT_1D
+ ? GL_TEXTURE_1D
+ : GL_TEXTURE_2D;
+#else
+ const GLenum aTarget = GL_TEXTURE_2D;
+#endif
+ const bool toPatchExisting = IsValid()
+ && myTextFormat == theFormat.PixelFormat()
+ && myTarget == aTarget
+ && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP)
+ && mySizeX == theSizeXY.x()
+ && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
+ if (!Create (theCtx))
{
- case Image_PixMap::ImgGrayF:
- {
- myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
- aPixelFormat = GL_ALPHA; // GL_RED
- aDataType = GL_FLOAT;
- break;
- }
- case Image_PixMap::ImgRGBAF:
- {
- myTextFormat = GL_RGBA8; // GL_RGBA32F
- aPixelFormat = GL_RGBA;
- aDataType = GL_FLOAT;
- break;
- }
- case Image_PixMap::ImgBGRAF:
- {
- if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
- {
- return false;
- }
- myTextFormat = GL_RGBA8; // GL_RGBA32F
- aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
- aDataType = GL_FLOAT;
- break;
- }
- case Image_PixMap::ImgRGBF:
- {
- myTextFormat = GL_RGB8; // GL_RGB32F
- aPixelFormat = GL_RGB;
- aDataType = GL_FLOAT;
- break;
- }
- case Image_PixMap::ImgBGRF:
- {
- myTextFormat = GL_RGB8; // GL_RGB32F
- aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
- aDataType = GL_FLOAT;
- break;
- }
- case Image_PixMap::ImgRGBA:
- {
- myTextFormat = GL_RGBA8;
- aPixelFormat = GL_RGBA;
- aDataType = GL_UNSIGNED_BYTE;
- break;
- }
- case Image_PixMap::ImgBGRA:
- {
- if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
- {
- return false;
- }
- myTextFormat = GL_RGBA8;
- aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
- aDataType = GL_UNSIGNED_BYTE;
- break;
- }
- case Image_PixMap::ImgRGB32:
- {
- myTextFormat = GL_RGB8;
- aPixelFormat = GL_RGBA;
- aDataType = GL_UNSIGNED_BYTE;
- break;
- }
- case Image_PixMap::ImgBGR32:
- {
- if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
- {
- return false;
- }
- myTextFormat = GL_RGB8;
- aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
- aDataType = GL_UNSIGNED_BYTE;
- break;
- }
- case Image_PixMap::ImgRGB:
- {
- myTextFormat = GL_RGB8;
- aPixelFormat = GL_RGB;
- aDataType = GL_UNSIGNED_BYTE;
- break;
- }
- case Image_PixMap::ImgBGR:
- {
- if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
- {
- return false;
- }
- myTextFormat = GL_RGB8;
- aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
- aDataType = GL_UNSIGNED_BYTE;
- break;
- }
- case Image_PixMap::ImgGray:
+ Release (theCtx.get());
+ return false;
+ }
+
+ if (theImage != NULL)
+ {
+ myIsAlpha = theImage->Format() == Image_Format_Alpha
+ || theImage->Format() == Image_Format_AlphaF;
+ myIsTopDown = theImage->IsTopDown();
+ }
+ else
+ {
+ myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
+ }
+
+ myMaxMipLevel = theType == Graphic3d_TOT_2D_MIPMAP && theCtx->arbFBO != NULL
+ ? computeUpperMipMapLevel (theSizeXY.x(), theSizeXY.y())
+ : 0;
+ myTextFormat = theFormat.PixelFormat();
+ mySizedFormat = theFormat.InternalFormat();
+ myNbSamples = 1;
+#if !defined(GL_ES_VERSION_2_0)
+ const GLint anIntFormat = theFormat.InternalFormat();
+#else
+ // ES 2.0 does not support sized formats and format conversions - them detected from data type
+ const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? theFormat.InternalFormat() : theFormat.PixelFormat();
+#endif
+
+ if (theFormat.DataType() == GL_FLOAT
+ && !theCtx->arbTexFloat)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: floating-point textures are not supported by hardware.");
+ Release (theCtx.get());
+ return false;
+ }
+
+ const GLsizei aMaxSize = theCtx->MaxTextureSize();
+ if (theSizeXY.x() > aMaxSize
+ || theSizeXY.y() > aMaxSize)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y()
+ + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")");
+ Release (theCtx.get());
+ return false;
+ }
+#if !defined(GL_ES_VERSION_2_0)
+ else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
+ {
+ // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
+ // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
+ // Trying to create NPOT textures on such hardware will not fail
+ // but driver will fall back into software rendering,
+ const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
+ const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
+ if (theSizeXY.x() != aWidthP2
+ || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2))
{
- myTextFormat = GL_ALPHA8; // GL_R8
- aPixelFormat = GL_ALPHA; // GL_RED
- aDataType = GL_UNSIGNED_BYTE;
- break;
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
+ " are not supported by hardware.");
+ Release (theCtx.get());
+ return false;
}
- default:
+ }
+#else
+ else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
+ {
+ // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
+ const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
+ const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
+ if (theSizeXY.x() != aWidthP2
+ || theSizeXY.y() != aHeightP2)
{
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
+ " are not supported by OpenGL ES 2.0");
+ Release (theCtx.get());
return false;
}
}
+#endif
- const GLsizei aMaxSize = theCtx->MaxTextureSize();
- const GLsizei aWidth = (GLsizei )theImage.SizeX();
- const GLsizei aHeight = (GLsizei )theImage.SizeY();
-
- // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
- // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
- // Trying to create NPOT rextures on such hardware will not fail
- // but driver will fall back into software rendering,
- const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
- const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
- const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
-
- GLint aTestWidth = 0;
- GLint aTestHeight = 0;
+#if !defined(GL_ES_VERSION_2_0)
+ GLint aTestWidth = 0, aTestHeight = 0;
+#endif
+ GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
// setup the alignment
OpenGl_UnpackAlignmentSentry anUnpackSentry;
- const GLint anAligment = Min ((GLint )theImage.MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
- glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
+ (void)anUnpackSentry; // avoid compiler warning
+
+ if (aDataPtr != NULL)
+ {
+ const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
+ glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
- // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
- const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
- const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
- glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
+ #if !defined(GL_ES_VERSION_2_0)
+ // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
+ const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
+ const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
+ #endif
+ }
+ myTarget = aTarget;
switch (theType)
{
case Graphic3d_TOT_1D:
{
- myTarget = GL_TEXTURE_1D;
+ #if !defined(GL_ES_VERSION_2_0)
Bind (theCtx);
- glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- Image_PixMap aCopy;
- GLvoid* aDataPtr = (GLvoid* )theImage.Data();
- if (aWidth != aWidthOut)
+ applyDefaultSamplerParams (theCtx);
+ if (toPatchExisting)
{
- glPixelStorei (GL_PACK_ALIGNMENT, 1);
- glPixelStorei (GL_PACK_ROW_LENGTH, 0);
- if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
- || gluScaleImage (aPixelFormat,
- aWidth, 1, aDataType, theImage.Data(),
- aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
- {
- Unbind (theCtx);
- return false;
- }
-
- aDataPtr = (GLvoid* )aCopy.Data();
- anUnpackSentry.Reset();
+ glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
+ theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
+ Unbind (theCtx);
+ return true;
}
// use proxy to check texture could be created or not
- glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
- aWidthOut, 0,
- aPixelFormat, aDataType, NULL);
- glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
+ glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
+ theSizeXY.x(), 0,
+ theFormat.PixelFormat(), theFormat.DataType(), NULL);
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestWidth == 0)
{
// no memory or broken input parameters
Unbind (theCtx);
+ Release (theCtx.operator->());
return false;
}
- glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
- aWidthOut, 0,
- aPixelFormat, aDataType, aDataPtr);
+ glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
+ theSizeXY.x(), 0,
+ theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
if (glGetError() != GL_NO_ERROR)
{
Unbind (theCtx);
+ Release (theCtx.get());
return false;
}
- mySizeX = aWidthOut;
+ mySizeX = theSizeXY.x();
mySizeY = 1;
Unbind (theCtx);
return true;
+ #else
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: 1D textures are not supported by hardware.");
+ Release (theCtx.get());
+ return false;
+ #endif
}
case Graphic3d_TOT_2D:
+ case Graphic3d_TOT_2D_MIPMAP:
{
- myTarget = GL_TEXTURE_2D;
Bind (theCtx);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- Image_PixMap aCopy;
- GLvoid* aDataPtr = (GLvoid* )theImage.Data();
- if (aWidth != aWidthOut || aHeight != aHeightOut)
+ applyDefaultSamplerParams (theCtx);
+ if (toPatchExisting)
{
- // scale texture
- glPixelStorei (GL_PACK_ALIGNMENT, 1);
- glPixelStorei (GL_PACK_ROW_LENGTH, 0);
- if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
- || gluScaleImage (aPixelFormat,
- aWidth, aHeight, aDataType, theImage.Data(),
- aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
+ glTexSubImage2D (GL_TEXTURE_2D, 0,
+ 0, 0,
+ theSizeXY.x(), theSizeXY.y(),
+ theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
+
+ if (myMaxMipLevel > 0)
{
- Unbind (theCtx);
- return false;
+ // generate mipmaps
+ theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
+ if (glGetError() != GL_NO_ERROR)
+ {
+ myMaxMipLevel = 0;
+ }
}
- aDataPtr = (GLvoid* )aCopy.Data();
- anUnpackSentry.Reset();
+ Unbind (theCtx);
+ return true;
}
+ #if !defined(GL_ES_VERSION_2_0)
// use proxy to check texture could be created or not
- glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
- aWidthOut, aHeightOut, 0,
- aPixelFormat, aDataType, NULL);
+ glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
+ theSizeXY.x(), theSizeXY.y(), 0,
+ theFormat.PixelFormat(), theFormat.DataType(), NULL);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
if (aTestWidth == 0 || aTestHeight == 0)
{
// no memory or broken input parameters
Unbind (theCtx);
+ Release (theCtx.get());
return false;
}
+ #endif
- glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
- aWidthOut, aHeightOut, 0,
- aPixelFormat, aDataType, aDataPtr);
- if (glGetError() != GL_NO_ERROR)
+ glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
+ theSizeXY.x(), theSizeXY.y(), 0,
+ theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
+ GLenum anErr = glGetError();
+ if (anErr != GL_NO_ERROR)
{
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
+ + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
+ + " DT: " + int(theFormat.DataType())
+ + " can not be created with error " + int(anErr) + ".");
Unbind (theCtx);
+ Release (theCtx.get());
return false;
}
- mySizeX = aWidthOut;
- mySizeY = aHeightOut;
+ mySizeX = theSizeXY.x();
+ mySizeY = theSizeXY.y();
+
+ if (myMaxMipLevel > 0)
+ {
+ // generate mipmaps
+ //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
+ theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
+ anErr = glGetError();
+ if (anErr != GL_NO_ERROR)
+ {
+ myMaxMipLevel = 0;
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
+ }
+ }
Unbind (theCtx);
return true;
}
- case Graphic3d_TOT_2D_MIPMAP:
+ case Graphic3d_TOT_CUBEMAP:
{
- myTarget = GL_TEXTURE_2D;
- myHasMipmaps = Standard_True;
- Bind (theCtx);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ Unbind (theCtx);
+ Release (theCtx.get());
+ return false;
+ }
+ }
+
+ Release (theCtx.get());
+ return false;
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
+ const Image_PixMap& theImage,
+ const Graphic3d_TypeOfTexture theType,
+ const Standard_Boolean theIsColorMap)
+{
+ if (theImage.IsEmpty())
+ {
+ Release (theCtx.get());
+ return false;
+ }
- if (theCtx->extFBO != NULL
- && aWidth == aWidthOut && aHeight == aHeightOut)
+ const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap);
+ if (!aFormat.IsValid())
+ {
+ Release (theCtx.get());
+ return false;
+ }
+
+ return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()),
+ theType, &theImage);
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
+ const Handle(Graphic3d_TextureMap)& theTextureMap)
+{
+ if (theTextureMap.IsNull())
+ {
+ return false;
+ }
+
+ switch (theTextureMap->Type())
+ {
+ case Graphic3d_TOT_CUBEMAP:
+ {
+ return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap),
+ 0, Image_Format_RGB, false, theTextureMap->IsColorMap());
+ }
+ default:
+ {
+ if (theCtx->SupportedTextureFormats()->HasCompressed()
+ && !theCtx->caps->compressedTexturesDisable)
{
- // use proxy to check texture could be created or not
- glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
- aWidthOut, aHeightOut, 0,
- aPixelFormat, aDataType, NULL);
- glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
- glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
- if (aTestWidth == 0 || aTestHeight == 0)
+ if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats()))
{
- // no memory or broken input parameters
- Unbind (theCtx);
- return false;
+ return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap());
}
+ }
- // upload main picture
- glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
- aWidthOut, aHeightOut, 0,
- aPixelFormat, aDataType, theImage.Data());
- if (glGetError() != GL_NO_ERROR)
+ Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats());
+ if (anImage.IsNull())
+ {
+ return false;
+ }
+ return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap());
+ }
+ }
+}
+
+// =======================================================================
+// function : InitCompressed
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
+ const Image_CompressedPixMap& theImage,
+ const Standard_Boolean theIsColorMap)
+{
+ if (theImage.SizeX() < 1
+ || theImage.SizeY() < 1
+ || theImage.FaceData().IsNull())
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: texture of 0 size cannot be created.");
+ Release (theCtx.get());
+ return false;
+ }
+ if (theImage.SizeX() > theCtx->MaxTextureSize()
+ || theImage.SizeY() > theCtx->MaxTextureSize())
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: Texture dimension - ") + theImage.SizeX() + "x" + theImage.SizeY()
+ + " exceeds hardware limits (" + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ")");
+ Release (theCtx.get());
+ return false;
+ }
+
+ const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap);
+ if (!aFormat.IsValid())
+ {
+ Release (theCtx.get());
+ return false;
+ }
+
+ if (!Create (theCtx))
+ {
+ return false;
+ }
+
+ myTarget = GL_TEXTURE_2D;
+ myNbSamples = 1;
+ myTextFormat = aFormat.Format();
+ mySizedFormat = aFormat.Internal();
+ myIsTopDown = theImage.IsTopDown();
+ mySizeX = theImage.SizeX();
+ mySizeY = theImage.SizeY();
+ myMaxMipLevel = Max (theImage.MipMaps().Size() - 1, 0);
+ if (myMaxMipLevel > 0
+ && !theImage.IsCompleteMipMapSet())
+ {
+ const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (mySizeX, mySizeY), myMaxMipLevel);
+ if (!theCtx->HasTextureBaseLevel())
+ {
+ myMaxMipLevel = 0;
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
+ TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
+ + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
+ }
+ else
+ {
+ Message::SendTrace (TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
+ + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
+ }
+ }
+
+ Bind (theCtx);
+ applyDefaultSamplerParams (theCtx);
+
+ // setup the alignment
+ OpenGl_UnpackAlignmentSentry::Reset();
+
+ Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY());
+ const Standard_Byte* aData = theImage.FaceData()->Data();
+ for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
+ {
+ const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter);
+ theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
+ const GLenum aTexImgErr = glGetError();
+ if (aTexImgErr != GL_NO_ERROR)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: 2D compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
+ + " IF: " + int(aFormat.Internal()) + " PF: " + int(aFormat.PixelFormat())
+ + " DT: " + int(aFormat.DataType())
+ + " can not be created with error " + int(aTexImgErr) + ".");
+ Unbind (theCtx);
+ Release (theCtx.get());
+ return false;
+ }
+
+ aData += aMipLength;
+ aMipSizeXY /= 2;
+ if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+ if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
+ }
+
+ Unbind (theCtx);
+ return true;
+}
+
+// =======================================================================
+// function : Init2DMultisample
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
+ const GLsizei theNbSamples,
+ const GLint theTextFormat,
+ const GLsizei theSizeX,
+ const GLsizei theSizeY)
+{
+ if (!Create (theCtx)
+ || theNbSamples > theCtx->MaxMsaaSamples()
+ || theNbSamples < 1)
+ {
+ return false;
+ }
+
+ myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
+ myTarget = GL_TEXTURE_2D_MULTISAMPLE;
+ myMaxMipLevel = 0;
+ if(theSizeX > theCtx->MaxTextureSize()
+ || theSizeY > theCtx->MaxTextureSize())
+ {
+ return false;
+ }
+
+ Bind (theCtx);
+ //myTextFormat = theTextFormat;
+ mySizedFormat = theTextFormat;
+#if !defined(GL_ES_VERSION_2_0)
+ if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
+ {
+ theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
+ }
+ else
+ {
+ theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
+ }
+#else
+ theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
+#endif
+ if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
+ {
+ Unbind (theCtx);
+ return false;
+ }
+
+ mySizeX = theSizeX;
+ mySizeY = theSizeY;
+
+ Unbind (theCtx);
+ return true;
+}
+
+// =======================================================================
+// function : InitRectangle
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
+ const Standard_Integer theSizeX,
+ const Standard_Integer theSizeY,
+ const OpenGl_TextureFormat& theFormat)
+{
+ if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
+ {
+ return false;
+ }
+
+#if !defined(GL_ES_VERSION_2_0)
+ myTarget = GL_TEXTURE_RECTANGLE;
+ myNbSamples = 1;
+ myMaxMipLevel = 0;
+
+ const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
+ const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
+
+ Bind (theCtx);
+ applyDefaultSamplerParams (theCtx);
+
+ myTextFormat = theFormat.Format();
+ mySizedFormat = theFormat.Internal();
+
+ // setup the alignment
+ OpenGl_UnpackAlignmentSentry::Reset();
+
+ glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
+ aSizeX, aSizeY, 0,
+ myTextFormat, GL_FLOAT, NULL);
+
+ GLint aTestSizeX = 0;
+ GLint aTestSizeY = 0;
+
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
+
+ if (aTestSizeX == 0 || aTestSizeY == 0)
+ {
+ Unbind (theCtx);
+ return false;
+ }
+
+ glTexImage2D (myTarget, 0, mySizedFormat,
+ aSizeX, aSizeY, 0,
+ myTextFormat, GL_FLOAT, NULL);
+
+ if (glGetError() != GL_NO_ERROR)
+ {
+ Unbind (theCtx);
+ return false;
+ }
+
+ mySizeX = aSizeX;
+ mySizeY = aSizeY;
+
+ Unbind (theCtx);
+ return true;
+#else
+ (void )theSizeX;
+ (void )theSizeY;
+ (void )theFormat;
+ return false;
+#endif
+}
+
+// =======================================================================
+// function : Init3D
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
+ const OpenGl_TextureFormat& theFormat,
+ const Graphic3d_Vec3i& theSizeXYZ,
+ const void* thePixels)
+{
+ if (theCtx->Functions()->glTexImage3D == NULL)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: three-dimensional textures are not supported by hardware.");
+ return false;
+ }
+
+ if (!Create(theCtx))
+ {
+ return false;
+ }
+
+ myTarget = GL_TEXTURE_3D;
+ myNbSamples = 1;
+ myMaxMipLevel = 0;
+
+ const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
+ if (aSizeXYZ != theSizeXYZ)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: 3D texture dimensions exceed hardware limits.");
+ Release (theCtx.get());
+ Unbind (theCtx);
+ return false;
+ }
+ Bind (theCtx);
+
+ if (theFormat.DataType() == GL_FLOAT
+ && !theCtx->arbTexFloat)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Error: floating-point textures are not supported by hardware.");
+ Release (theCtx.get());
+ Unbind (theCtx);
+ return false;
+ }
+
+ mySizedFormat = theFormat.InternalFormat();
+
+ // setup the alignment
+ OpenGl_UnpackAlignmentSentry::Reset();
+
+#if !defined (GL_ES_VERSION_2_0)
+ theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
+ aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
+ theFormat.PixelFormat(), theFormat.DataType(), NULL);
+
+ NCollection_Vec3<GLint> aTestSizeXYZ;
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x());
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y());
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z());
+ glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
+ if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0)
+ {
+ Unbind (theCtx);
+ Release (theCtx.get());
+ return false;
+ }
+#endif
+
+ applyDefaultSamplerParams (theCtx);
+ theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
+ aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
+ theFormat.PixelFormat(), theFormat.DataType(), thePixels);
+
+ if (glGetError() != GL_NO_ERROR)
+ {
+ Unbind (theCtx);
+ Release (theCtx.get());
+ return false;
+ }
+
+ mySizeX = aSizeXYZ.x();
+ mySizeY = aSizeXYZ.y();
+ mySizeZ = aSizeXYZ.z();
+
+ Unbind (theCtx);
+ return true;
+}
+
+// =======================================================================
+// function : InitCubeMap
+// purpose :
+// =======================================================================
+bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx,
+ const Handle(Graphic3d_CubeMap)& theCubeMap,
+ Standard_Size theSize,
+ Image_Format theFormat,
+ Standard_Boolean theToGenMipmap,
+ Standard_Boolean theIsColorMap)
+{
+ if (!Create (theCtx))
+ {
+ Release (theCtx.get());
+ return false;
+ }
+
+ Handle(Image_PixMap) anImage;
+ Handle(Image_CompressedPixMap) aCompImage;
+ OpenGl_TextureFormat aFormat;
+ if (!theCubeMap.IsNull())
+ {
+ theCubeMap->Reset();
+ if (theCtx->SupportedTextureFormats()->HasCompressed()
+ && !theCtx->caps->compressedTexturesDisable)
+ {
+ aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
+ }
+ if (!aCompImage.IsNull())
+ {
+ aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, aCompImage->CompressedFormat(), theIsColorMap);
+ if (aFormat.IsValid())
+ {
+ theToGenMipmap = false;
+ theSize = aCompImage->SizeX();
+ theFormat = aCompImage->BaseFormat();
+ myMaxMipLevel = Max (aCompImage->MipMaps().Size() - 1, 0);
+ if (myMaxMipLevel > 0
+ && !aCompImage->IsCompleteMipMapSet())
{
- Unbind (theCtx);
- return false;
+ const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (aCompImage->SizeX(), aCompImage->SizeY()), myMaxMipLevel);
+ if (!theCtx->HasTextureBaseLevel())
+ {
+ myMaxMipLevel = 0;
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
+ TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
+ + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
+ }
+ else
+ {
+ Message::SendTrace (TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
+ + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
+ }
}
- mySizeX = aWidthOut;
- mySizeY = aHeightOut;
+ OpenGl_UnpackAlignmentSentry::Reset();
+ }
+ else
+ {
+ aCompImage.Nullify();
+ }
+ }
- // generate mipmaps
- //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
- theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
+ if (!aFormat.IsValid())
+ {
+ anImage = theCubeMap->Reset().Value (theCtx->SupportedTextureFormats());
+ if (anImage.IsNull())
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ "Unable to get the first side of cubemap");
+ Release(theCtx.get());
+ return false;
+ }
- Unbind (theCtx);
- return true;
+ theSize = anImage->SizeX();
+ theFormat = anImage->Format();
+ theToGenMipmap = theCubeMap->HasMipmaps();
+ myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
+ }
+
+ myIsTopDown = theCubeMap->IsTopDown();
+ }
+ else
+ {
+ myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
+ }
+
+ if (!aFormat.IsValid())
+ {
+ aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
+ }
+ if (!aFormat.IsValid())
+ {
+ Unbind(theCtx);
+ Release(theCtx.get());
+ return false;
+ }
+
+ myTarget = GL_TEXTURE_CUBE_MAP;
+ myNbSamples = 1;
+ mySizeX = (GLsizei )theSize;
+ mySizeY = (GLsizei )theSize;
+ myTextFormat = aFormat.Format();
+ mySizedFormat = aFormat.Internal();
+#if !defined(GL_ES_VERSION_2_0)
+ const GLint anIntFormat = aFormat.InternalFormat();
+#else
+ // ES 2.0 does not support sized formats and format conversions - them detected from data type
+ const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? aFormat.InternalFormat() : aFormat.PixelFormat();
+#endif
+
+ Bind (theCtx);
+ applyDefaultSamplerParams (theCtx);
+
+ for (Standard_Integer i = 0; i < 6; ++i)
+ {
+ const Standard_Byte* aData = NULL;
+
+ if (!theCubeMap.IsNull())
+ {
+ if (i != 0)
+ {
+ if (!aCompImage.IsNull())
+ {
+ aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
+ }
+ else
+ {
+ anImage = theCubeMap->Value (theCtx->SupportedTextureFormats());
+ }
}
- else
+ if (!aCompImage.IsNull())
{
- bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
- aWidth, aHeight,
- aPixelFormat, aDataType, theImage.Data()) == 0;
- if (isCreated)
+ Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY);
+ aData = aCompImage->FaceData()->Data();
+ for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
{
- glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
- glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
+ const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter);
+ theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
+ const GLenum aTexImgErr = glGetError();
+ if (aTexImgErr != GL_NO_ERROR)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Error: cubemap compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
+ + " IF: " + int(aFormat.Internal()) + " PF: " + int(aFormat.PixelFormat())
+ + " DT: " + int(aFormat.DataType())
+ + " can not be created with error " + int(aTexImgErr) + ".");
+ Unbind (theCtx);
+ Release (theCtx.get());
+ return false;
+ }
+
+ aData += aMipLength;
+ aMipSizeXY /= 2;
+ if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
+ if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
}
+ theCubeMap->Next();
+ continue;
+ }
+
+ if (!anImage.IsNull())
+ {
+#if !defined(GL_ES_VERSION_2_0)
+ const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
+ glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
+
+ // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
+ const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
+ const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
+ const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
+ glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
+#else
+ Handle(Image_PixMap) aCopyImage = new Image_PixMap();
+ aCopyImage->InitTrash (theFormat, theSize, theSize);
+ for (unsigned int y = 0; y < theSize; ++y)
+ {
+ for (unsigned int x = 0; x < theSize; ++x)
+ {
+ for (unsigned int aByte = 0; aByte < anImage->SizePixelBytes(); ++aByte)
+ {
+ aCopyImage->ChangeRawValue (y, x)[aByte] = anImage->RawValue (y, x)[aByte];
+ }
+ }
+ }
+ anImage = aCopyImage;
+ const GLint anAligment = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
+ glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
+#endif
+ aData = anImage->Data();
+ }
+ else
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap");
Unbind (theCtx);
- return isCreated;
+ Release (theCtx.get());
+ return false;
}
+ theCubeMap->Next();
}
- default:
+
+ glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
+ anIntFormat,
+ GLsizei(theSize), GLsizei(theSize),
+ 0, aFormat.PixelFormat(), aFormat.DataType(),
+ aData);
+
+ OpenGl_UnpackAlignmentSentry::Reset();
+
+ const GLenum anErr = glGetError();
+ if (anErr != GL_NO_ERROR)
+ {
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Unable to initialize side of cubemap. Error #") + int(anErr));
+ Unbind (theCtx);
+ Release (theCtx.get());
+ return false;
+ }
+ }
+
+ if (theToGenMipmap && theCtx->arbFBO != NULL)
+ {
+ theCtx->arbFBO->glGenerateMipmap (myTarget);
+ const GLenum anErr = glGetError();
+ if (anErr != GL_NO_ERROR)
{
+ theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+ TCollection_AsciiString ("Unable to generate mipmap of cubemap. Error #") + int(anErr));
+ Unbind (theCtx);
+ Release (theCtx.get());
return false;
}
}
+
+ Unbind (theCtx.get());
+ return true;
+}
+
+// =======================================================================
+// function : PixelSizeOfPixelFormat
+// purpose :
+// =======================================================================
+Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
+{
+ switch(theInternalFormat)
+ {
+ // RED variations (GL_RED, OpenGL 3.0+)
+ case GL_RED:
+ case GL_R8: return 1;
+ case GL_R16: return 2;
+ case GL_R16F: return 2;
+ case GL_R32F: return 4;
+ // RGB variations
+ case GL_RGB: return 3;
+ case GL_RGB8: return 3;
+ case GL_RGB16: return 6;
+ case GL_RGB16F: return 6;
+ case GL_RGB32F: return 12;
+ // RGBA variations
+ case GL_RGBA: return 4;
+ case GL_RGBA8: return 4;
+ case GL_RGB10_A2: return 4;
+ case GL_RGBA12: return 6;
+ case GL_RGBA16: return 8;
+ case GL_RGBA16F: return 8;
+ case GL_RGBA32F: return 16;
+ //
+ case GL_BGRA_EXT: return 4;
+ // ALPHA variations (deprecated)
+ case GL_ALPHA:
+ case GL_ALPHA8: return 1;
+ case GL_ALPHA16: return 2;
+ case GL_LUMINANCE: return 1;
+ case GL_LUMINANCE_ALPHA: return 2;
+ // depth-stencil
+ case GL_DEPTH24_STENCIL8: return 4;
+ case GL_DEPTH32F_STENCIL8: return 8;
+ case GL_DEPTH_COMPONENT16: return 2;
+ case GL_DEPTH_COMPONENT24: return 3;
+ case GL_DEPTH_COMPONENT32F: return 4;
+ // compressed
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block)
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block)
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+ case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+ return 1;
+ }
+ return 1;
+}
+
+// =======================================================================
+// function : EstimatedDataSize
+// purpose :
+// =======================================================================
+Standard_Size OpenGl_Texture::EstimatedDataSize() const
+{
+ if (!IsValid())
+ {
+ return 0;
+ }
+
+ Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
+ if (mySizeY != 0)
+ {
+ aSize *= Standard_Size(mySizeY);
+ }
+ if (mySizeZ != 0)
+ {
+ aSize *= Standard_Size(mySizeZ);
+ }
+ if (myTarget == GL_TEXTURE_CUBE_MAP)
+ {
+ aSize *= 6; // cube sides
+ }
+ if (myMaxMipLevel > 0)
+ {
+ aSize = aSize + aSize / 3;
+ }
+ return aSize;
}