diff --git a/samples/mfc/standard/Common/Primitive/Sample2D_Image.cpp b/samples/mfc/standard/Common/Primitive/Sample2D_Image.cpp index 549790f7a7..957791b9a1 100755 --- a/samples/mfc/standard/Common/Primitive/Sample2D_Image.cpp +++ b/samples/mfc/standard/Common/Primitive/Sample2D_Image.cpp @@ -3,6 +3,7 @@ #include "Sample2D_Image.h" #include +#include IMPLEMENT_STANDARD_RTTIEXT(Sample2D_Image,AIS_Shape) @@ -19,10 +20,13 @@ Sample2D_Image::Sample2D_Image(TCollection_AsciiString& aFileName, } void Sample2D_Image::MakeShape() { - Handle(Graphic3d_Texture1D) anImageTexture = - new Graphic3d_Texture1Dsegment(myFilename); - Standard_Real coeff = (Standard_Real)(anImageTexture->GetImage()->Height())/ - (anImageTexture->GetImage()->Width())*myScale; + Standard_Real coeff = 1.0; + Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap(); + if (anImage->Load (myFilename)) + { + coeff = Standard_Real(anImage->Height()) / Standard_Real(anImage->Width()) * myScale; + } + TopoDS_Edge E1 = BRepBuilderAPI_MakeEdge(gp_Pnt(myX,myY,0.), gp_Pnt(100*myScale+myX,myY,0.)); TopoDS_Edge E2 = BRepBuilderAPI_MakeEdge(gp_Pnt(100*myScale+myX,myY,0.), gp_Pnt(100*myScale+myX,100*coeff+myY,0.)); TopoDS_Edge E3 = BRepBuilderAPI_MakeEdge(gp_Pnt(100*myScale+myX,100*coeff+myY,0.), gp_Pnt(myX,100*coeff+myY,0.)); diff --git a/src/AIS/AIS_XRTrackedDevice.cxx b/src/AIS/AIS_XRTrackedDevice.cxx index c60f4add0f..345d63a989 100644 --- a/src/AIS/AIS_XRTrackedDevice.cxx +++ b/src/AIS/AIS_XRTrackedDevice.cxx @@ -43,7 +43,10 @@ public: } //! Image reader. - virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE { return myImageSource->ReadImage(); } + virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE + { + return myImageSource->ReadImage (theSupported); + } protected: Handle(Image_Texture) myImageSource; diff --git a/src/Aspect/Aspect_OpenVRSession.cxx b/src/Aspect/Aspect_OpenVRSession.cxx index bd5888c9fa..d04f729ea0 100644 --- a/src/Aspect/Aspect_OpenVRSession.cxx +++ b/src/Aspect/Aspect_OpenVRSession.cxx @@ -261,7 +261,7 @@ public: protected: //! Read image. - virtual Handle(Image_PixMap) ReadImage() const Standard_OVERRIDE + virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& ) const Standard_OVERRIDE { Handle(VRImagePixmap) aPixmap = new VRImagePixmap(); if (!aPixmap->Load (myVrTextureId, myVrModelName)) diff --git a/src/Graphic3d/Graphic3d_CubeMap.hxx b/src/Graphic3d/Graphic3d_CubeMap.hxx index 494ce29b92..52473ee244 100644 --- a/src/Graphic3d/Graphic3d_CubeMap.hxx +++ b/src/Graphic3d/Graphic3d_CubeMap.hxx @@ -31,7 +31,6 @@ public: Graphic3d_TextureMap (theFileName, Graphic3d_TOT_CUBEMAP), myCurrentSide (Graphic3d_CMS_POS_X), myEndIsReached (false), - myIsTopDown (true), myZIsInverted (false), myHasMipmaps (theToGenerateMipmaps) {} @@ -42,7 +41,6 @@ public: Graphic3d_TextureMap (thePixmap, Graphic3d_TOT_CUBEMAP), myCurrentSide (Graphic3d_CMS_POS_X), myEndIsReached (false), - myIsTopDown (true), myZIsInverted (false), myHasMipmaps (theToGenerateMipmaps) {} @@ -67,12 +65,6 @@ public: } } - //! Returns whether row's memory layout is top-down. - Standard_Boolean IsTopDown() const - { - return myIsTopDown; - } - //! Sets Z axis inversion (vertical flipping). void SetZInversion (Standard_Boolean theZIsInverted) { @@ -91,9 +83,13 @@ public: //! Sets whether to generate mipmaps of cubemap or not. void SetMipmapsGeneration (Standard_Boolean theToGenerateMipmaps) { myHasMipmaps = theToGenerateMipmaps; } + //! Returns current cubemap side as compressed PixMap. + //! Returns null handle if current side is invalid or if image is not in supported compressed format. + virtual Handle(Image_CompressedPixMap) CompressedValue (const Handle(Image_SupportedFormats)& theSupported) = 0; + //! Returns PixMap containing current side of cubemap. //! Returns null handle if current side is invalid. - virtual Handle(Image_PixMap) Value() = 0; + virtual Handle(Image_PixMap) Value (const Handle(Image_SupportedFormats)& theSupported) = 0; //! Sets iterator state to +X cubemap side. Graphic3d_CubeMap& Reset() @@ -110,7 +106,6 @@ protected: Graphic3d_CubeMapSide myCurrentSide; //!< Iterator state Standard_Boolean myEndIsReached; //!< Indicates whether end of iteration has been reached or hasn't - Standard_Boolean myIsTopDown; //!< Stores rows's memory layout Standard_Boolean myZIsInverted; //!< Indicates whether Z axis is inverted that allows to synchronize vertical flip of cubemap Standard_Boolean myHasMipmaps; //!< Indicates whether mipmaps of cubemap will be generated or not diff --git a/src/Graphic3d/Graphic3d_CubeMapPacked.cxx b/src/Graphic3d/Graphic3d_CubeMapPacked.cxx index ac57c48fa7..2f9e180158 100644 --- a/src/Graphic3d/Graphic3d_CubeMapPacked.cxx +++ b/src/Graphic3d/Graphic3d_CubeMapPacked.cxx @@ -13,7 +13,9 @@ // commercial license or contractual agreement. #include + #include +#include IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_CubeMapPacked, Graphic3d_CubeMap) @@ -40,17 +42,46 @@ Graphic3d_CubeMapPacked::Graphic3d_CubeMapPacked (const Handle(Image_PixMap)& myOrder (theOrder), myTileNumberX (1) { - if (checkImage (theImage, myTileNumberX)) + if (checkImage (theImage, myTileNumberX)) + { + myPixMap = theImage; + } +} + +// ======================================================================= +// function : CompressedValue +// purpose : +// ======================================================================= +Handle(Image_CompressedPixMap) Graphic3d_CubeMapPacked::CompressedValue (const Handle(Image_SupportedFormats)& theSupported) +{ + if (myTileNumberX == 0 + || !myPixMap.IsNull()) + { + return Handle(Image_CompressedPixMap)(); + } + + TCollection_AsciiString aFilePath; + myPath.SystemName (aFilePath); + if (!aFilePath.IsEmpty()) + { + const unsigned int aTileIndex = myOrder[myCurrentSide]; + Handle(Image_CompressedPixMap) anImage = Image_DDSParser::Load (theSupported, aFilePath, (Standard_Integer )aTileIndex); + if (!anImage.IsNull() + && anImage->NbFaces() == 6 + && anImage->SizeX() == anImage->SizeY()) { - myPixMap = theImage; + myIsTopDown = anImage->IsTopDown(); + return anImage; } + } + return Handle(Image_CompressedPixMap)(); } // ======================================================================= // function : Value // purpose : // ======================================================================= -Handle(Image_PixMap) Graphic3d_CubeMapPacked::Value() +Handle(Image_PixMap) Graphic3d_CubeMapPacked::Value (const Handle(Image_SupportedFormats)& theSupported) { if (myTileNumberX != 0) { @@ -60,7 +91,7 @@ Handle(Image_PixMap) Graphic3d_CubeMapPacked::Value() myPath.SystemName (aFilePath); if (!aFilePath.IsEmpty()) { - tryLoadImage (aFilePath); + tryLoadImage (theSupported, aFilePath); } } @@ -183,13 +214,15 @@ Standard_Boolean Graphic3d_CubeMapPacked::checkImage (const Handle(Image_PixMap) // function : tryLoadImage // purpose : // ======================================================================= -void Graphic3d_CubeMapPacked::tryLoadImage (const TCollection_AsciiString& theFilePath) +void Graphic3d_CubeMapPacked::tryLoadImage (const Handle(Image_SupportedFormats)& theSupported, + const TCollection_AsciiString& theFilePath) { Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap; if (anImage->Load (theFilePath)) { if (checkImage (anImage, myTileNumberX)) { + convertToCompatible (theSupported, anImage); myPixMap = anImage; } } diff --git a/src/Graphic3d/Graphic3d_CubeMapPacked.hxx b/src/Graphic3d/Graphic3d_CubeMapPacked.hxx index 4a6da463dc..41a4f94d7e 100644 --- a/src/Graphic3d/Graphic3d_CubeMapPacked.hxx +++ b/src/Graphic3d/Graphic3d_CubeMapPacked.hxx @@ -25,23 +25,26 @@ class Graphic3d_CubeMapPacked : public Graphic3d_CubeMap DEFINE_STANDARD_RTTIEXT(Graphic3d_CubeMapPacked, Graphic3d_CubeMap) public: - //! Initialization to load cubemef from file. + //! Initialization to load cubemap from file. //! @theFileName - path to the cubemap image - //! @theOrder - array conaining six different indexes of cubemap sides which maps tile grid to cubemap sides + //! @theOrder - array containing six different indexes of cubemap sides which maps tile grid to cubemap sides Standard_EXPORT Graphic3d_CubeMapPacked (const TCollection_AsciiString& theFileName, const Graphic3d_ValidatedCubeMapOrder theOrder = Graphic3d_CubeMapOrder::Default()); //! Initialization to set cubemap directly by PixMap. //! @thePixMap - origin PixMap - //! @theOrder - array conaining six different indexes of cubemap sides which maps tile grid to cubemap sides + //! @theOrder - array containing six different indexes of cubemap sides which maps tile grid to cubemap sides Standard_EXPORT Graphic3d_CubeMapPacked (const Handle(Image_PixMap)& theImage, const Graphic3d_ValidatedCubeMapOrder theOrder = Graphic3d_CubeMapOrder::Default()); + //! Returns current cubemap side as compressed PixMap. + Standard_EXPORT virtual Handle(Image_CompressedPixMap) CompressedValue (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; + //! Returns current cubemap side as PixMap. //! Resulting PixMap is memory wrapper over original image. //! Returns null handle if current side or whole cubemap is invalid. //! Origin image has to contain six quad tiles having one sizes without any gaps to be valid. - Standard_EXPORT Handle(Image_PixMap) Value() Standard_OVERRIDE; + Standard_EXPORT virtual Handle(Image_PixMap) Value (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; //! Empty destructor. ~Graphic3d_CubeMapPacked() {} @@ -57,7 +60,8 @@ private: //! Tries to load image from file and checks it after that. //! Does nothing in case of fail. - void tryLoadImage (const TCollection_AsciiString &theFilePath); + void tryLoadImage (const Handle(Image_SupportedFormats)& theSupported, + const TCollection_AsciiString &theFilePath); protected: diff --git a/src/Graphic3d/Graphic3d_CubeMapSeparate.cxx b/src/Graphic3d/Graphic3d_CubeMapSeparate.cxx index 896c0eecd2..2646d2f5bc 100644 --- a/src/Graphic3d/Graphic3d_CubeMapSeparate.cxx +++ b/src/Graphic3d/Graphic3d_CubeMapSeparate.cxx @@ -13,7 +13,9 @@ // commercial license or contractual agreement. #include + #include +#include #include #include #include @@ -83,11 +85,55 @@ Graphic3d_CubeMapSeparate::Graphic3d_CubeMapSeparate (const NCollection_Array1SizeX() != anImage->SizeY()) + { + return Handle(Image_CompressedPixMap)(); + } + + if (myCurrentSide == 0) + { + mySize = anImage->SizeX(); + myFormat = anImage->BaseFormat(); + myIsTopDown = anImage->IsTopDown(); + return anImage; + } + + if (anImage->BaseFormat() == myFormat + && anImage->SizeX() == (Standard_Integer )mySize) + { + return anImage; + } + + Message::SendWarning (TCollection_AsciiString() + "'" + aFilePath + "' inconsistent image format or dimension in Graphic3d_CubeMapSeparate"); + return Handle(Image_CompressedPixMap)(); +} + // ======================================================================= // function : Value // purpose : // ======================================================================= -Handle(Image_PixMap) Graphic3d_CubeMapSeparate::Value() +Handle(Image_PixMap) Graphic3d_CubeMapSeparate::Value (const Handle(Image_SupportedFormats)& theSupported) { Graphic3d_CubeMapOrder anOrder = Graphic3d_CubeMapOrder::Default(); if (!myIsTopDown) @@ -108,6 +154,7 @@ Handle(Image_PixMap) Graphic3d_CubeMapSeparate::Value() Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap; if (anImage->Load(aFilePath)) { + convertToCompatible (theSupported, anImage); if (anImage->SizeX() == anImage->SizeY()) { if (myCurrentSide == 0) diff --git a/src/Graphic3d/Graphic3d_CubeMapSeparate.hxx b/src/Graphic3d/Graphic3d_CubeMapSeparate.hxx index 6f0012d616..74f72c5037 100644 --- a/src/Graphic3d/Graphic3d_CubeMapSeparate.hxx +++ b/src/Graphic3d/Graphic3d_CubeMapSeparate.hxx @@ -33,13 +33,16 @@ public: //! @theImages - array if PixMaps (has to have size equal 6). Standard_EXPORT Graphic3d_CubeMapSeparate(const NCollection_Array1& theImages); + //! Returns current cubemap side as compressed PixMap. + Standard_EXPORT virtual Handle(Image_CompressedPixMap) CompressedValue (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; + //! Returns current side of cubemap as PixMap. //! Returns null handle if current side or whole cubemap is invalid. //! All origin images have to have the same sizes, format and quad shapes to form valid cubemap. - Standard_EXPORT Handle(Image_PixMap) Value() Standard_OVERRIDE; + Standard_EXPORT virtual Handle(Image_PixMap) Value (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; //! Returns NULL. - virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE + virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& ) Standard_OVERRIDE { return Handle(Image_PixMap)(); } diff --git a/src/Graphic3d/Graphic3d_MediaTexture.cxx b/src/Graphic3d/Graphic3d_MediaTexture.cxx index cb23f01be9..46a987ce7f 100644 --- a/src/Graphic3d/Graphic3d_MediaTexture.cxx +++ b/src/Graphic3d/Graphic3d_MediaTexture.cxx @@ -56,7 +56,7 @@ Graphic3d_MediaTexture::Graphic3d_MediaTexture (const Handle(Media_HMutex)& theM // Function : GetImage // Purpose : // ================================================================ -Handle(Image_PixMap) Graphic3d_MediaTexture::GetImage() const +Handle(Image_PixMap) Graphic3d_MediaTexture::GetImage (const Handle(Image_SupportedFormats)& ) { Standard_Mutex::Sentry aLock (myMutex.get()); if (myFrame.IsNull() diff --git a/src/Graphic3d/Graphic3d_MediaTexture.hxx b/src/Graphic3d/Graphic3d_MediaTexture.hxx index bf74e92b9f..c081e471f3 100644 --- a/src/Graphic3d/Graphic3d_MediaTexture.hxx +++ b/src/Graphic3d/Graphic3d_MediaTexture.hxx @@ -34,7 +34,7 @@ public: Standard_Integer thePlane = -1); //! Image reader. - Standard_EXPORT virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE; + Standard_EXPORT virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; //! Return the frame. const Handle(Media_Frame)& Frame() const { return myFrame; } diff --git a/src/Graphic3d/Graphic3d_TextureParams.hxx b/src/Graphic3d/Graphic3d_TextureParams.hxx index e2c44b27eb..672275bf0e 100644 --- a/src/Graphic3d/Graphic3d_TextureParams.hxx +++ b/src/Graphic3d/Graphic3d_TextureParams.hxx @@ -72,22 +72,22 @@ public: //! @param theLevel level of anisontropy texture filter. Standard_EXPORT void SetAnisoFilter (const Graphic3d_LevelOfTextureAnisotropy theLevel); - //! @return rotation angle in degrees - //! Default value is 0. + //! Return rotation angle in degrees; 0 by default. + //! Complete transformation matrix: Rotation -> Translation -> Scale. Standard_ShortReal Rotation() const { return myRotAngle; } //! @param theAngleDegrees rotation angle. Standard_EXPORT void SetRotation (const Standard_ShortReal theAngleDegrees); - //! @return scale factor - //! Default value is no scaling (1.0; 1.0). + //! Return scale factor; (1.0; 1.0) by default, which means no scaling. + //! Complete transformation matrix: Rotation -> Translation -> Scale. const Graphic3d_Vec2& Scale() const { return myScale; } //! @param theScale scale factor. Standard_EXPORT void SetScale (const Graphic3d_Vec2 theScale); - - //! @return translation vector - //! Default value is no translation (0.0; 0.0). + + //! Return translation vector; (0.0; 0.0), which means no translation. + //! Complete transformation matrix: Rotation -> Translation -> Scale. const Graphic3d_Vec2& Translation() const { return myTranslation; } //! @param theVec translation vector. @@ -109,7 +109,8 @@ public: //! @return base texture mipmap level; 0 by default. Standard_Integer BaseLevel() const { return myBaseLevel; } - //! @return maximum texture mipmap array level; 1000 by default. + //! Return maximum texture mipmap array level; 1000 by default. + //! Real rendering limit will take into account mipmap generation flags and presence of mipmaps in loaded image. Standard_Integer MaxLevel() const { return myMaxLevel; } //! Setups texture mipmap array levels range. diff --git a/src/Graphic3d/Graphic3d_TextureRoot.cxx b/src/Graphic3d/Graphic3d_TextureRoot.cxx index 919086c5c3..21ec53ff5a 100644 --- a/src/Graphic3d/Graphic3d_TextureRoot.cxx +++ b/src/Graphic3d/Graphic3d_TextureRoot.cxx @@ -19,9 +19,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include @@ -90,7 +93,8 @@ Graphic3d_TextureRoot::Graphic3d_TextureRoot (const TCollection_AsciiString& the myPath (theFileName), myRevision (0), myType (theType), - myIsColorMap (true) + myIsColorMap (true), + myIsTopDown (true) { generateId(); } @@ -105,7 +109,8 @@ Graphic3d_TextureRoot::Graphic3d_TextureRoot (const Handle(Image_PixMap)& theP myPixMap (thePixMap), myRevision (0), myType (theType), - myIsColorMap (true) + myIsColorMap (true), + myIsTopDown (true) { generateId(); } @@ -129,15 +134,57 @@ void Graphic3d_TextureRoot::generateId() + TCollection_AsciiString (Standard_Atomic_Increment (&THE_TEXTURE_COUNTER)); } +// ======================================================================= +// function : GetCompressedImage +// purpose : +// ======================================================================= +Handle(Image_CompressedPixMap) Graphic3d_TextureRoot::GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported) +{ + if (!myPixMap.IsNull()) + { + return Handle(Image_CompressedPixMap)(); + } + + // Case 2: texture source is specified as path + TCollection_AsciiString aFilePath; + myPath.SystemName (aFilePath); + if (aFilePath.IsEmpty()) + { + return Handle(Image_CompressedPixMap)(); + } + + TCollection_AsciiString aFilePathLower = aFilePath; + aFilePathLower.LowerCase(); + if (!aFilePathLower.EndsWith (".dds")) + { + // do not waste time on file system access in case of wrong file extension + return Handle(Image_CompressedPixMap)(); + } + + if (Handle(Image_CompressedPixMap) anImage = Image_DDSParser::Load (theSupported, aFilePath, 0)) + { + myIsTopDown = anImage->IsTopDown(); + return anImage; + } + return Handle(Image_CompressedPixMap)(); +} + // ======================================================================= // function : GetImage // purpose : // ======================================================================= -Handle(Image_PixMap) Graphic3d_TextureRoot::GetImage() const +Handle(Image_PixMap) Graphic3d_TextureRoot::GetImage (const Handle(Image_SupportedFormats)& theSupported) { + if (Handle(Image_PixMap) anOldImage = GetImage()) + { + myIsTopDown = anOldImage->IsTopDown(); + return anOldImage; // compatibility with old API + } + // Case 1: texture source is specified as pixmap if (!myPixMap.IsNull()) { + myIsTopDown = myPixMap->IsTopDown(); return myPixMap; } @@ -150,12 +197,38 @@ Handle(Image_PixMap) Graphic3d_TextureRoot::GetImage() const } Handle(Image_AlienPixMap) anImage = new Image_AlienPixMap(); - if (!anImage->Load (aFilePath)) + if (anImage->Load (aFilePath)) { - return Handle(Image_PixMap)(); + myIsTopDown = anImage->IsTopDown(); + convertToCompatible (theSupported, anImage); + return anImage; } - return anImage; + return Handle(Image_PixMap)(); +} + +// ======================================================================= +// function : convertToCompatible +// purpose : +// ======================================================================= +void Graphic3d_TextureRoot::convertToCompatible (const Handle(Image_SupportedFormats)& theSupported, + const Handle(Image_PixMap)& theImage) +{ + if (theSupported.IsNull() + || theSupported->IsSupported (theImage->Format()) + || theImage.IsNull()) + { + return; + } + + if ((theImage->Format() == Image_Format_BGR32 + || theImage->Format() == Image_Format_BGR32)) + { + Image_PixMap::SwapRgbaBgra (*theImage); + theImage->SetFormat (theImage->Format() == Image_Format_BGR32 + ? Image_Format_RGB32 + : Image_Format_RGBA); + } } // ======================================================================= diff --git a/src/Graphic3d/Graphic3d_TextureRoot.hxx b/src/Graphic3d/Graphic3d_TextureRoot.hxx index 5cf14be367..fb155c4268 100644 --- a/src/Graphic3d/Graphic3d_TextureRoot.hxx +++ b/src/Graphic3d/Graphic3d_TextureRoot.hxx @@ -25,6 +25,8 @@ #include #include +class Image_CompressedPixMap; +class Image_SupportedFormats; class Graphic3d_TextureParams; //! This is the texture root class enable the dialog with the GraphicDriver allows the loading of texture. @@ -79,6 +81,13 @@ public: //! without re-creating texture source itself (since unique id should be never modified). void UpdateRevision() { ++myRevision; } + //! This method will be called by graphic driver each time when texture resource should be created. + //! It is called in front of GetImage() for uploading compressed image formats natively supported by GPU. + //! @param theSupported [in] the list of supported compressed texture formats; + //! returning image in unsupported format will result in texture upload failure + //! @return compressed pixmap or NULL if image is not in supported compressed format + Standard_EXPORT virtual Handle(Image_CompressedPixMap) GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported); + //! This method will be called by graphic driver each time when texture resource should be created. //! Default constructors allow defining the texture source as path to texture image or directly as pixmap. //! If the source is defined as path, then the image will be dynamically loaded when this method is called @@ -86,7 +95,7 @@ public: //! Inheritors may dynamically generate the image. //! Notice, image data should be in Bottom-Up order (see Image_PixMap::IsTopDown())! //! @return the image for texture. - Standard_EXPORT virtual Handle(Image_PixMap) GetImage() const; + Standard_EXPORT virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported); //! @return low-level texture parameters const Handle(Graphic3d_TextureParams)& GetParams() const { return myParams; } @@ -104,6 +113,9 @@ public: //! Set flag indicating color nature of values within the texture. void SetColorMap (Standard_Boolean theIsColor) { myIsColorMap = theIsColor; } + //! Returns whether row's memory layout is top-down. + Standard_Boolean IsTopDown() const { return myIsTopDown; } + protected: //! Creates a texture from a file @@ -119,6 +131,13 @@ protected: //! Unconditionally generate new texture id. Should be called only within constructor. Standard_EXPORT void generateId(); + //! Try converting image to compatible format. + Standard_EXPORT static void convertToCompatible (const Handle(Image_SupportedFormats)& theSupported, + const Handle(Image_PixMap)& theImage); + + //! Method for supporting old API; another GetImage() method should be implemented instead. + virtual Handle(Image_PixMap) GetImage() const { return Handle(Image_PixMap)(); } + protected: Handle(Graphic3d_TextureParams) myParams; //!< associated texture parameters @@ -128,6 +147,8 @@ protected: Standard_Size myRevision; //!< image revision - for signaling changes in the texture source (e.g. file update, pixmap update) Graphic3d_TypeOfTexture myType; //!< texture type Standard_Boolean myIsColorMap; //!< flag indicating color nature of values within the texture + Standard_Boolean myIsTopDown; //!< Stores rows's memory layout + }; diff --git a/src/Image/FILES b/src/Image/FILES index 8055875c29..f752166c5f 100755 --- a/src/Image/FILES +++ b/src/Image/FILES @@ -1,6 +1,10 @@ Image_AlienPixMap.cxx Image_AlienPixMap.hxx Image_Color.hxx +Image_CompressedFormat.hxx +Image_CompressedPixMap.hxx +Image_DDSParser.cxx +Image_DDSParser.hxx Image_Diff.cxx Image_Diff.hxx Image_Format.hxx @@ -8,6 +12,8 @@ Image_PixMap.cxx Image_PixMap.hxx Image_PixMapData.hxx Image_PixMapTypedData.hxx +Image_SupportedFormats.cxx +Image_SupportedFormats.hxx Image_Texture.cxx Image_Texture.hxx Image_VideoRecorder.cxx diff --git a/src/Image/Image_CompressedFormat.hxx b/src/Image/Image_CompressedFormat.hxx new file mode 100644 index 0000000000..2d8e697e02 --- /dev/null +++ b/src/Image/Image_CompressedFormat.hxx @@ -0,0 +1,31 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_CompressedFormat_HeaderFile +#define _Image_CompressedFormat_HeaderFile + +#include + +//! List of compressed pixel formats natively supported by various graphics hardware (e.g. for efficient decoding on-the-fly). +//! It is defined as extension of Image_Format. +enum Image_CompressedFormat +{ + Image_CompressedFormat_UNKNOWN = Image_Format_UNKNOWN, + Image_CompressedFormat_RGB_S3TC_DXT1 = Image_Format_NB, + Image_CompressedFormat_RGBA_S3TC_DXT1, + Image_CompressedFormat_RGBA_S3TC_DXT3, + Image_CompressedFormat_RGBA_S3TC_DXT5 +}; +enum { Image_CompressedFormat_NB = Image_CompressedFormat_RGBA_S3TC_DXT5 + 1 }; + +#endif // _Image_CompressedFormat_HeaderFile diff --git a/src/Image/Image_CompressedPixMap.hxx b/src/Image/Image_CompressedPixMap.hxx new file mode 100644 index 0000000000..541d5d8673 --- /dev/null +++ b/src/Image/Image_CompressedPixMap.hxx @@ -0,0 +1,108 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_CompressedPixMap_HeaderFile +#define _Image_CompressedPixMap_HeaderFile + +#include +#include +#include +#include +#include + +//! Compressed pixmap data definition. +//! It is defined independently from Image_PixMap, which defines only uncompressed formats. +class Image_CompressedPixMap : public Standard_Transient +{ + DEFINE_STANDARD_RTTIEXT(Image_CompressedPixMap, Standard_Transient) +public: + + //! Return base (uncompressed) pixel format. + Image_Format BaseFormat() const { return myBaseFormat; } + + //! Set base (uncompressed) pixel format. + void SetBaseFormat (Image_Format theFormat) { myBaseFormat = theFormat; } + + //! Return compressed format. + Image_CompressedFormat CompressedFormat() const { return myFormat; } + + //! Set compressed format. + void SetCompressedFormat (Image_CompressedFormat theFormat) { myFormat = theFormat; } + + //! Return raw (compressed) data. + const Handle(NCollection_Buffer)& FaceData() const { return myFaceData; } + + //! Set raw (compressed) data. + void SetFaceData (const Handle(NCollection_Buffer)& theBuffer) { myFaceData = theBuffer; } + + //! Return Array of mipmap sizes, including base level. + const NCollection_Array1& MipMaps() const { return myMipMaps; } + + //! Return Array of mipmap sizes, including base level. + NCollection_Array1& ChangeMipMaps() { return myMipMaps; } + + //! Return TRUE if complete mip map level set (up to 1x1 resolution). + Standard_Boolean IsCompleteMipMapSet() const { return myIsCompleteMips; } + + //! Set if complete mip map level set (up to 1x1 resolution). + void SetCompleteMipMapSet (Standard_Boolean theIsComplete) { myIsCompleteMips = theIsComplete; } + + //! Return surface length in bytes. + Standard_Size FaceBytes() const { return myFaceBytes; } + + //! Set surface length in bytes. + void SetFaceBytes (Standard_Size theSize) { myFaceBytes = theSize; } + + //! Return surface width. + Standard_Integer SizeX() const { return mySizeX; } + + //! Return surface height. + Standard_Integer SizeY() const { return mySizeY; } + + //! Set surface width x height. + void SetSize (Standard_Integer theSizeX, Standard_Integer theSizeY) + { + mySizeX = theSizeX; + mySizeY = theSizeY; + } + + //! Return TRUE if image layout is top-down (always true). + bool IsTopDown() const { return true; } + + //! Return number of faces in the file; should be 6 for cubemap. + Standard_Integer NbFaces() const { return myNbFaces; } + + //! Set number of faces in the file. + void SetNbFaces (Standard_Integer theSize) { myNbFaces = theSize; } + +public: + + //! Empty constructor. + Image_CompressedPixMap() + : myFaceBytes (0), myNbFaces (0), mySizeX (0), mySizeY (0), myBaseFormat (Image_Format_UNKNOWN), myFormat (Image_CompressedFormat_UNKNOWN), myIsCompleteMips (false) {} + +protected: + + NCollection_Array1 myMipMaps; //!< Array of mipmap sizes, including base level + Handle(NCollection_Buffer) myFaceData; //!< raw compressed data + Standard_Size myFaceBytes; //!< surface length in bytes + Standard_Integer myNbFaces; //!< number of faces in the file + Standard_Integer mySizeX; //!< surface width + Standard_Integer mySizeY; //!< surface height + Image_Format myBaseFormat; //!< base (uncompressed) pixel format + Image_CompressedFormat myFormat; //!< compressed format + Standard_Boolean myIsCompleteMips; //!< flag indicating complete mip map level set (up to 1x1 resolution) + +}; + +#endif // _Image_CompressedPixMap_HeaderFile diff --git a/src/Image/Image_DDSParser.cxx b/src/Image/Image_DDSParser.cxx new file mode 100644 index 0000000000..7addc9361c --- /dev/null +++ b/src/Image/Image_DDSParser.cxx @@ -0,0 +1,255 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include +#include +#include + +IMPLEMENT_STANDARD_RTTIEXT(Image_CompressedPixMap, Standard_Transient) + +//! DDS Pixel Format structure. +struct Image_DDSParser::DDSPixelFormat +{ + uint32_t Size; + uint32_t Flags; + uint32_t FourCC; + uint32_t RGBBitCount; + uint32_t RBitMask; + uint32_t GBitMask; + uint32_t BBitMask; + uint32_t ABitMask; +}; + +//! DDS File header structure. +struct Image_DDSParser::DDSFileHeader +{ + //! Caps2 flag indicating complete (6 faces) cubemap. + enum { DDSCompleteCubemap = 0xFE00 }; + + //! Return TRUE if cubmap flag is set. + bool IscompleteCubemap() const { return (Caps2 & DDSFileHeader::DDSCompleteCubemap) == DDSFileHeader::DDSCompleteCubemap; } + + uint32_t Size; + uint32_t Flags; + uint32_t Height; + uint32_t Width; + uint32_t PitchOrLinearSize; + uint32_t Depth; + uint32_t MipMapCount; + uint32_t Reserved1[11]; + DDSPixelFormat PixelFormatDef; + uint32_t Caps; + uint32_t Caps2; + uint32_t Caps3; + uint32_t Caps4; + uint32_t Reserved2; +}; + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_SupportedFormats)& theSupported, + const TCollection_AsciiString& theFile, + const Standard_Integer theFaceIndex, + const int64_t theFileOffset) +{ + std::ifstream aFile; + OSD_OpenStream (aFile, theFile.ToCString(), std::ios::in | std::ios::binary); + + char aHeader[128] = {}; + if (!aFile.is_open() + || !aFile.good()) + { + return Handle(Image_CompressedPixMap)(); + } + if (theFileOffset != 0) + { + aFile.seekg ((std::streamoff )theFileOffset, std::ios::beg); + } + aFile.read (aHeader, 128); + Standard_Size aNbReadBytes = (Standard_Size )aFile.gcount(); + if (aNbReadBytes < 128 + || ::memcmp (aHeader, "DDS ", 4) != 0) + { + return Handle(Image_CompressedPixMap)(); + } + + Handle(Image_CompressedPixMap) aDef = parseHeader (*(const DDSFileHeader* )(aHeader + 4)); + if (aDef.IsNull()) + { + return Handle(Image_CompressedPixMap)(); + } + + if (!theSupported.IsNull() + && !theSupported->IsSupported (aDef->CompressedFormat())) + { + return Handle(Image_CompressedPixMap)(); + } + + if (theFaceIndex < 0) + { + return aDef; + } + + if (theFaceIndex >= aDef->NbFaces() + || aDef->FaceBytes() == 0) + { + Message::SendFail (TCollection_AsciiString ("DDS Reader error - invalid face index #") + theFaceIndex + " within file\n" + theFile); + return Handle(Image_CompressedPixMap)(); + } + + const Standard_Size anOffset = aDef->FaceBytes() * theFaceIndex; + if (anOffset != 0) + { + aFile.seekg ((std::streamoff )anOffset, std::ios::cur); + } + Handle(NCollection_Buffer) aBuffer = new NCollection_Buffer (Image_PixMap::DefaultAllocator(), aDef->FaceBytes()); + aFile.read ((char* )aBuffer->ChangeData(), aDef->FaceBytes()); + aNbReadBytes = (Standard_Size )aFile.gcount(); + if (aNbReadBytes < aDef->FaceBytes()) + { + Message::SendFail (TCollection_AsciiString ("DDS Reader error - unable to read face #") + theFaceIndex + " data from file\n" + theFile); + return Handle(Image_CompressedPixMap)(); + } + aDef->SetFaceData (aBuffer); + return aDef; +} + +// ======================================================================= +// function : Load +// purpose : +// ======================================================================= +Handle(Image_CompressedPixMap) Image_DDSParser::Load (const Handle(Image_SupportedFormats)& theSupported, + const Handle(NCollection_Buffer)& theBuffer, + const Standard_Integer theFaceIndex) +{ + if (theBuffer.IsNull() + || theBuffer->Size() < 128 + || ::memcmp (theBuffer->Data(), "DDS ", 4) != 0) + { + return Handle(Image_CompressedPixMap)(); + } + + Handle(Image_CompressedPixMap) aDef = parseHeader (*(const DDSFileHeader* )(theBuffer->Data() + 4)); + if (aDef.IsNull()) + { + return Handle(Image_CompressedPixMap)(); + } + + if (!theSupported.IsNull() + && !theSupported->IsSupported (aDef->CompressedFormat())) + { + return Handle(Image_CompressedPixMap)(); + } + + if (theFaceIndex < 0) + { + return aDef; + } + + if (theFaceIndex >= aDef->NbFaces() + || aDef->FaceBytes() == 0) + { + Message::SendFail (TCollection_AsciiString ("DDS Reader error - invalid face index #") + theFaceIndex + " within buffer"); + return Handle(Image_CompressedPixMap)(); + } + + const Standard_Size anOffset = aDef->FaceBytes() * theFaceIndex + 128; + if (theBuffer->Size() < anOffset + aDef->FaceBytes()) + { + Message::SendFail (TCollection_AsciiString ("DDS Reader error - unable to read face #") + theFaceIndex + " data from buffer"); + return Handle(Image_CompressedPixMap)(); + } + + Handle(NCollection_Buffer) aBuffer = new NCollection_Buffer (Image_PixMap::DefaultAllocator(), aDef->FaceBytes()); + memcpy (aBuffer->ChangeData(), theBuffer->Data() + anOffset, aDef->FaceBytes()); + aDef->SetFaceData (aBuffer); + return aDef; +} + +// ======================================================================= +// function : parseHeader +// purpose : +// ======================================================================= +Handle(Image_CompressedPixMap) Image_DDSParser::parseHeader (const DDSFileHeader& theHeader) +{ + if (theHeader.Size != 124 + || theHeader.Width == 0 + || theHeader.Height == 0 + || theHeader.PixelFormatDef.Size != 32) + { + return Handle(Image_CompressedPixMap)(); + } + + Image_Format aBaseFormat = Image_Format_UNKNOWN; + Image_CompressedFormat aFormat = Image_CompressedFormat_UNKNOWN; + Standard_Integer aBlockSize = 8; + const bool hasAlpha = (theHeader.PixelFormatDef.Flags & 0x1) != 0; + if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT5", 4) == 0) + { + aBaseFormat = Image_Format_RGBA; + aFormat = Image_CompressedFormat_RGBA_S3TC_DXT5; + aBlockSize = 16; + } + else if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT3", 4) == 0) + { + aBaseFormat = Image_Format_RGBA; + aFormat = Image_CompressedFormat_RGBA_S3TC_DXT3; + aBlockSize = 16; + } + else if (::memcmp (&theHeader.PixelFormatDef.FourCC, "DXT1", 4) == 0) + { + aBaseFormat = hasAlpha ? Image_Format_RGBA : Image_Format_RGB; + aFormat = hasAlpha ? Image_CompressedFormat_RGBA_S3TC_DXT1 : Image_CompressedFormat_RGB_S3TC_DXT1; + aBlockSize = 8; + } + if (aFormat == Image_CompressedFormat_UNKNOWN) + { + return Handle(Image_CompressedPixMap)(); + } + + Handle(Image_CompressedPixMap) aDef = new Image_CompressedPixMap(); + aDef->SetSize ((Standard_Integer )theHeader.Width, (Standard_Integer )theHeader.Height); + aDef->SetNbFaces (theHeader.IscompleteCubemap() != 0 ? 6 : 1); + aDef->SetBaseFormat (aBaseFormat); + aDef->SetCompressedFormat (aFormat); + + const Standard_Integer aNbMipMaps = Max ((Standard_Integer )theHeader.MipMapCount, 1); + aDef->ChangeMipMaps().Resize (0, aNbMipMaps - 1, false); + { + Standard_Size aFaceSize = 0; + NCollection_Vec2 aMipSizeXY (aDef->SizeX(), aDef->SizeY()); + for (Standard_Integer aMipIter = 0;; ++aMipIter) + { + const Standard_Integer aMipLength = ((aMipSizeXY.x() + 3) / 4) * ((aMipSizeXY.y() + 3) / 4) * aBlockSize; + aFaceSize += aMipLength; + aDef->ChangeMipMaps().SetValue (aMipIter, aMipLength); + if (aMipIter + 1 >= aNbMipMaps) + { + break; + } + + aMipSizeXY /= 2; + if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; } + if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; } + } + aDef->SetCompleteMipMapSet (aMipSizeXY.x() == 1 && aMipSizeXY.y() == 1); + aDef->SetFaceBytes (aFaceSize); + } + + return aDef; +} diff --git a/src/Image/Image_DDSParser.hxx b/src/Image/Image_DDSParser.hxx new file mode 100644 index 0000000000..70106979e7 --- /dev/null +++ b/src/Image/Image_DDSParser.hxx @@ -0,0 +1,62 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_DDSParser_HeaderFile +#define _Image_DDSParser_HeaderFile + +#include +#include + +class Image_SupportedFormats; + +//! Auxiliary tool for parsing DDS file structure (without decoding). +class Image_DDSParser +{ +public: + + //! Load the face from DDS file. + //! @param theSupported [in] list of supported image formats + //! @param theFile [in] file path + //! @param theFaceIndex [in] face index, within [0, Image_CompressedPixMap::NbFaces()) range; + //! use -1 to skip reading the face data + //! @param theFileOffset [in] offset to the DDS data + //! @return loaded face or NULL if file cannot be read or not valid DDS file + Standard_EXPORT static Handle(Image_CompressedPixMap) Load (const Handle(Image_SupportedFormats)& theSupported, + const TCollection_AsciiString& theFile, + const Standard_Integer theFaceIndex, + const int64_t theFileOffset = 0); + + //! Load the face from DDS file. + //! @param theSupported [in] list of supported image formats + //! @param theBuffer [in] pre-loaded file data, should be at least of 128 bytes long defining DDS header. + //! @param theFaceIndex [in] face index, within [0, Image_CompressedPixMap::NbFaces()) range; + //! use -1 to skip reading the face data + //! @return loaded face or NULL if file cannot be read or not valid DDS file + Standard_EXPORT static Handle(Image_CompressedPixMap) Load (const Handle(Image_SupportedFormats)& theSupported, + const Handle(NCollection_Buffer)& theBuffer, + const Standard_Integer theFaceIndex); + + +private: + + struct DDSPixelFormat; + struct DDSFileHeader; + +private: + + //! Parse DDS header. + static Handle(Image_CompressedPixMap) parseHeader (const DDSFileHeader& theHeader); + +}; + +#endif // _Image_DDSParser_HeaderFile diff --git a/src/Image/Image_Format.hxx b/src/Image/Image_Format.hxx index 58426258c6..28bfcf4d69 100644 --- a/src/Image/Image_Format.hxx +++ b/src/Image/Image_Format.hxx @@ -34,5 +34,6 @@ enum Image_Format Image_Format_RGBAF, //!< 4 floats (16-bytes) RGBA image plane Image_Format_BGRAF, //!< same as RGBAF but with different components order }; +enum { Image_Format_NB = Image_Format_BGRAF + 1 }; #endif // _Image_Format_HeaderFile diff --git a/src/Image/Image_PixMap.cxx b/src/Image/Image_PixMap.cxx index 57f76f1e2c..6d9f002a5e 100644 --- a/src/Image/Image_PixMap.cxx +++ b/src/Image/Image_PixMap.cxx @@ -14,6 +14,7 @@ // commercial license or contractual agreement. #include + #include #include @@ -21,6 +22,16 @@ IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap,Standard_Transient) +// ======================================================================= +// function : DefaultAllocator +// purpose : +// ======================================================================= +const Handle(NCollection_BaseAllocator)& Image_PixMap::DefaultAllocator() +{ + static const Handle(NCollection_BaseAllocator) THE_ALLOC = new NCollection_AlignedAllocator (16); + return THE_ALLOC; +} + // ======================================================================= // function : Image_PixMap // purpose : @@ -40,6 +51,10 @@ Image_PixMap::~Image_PixMap() Clear(); } +// ======================================================================= +// function : SizePixelBytes +// purpose : +// ======================================================================= Standard_Size Image_PixMap::SizePixelBytes (const Image_Format thePixelFormat) { switch (thePixelFormat) @@ -135,8 +150,7 @@ bool Image_PixMap::InitTrash (Image_Format thePixelFormat, // use argument only if it greater const Standard_Size aSizeRowBytes = std::max (theSizeRowBytes, theSizeX * SizePixelBytes (thePixelFormat)); - Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16); - myData.Init (anAlloc, Image_PixMap::SizePixelBytes (thePixelFormat), + myData.Init (DefaultAllocator(), Image_PixMap::SizePixelBytes (thePixelFormat), theSizeX, theSizeY, aSizeRowBytes, NULL); return !myData.IsEmpty(); } diff --git a/src/Image/Image_PixMap.hxx b/src/Image/Image_PixMap.hxx index 6323445156..c7775e58ec 100644 --- a/src/Image/Image_PixMap.hxx +++ b/src/Image/Image_PixMap.hxx @@ -48,6 +48,9 @@ public: //! Convert image to Black/White. Standard_EXPORT static void ToBlackWhite (Image_PixMap& theImage); + //! Return default image data allocator. + Standard_EXPORT static const Handle(NCollection_BaseAllocator)& DefaultAllocator(); + public: // high-level API Image_Format Format() const { return myImgFormat; } diff --git a/src/Image/Image_SupportedFormats.cxx b/src/Image/Image_SupportedFormats.cxx new file mode 100644 index 0000000000..4522583fce --- /dev/null +++ b/src/Image/Image_SupportedFormats.cxx @@ -0,0 +1,27 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +IMPLEMENT_STANDARD_RTTIEXT(Image_SupportedFormats, Standard_Transient) + +// ======================================================================= +// function : Image_SupportedFormats +// purpose : +// ======================================================================= +Image_SupportedFormats::Image_SupportedFormats() +: myFormats (Image_Format_UNKNOWN, Image_CompressedFormat_NB - 1), + myHasCompressed (false) +{ + myFormats.Init (false); +} diff --git a/src/Image/Image_SupportedFormats.hxx b/src/Image/Image_SupportedFormats.hxx new file mode 100644 index 0000000000..91abe1665f --- /dev/null +++ b/src/Image/Image_SupportedFormats.hxx @@ -0,0 +1,63 @@ +// Copyright (c) 2020 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// 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. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Image_SupportedFormats_HeaderFile +#define _Image_SupportedFormats_HeaderFile + +#include +#include +#include + +//! Structure holding information about supported texture formats. +class Image_SupportedFormats : public Standard_Transient +{ + DEFINE_STANDARD_RTTIEXT(Image_SupportedFormats, Standard_Transient) +public: + + //! Empty constructor. + Standard_EXPORT Image_SupportedFormats(); + + //! Return TRUE if image format is supported. + bool IsSupported (Image_Format theFormat) const { return myFormats.Value (theFormat); } + + //! Set if image format is supported or not. + void Add (Image_Format theFormat) { myFormats.SetValue (theFormat, true); } + + //! Return TRUE if there are compressed image formats supported. + bool HasCompressed() const { return myHasCompressed; } + + //! Return TRUE if compressed image format is supported. + bool IsSupported (Image_CompressedFormat theFormat) const { return myFormats.Value (theFormat); } + + //! Set if compressed image format is supported or not. + void Add (Image_CompressedFormat theFormat) + { + myFormats.SetValue (theFormat, true); + myHasCompressed = true; + } + + //! Reset flags. + void Clear() + { + myFormats.Init (false); + myHasCompressed = false; + } + +protected: + + NCollection_Array1 myFormats; //!< list of supported formats + Standard_Boolean myHasCompressed; //!< flag indicating that some compressed image formats are supported + +}; + +#endif // _Image_SupportedFormats_HeaderFile diff --git a/src/Image/Image_Texture.cxx b/src/Image/Image_Texture.cxx index 63f1153ac9..ce9d2a540a 100644 --- a/src/Image/Image_Texture.cxx +++ b/src/Image/Image_Texture.cxx @@ -15,6 +15,8 @@ #include #include +#include +#include #include #include #include @@ -73,11 +75,41 @@ Image_Texture::Image_Texture (const Handle(NCollection_Buffer)& theBuffer, } } +// ================================================================ +// Function : ReadCompressedImage +// Purpose : +// ================================================================ +Handle(Image_CompressedPixMap) Image_Texture::ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const +{ + if (!theSupported->HasCompressed()) + { + return Handle(Image_CompressedPixMap)(); + } + + if (!myBuffer.IsNull()) + { + return Image_DDSParser::Load (theSupported, myBuffer, 0); + } + else if (myOffset >= 0) + { + return Image_DDSParser::Load (theSupported, myImagePath, 0, myOffset); + } + + TCollection_AsciiString aFilePathLower = myImagePath; + aFilePathLower.LowerCase(); + if (!aFilePathLower.EndsWith (".dds")) + { + // do not waste time on file system access in case of wrong file extension + return Handle(Image_CompressedPixMap)(); + } + return Image_DDSParser::Load (theSupported, myImagePath, 0); +} + // ================================================================ // Function : ReadImage // Purpose : // ================================================================ -Handle(Image_PixMap) Image_Texture::ReadImage() const +Handle(Image_PixMap) Image_Texture::ReadImage (const Handle(Image_SupportedFormats)& ) const { Handle(Image_PixMap) anImage; if (!myBuffer.IsNull()) @@ -240,6 +272,10 @@ TCollection_AsciiString Image_Texture::ProbeImageFileFormat() const { return "webp"; } + else if (memcmp (aBuffer, "DDS ", 4) == 0) + { + return "dds"; + } return ""; } diff --git a/src/Image/Image_Texture.hxx b/src/Image/Image_Texture.hxx index 688f0e11e2..7a6f53be6b 100644 --- a/src/Image/Image_Texture.hxx +++ b/src/Image/Image_Texture.hxx @@ -18,6 +18,8 @@ #include #include +class Image_CompressedPixMap; +class Image_SupportedFormats; class Image_PixMap; //! Texture image definition. @@ -57,8 +59,11 @@ public: //! Return image file format. Standard_EXPORT TCollection_AsciiString ProbeImageFileFormat() const; + //! Image reader without decoding data for formats supported natively by GPUs. + Standard_EXPORT virtual Handle(Image_CompressedPixMap) ReadCompressedImage (const Handle(Image_SupportedFormats)& theSupported) const; + //! Image reader. - Standard_EXPORT virtual Handle(Image_PixMap) ReadImage() const; + Standard_EXPORT virtual Handle(Image_PixMap) ReadImage (const Handle(Image_SupportedFormats)& theSupported) const; //! Write image to specified file without decoding data. Standard_EXPORT virtual Standard_Boolean WriteImage (const TCollection_AsciiString& theFile); diff --git a/src/OpenGl/OpenGl_Caps.cxx b/src/OpenGl/OpenGl_Caps.cxx index d352e9b2b8..5f8c3d3cfd 100755 --- a/src/OpenGl/OpenGl_Caps.cxx +++ b/src/OpenGl/OpenGl_Caps.cxx @@ -25,6 +25,7 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Caps,Standard_Transient) // ======================================================================= OpenGl_Caps::OpenGl_Caps() : sRGBDisable (Standard_False), + compressedTexturesDisable (Standard_False), vboDisable (Standard_False), pntSpritesDisable (Standard_False), keepArrayData (Standard_False), @@ -54,6 +55,7 @@ OpenGl_Caps::OpenGl_Caps() contextNoExtensions (Standard_False), contextMajorVersionUpper (-1), contextMinorVersionUpper (-1), + isTopDownTextureUV(Standard_False), glslWarnings (Standard_False), suppressExtraMsg (Standard_True), glslDumpLevel (OpenGl_ShaderProgramDumpLevel_Off) @@ -68,6 +70,7 @@ OpenGl_Caps::OpenGl_Caps() OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy) { sRGBDisable = theCopy.sRGBDisable; + compressedTexturesDisable = theCopy.compressedTexturesDisable; vboDisable = theCopy.vboDisable; pntSpritesDisable = theCopy.pntSpritesDisable; keepArrayData = theCopy.keepArrayData; @@ -83,6 +86,7 @@ OpenGl_Caps& OpenGl_Caps::operator= (const OpenGl_Caps& theCopy) contextNoExtensions = theCopy.contextNoExtensions; contextMajorVersionUpper = theCopy.contextMajorVersionUpper; contextMinorVersionUpper = theCopy.contextMinorVersionUpper; + isTopDownTextureUV = theCopy.isTopDownTextureUV; glslWarnings = theCopy.glslWarnings; suppressExtraMsg = theCopy.suppressExtraMsg; glslDumpLevel = theCopy.glslDumpLevel; diff --git a/src/OpenGl/OpenGl_Caps.hxx b/src/OpenGl/OpenGl_Caps.hxx index e0b123c1df..6a1a386e27 100755 --- a/src/OpenGl/OpenGl_Caps.hxx +++ b/src/OpenGl/OpenGl_Caps.hxx @@ -28,6 +28,7 @@ class OpenGl_Caps : public Standard_Transient public: //! @name flags to disable particular functionality, should be used only for testing purposes! Standard_Boolean sRGBDisable; //!< Disables sRGB rendering (OFF by default) + Standard_Boolean compressedTexturesDisable; //!< Disables uploading of compressed texture formats native to GPU (OFF by default) Standard_Boolean vboDisable; //!< disallow VBO usage for debugging purposes (OFF by default) Standard_Boolean pntSpritesDisable; //!< flag permits Point Sprites usage, will significantly affect performance (OFF by default) Standard_Boolean keepArrayData; //!< Disables freeing CPU memory after building VBOs (OFF by default) @@ -125,6 +126,19 @@ public: //! @name context creation parameters Standard_Integer contextMajorVersionUpper; Standard_Integer contextMinorVersionUpper; + /** + * Define if 2D texture UV coordinates are defined top-down or bottom-up. FALSE by default. + * + * Proper rendering requires image texture uploading and UV texture coordinates being consistent, + * otherwise texture mapping might appear vertically flipped. + * Historically, OCCT used image library loading images bottom-up, + * so that applications have to generate UV accordingly (flip V when necessary, V' = 1.0 - V). + * + * Graphic driver now compares this flag with image layout reported by Image_PixMap::IsTopDown(), + * and in case of mismatch applies implicit texture coordinates conversion in GLSL program. + */ + Standard_Boolean isTopDownTextureUV; + public: //! @name flags to activate verbose output //! Print GLSL program compilation/linkage warnings, if any. OFF by default. diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx index f47bcc73fd..531d4fd22d 100644 --- a/src/OpenGl/OpenGl_Context.cxx +++ b/src/OpenGl/OpenGl_Context.cxx @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -188,6 +189,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps) myClippingState (), myGlLibHandle (NULL), myFuncs (new OpenGl_GlFunctions()), + mySupportedFormats (new Image_SupportedFormats()), myAnisoMax (1), myTexClamp (GL_CLAMP_TO_EDGE), myMaxTexDim (1024), @@ -1319,6 +1321,14 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) myVendor = (const char* )::glGetString (GL_VENDOR); myVendor.LowerCase(); + // standard formats + mySupportedFormats->Clear(); + mySupportedFormats->Add (Image_PixMap::ImgGray); + mySupportedFormats->Add (Image_PixMap::ImgAlpha); + mySupportedFormats->Add (Image_PixMap::ImgRGB); + mySupportedFormats->Add (Image_PixMap::ImgRGB32); + mySupportedFormats->Add (Image_PixMap::ImgRGBA); + if (caps->contextMajorVersionUpper != -1) { // synthetically restrict OpenGL version for testing @@ -1467,6 +1477,13 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) } #endif + if (extBgra) + { + // no BGR on OpenGL ES - only BGRA as extension + mySupportedFormats->Add (Image_PixMap::ImgBGR32); + mySupportedFormats->Add (Image_PixMap::ImgBGRA); + } + core11fwd = (OpenGl_GlCore11Fwd* )(&(*myFuncs)); if (IsGlGreaterEqual (2, 0)) { @@ -1613,7 +1630,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP; hasTexRGBA8 = Standard_True; - hasTexSRGB = IsGlGreaterEqual (2, 0); + hasTexSRGB = IsGlGreaterEqual (2, 1); hasFboSRGB = IsGlGreaterEqual (2, 1); hasSRGBControl = hasFboSRGB; arbDrawBuffers = CheckExtension ("GL_ARB_draw_buffers"); @@ -1622,12 +1639,20 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) || CheckExtension ("GL_ARB_texture_float"); hasTexFloatLinear = arbTexFloat; arbSampleShading = CheckExtension ("GL_ARB_sample_shading"); - extBgra = CheckExtension ("GL_EXT_bgra"); + extBgra = IsGlGreaterEqual (1, 2) + || CheckExtension ("GL_EXT_bgra"); extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic"); extPDS = CheckExtension ("GL_EXT_packed_depth_stencil"); atiMem = CheckExtension ("GL_ATI_meminfo"); nvxMem = CheckExtension ("GL_NVX_gpu_memory_info"); + if (extBgra) + { + mySupportedFormats->Add (Image_PixMap::ImgBGR); + mySupportedFormats->Add (Image_PixMap::ImgBGR32); + mySupportedFormats->Add (Image_PixMap::ImgBGRA); + } + hasDrawBuffers = IsGlGreaterEqual (2, 0) ? OpenGl_FeatureInCore : arbDrawBuffers ? OpenGl_FeatureInExtensions : OpenGl_FeatureNotAvailable; @@ -2974,6 +2999,59 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile) } } + if (arbTexFloat) + { + mySupportedFormats->Add (Image_Format_GrayF); + mySupportedFormats->Add (Image_Format_AlphaF); + mySupportedFormats->Add (Image_Format_RGBF); + mySupportedFormats->Add (Image_Format_RGBAF); + if (arbTexRG) + { + mySupportedFormats->Add (Image_Format_RGF); + } + if (extBgra) + { + #if !defined(GL_ES_VERSION_2_0) + mySupportedFormats->Add (Image_Format_BGRF); + #endif + mySupportedFormats->Add (Image_Format_BGRAF); + } + } + +#ifdef __EMSCRIPTEN__ + if (checkEnableWebGlExtension (*this, "GL_WEBGL_compressed_texture_s3tc")) // GL_WEBGL_compressed_texture_s3tc_srgb for sRGB formats + { + mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5); + } +#else + if (CheckExtension ("GL_EXT_texture_compression_s3tc")) // GL_EXT_texture_sRGB for sRGB formats + { + mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5); + } + else + { + if (CheckExtension ("GL_EXT_texture_compression_dxt1")) + { + mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1); + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1); + } + if (CheckExtension ("GL_ANGLE_texture_compression_dxt3")) + { + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3); + } + if (CheckExtension ("GL_ANGLE_texture_compression_dxt5")) + { + mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5); + } + } +#endif + // check whether PBR shading model is supported myHasPBR = arbFBO != NULL && myMaxTexCombined >= 4 @@ -3461,7 +3539,7 @@ Handle(OpenGl_TextureSet) OpenGl_Context::BindTextures (const Handle(OpenGl_Text } else { - OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->HasMipmaps()); + OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->MaxMipmapLevel()); } } #if !defined(GL_ES_VERSION_2_0) @@ -3791,13 +3869,17 @@ void OpenGl_Context::SetLineWidth (const Standard_ShortReal theWidth) // function : SetTextureMatrix // purpose : // ======================================================================= -void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams) +void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams, + const Standard_Boolean theIsTopDown) { if (theParams.IsNull()) { return; } - else if (!myActiveProgram.IsNull()) + + const Graphic3d_Vec2& aScale = theParams->Scale(); + const Graphic3d_Vec2& aTrans = theParams->Translation(); + if (!myActiveProgram.IsNull()) { const GLint aUniLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_TRSF2D); if (aUniLoc == OpenGl_ShaderProgram::INVALID_LOCATION) @@ -3808,14 +3890,17 @@ void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& th // pack transformation parameters OpenGl_Vec4 aTrsf[2] = { - OpenGl_Vec4 (-theParams->Translation().x(), - -theParams->Translation().y(), - theParams->Scale().x(), - theParams->Scale().y()), + OpenGl_Vec4 (-aTrans.x(), -aTrans.y(), aScale.x(), aScale.y()), OpenGl_Vec4 (static_cast (std::sin (-theParams->Rotation() * M_PI / 180.0)), static_cast (std::cos (-theParams->Rotation() * M_PI / 180.0)), 0.0f, 0.0f) }; + if (caps->isTopDownTextureUV != theIsTopDown) + { + // flip V + aTrsf[0].y() = -aTrans.y() + 1.0f / aScale.y(); + aTrsf[0].w() = -aScale.y(); + } myActiveProgram->SetUniform (this, aUniLoc, 2, aTrsf); return; } @@ -3828,11 +3913,18 @@ void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& th core11->glMatrixMode (GL_TEXTURE); OpenGl_Mat4 aTextureMat; - const Graphic3d_Vec2& aScale = theParams->Scale(); - const Graphic3d_Vec2& aTrans = theParams->Translation(); - Graphic3d_TransformUtils::Scale (aTextureMat, aScale.x(), aScale.y(), 1.0f); - Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f); - Graphic3d_TransformUtils::Rotate (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f); + if (caps->isTopDownTextureUV != theIsTopDown) + { + // flip V + Graphic3d_TransformUtils::Scale (aTextureMat, aScale.x(), -aScale.y(), 1.0f); + Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y() + 1.0f / aScale.y(), 0.0f); + } + else + { + Graphic3d_TransformUtils::Scale (aTextureMat, aScale.x(), aScale.y(), 1.0f); + Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f); + } + Graphic3d_TransformUtils::Rotate (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f); core11->glLoadMatrixf (aTextureMat); core11->glMatrixMode (aMatrixMode); } diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx index 3806df404c..7ba13a9aeb 100644 --- a/src/OpenGl/OpenGl_Context.hxx +++ b/src/OpenGl/OpenGl_Context.hxx @@ -506,6 +506,9 @@ public: #endif } + //! Return map of supported texture formats. + const Handle(Image_SupportedFormats)& SupportedTextureFormats() const { return mySupportedFormats; } + //! @return maximum degree of anisotropy texture filter Standard_Integer MaxDegreeOfAnisotropy() const { return myAnisoMax; } @@ -911,7 +914,10 @@ public: //! @name methods to alter or retrieve current state Standard_EXPORT void SetPointSpriteOrigin(); //! Setup texture matrix to active GLSL program or to FFP global state using glMatrixMode (GL_TEXTURE). - Standard_EXPORT void SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams); + //! @param theParams [in] texture parameters + //! @param theIsTopDown [in] texture top-down flag + Standard_EXPORT void SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams, + const Standard_Boolean theIsTopDown); //! Bind default Vertex Array Object Standard_EXPORT void BindDefaultVao(); @@ -1040,7 +1046,7 @@ public: //! @name extensions Standard_Boolean hasUintIndex; //!< GLuint for index buffer is supported (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_element_index_uint) Standard_Boolean hasTexRGBA8; //!< always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_rgb8_rgba8 Standard_Boolean hasTexFloatLinear; //!< texture-filterable state for 32-bit floating texture formats (always on desktop, GL_OES_texture_float_linear within OpenGL ES) - Standard_Boolean hasTexSRGB; //!< sRGB texture formats (desktop OpenGL 2.0, OpenGL ES 3.0 or GL_EXT_texture_sRGB) + Standard_Boolean hasTexSRGB; //!< sRGB texture formats (desktop OpenGL 2.1, OpenGL ES 3.0 or GL_EXT_texture_sRGB) Standard_Boolean hasFboSRGB; //!< sRGB FBO render targets (desktop OpenGL 2.1, OpenGL ES 3.0) Standard_Boolean hasSRGBControl; //!< sRGB write control (any desktop OpenGL, OpenGL ES + GL_EXT_sRGB_write_control extension) OpenGl_FeatureFlag hasFlatShading; //!< Complex flag indicating support of Flat shading (Graphic3d_TOSM_FACET) (always available on desktop; on OpenGL ES - since 3.0 or as extension GL_OES_standard_derivatives) @@ -1116,6 +1122,8 @@ private: // context info void* myGlLibHandle; //!< optional handle to GL library NCollection_Handle myFuncs; //!< mega structure for all GL functions + Handle(Image_SupportedFormats) + mySupportedFormats; //!< map of supported texture formats Standard_Integer myAnisoMax; //!< maximum level of anisotropy texture filter Standard_Integer myTexClamp; //!< either GL_CLAMP_TO_EDGE (1.2+) or GL_CLAMP (1.1) Standard_Integer myMaxTexDim; //!< value for GL_MAX_TEXTURE_SIZE diff --git a/src/OpenGl/OpenGl_GlFunctions.hxx b/src/OpenGl/OpenGl_GlFunctions.hxx index 6cc1c66a29..0c3136e62e 100644 --- a/src/OpenGl/OpenGl_GlFunctions.hxx +++ b/src/OpenGl/OpenGl_GlFunctions.hxx @@ -152,6 +152,17 @@ #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_PATCHES 0x000E + + // GL_EXT_texture_compression_s3tc extension + #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 + #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 + #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 + #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 + // + #define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C + #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D + #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E + #define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F #endif #if !defined(HAVE_EGL) && (defined(__ANDROID__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(HAVE_GLES2) || defined(OCCT_UWP)) @@ -191,87 +202,87 @@ public: //! @name OpenGL ES 1.1 #if defined(GL_ES_VERSION_2_0) - inline void glActiveTexture (GLenum texture) + inline void glActiveTexture (GLenum texture) const { ::glActiveTexture (texture); } - inline void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) + inline void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const { ::glCompressedTexImage2D (target, level, internalformat, width, height, border, imageSize, data); } - inline void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) + inline void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) const { ::glCompressedTexSubImage2D (target, level, xoffset, yoffset, width, height, format, imageSize, data); } - inline void glBindBuffer (GLenum target, GLuint buffer) + inline void glBindBuffer (GLenum target, GLuint buffer) const { ::glBindBuffer (target, buffer); } - inline void glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage) + inline void glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage) const { ::glBufferData (target, size, data, usage); } - inline void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data) + inline void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data) const { ::glBufferSubData (target, offset, size, data); } - inline void glDeleteBuffers (GLsizei n, const GLuint *buffers) + inline void glDeleteBuffers (GLsizei n, const GLuint *buffers) const { ::glDeleteBuffers (n, buffers); } - inline void glDeleteTextures (GLsizei n, const GLuint *textures) + inline void glDeleteTextures (GLsizei n, const GLuint *textures) const { ::glDeleteTextures (n, textures); } - inline void glDepthFunc (GLenum func) + inline void glDepthFunc (GLenum func) const { ::glDepthFunc (func); } - inline void glDepthMask (GLboolean flag) + inline void glDepthMask (GLboolean flag) const { ::glDepthMask (flag); } - inline void glDepthRangef (GLfloat n, GLfloat f) + inline void glDepthRangef (GLfloat n, GLfloat f) const { ::glDepthRangef (n, f); } - inline void glGenBuffers (GLsizei n, GLuint *buffers) + inline void glGenBuffers (GLsizei n, GLuint *buffers) const { ::glGenBuffers (n, buffers); } - inline void glGenTextures (GLsizei n, GLuint *textures) + inline void glGenTextures (GLsizei n, GLuint *textures) const { ::glGenTextures (n, textures); } - inline void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params) + inline void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params) const { ::glGetBufferParameteriv (target, pname, params); } - inline GLboolean glIsBuffer (GLuint buffer) + inline GLboolean glIsBuffer (GLuint buffer) const { return ::glIsBuffer (buffer); } - inline void glSampleCoverage (GLfloat value, GLboolean invert) + inline void glSampleCoverage (GLfloat value, GLboolean invert) const { ::glSampleCoverage (value, invert); } - inline void glMultiDrawElements (GLenum theMode, const GLsizei* theCount, GLenum theType, const void* const* theIndices, GLsizei theDrawCount) + inline void glMultiDrawElements (GLenum theMode, const GLsizei* theCount, GLenum theType, const void* const* theIndices, GLsizei theDrawCount) const { if (theCount == NULL || theIndices == NULL) @@ -290,422 +301,422 @@ public: //! @name OpenGL ES 1.1 public: //! @name OpenGL ES 2.0 #if defined(GL_ES_VERSION_2_0) - inline void glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) + inline void glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) const { ::glBlendColor (red, green, blue, alpha); } - inline void glBlendEquation (GLenum mode) + inline void glBlendEquation (GLenum mode) const { ::glBlendEquation (mode); } - inline void glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) + inline void glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) const { ::glBlendFuncSeparate (sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha); } - inline void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) + inline void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) const { ::glBlendEquationSeparate (modeRGB, modeAlpha); } - inline void glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) + inline void glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) const { ::glStencilOpSeparate (face, sfail, dpfail, dppass); } - inline void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) + inline void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) const { ::glStencilFuncSeparate (face, func, ref, mask); } - inline void glStencilMaskSeparate (GLenum face, GLuint mask) + inline void glStencilMaskSeparate (GLenum face, GLuint mask) const { ::glStencilMaskSeparate (face, mask); } - inline void glAttachShader (GLuint program, GLuint shader) + inline void glAttachShader (GLuint program, GLuint shader) const { ::glAttachShader (program, shader); } - inline void glBindAttribLocation (GLuint program, GLuint index, const GLchar *name) + inline void glBindAttribLocation (GLuint program, GLuint index, const GLchar *name) const { ::glBindAttribLocation (program, index, name); } - inline void glBindFramebuffer (GLenum target, GLuint framebuffer) + inline void glBindFramebuffer (GLenum target, GLuint framebuffer) const { ::glBindFramebuffer (target, framebuffer); } - inline void glBindRenderbuffer (GLenum target, GLuint renderbuffer) + inline void glBindRenderbuffer (GLenum target, GLuint renderbuffer) const { ::glBindRenderbuffer (target, renderbuffer); } - inline GLenum glCheckFramebufferStatus (GLenum target) + inline GLenum glCheckFramebufferStatus (GLenum target) const { return ::glCheckFramebufferStatus (target); } - inline void glCompileShader (GLuint shader) + inline void glCompileShader (GLuint shader) const { ::glCompileShader (shader); } - inline GLuint glCreateProgram() + inline GLuint glCreateProgram() const { return ::glCreateProgram(); } - inline GLuint glCreateShader (GLenum type) + inline GLuint glCreateShader (GLenum type) const { return ::glCreateShader (type); } - inline void glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers) + inline void glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers) const { ::glDeleteFramebuffers (n, framebuffers); } - inline void glDeleteProgram (GLuint program) + inline void glDeleteProgram (GLuint program) const { ::glDeleteProgram (program); } - inline void glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers) + inline void glDeleteRenderbuffers (GLsizei n, const GLuint *renderbuffers) const { ::glDeleteRenderbuffers (n, renderbuffers); } - inline void glDeleteShader (GLuint shader) + inline void glDeleteShader (GLuint shader) const { ::glDeleteShader (shader); } - inline void glDetachShader (GLuint program, GLuint shader) + inline void glDetachShader (GLuint program, GLuint shader) const { ::glDetachShader (program, shader); } - inline void glDisableVertexAttribArray (GLuint index) + inline void glDisableVertexAttribArray (GLuint index) const { ::glDisableVertexAttribArray (index); } - inline void glEnableVertexAttribArray (GLuint index) + inline void glEnableVertexAttribArray (GLuint index) const { ::glEnableVertexAttribArray (index); } - inline void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) + inline void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) const { ::glFramebufferRenderbuffer (target, attachment, renderbuffertarget, renderbuffer); } - inline void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + inline void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) const { ::glFramebufferTexture2D (target, attachment, textarget, texture, level); } - inline void glGenerateMipmap (GLenum target) + inline void glGenerateMipmap (GLenum target) const { ::glGenerateMipmap (target); } - inline void glGenFramebuffers (GLsizei n, GLuint *framebuffers) + inline void glGenFramebuffers (GLsizei n, GLuint *framebuffers) const { ::glGenFramebuffers (n, framebuffers); } - inline void glGenRenderbuffers (GLsizei n, GLuint *renderbuffers) + inline void glGenRenderbuffers (GLsizei n, GLuint *renderbuffers) const { ::glGenRenderbuffers (n, renderbuffers); } - inline void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name) + inline void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name) const { ::glGetActiveAttrib (program, index, bufSize, length, size, type, name); } - inline void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name) + inline void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint* size, GLenum *type, GLchar *name) const { ::glGetActiveUniform (program, index, bufSize, length, size, type, name); } - inline void glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) + inline void glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders) const { ::glGetAttachedShaders (program, maxCount, count, shaders); } - inline GLint glGetAttribLocation (GLuint program, const GLchar *name) + inline GLint glGetAttribLocation (GLuint program, const GLchar *name) const { return ::glGetAttribLocation (program, name); } - inline void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params) + inline void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params) const { ::glGetFramebufferAttachmentParameteriv (target, attachment, pname, params); } - inline void glGetProgramiv (GLuint program, GLenum pname, GLint* params) + inline void glGetProgramiv (GLuint program, GLenum pname, GLint* params) const { ::glGetProgramiv (program, pname, params); } - inline void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) + inline void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) const { ::glGetProgramInfoLog (program, bufSize, length, infoLog); } - inline void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params) + inline void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params) const { ::glGetRenderbufferParameteriv (target, pname, params); } - inline void glGetShaderiv (GLuint shader, GLenum pname, GLint* params) + inline void glGetShaderiv (GLuint shader, GLenum pname, GLint* params) const { ::glGetShaderiv (shader, pname, params); } - inline void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) + inline void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) const { ::glGetShaderInfoLog (shader, bufSize, length, infoLog); } - inline void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) + inline void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) const { ::glGetShaderPrecisionFormat (shadertype, precisiontype, range, precision); } - inline void glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) + inline void glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) const { ::glGetShaderSource (shader, bufSize, length, source); } - inline void glGetUniformfv (GLuint program, GLint location, GLfloat* params) + inline void glGetUniformfv (GLuint program, GLint location, GLfloat* params) const { ::glGetUniformfv (program, location, params); } - inline void glGetUniformiv (GLuint program, GLint location, GLint* params) + inline void glGetUniformiv (GLuint program, GLint location, GLint* params) const { ::glGetUniformiv (program, location, params); } - GLint glGetUniformLocation (GLuint program, const GLchar *name) + GLint glGetUniformLocation (GLuint program, const GLchar *name) const { return ::glGetUniformLocation (program, name); } - inline void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params) + inline void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params) const { ::glGetVertexAttribfv (index, pname, params); } - inline void glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params) + inline void glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params) const { ::glGetVertexAttribiv (index, pname, params); } - inline void glGetVertexAttribPointerv (GLuint index, GLenum pname, void* *pointer) + inline void glGetVertexAttribPointerv (GLuint index, GLenum pname, void* *pointer) const { ::glGetVertexAttribPointerv (index, pname, pointer); } - inline GLboolean glIsFramebuffer (GLuint framebuffer) + inline GLboolean glIsFramebuffer (GLuint framebuffer) const { return ::glIsFramebuffer (framebuffer); } - inline GLboolean glIsProgram (GLuint program) + inline GLboolean glIsProgram (GLuint program) const { return ::glIsProgram (program); } - inline GLboolean glIsRenderbuffer (GLuint renderbuffer) + inline GLboolean glIsRenderbuffer (GLuint renderbuffer) const { return ::glIsRenderbuffer (renderbuffer); } - inline GLboolean glIsShader (GLuint shader) + inline GLboolean glIsShader (GLuint shader) const { return ::glIsShader (shader); } - inline void glLinkProgram (GLuint program) + inline void glLinkProgram (GLuint program) const { ::glLinkProgram (program); } - inline void glReleaseShaderCompiler() + inline void glReleaseShaderCompiler() const { ::glReleaseShaderCompiler(); } - inline void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) + inline void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) const { ::glRenderbufferStorage (target, internalformat, width, height); } - inline void glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void* binary, GLsizei length) + inline void glShaderBinary (GLsizei count, const GLuint *shaders, GLenum binaryformat, const void* binary, GLsizei length) const { ::glShaderBinary (count, shaders, binaryformat, binary, length); } - inline void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length) + inline void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length) const { ::glShaderSource (shader, count, string, length); } - inline void glUniform1f (GLint location, GLfloat v0) + inline void glUniform1f (GLint location, GLfloat v0) const { ::glUniform1f (location, v0); } - inline void glUniform1fv (GLint location, GLsizei count, const GLfloat* value) + inline void glUniform1fv (GLint location, GLsizei count, const GLfloat* value) const { ::glUniform1fv (location, count, value); } - inline void glUniform1i (GLint location, GLint v0) + inline void glUniform1i (GLint location, GLint v0) const { ::glUniform1i (location, v0); } - inline void glUniform1iv (GLint location, GLsizei count, const GLint* value) + inline void glUniform1iv (GLint location, GLsizei count, const GLint* value) const { ::glUniform1iv (location, count, value); } - inline void glUniform2f (GLint location, GLfloat v0, GLfloat v1) + inline void glUniform2f (GLint location, GLfloat v0, GLfloat v1) const { ::glUniform2f (location, v0, v1); } - inline void glUniform2fv (GLint location, GLsizei count, const GLfloat* value) + inline void glUniform2fv (GLint location, GLsizei count, const GLfloat* value) const { ::glUniform2fv (location, count, value); } - inline void glUniform2i (GLint location, GLint v0, GLint v1) + inline void glUniform2i (GLint location, GLint v0, GLint v1) const { ::glUniform2i (location, v0, v1); } - inline void glUniform2iv (GLint location, GLsizei count, const GLint* value) + inline void glUniform2iv (GLint location, GLsizei count, const GLint* value) const { ::glUniform2iv (location, count, value); } - inline void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) + inline void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) const { ::glUniform3f (location, v0, v1, v2); } - inline void glUniform3fv (GLint location, GLsizei count, const GLfloat* value) + inline void glUniform3fv (GLint location, GLsizei count, const GLfloat* value) const { ::glUniform3fv (location, count, value); } - inline void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2) + inline void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2) const { ::glUniform3i (location, v0, v1, v2); } - inline void glUniform3iv (GLint location, GLsizei count, const GLint* value) + inline void glUniform3iv (GLint location, GLsizei count, const GLint* value) const { ::glUniform3iv (location, count, value); } - inline void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) + inline void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) const { ::glUniform4f (location, v0, v1, v2, v3); } - inline void glUniform4fv (GLint location, GLsizei count, const GLfloat* value) + inline void glUniform4fv (GLint location, GLsizei count, const GLfloat* value) const { ::glUniform4fv (location, count, value); } - inline void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) + inline void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) const { ::glUniform4i (location, v0, v1, v2, v3); } - inline void glUniform4iv (GLint location, GLsizei count, const GLint* value) + inline void glUniform4iv (GLint location, GLsizei count, const GLint* value) const { ::glUniform4iv (location, count, value); } - inline void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) + inline void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) const { ::glUniformMatrix2fv (location, count, transpose, value); } - inline void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) + inline void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) const { ::glUniformMatrix3fv (location, count, transpose, value); } - inline void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) + inline void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) const { ::glUniformMatrix4fv (location, count, transpose, value); } - inline void glUseProgram (GLuint program) + inline void glUseProgram (GLuint program) const { ::glUseProgram (program); } - inline void glValidateProgram (GLuint program) + inline void glValidateProgram (GLuint program) const { ::glValidateProgram (program); } - inline void glVertexAttrib1f (GLuint index, GLfloat x) + inline void glVertexAttrib1f (GLuint index, GLfloat x) const { ::glVertexAttrib1f (index, x); } - inline void glVertexAttrib1fv (GLuint index, const GLfloat* v) + inline void glVertexAttrib1fv (GLuint index, const GLfloat* v) const { ::glVertexAttrib1fv (index, v); } - inline void glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y) + inline void glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y) const { ::glVertexAttrib2f (index, x, y); } - inline void glVertexAttrib2fv (GLuint index, const GLfloat* v) + inline void glVertexAttrib2fv (GLuint index, const GLfloat* v) const { ::glVertexAttrib2fv (index, v); } - inline void glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z) + inline void glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z) const { ::glVertexAttrib3f (index, x, y, z); } - inline void glVertexAttrib3fv (GLuint index, const GLfloat* v) + inline void glVertexAttrib3fv (GLuint index, const GLfloat* v) const { ::glVertexAttrib3fv (index, v); } - inline void glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) + inline void glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) const { ::glVertexAttrib4f (index, x, y, z, w); } - inline void glVertexAttrib4fv (GLuint index, const GLfloat* v) + inline void glVertexAttrib4fv (GLuint index, const GLfloat* v) const { ::glVertexAttrib4fv (index, v); } - inline void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) + inline void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer) const { ::glVertexAttribPointer (index, size, type, normalized, stride, pointer); } diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx index 38f04754dc..2b8cb2f437 100644 --- a/src/OpenGl/OpenGl_PrimitiveArray.cxx +++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx @@ -1020,7 +1020,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace { if (const Handle(OpenGl_Texture)& aFirstTexture = aTextureSet->First()) { - aCtx->SetTextureMatrix (aFirstTexture->Sampler()->Parameters()); + aCtx->SetTextureMatrix (aFirstTexture->Sampler()->Parameters(), aFirstTexture->IsTopDown()); } } aCtx->SetSampleAlphaToCoverage (aCtx->ShaderManager()->MaterialState().HasAlphaCutoff()); diff --git a/src/OpenGl/OpenGl_Sampler.cxx b/src/OpenGl/OpenGl_Sampler.cxx index 6e7bb10de6..3ec1e07723 100644 --- a/src/OpenGl/OpenGl_Sampler.cxx +++ b/src/OpenGl/OpenGl_Sampler.cxx @@ -105,7 +105,7 @@ Standard_Boolean OpenGl_Sampler::Init (const Handle(OpenGl_Context)& theCtx, } else if (!myIsImmutable) { - applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.HasMipmaps()); + applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.MaxMipmapLevel()); return Standard_True; } Release (theCtx.get()); @@ -116,7 +116,7 @@ Standard_Boolean OpenGl_Sampler::Init (const Handle(OpenGl_Context)& theCtx, return Standard_False; } - applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.HasMipmaps()); + applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.MaxMipmapLevel()); return Standard_True; } @@ -187,7 +187,7 @@ void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx, const Handle(Graphic3d_TextureParams)& theParams, OpenGl_Sampler* theSampler, const GLenum theTarget, - const bool theHasMipMaps) + const Standard_Integer theMaxMipLevels) { if (theSampler != NULL && theSampler->Parameters() == theParams) { @@ -197,7 +197,7 @@ void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx, // setup texture filtering const GLenum aFilter = (theParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR; GLenum aFilterMin = aFilter; - if (theHasMipMaps) + if (theMaxMipLevels > 0) { aFilterMin = GL_NEAREST_MIPMAP_NEAREST; if (theParams->Filter() == Graphic3d_TOTF_BILINEAR) @@ -266,8 +266,9 @@ void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx, if (theCtx->HasTextureBaseLevel() && (theSampler == NULL || !theSampler->isValidSampler())) { + const Standard_Integer aMaxLevel = Min (theMaxMipLevels, theParams->MaxLevel()); setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_BASE_LEVEL, theParams->BaseLevel()); - setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_LEVEL, theParams->MaxLevel()); + setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_LEVEL, aMaxLevel); } } diff --git a/src/OpenGl/OpenGl_Sampler.hxx b/src/OpenGl/OpenGl_Sampler.hxx index bb742351f2..8a2b91e08e 100644 --- a/src/OpenGl/OpenGl_Sampler.hxx +++ b/src/OpenGl/OpenGl_Sampler.hxx @@ -129,13 +129,17 @@ protected: GLint theValue); //! Apply sampler parameters. - //! If Sampler Object is not NULL and valid resource, the parameters will be set to it (and it is not required Sampler Object being bound). - //! Otherwise, parameters will be applied to currently bound Texture object. + //! @param theCtx [in] active OpenGL context + //! @param theParams [in] texture parameters to apply + //! @param theSampler [in] apply parameters to Texture object (NULL) + //! or to specified Sampler object (non-NULL, sampler is not required to be bound) + //! @param theTarget [in] OpenGL texture target + //! @param theMaxMipLevel [in] maximum mipmap level defined within the texture Standard_EXPORT static void applySamplerParams (const Handle(OpenGl_Context)& theCtx, const Handle(Graphic3d_TextureParams)& theParams, OpenGl_Sampler* theSampler, const GLenum theTarget, - const bool theHasMipMaps); + const Standard_Integer theMaxMipLevel); //! Apply global texture state for deprecated OpenGL functionality. Standard_EXPORT static void applyGlobalTextureParams (const Handle(OpenGl_Context)& theCtx, diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index 651ceed61c..06e352b1be 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -58,10 +58,9 @@ namespace const char THE_VARY_TexCoord_Trsf[] = EOL" float aRotSin = occTextureTrsf_RotationSin();" EOL" float aRotCos = occTextureTrsf_RotationCos();" - EOL" vec2 aTex2 = (occTexCoord.xy + occTextureTrsf_Translation()) * occTextureTrsf_Scale();" - EOL" vec2 aCopy = aTex2;" - EOL" aTex2.x = aCopy.x * aRotCos - aCopy.y * aRotSin;" - EOL" aTex2.y = aCopy.x * aRotSin + aCopy.y * aRotCos;" + EOL" vec2 aTex2 = vec2 (occTexCoord.x * aRotCos - occTexCoord.y * aRotSin," + EOL" occTexCoord.x * aRotSin + occTexCoord.y * aRotCos);" + EOL" aTex2 = (aTex2 + occTextureTrsf_Translation()) * occTextureTrsf_Scale();" EOL" TexCoord = vec4(aTex2, occTexCoord.zw);"; //! Auxiliary function to flip gl_PointCoord vertically diff --git a/src/OpenGl/OpenGl_Texture.cxx b/src/OpenGl/OpenGl_Texture.cxx index aa01fac17b..383e7f5ef0 100644 --- a/src/OpenGl/OpenGl_Texture.cxx +++ b/src/OpenGl/OpenGl_Texture.cxx @@ -21,10 +21,15 @@ #include #include #include +#include #include +#include IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource) +namespace +{ + //! Simple class to reset unpack alignment settings struct OpenGl_UnpackAlignmentSentry { @@ -47,6 +52,43 @@ struct OpenGl_UnpackAlignmentSentry }; +//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level). +static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize) +{ + for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2) + { + if (theSize <= 1) + { + return aMipIter; + } + } +} + +//! 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) +{ + return computeUpperMipMapLevel (Max (theSizeX, theSizeY)); +} + +//! Compute size of the smallest defined mipmap level (for verbose messages). +static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel) +{ + 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 : OpenGl_Texture // purpose : @@ -64,8 +106,9 @@ OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId, myTextFormat (GL_RGBA), mySizedFormat(GL_RGBA8), myNbSamples (1), - myHasMipmaps (Standard_False), - myIsAlpha (false) + myMaxMipLevel(0), + myIsAlpha (false), + myIsTopDown (true) { // } @@ -130,10 +173,10 @@ void OpenGl_Texture::Release (OpenGl_Context* theGlCtx) // ======================================================================= void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx) { - OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myHasMipmaps); + OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel); if (mySampler->IsValid() && !mySampler->IsImmutable()) { - OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myHasMipmaps); + OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel); } } @@ -203,11 +246,10 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, #else const GLenum aTarget = GL_TEXTURE_2D; #endif - const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP); const bool toPatchExisting = IsValid() && myTextFormat == theFormat.PixelFormat() && myTarget == aTarget - && myHasMipmaps == toCreateMipMaps + && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP) && mySizeX == theSizeXY.x() && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D); if (!Create (theCtx)) @@ -220,16 +262,19 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, { myIsAlpha = theImage->Format() == Image_Format_Alpha || theImage->Format() == Image_Format_AlphaF; + myIsTopDown = theImage->IsTopDown(); } else { myIsAlpha = theFormat.PixelFormat() == GL_ALPHA; } - myHasMipmaps = toCreateMipMaps; - myTextFormat = theFormat.PixelFormat(); - mySizedFormat = theFormat.InternalFormat(); - myNbSamples = 1; + 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 @@ -294,8 +339,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, #endif #if !defined(GL_ES_VERSION_2_0) - GLint aTestWidth = 0; - GLint aTestHeight = 0; + GLint aTestWidth = 0, aTestHeight = 0; #endif GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL; @@ -369,58 +413,6 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, #endif } case Graphic3d_TOT_2D: - { - Bind (theCtx); - applyDefaultSamplerParams (theCtx); - if (toPatchExisting) - { - glTexSubImage2D (GL_TEXTURE_2D, 0, - 0, 0, - theSizeXY.x(), theSizeXY.y(), - theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); - 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, 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, anIntFormat, - theSizeXY.x(), theSizeXY.y(), 0, - theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); - 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 ("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 = theSizeXY.x(); - mySizeY = theSizeXY.y(); - - Unbind (theCtx); - return true; - } case Graphic3d_TOT_2D_MIPMAP: { Bind (theCtx); @@ -431,15 +423,14 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, 0, 0, theSizeXY.x(), theSizeXY.y(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); - if (theCtx->arbFBO != NULL) + + if (myMaxMipLevel > 0) { // generate mipmaps theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D); if (glGetError() != GL_NO_ERROR) { - Unbind (theCtx); - Release (theCtx.get()); - return false; + myMaxMipLevel = 0; } } @@ -464,18 +455,17 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, } #endif - // upload main picture glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat, theSizeXY.x(), theSizeXY.y(), 0, - theFormat.PixelFormat(), theFormat.DataType(), theImage->Data()); - const GLenum aTexImgErr = glGetError(); - if (aTexImgErr != GL_NO_ERROR) + 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(aTexImgErr) + "."); + + " 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; @@ -484,27 +474,19 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, mySizeX = theSizeXY.x(); mySizeY = theSizeXY.y(); - if (theCtx->arbFBO != NULL) + if (myMaxMipLevel > 0) { // generate mipmaps //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST); theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D); - - if (glGetError() != GL_NO_ERROR) + anErr = glGetError(); + if (anErr != GL_NO_ERROR) { - Unbind (theCtx); - Release (theCtx.get()); - return false; + 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."); } } - else - { - 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); - Release (theCtx.get()); - return false; - } Unbind (theCtx); return true; @@ -568,7 +550,16 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, } default: { - Handle(Image_PixMap) anImage = theTextureMap->GetImage(); + if (theCtx->SupportedTextureFormats()->HasCompressed() + && !theCtx->caps->compressedTexturesDisable) + { + if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats())) + { + return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap()); + } + } + + Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats()); if (anImage.IsNull()) { return false; @@ -578,6 +569,106 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, } } +// ======================================================================= +// 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 : @@ -597,7 +688,7 @@ bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx, myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples()); myTarget = GL_TEXTURE_2D_MULTISAMPLE; - myHasMipmaps = false; + myMaxMipLevel = 0; if(theSizeX > theCtx->MaxTextureSize() || theSizeY > theCtx->MaxTextureSize()) { @@ -649,7 +740,7 @@ bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx, #if !defined(GL_ES_VERSION_2_0) myTarget = GL_TEXTURE_RECTANGLE; myNbSamples = 1; - myHasMipmaps = false; + myMaxMipLevel = 0; const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX); const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY); @@ -726,7 +817,7 @@ bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx, myTarget = GL_TEXTURE_3D; myNbSamples = 1; - myHasMipmaps = false; + myMaxMipLevel = 0; const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize())); if (aSizeXYZ != theSizeXYZ) @@ -809,24 +900,80 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx, return false; } + Handle(Image_PixMap) anImage; + Handle(Image_CompressedPixMap) aCompImage; + OpenGl_TextureFormat aFormat; if (!theCubeMap.IsNull()) { - theToGenMipmap = theCubeMap->HasMipmaps(); - if (Handle(Image_PixMap) anImage = theCubeMap->Reset().Value()) + 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()) + { + 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()); + } + } + + OpenGl_UnpackAlignmentSentry::Reset(); + } + else + { + aCompImage.Nullify(); + } + } + + 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; + } + theSize = anImage->SizeX(); theFormat = anImage->Format(); + theToGenMipmap = theCubeMap->HasMipmaps(); + myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0; } - else - { - 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; - } + + myIsTopDown = theCubeMap->IsTopDown(); + } + else + { + myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0; } - OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap); + if (!aFormat.IsValid()) + { + aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap); + } if (!aFormat.IsValid()) { Unbind(theCtx); @@ -835,21 +982,62 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx, } myTarget = GL_TEXTURE_CUBE_MAP; - myHasMipmaps = theToGenMipmap; myNbSamples = 1; mySizeX = (GLsizei )theSize; mySizeY = (GLsizei )theSize; + myTextFormat = aFormat.Format(); + mySizedFormat = aFormat.Internal(); Bind (theCtx); applyDefaultSamplerParams (theCtx); for (Standard_Integer i = 0; i < 6; ++i) { - const void* aData = NULL; - Handle(Image_PixMap) anImage; + const Standard_Byte* aData = NULL; if (!theCubeMap.IsNull()) { - anImage = theCubeMap->Value(); + if (i != 0) + { + if (!aCompImage.IsNull()) + { + aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats()); + } + else + { + anImage = theCubeMap->Value (theCtx->SupportedTextureFormats()); + } + } + if (!aCompImage.IsNull()) + { + Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY); + aData = aCompImage->FaceData()->Data(); + for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter) + { + 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) @@ -970,8 +1158,18 @@ Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theIntern 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 0; + return 1; } // ======================================================================= @@ -998,7 +1196,7 @@ Standard_Size OpenGl_Texture::EstimatedDataSize() const { aSize *= 6; // cube sides } - if (myHasMipmaps) + if (myMaxMipLevel > 0) { aSize = aSize + aSize / 3; } diff --git a/src/OpenGl/OpenGl_Texture.hxx b/src/OpenGl/OpenGl_Texture.hxx index e7ffd82ea4..8fe1db94ab 100644 --- a/src/OpenGl/OpenGl_Texture.hxx +++ b/src/OpenGl/OpenGl_Texture.hxx @@ -72,10 +72,17 @@ public: //! Return true for GL_RED and GL_ALPHA formats. bool IsAlpha() const { return myIsAlpha; } - //! Setup to interprete the format as Alpha by Shader Manager + //! Setup to interpret the format as Alpha by Shader Manager //! (should be GL_ALPHA within compatible context or GL_RED otherwise). void SetAlpha (const bool theValue) { myIsAlpha = theValue; } + //! Return if 2D surface is defined top-down (TRUE) or bottom-up (FALSE). + //! Normally set from Image_PixMap::IsTopDown() within texture initialization. + bool IsTopDown() const { return myIsTopDown; } + + //! Set if 2D surface is defined top-down (TRUE) or bottom-up (FALSE). + void SetTopDown (bool theIsTopDown) { myIsTopDown = theIsTopDown; } + //! Creates Texture id if not yet generated. //! Data should be initialized by another method. Standard_EXPORT bool Create (const Handle(OpenGl_Context)& theCtx); @@ -144,6 +151,11 @@ public: Standard_EXPORT bool Init (const Handle(OpenGl_Context)& theCtx, const Handle(Graphic3d_TextureMap)& theTextureMap); + //! Initialize the texture with Image_CompressedPixMap. + Standard_EXPORT bool InitCompressed (const Handle(OpenGl_Context)& theCtx, + const Image_CompressedPixMap& theImage, + const Standard_Boolean theIsColorMap); + //! Initialize the 2D multisampling texture using glTexImage2DMultisample(). Standard_EXPORT bool Init2DMultisample (const Handle(OpenGl_Context)& theCtx, const GLsizei theNbSamples, @@ -165,7 +177,10 @@ public: const void* thePixels); //! @return true if texture was generated within mipmaps - Standard_Boolean HasMipmaps() const { return myHasMipmaps; } + Standard_Boolean HasMipmaps() const { return myMaxMipLevel > 0; } + + //! Return upper mipmap level index (0 means no mipmaps). + Standard_Integer MaxMipmapLevel() const { return myMaxMipLevel; } //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules. Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE; @@ -278,8 +293,9 @@ protected: GLenum myTextFormat; //!< texture format - GL_RGB, GL_RGBA,... GLint mySizedFormat;//!< internal (sized) texture format Standard_Integer myNbSamples; //!< number of MSAA samples - Standard_Boolean myHasMipmaps; //!< flag indicates that texture was uploaded with mipmaps + Standard_Integer myMaxMipLevel;//!< upper mipmap level index (0 means no mipmaps) bool myIsAlpha; //!< indicates alpha format + bool myIsTopDown; //!< indicates if 2D surface is defined top-down (TRUE) or bottom-up (FALSE) }; diff --git a/src/OpenGl/OpenGl_TextureFormat.cxx b/src/OpenGl/OpenGl_TextureFormat.cxx index 30c70189a4..19d4002818 100644 --- a/src/OpenGl/OpenGl_TextureFormat.cxx +++ b/src/OpenGl/OpenGl_TextureFormat.cxx @@ -13,6 +13,7 @@ #include +#include #include // ======================================================================= @@ -157,7 +158,7 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindFormat (const Handle(OpenGl_Conte return OpenGl_TextureFormat(); } aFormat.SetNbComponents (4); - aFormat.SetInternalFormat (GL_BGRA_EXT); + aFormat.SetInternalFormat (GL_BGRA_EXT); #endif aFormat.SetPixelFormat (GL_BGRA_EXT); // equals to GL_BGRA aFormat.SetDataType (GL_UNSIGNED_BYTE); @@ -449,3 +450,79 @@ OpenGl_TextureFormat OpenGl_TextureFormat::FindSizedFormat (const Handle(OpenGl_ } return aFormat; } + +// ======================================================================= +// function : FindCompressedFormat +// purpose : +// ======================================================================= +OpenGl_TextureFormat OpenGl_TextureFormat::FindCompressedFormat (const Handle(OpenGl_Context)& theCtx, + Image_CompressedFormat theFormat, + bool theIsColorMap) +{ + OpenGl_TextureFormat aFormat; + if (!theCtx->SupportedTextureFormats()->IsSupported (theFormat)) + { + return aFormat; + } + + switch (theFormat) + { + case Image_CompressedFormat_UNKNOWN: + { + return aFormat; + } + case Image_CompressedFormat_RGB_S3TC_DXT1: + { + aFormat.SetNbComponents (3); + aFormat.SetPixelFormat (GL_RGB); + aFormat.SetDataType (GL_UNSIGNED_BYTE); + aFormat.SetInternalFormat (GL_COMPRESSED_RGB_S3TC_DXT1_EXT); + if (theIsColorMap + && theCtx->ToRenderSRGB()) + { + aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_S3TC_DXT1_EXT); + } + return aFormat; + } + case Image_CompressedFormat_RGBA_S3TC_DXT1: + { + aFormat.SetNbComponents (4); + aFormat.SetPixelFormat (GL_RGBA); + aFormat.SetDataType (GL_UNSIGNED_BYTE); + aFormat.SetInternalFormat (GL_COMPRESSED_RGBA_S3TC_DXT1_EXT); + if (theIsColorMap + && theCtx->ToRenderSRGB()) + { + aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT); + } + return aFormat; + } + case Image_CompressedFormat_RGBA_S3TC_DXT3: + { + aFormat.SetNbComponents (4); + aFormat.SetPixelFormat (GL_RGBA); + aFormat.SetDataType (GL_UNSIGNED_BYTE); + aFormat.SetInternalFormat (GL_COMPRESSED_RGBA_S3TC_DXT3_EXT); + if (theIsColorMap + && theCtx->ToRenderSRGB()) + { + aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT); + } + return aFormat; + } + case Image_CompressedFormat_RGBA_S3TC_DXT5: + { + aFormat.SetNbComponents (4); + aFormat.SetPixelFormat (GL_RGBA); + aFormat.SetDataType (GL_UNSIGNED_BYTE); + aFormat.SetInternalFormat (GL_COMPRESSED_RGBA_S3TC_DXT5_EXT); + if (theIsColorMap + && theCtx->ToRenderSRGB()) + { + aFormat.SetInternalFormat (GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT); + } + return aFormat; + } + } + return aFormat; +} diff --git a/src/OpenGl/OpenGl_TextureFormat.hxx b/src/OpenGl/OpenGl_TextureFormat.hxx index 244f641fb7..bb4eb69f3e 100644 --- a/src/OpenGl/OpenGl_TextureFormat.hxx +++ b/src/OpenGl/OpenGl_TextureFormat.hxx @@ -14,6 +14,7 @@ #ifndef _OpenGl_TextureFormat_HeaderFile #define _OpenGl_TextureFormat_HeaderFile +#include #include #include #include @@ -47,6 +48,14 @@ public: Standard_EXPORT static OpenGl_TextureFormat FindSizedFormat (const Handle(OpenGl_Context)& theCtx, GLint theSizedFormat); + //! Find texture format suitable to specified compressed texture format. + //! @param theCtx [in] OpenGL context defining supported texture formats + //! @param theFormat [in] compressed texture format + //! @return found format or invalid format + Standard_EXPORT static OpenGl_TextureFormat FindCompressedFormat (const Handle(OpenGl_Context)& theCtx, + Image_CompressedFormat theFormat, + bool theIsColorMap); + public: //! Empty constructor (invalid texture format). diff --git a/src/OpenGl/OpenGl_View.cxx b/src/OpenGl/OpenGl_View.cxx index ac79137b82..c6c3e97b75 100644 --- a/src/OpenGl/OpenGl_View.cxx +++ b/src/OpenGl/OpenGl_View.cxx @@ -282,7 +282,7 @@ void OpenGl_View::initTextureEnv (const Handle(OpenGl_Context)& theContext) } Handle(OpenGl_Texture) aTextureEnv = new OpenGl_Texture (myTextureEnvData->GetId(), myTextureEnvData->GetParams()); - if (Handle(Image_PixMap) anImage = myTextureEnvData->GetImage()) + if (Handle(Image_PixMap) anImage = myTextureEnvData->GetImage (theContext->SupportedTextureFormats())) { aTextureEnv->Init (theContext, *anImage, myTextureEnvData->Type(), true); } diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index dcc828f15e..6e924399a7 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -6808,6 +6808,7 @@ static int VCaps (Draw_Interpretor& theDI, theDI << "WinBuffer: " << (aCaps->useSystemBuffer ? "1" : "0") << "\n"; theDI << "NoExt:" << (aCaps->contextNoExtensions ? "1" : "0") << "\n"; theDI << "MaxVersion:" << aCaps->contextMajorVersionUpper << "." << aCaps->contextMinorVersionUpper << "\n"; + theDI << "CompressTextures: " << (aCaps->compressedTexturesDisable ? "0" : "1") << "\n"; return 0; } @@ -6862,6 +6863,16 @@ static int VCaps (Draw_Interpretor& theDI, } aCaps->sRGBDisable = !toEnable; } + else if (anArgCase == "-compressedtextures") + { + Standard_Boolean toEnable = Standard_True; + if (++anArgIter < theArgNb + && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable)) + { + --anArgIter; + } + aCaps->compressedTexturesDisable = !toEnable; + } else if (anArgCase == "-vbo") { Standard_Boolean toEnable = Standard_True; @@ -14374,7 +14385,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) __FILE__, VStereo, group); theCommands.Add ("vcaps", "vcaps [-sRGB {0|1}] [-vbo {0|1}] [-sprites {0|1}] [-ffp {0|1}] [-polygonMode {0|1}]" - "\n\t\t: [-compatibleProfile {0|1}]" + "\n\t\t: [-compatibleProfile {0|1}] [-compressedTextures {0|1}]" "\n\t\t: [-vsync {0|1}] [-useWinBuffer {0|1}]" "\n\t\t: [-quadBuffer {0|1}] [-stereo {0|1}]" "\n\t\t: [-softMode {0|1}] [-noupdate|-update]" @@ -14385,6 +14396,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\n\t\t: built-in GLSL programs" "\n\t\t: (requires compatible profile)" "\n\t\t: polygonMode - use Polygon Mode instead of built-in GLSL programs" + "\n\t\t: compressedTexture - allow uploading of GPU-supported compressed texture formats" "\n\t\t: VBO - use Vertex Buffer Object (copy vertex" "\n\t\t: arrays to GPU memory)" "\n\t\t: sprite - use textured sprites instead of bitmaps" diff --git a/src/XCAFPrs/XCAFPrs_Texture.cxx b/src/XCAFPrs/XCAFPrs_Texture.cxx index 798cbab366..3c5519cadc 100644 --- a/src/XCAFPrs/XCAFPrs_Texture.cxx +++ b/src/XCAFPrs/XCAFPrs_Texture.cxx @@ -35,11 +35,22 @@ XCAFPrs_Texture::XCAFPrs_Texture (const Image_Texture& theImageSource, || theUnit == Graphic3d_TextureUnit_Emissive; } +//======================================================================= +//function : GetCompressedImage +//purpose : +//======================================================================= +Handle(Image_CompressedPixMap) XCAFPrs_Texture::GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported) +{ + return myImageSource.ReadCompressedImage (theSupported); +} + //======================================================================= //function : GetImage //purpose : //======================================================================= -Handle(Image_PixMap) XCAFPrs_Texture::GetImage() const +Handle(Image_PixMap) XCAFPrs_Texture::GetImage (const Handle(Image_SupportedFormats)& theSupported) { - return myImageSource.ReadImage(); + Handle(Image_PixMap) anImage = myImageSource.ReadImage (theSupported); + convertToCompatible (theSupported, anImage); + return anImage; } diff --git a/src/XCAFPrs/XCAFPrs_Texture.hxx b/src/XCAFPrs/XCAFPrs_Texture.hxx index ff8efa806d..f950139efd 100644 --- a/src/XCAFPrs/XCAFPrs_Texture.hxx +++ b/src/XCAFPrs/XCAFPrs_Texture.hxx @@ -31,7 +31,10 @@ public: const Graphic3d_TextureUnit theUnit); //! Image reader. - Standard_EXPORT virtual Handle(Image_PixMap) GetImage() const Standard_OVERRIDE; + Standard_EXPORT virtual Handle(Image_CompressedPixMap) GetCompressedImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; + + //! Image reader. + Standard_EXPORT virtual Handle(Image_PixMap) GetImage (const Handle(Image_SupportedFormats)& theSupported) Standard_OVERRIDE; //! Return image source. const Image_Texture& GetImageSource() const { return myImageSource; } diff --git a/tests/v3d/glsl/cubemap_dds b/tests/v3d/glsl/cubemap_dds new file mode 100644 index 0000000000..9f701fd095 --- /dev/null +++ b/tests/v3d/glsl/cubemap_dds @@ -0,0 +1,25 @@ +puts "============" +puts "0031478: Visualization, TKOpenGl - allow uploading Cubemap in compressed DDS format when supported by GPU" +puts "============" +puts "" + +set aCubeMapPNG [locate_data_file cubemap_labels.png] +set aCubeMapDDS [locate_data_file cubemap_labels.dds] + +box b 1 2 3 +psphere s 1 + +vclear +vinit View1 -w 512 -h 512 +vcamera -fovy 100 +vzbufftrihedron +#vdisplay -dispMode 1 b +vdisplay -dispMode 1 s +vfit + +vrenderparams -shadingModel pbr +vbackground -cubemap $aCubeMapPNG -invertedz +vdump $imagedir/${casename}_png.png + +vbackground -cubemap $aCubeMapDDS -invertedz +vdump $imagedir/${casename}_dds.png diff --git a/tests/v3d/glsl/texture_trsf2 b/tests/v3d/glsl/texture_trsf2 index a5c6027879..18aab8728d 100644 --- a/tests/v3d/glsl/texture_trsf2 +++ b/tests/v3d/glsl/texture_trsf2 @@ -28,12 +28,15 @@ for { set aPass 0 } { $aPass < 2 } { incr aPass } { vtexture b_6 $aTexture -modulate off vdump $::imagedir/${::casename}_identity_${aSuffix}.png - vtexture b_6 $aTexture -trsfTranslate 0.0 0.0 -trsfScale 0.8 2.0 + vtexture b_6 $aTexture -trsfTranslate 0.0 0.0 -trsfScale 0.8 2.0 -trsfAngle 0 vdump $::imagedir/${::casename}_scale_${aSuffix}.png - vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.0 1.0 + vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.0 1.0 -trsfAngle 0 vdump $::imagedir/${::casename}_translate_${aSuffix}.png - vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.1 0.8 + vtexture b_6 $aTexture -trsfTranslate 0.0 0.1 -trsfScale 1 1.1 -trsfAngle 30 + vdump $::imagedir/${::casename}_rotate_${aSuffix}.png + + vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.1 0.8 -trsfAngle 0 vdump $::imagedir/${::casename}_${aSuffix}.png } diff --git a/tests/v3d/glsl/texture_trsf3 b/tests/v3d/glsl/texture_trsf3 new file mode 100644 index 0000000000..b719cce32f --- /dev/null +++ b/tests/v3d/glsl/texture_trsf3 @@ -0,0 +1,42 @@ +puts "========" +puts "Texture 2D transformation (presentation trsf) on DDS texture" +puts "========" + +set aTexture [locate_data_file bug31478_texture_trsf_ref_dxt3.dds] +pload MODELING VISUALIZATION +box b 1 1 1 +explode b F + +for { set aPass 0 } { $aPass < 2 } { incr aPass } { + vclear + vclose ALL + + set aSuffix "" + if { $aPass == 0 } { + set aSuffix "ffp" + vcaps -ffp 1 + } else { + set aSuffix "glsl" + vcaps -ffp 0 + } + + vinit View1 w=512 h=512 + vtop + vdisplay -dispMode 1 b_6 + vfit + + vtexture b_6 $aTexture -modulate off + vdump $::imagedir/${::casename}_identity_${aSuffix}.png + + vtexture b_6 $aTexture -trsfTranslate 0.0 0.0 -trsfScale 0.8 2.0 -trsfAngle 0 + vdump $::imagedir/${::casename}_scale_${aSuffix}.png + + vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.0 1.0 -trsfAngle 0 + vdump $::imagedir/${::casename}_translate_${aSuffix}.png + + vtexture b_6 $aTexture -trsfTranslate 0.0 0.1 -trsfScale 1 1.1 -trsfAngle 30 + vdump $::imagedir/${::casename}_rotate_${aSuffix}.png + + vtexture b_6 $aTexture -trsfTranslate 0.25 -0.25 -trsfScale 1.1 0.8 -trsfAngle 0 + vdump $::imagedir/${::casename}_${aSuffix}.png +}