From 076ca35c3f902987294855b4e858eee503904100 Mon Sep 17 00:00:00 2001 From: kgv Date: Thu, 4 Dec 2014 15:31:31 +0300 Subject: [PATCH] 0025544: Visualization, TKOpenGl - support grayscale textures Image_PixMap::ImgFormat - extend enumeration by ImgAlpha and ImgAlphaF. OpenGl_Workspace::setTextureParams() - specify GL_REPLACE for 1-component textures with disabled modulation. OpenGl_Texture::GetDataFormat() - return GL_LUMINANCE format for ImgGray format and GL_ALPHA for ImgAlpha. vmarkerstest - override pixel format for grayscale images to ImgAlpha. Add test case bugs/vis/bug25544_graytexture. --- src/Font/Font_FTFont.cxx | 2 +- src/Graphic3d/Graphic3d_MarkerImage.cxx | 13 ++-- src/Image/Image_AlienPixMap.cxx | 5 +- src/Image/Image_PixMap.cxx | 45 +++++++++++--- src/Image/Image_PixMap.hxx | 17 ++--- src/OpenGl/OpenGl_AspectMarker.cxx | 6 +- src/OpenGl/OpenGl_Font.cxx | 2 +- src/OpenGl/OpenGl_GraphicDriver_7.cxx | 15 ++++- src/OpenGl/OpenGl_PointSprite.cxx | 1 + src/OpenGl/OpenGl_Texture.cxx | 65 +++++++++++++++++--- src/OpenGl/OpenGl_Workspace.cxx | 18 ++++-- src/ViewerTest/ViewerTest_ObjectCommands.cxx | 8 +++ tests/bugs/vis/bug25544_graytexture | 28 +++++++++ 13 files changed, 186 insertions(+), 39 deletions(-) create mode 100644 tests/bugs/vis/bug25544_graytexture diff --git a/src/Font/Font_FTFont.cxx b/src/Font/Font_FTFont.cxx index 213f6b6880..f4d203b12d 100755 --- a/src/Font/Font_FTFont.cxx +++ b/src/Font/Font_FTFont.cxx @@ -164,7 +164,7 @@ bool Font_FTFont::RenderGlyph (const Standard_Utf32Char theUChar) { return false; } - if (!myGlyphImg.InitWrapper (Image_PixMap::ImgGray, aBitmap.buffer, + if (!myGlyphImg.InitWrapper (Image_PixMap::ImgAlpha, aBitmap.buffer, aBitmap.width, aBitmap.rows, Abs (aBitmap.pitch))) { return false; diff --git a/src/Graphic3d/Graphic3d_MarkerImage.cxx b/src/Graphic3d/Graphic3d_MarkerImage.cxx index ceb1eacf0e..2236590bbc 100755 --- a/src/Graphic3d/Graphic3d_MarkerImage.cxx +++ b/src/Graphic3d/Graphic3d_MarkerImage.cxx @@ -98,7 +98,11 @@ Handle(TColStd_HArray1OfByte) Graphic3d_MarkerImage::GetBitMapArray (const Stand Quantity_Color aColor = myImage->PixelColor (aColumn, aRow, anAlphaValue); Standard_Boolean aBitOn = Standard_False; - if (myImage->Format() == Image_PixMap::ImgGray) + if (myImage->Format() == Image_PixMap::ImgAlpha) + { + aBitOn = anAlphaValue > theAlphaValue; + } + else if (myImage->Format() == Image_PixMap::ImgGray) { aBitOn = aColor.Red() > theAlphaValue; } @@ -142,7 +146,7 @@ const Handle(Image_PixMap)& Graphic3d_MarkerImage::GetImage() const Standard_Integer aLowerIndex = myBitMap->Lower(); myImage = new Image_PixMap(); - myImage->InitZero (Image_PixMap::ImgGray, aSize + myMargin * 2, aSize + myMargin * 2); + myImage->InitZero (Image_PixMap::ImgAlpha, aSize + myMargin * 2, aSize + myMargin * 2); for (Standard_Integer aRowIter = 0; aRowIter < myHeight; aRowIter++) { Standard_Byte* anImageRow = myImage->ChangeRow (aRowIter + aRowOffset); @@ -169,14 +173,15 @@ const Handle(Image_PixMap)& Graphic3d_MarkerImage::GetImageAlpha() if (!myImage.IsNull()) { - if (myImage->Format() == Image_PixMap::ImgGray) + if (myImage->Format() == Image_PixMap::ImgGray + || myImage->Format() == Image_PixMap::ImgAlpha) { myImageAlpha = myImage; } else { myImageAlpha = new Image_PixMap(); - myImageAlpha->InitZero (Image_PixMap::ImgGray, myImage->Width(), myImage->Height()); + myImageAlpha->InitZero (Image_PixMap::ImgAlpha, myImage->Width(), myImage->Height()); myImageAlpha->SetTopDown (Standard_False); Quantity_Parameter anAlpha; for (Standard_Size aRowIter = 0; aRowIter < myImage->Height(); aRowIter++) diff --git a/src/Image/Image_AlienPixMap.cxx b/src/Image/Image_AlienPixMap.cxx index a264254dd1..76a9a0eb72 100644 --- a/src/Image/Image_AlienPixMap.cxx +++ b/src/Image/Image_AlienPixMap.cxx @@ -78,6 +78,7 @@ namespace switch (theFormat) { case Image_PixMap::ImgGrayF: + case Image_PixMap::ImgAlphaF: return FIT_FLOAT; case Image_PixMap::ImgRGBAF: return FIT_RGBAF; @@ -90,6 +91,7 @@ namespace case Image_PixMap::ImgRGB: case Image_PixMap::ImgBGR: case Image_PixMap::ImgGray: + case Image_PixMap::ImgAlpha: return FIT_BITMAP; default: return FIT_UNKNOWN; @@ -448,7 +450,8 @@ bool Image_AlienPixMap::Save (const TCollection_AsciiString& theFileName) } case FIF_EXR: { - if (Format() == Image_PixMap::ImgGray) + if (Format() == Image_PixMap::ImgGray + || Format() == Image_PixMap::ImgAlpha) { anImageToDump = FreeImage_ConvertToType (myLibImage, FIT_FLOAT); } diff --git a/src/Image/Image_PixMap.cxx b/src/Image/Image_PixMap.cxx index 61cac86dad..0cb8815872 100644 --- a/src/Image/Image_PixMap.cxx +++ b/src/Image/Image_PixMap.cxx @@ -15,6 +15,7 @@ #include #include +#include #include @@ -48,6 +49,7 @@ Standard_Size Image_PixMap::SizePixelBytes (const Image_PixMap::ImgFormat thePix switch (thePixelFormat) { case ImgGrayF: + case ImgAlphaF: return sizeof(float); case ImgRGBAF: case ImgBGRAF: @@ -65,17 +67,32 @@ Standard_Size Image_PixMap::SizePixelBytes (const Image_PixMap::ImgFormat thePix case ImgBGR: return 3; case ImgGray: - default: + case ImgAlpha: + return 1; + case ImgUNKNOWN: return 1; } + return 1; } // ======================================================================= -// function : setFormat +// function : SetFormat // purpose : // ======================================================================= -void Image_PixMap::setFormat (Image_PixMap::ImgFormat thePixelFormat) +void Image_PixMap::SetFormat (Image_PixMap::ImgFormat thePixelFormat) { + if (myImgFormat == thePixelFormat) + { + return; + } + + if (!IsEmpty() + && SizePixelBytes (myImgFormat) != SizePixelBytes (thePixelFormat)) + { + Standard_ProgramError::Raise ("Image_PixMap::SetFormat() - incompatible pixel format"); + return; + } + myImgFormat = thePixelFormat; } @@ -201,6 +218,12 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX, Quantity_Parameter (Standard_Real (aPixel)), Quantity_TOC_RGB); } + case ImgAlphaF: + { + const Standard_ShortReal& aPixel = Value (theY, theX); + theAlpha = aPixel; + return Quantity_Color (1.0, 1.0, 1.0, Quantity_TOC_RGB); + } case ImgRGBAF: { const Image_ColorRGBAF& aPixel = Value (theY, theX); @@ -300,11 +323,19 @@ Quantity_Color Image_PixMap::PixelColor (const Standard_Integer theX, Quantity_Parameter (Standard_Real (aPixel) / 255.0), Quantity_TOC_RGB); } - default: + case ImgAlpha: { - // not supported image type - theAlpha = 0.0; // transparent - return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB); + const Standard_Byte& aPixel = Value (theY, theX); + theAlpha = Standard_Real (aPixel) / 255.0; + return Quantity_Color (1.0, 1.0, 1.0, Quantity_TOC_RGB); + } + case ImgUNKNOWN: + { + break; } } + + // unsupported image type + theAlpha = 0.0; // transparent + return Quantity_Color (0.0, 0.0, 0.0, Quantity_TOC_RGB); } diff --git a/src/Image/Image_PixMap.hxx b/src/Image/Image_PixMap.hxx index fe64ff3db3..9cf87fc602 100644 --- a/src/Image/Image_PixMap.hxx +++ b/src/Image/Image_PixMap.hxx @@ -30,14 +30,16 @@ public: //! This enumeration define packed image plane formats typedef enum tagFormat { ImgUNKNOWN = 0, //!< unsupported or unknown format - ImgGray = 1, //!< 1 byte per pixel + ImgGray = 1, //!< 1 byte per pixel, intensity of the color + ImgAlpha, //!< 1 byte per pixel, transparency ImgRGB, //!< 3 bytes packed RGB image plane ImgBGR, //!< same as RGB but with different components order ImgRGB32, //!< 4 bytes packed RGB image plane (1 extra byte for alignment, may have undefined value) ImgBGR32, //!< same as RGB but with different components order ImgRGBA, //!< 4 bytes packed RGBA image plane ImgBGRA, //!< same as RGBA but with different components order - ImgGrayF, //!< 1 float (4-bytes) per pixel (1-component plane) + ImgGrayF, //!< 1 float (4-bytes) per pixel (1-component plane), intensity of the color + ImgAlphaF, //!< 1 float (4-bytes) per pixel (1-component plane), transparency ImgRGBF, //!< 3 floats (12-bytes) RGB image plane ImgBGRF, //!< same as RGBF but with different components order ImgRGBAF, //!< 4 floats (16-bytes) RGBA image plane @@ -59,6 +61,12 @@ public: // high-level API return myImgFormat; } + //! Override pixel format specified by InitXXX() methods. + //! Will throw exception if pixel size of new format is not equal to currently initialized format. + //! Intended to switch formats indicating different interpretation of the same data + //! (e.g. ImgGray and ImgAlpha). + Standard_EXPORT void SetFormat (const ImgFormat thePixelFormat); + //! @return image width in pixels inline Standard_Size Width() const { @@ -258,11 +266,6 @@ public: //! @name low-level API for batch-processing (pixels reading / compariso return *reinterpret_cast(myData.ChangeValue (theRow, theCol)); } -protected: - - //! Setup pixel format - Standard_EXPORT void setFormat (ImgFormat thePixelFormat); - protected: Image_PixMapData myData; //!< data buffer diff --git a/src/OpenGl/OpenGl_AspectMarker.cxx b/src/OpenGl/OpenGl_AspectMarker.cxx index c679aea841..4eecb22b4f 100644 --- a/src/OpenGl/OpenGl_AspectMarker.cxx +++ b/src/OpenGl/OpenGl_AspectMarker.cxx @@ -1421,7 +1421,7 @@ Handle(Image_PixMap) MergeImages (const Handle(Image_PixMap)& theImage1, const Standard_Integer aMaxHeight = Max (aHeight1, aHeight2); const Standard_Integer aSize = Max (aMaxWidth, aMaxHeight); - aResultImage->InitZero (Image_PixMap::ImgGray, aSize, aSize); + aResultImage->InitZero (Image_PixMap::ImgAlpha, aSize, aSize); if (!theImage1.IsNull()) { @@ -1714,8 +1714,8 @@ void OpenGl_AspectMarker::Resources::BuildSprites (const Handle(OpenGl_Context)& const Standard_Integer aSize = Max (aWidth + 2, aHeight + 2); // includes extra margin anImage = new Image_PixMap(); anImageA = new Image_PixMap(); - anImage ->InitZero (Image_PixMap::ImgBGRA, aSize, aSize); - anImageA->InitZero (Image_PixMap::ImgGray, aSize, aSize); + anImage ->InitZero (Image_PixMap::ImgBGRA, aSize, aSize); + anImageA->InitZero (Image_PixMap::ImgAlpha, aSize, aSize); // we draw a set of circles Image_ColorBGRA aColor32; diff --git a/src/OpenGl/OpenGl_Font.cxx b/src/OpenGl/OpenGl_Font.cxx index 2b888b69da..c29f3c7874 100755 --- a/src/OpenGl/OpenGl_Font.cxx +++ b/src/OpenGl/OpenGl_Font.cxx @@ -117,7 +117,7 @@ bool OpenGl_Font::createTexture (const Handle(OpenGl_Context)& theCtx) Handle(OpenGl_Texture)& aTexture = myTextures.ChangeLast(); Image_PixMap aBlackImg; - if (!aBlackImg.InitZero (Image_PixMap::ImgGray, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY)) + if (!aBlackImg.InitZero (Image_PixMap::ImgAlpha, Standard_Size(aTextureSizeX), Standard_Size(aTextureSizeY)) || !aTexture->Init (theCtx, aBlackImg, Graphic3d_TOT_2D)) // myTextureFormat { TCollection_ExtendedString aMsg; diff --git a/src/OpenGl/OpenGl_GraphicDriver_7.cxx b/src/OpenGl/OpenGl_GraphicDriver_7.cxx index 5f40749b39..6340198045 100644 --- a/src/OpenGl/OpenGl_GraphicDriver_7.cxx +++ b/src/OpenGl/OpenGl_GraphicDriver_7.cxx @@ -266,6 +266,15 @@ inline bool getDataFormat (const Image_PixMap& theData, thePixelFormat = GL_BGRA; theDataType = GL_FLOAT; return true; + #else + case Image_PixMap::ImgGray: + case Image_PixMap::ImgGrayF: + case Image_PixMap::ImgBGR: + case Image_PixMap::ImgBGRA: + case Image_PixMap::ImgBGR32: + case Image_PixMap::ImgBGRF: + case Image_PixMap::ImgBGRAF: + return false; #endif case Image_PixMap::ImgRGB: thePixelFormat = GL_RGB; @@ -284,9 +293,13 @@ inline bool getDataFormat (const Image_PixMap& theData, thePixelFormat = GL_RGBA; theDataType = GL_FLOAT; return true; - default: + case Image_PixMap::ImgAlpha: + case Image_PixMap::ImgAlphaF: + return false; // GL_ALPHA is no more supported in core context + case Image_PixMap::ImgUNKNOWN: return false; } + return false; } Standard_Boolean OpenGl_GraphicDriver::BufferDump (const Graphic3d_CView& theCView, diff --git a/src/OpenGl/OpenGl_PointSprite.cxx b/src/OpenGl/OpenGl_PointSprite.cxx index 181f5f4f49..1f6023c219 100755 --- a/src/OpenGl/OpenGl_PointSprite.cxx +++ b/src/OpenGl/OpenGl_PointSprite.cxx @@ -31,6 +31,7 @@ OpenGl_PointSprite::OpenGl_PointSprite() myBitmapList (0) { //myParams->SetFilter (Graphic3d_TOTF_NEAREST); + myParams->SetModulate (Standard_False); myParams->SetGenMode (Graphic3d_TOTM_SPRITE, Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f), Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f)); diff --git a/src/OpenGl/OpenGl_Texture.cxx b/src/OpenGl/OpenGl_Texture.cxx index 72aafc4396..e5b4287228 100644 --- a/src/OpenGl/OpenGl_Texture.cxx +++ b/src/OpenGl/OpenGl_Texture.cxx @@ -181,14 +181,37 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx, { case Image_PixMap::ImgGrayF: { - theTextFormat = GL_ALPHA8; // GL_R8, GL_R32F - thePixelFormat = GL_ALPHA; // GL_RED - theDataType = GL_FLOAT; + if (theCtx->core11 == NULL) + { + theTextFormat = GL_R8; // GL_R32F + thePixelFormat = GL_RED; + } + else + { + theTextFormat = GL_LUMINANCE8; + thePixelFormat = GL_LUMINANCE; + } + theDataType = GL_FLOAT; + return true; + } + case Image_PixMap::ImgAlphaF: + { + if (theCtx->core11 == NULL) + { + theTextFormat = GL_R8; // GL_R32F + thePixelFormat = GL_RED; + } + else + { + theTextFormat = GL_ALPHA8; + thePixelFormat = GL_ALPHA; + } + theDataType = GL_FLOAT; return true; } case Image_PixMap::ImgRGBAF: { - theTextFormat = GL_RGBA8; // GL_RGBA32F + theTextFormat = GL_RGBA8; // GL_RGBA32F thePixelFormat = GL_RGBA; theDataType = GL_FLOAT; return true; @@ -206,7 +229,7 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx, } case Image_PixMap::ImgRGBF: { - theTextFormat = GL_RGB8; // GL_RGB32F + theTextFormat = GL_RGB8; // GL_RGB32F thePixelFormat = GL_RGB; theDataType = GL_FLOAT; return true; @@ -282,16 +305,40 @@ bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx, } case Image_PixMap::ImgGray: { - theTextFormat = GL_ALPHA8; // GL_R8 - thePixelFormat = GL_ALPHA; // GL_RED - theDataType = GL_UNSIGNED_BYTE; + if (theCtx->core11 == NULL) + { + theTextFormat = GL_R8; + thePixelFormat = GL_RED; + } + else + { + theTextFormat = GL_LUMINANCE8; + thePixelFormat = GL_LUMINANCE; + } + theDataType = GL_UNSIGNED_BYTE; return true; } - default: + case Image_PixMap::ImgAlpha: + { + if (theCtx->core11 == NULL) + { + theTextFormat = GL_R8; + thePixelFormat = GL_RED; + } + else + { + theTextFormat = GL_ALPHA8; + thePixelFormat = GL_ALPHA; + } + theDataType = GL_UNSIGNED_BYTE; + return true; + } + case Image_PixMap::ImgUNKNOWN: { return false; } } + return false; } // ======================================================================= diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx index ad95d7d180..75afc337ad 100644 --- a/src/OpenGl/OpenGl_Workspace.cxx +++ b/src/OpenGl/OpenGl_Workspace.cxx @@ -367,6 +367,17 @@ void OpenGl_Workspace::setTextureParams (Handle(OpenGl_Texture)& OpenGl_Utils::Rotate (aTextureMat, -aParams->Rotation(), 0.0f, 0.0f, 1.0f); glLoadMatrixf (aTextureMat); + GLint anEnvMode = GL_MODULATE; // lighting mode + if (!aParams->IsModulate()) + { + anEnvMode = GL_DECAL; + if (theTexture->GetFormat() == GL_ALPHA + || theTexture->GetFormat() == GL_LUMINANCE) + { + anEnvMode = GL_REPLACE; + } + } + // setup generation of texture coordinates switch (aParams->GenMode()) { @@ -416,7 +427,7 @@ void OpenGl_Workspace::setTextureParams (Handle(OpenGl_Texture)& { glEnable (GL_POINT_SPRITE); glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + anEnvMode = GL_REPLACE; GetGlContext()->core15->glPointParameteri (GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT); } break; @@ -426,10 +437,7 @@ void OpenGl_Workspace::setTextureParams (Handle(OpenGl_Texture)& } // setup lighting - if (aParams->GenMode() != Graphic3d_TOTM_SPRITE) - { - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, aParams->IsModulate() ? GL_MODULATE : GL_DECAL); - } + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, anEnvMode); #endif // get active sampler object to override default texture parameters diff --git a/src/ViewerTest/ViewerTest_ObjectCommands.cxx b/src/ViewerTest/ViewerTest_ObjectCommands.cxx index ef27aaccf1..9a3c184a11 100644 --- a/src/ViewerTest/ViewerTest_ObjectCommands.cxx +++ b/src/ViewerTest/ViewerTest_ObjectCommands.cxx @@ -5051,6 +5051,14 @@ static Standard_Integer VMarkersTest (Draw_Interpretor&, std::cerr << "Could not load image from file '" << aFileName << "'!\n"; return 1; } + if (anImage->Format() == Image_PixMap::ImgGray) + { + anImage->SetFormat (Image_PixMap::ImgAlpha); + } + else if (anImage->Format() == Image_PixMap::ImgGrayF) + { + anImage->SetFormat (Image_PixMap::ImgAlphaF); + } anAspect = new Graphic3d_AspectMarker3d (anImage); } else diff --git a/tests/bugs/vis/bug25544_graytexture b/tests/bugs/vis/bug25544_graytexture new file mode 100644 index 0000000000..1f07e8f5bf --- /dev/null +++ b/tests/bugs/vis/bug25544_graytexture @@ -0,0 +1,28 @@ +puts "============" +puts "0025544: Visualization, TKOpenGl - support grayscale textures" +puts "============" +puts "" + +vinit View1 +vclear + +box b 1 2 3 +vaxo +vsetdispmode 1 +vdisplay b +vtexture b 1 -modulate on +vfit + +set aColorMod [vreadpixel 290 180 rgb name] +vdump $imagedir/${casename}_modulated.png + +vtexture b 1 -modulate off +set aColorDec [vreadpixel 290 180 rgb name] +vdump $imagedir/${casename}_decal.png + +if {"$aColorMod" != "GOLDENROD4"} { + puts "Error: wrong color with modulation ON" +} +if {"$aColorDec" != "GRAY80"} { + puts "Error: wrong color with modulation OFF" +} -- 2.20.1