1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-06-30 12:14:08 +03:00
occt/src/OpenGl/OpenGl_AspectsSprite.cxx
mkrylova 59500bb229 0031705: Visualization - move out construction of predefined markers from OpenGl_AspectsSprite to Graphic3d_MarkerImage
Built-in markers definition has been moved from OpenGl_AspectsSprite to Graphic3d_MarkerImage and generalized.
RGBA8 pixel format is now preferred over BGRA8.
Fallback OpenGL 1.1 rendering code now supports drawing of colored markers using glDrawPixels().

Added function Image_PixMap::FlipY() flipping image rows.
2020-12-17 21:05:04 +03:00

362 lines
13 KiB
C++

// Copyright (c) 2019 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 <OpenGl_AspectsSprite.hxx>
#include <OpenGl_Context.hxx>
#include <OpenGl_PointSprite.hxx>
#include <OpenGl_TextureSet.hxx>
#include <Image_PixMap.hxx>
#include <Graphic3d_MarkerImage.hxx>
#include <TColStd_HArray1OfByte.hxx>
namespace
{
static const TCollection_AsciiString THE_EMPTY_KEY;
}
// =======================================================================
// function : Release
// purpose :
// =======================================================================
void OpenGl_AspectsSprite::Release (OpenGl_Context* theCtx)
{
myIsSpriteReady = Standard_False;
if (mySprite.IsNull())
{
return;
}
if (theCtx != NULL)
{
if (mySprite->ResourceId().IsEmpty())
{
theCtx->DelayedRelease (mySprite);
theCtx->DelayedRelease (mySpriteA);
}
else
{
{
const TCollection_AsciiString aSpriteKey = mySprite->ResourceId();
mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
theCtx->ReleaseResource (aSpriteKey, Standard_True);
}
if (!mySpriteA.IsNull())
{
const TCollection_AsciiString aSpriteKeyA = mySpriteA->ResourceId();
mySpriteA.Nullify();
theCtx->ReleaseResource (aSpriteKeyA, Standard_True);
}
}
}
mySprite.Nullify();
mySpriteA.Nullify();
}
// =======================================================================
// function : HasPointSprite
// purpose :
// =======================================================================
bool OpenGl_AspectsSprite::HasPointSprite (const Handle(OpenGl_Context)& theCtx,
const Handle(Graphic3d_Aspects)& theAspects)
{
const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
return !aSprite.IsNull()
&& !aSprite->IsDisplayList();
}
// =======================================================================
// function : IsDisplayListSprite
// purpose :
// =======================================================================
bool OpenGl_AspectsSprite::IsDisplayListSprite (const Handle(OpenGl_Context)& theCtx,
const Handle(Graphic3d_Aspects)& theAspects)
{
#if !defined(GL_ES_VERSION_2_0)
const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
return !aSprite.IsNull()
&& aSprite->IsDisplayList();
#else
(void )theCtx;
(void )theAspects;
return false;
#endif
}
// =======================================================================
// function : UpdateRediness
// purpose :
// =======================================================================
void OpenGl_AspectsSprite::UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect)
{
// update sprite resource bindings
TCollection_AsciiString aSpriteKeyNew, aSpriteAKeyNew;
spriteKeys (theAspect->MarkerImage(), theAspect->MarkerType(), theAspect->MarkerScale(), theAspect->ColorRGBA(), aSpriteKeyNew, aSpriteAKeyNew);
const TCollection_AsciiString& aSpriteKeyOld = !mySprite.IsNull() ? mySprite ->ResourceId() : THE_EMPTY_KEY;
const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
if (aSpriteKeyNew.IsEmpty() || aSpriteKeyOld != aSpriteKeyNew
|| aSpriteAKeyNew.IsEmpty() || aSpriteAKeyOld != aSpriteAKeyNew)
{
myIsSpriteReady = Standard_False;
myMarkerSize = theAspect->MarkerScale();
}
}
// =======================================================================
// function : Sprite
// purpose :
// =======================================================================
const Handle(OpenGl_PointSprite)& OpenGl_AspectsSprite::Sprite (const Handle(OpenGl_Context)& theCtx,
const Handle(Graphic3d_Aspects)& theAspects,
bool theIsAlphaSprite)
{
if (!myIsSpriteReady)
{
build (theCtx, theAspects->MarkerImage(), theAspects->MarkerType(), theAspects->MarkerScale(), theAspects->ColorRGBA(), myMarkerSize);
myIsSpriteReady = true;
}
return theIsAlphaSprite && !mySpriteA.IsNull() && mySpriteA->IsValid()
? mySpriteA
: mySprite;
}
// =======================================================================
// function : build
// purpose :
// =======================================================================
void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
const Handle(Graphic3d_MarkerImage)& theMarkerImage,
Aspect_TypeOfMarker theType,
Standard_ShortReal theScale,
const Graphic3d_Vec4& theColor,
Standard_ShortReal& theMarkerSize)
{
// generate key for shared resource
TCollection_AsciiString aNewKey, aNewKeyA;
spriteKeys (theMarkerImage, theType, theScale, theColor, aNewKey, aNewKeyA);
const TCollection_AsciiString& aSpriteKeyOld = !mySprite.IsNull() ? mySprite ->ResourceId() : THE_EMPTY_KEY;
const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
// release old shared resources
const Standard_Boolean aNewResource = aNewKey.IsEmpty()
|| aSpriteKeyOld != aNewKey;
if (aNewResource)
{
if (!mySprite.IsNull())
{
if (mySprite->ResourceId().IsEmpty())
{
theCtx->DelayedRelease (mySprite);
mySprite.Nullify();
}
else
{
const TCollection_AsciiString anOldKey = mySprite->ResourceId();
mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
theCtx->ReleaseResource (anOldKey, Standard_True);
}
}
}
if (aNewKeyA.IsEmpty() || aSpriteAKeyOld != aNewKeyA)
{
if (!mySpriteA.IsNull())
{
if (mySpriteA->ResourceId().IsEmpty())
{
theCtx->DelayedRelease (mySpriteA);
mySpriteA.Nullify();
}
else
{
const TCollection_AsciiString anOldKey = mySpriteA->ResourceId();
mySpriteA.Nullify(); // we need nullify all handles before ReleaseResource() call
theCtx->ReleaseResource (anOldKey, Standard_True);
}
}
}
if (!aNewResource)
{
const OpenGl_PointSprite* aSprite = dynamic_cast<OpenGl_PointSprite*> (mySprite.get());
if (!aSprite->IsDisplayList())
{
theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
}
return;
}
if (theType == Aspect_TOM_POINT
|| theType == Aspect_TOM_EMPTY
|| (theType == Aspect_TOM_USERDEFINED && theMarkerImage.IsNull()))
{
// nothing to do - just simple point
return;
}
Handle(OpenGl_PointSprite)& aSprite = mySprite;
Handle(OpenGl_PointSprite)& aSpriteA = mySpriteA;
if (!aNewKey.IsEmpty()
&& theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKeyA, aSpriteA) // alpha sprite could be shared
&& theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKey, aSprite))
{
// reuse shared resource
if (!aSprite->IsDisplayList())
{
theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
}
return;
}
const bool hadAlreadyAlpha = !aSpriteA.IsNull();
if (!hadAlreadyAlpha)
{
aSpriteA = new OpenGl_PointSprite (aNewKeyA);
}
aSprite = new OpenGl_PointSprite (aNewKey);
if (!aNewKey.IsEmpty())
{
theCtx->ShareResource (aNewKey, aSprite);
if (!hadAlreadyAlpha)
{
theCtx->ShareResource (aNewKeyA, aSpriteA);
}
}
Handle(Graphic3d_MarkerImage) aNewMarkerImage = theType == Aspect_TOM_USERDEFINED && !theMarkerImage.IsNull()
? theMarkerImage
: Graphic3d_MarkerImage::StandardMarker (theType, theScale, theColor);
if (aNewMarkerImage.IsNull())
{
return;
}
if (!theCtx.IsNull()
&& theCtx->core20fwd != NULL
&& !theCtx->caps->pntSpritesDisable)
{
// Creating texture resource for using it with point sprites
Handle(Image_PixMap) anImage = aNewMarkerImage->GetImage();
theMarkerSize = Max ((Standard_ShortReal )anImage->Width(),(Standard_ShortReal )anImage->Height());
aSprite->Init (theCtx, *anImage, Graphic3d_TOT_2D, true);
if (!hadAlreadyAlpha)
{
if (Handle(Image_PixMap) anImageA = aSprite->GetFormat() != GL_ALPHA ? aNewMarkerImage->GetImageAlpha() : Handle(Image_PixMap)())
{
aSpriteA->Init (theCtx, *anImageA, Graphic3d_TOT_2D, true);
}
}
}
else
{
#if !defined(GL_ES_VERSION_2_0)
// Creating list with bitmap for using it in compatibility mode
GLuint aBitmapList = glGenLists (1);
aSprite->SetDisplayList (theCtx, aBitmapList);
Handle(Image_PixMap) anImage = aNewMarkerImage->IsColoredImage()
? aNewMarkerImage->GetImage()
: Handle(Image_PixMap)();
const OpenGl_TextureFormat aFormat = !anImage.IsNull()
? OpenGl_TextureFormat::FindFormat (theCtx, anImage->Format(), true)
: OpenGl_TextureFormat();
if (aFormat.IsValid())
{
if (anImage->IsTopDown())
{
Handle(Image_PixMap) anImageCopy = new Image_PixMap();
anImageCopy->InitCopy (*anImage);
Image_PixMap::FlipY (*anImageCopy);
anImage = anImageCopy;
}
const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8);
glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
const GLint anExtraBytes = GLint (anImage->RowExtraBytes());
const GLint aPixelsWidth = GLint (anImage->SizeRowBytes() / anImage->SizePixelBytes());
const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
glNewList (aBitmapList, GL_COMPILE);
const Standard_Integer aWidth = (Standard_Integer )anImage->Width(), aHeight = (Standard_Integer )anImage->Height();
glBitmap (0, 0, 0, 0, GLfloat(-0.5f * aWidth), GLfloat(-0.5f * aHeight), NULL); // make offsets that will be added to the current raster position
glDrawPixels (GLsizei(anImage->Width()), GLsizei(anImage->Height()), aFormat.PixelFormat(), aFormat.DataType(), anImage->Data());
glEndList();
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
}
if (!aFormat.IsValid() || !hadAlreadyAlpha)
{
if (aFormat.IsValid())
{
aBitmapList = glGenLists (1);
aSpriteA->SetDisplayList (theCtx, aBitmapList);
}
Standard_Integer aWidth = 0, aHeight = 0;
aNewMarkerImage->GetTextureSize (aWidth, aHeight);
if (Handle(TColStd_HArray1OfByte) aBitMap = aNewMarkerImage->GetBitMapArray())
{
glNewList (aBitmapList, GL_COMPILE);
glBitmap ((GLsizei)aWidth, (GLsizei)aHeight, (GLfloat)(0.5f * aWidth), (GLfloat)(0.5f * aHeight),
0.f, 0.f, (const GLubyte*)&aBitMap->First());
glEndList();
}
}
#endif
}
}
// =======================================================================
// function : spriteKeys
// purpose :
// =======================================================================
void OpenGl_AspectsSprite::spriteKeys (const Handle(Graphic3d_MarkerImage)& theMarkerImage,
Aspect_TypeOfMarker theType,
Standard_ShortReal theScale,
const Graphic3d_Vec4& theColor,
TCollection_AsciiString& theKey,
TCollection_AsciiString& theKeyA)
{
// generate key for shared resource
if (theType == Aspect_TOM_USERDEFINED)
{
if (!theMarkerImage.IsNull())
{
theKey = theMarkerImage->GetImageId();
theKeyA = theMarkerImage->GetImageAlphaId();
}
}
else if (theType != Aspect_TOM_POINT
&& theType != Aspect_TOM_EMPTY)
{
// predefined markers are defined with 0.5 step
const Standard_Integer aScale = Standard_Integer(theScale * 10.0f + 0.5f);
theKey = TCollection_AsciiString ("OpenGl_AspectMarker") + theType + "_" + aScale;
theKeyA = theKey + "A";
if (theType == Aspect_TOM_BALL)
{
unsigned int aColor[3] =
{
(unsigned int )(255.0f * theColor.r()),
(unsigned int )(255.0f * theColor.g()),
(unsigned int )(255.0f * theColor.b())
};
char aBytes[8];
sprintf (aBytes, "%02X%02X%02X", aColor[0], aColor[1], aColor[2]);
theKey += aBytes;
}
}
}