Skip to content

Commit

Permalink
Adds gl::ScopedColorMask and gl::ScopedStencilMask. (cinder#2324)
Browse files Browse the repository at this point in the history
* Adds gl::ScopedColorMask and gl::ScopedStencilMask.

* Changed the implementation of gl::ScopedColorMask and gl::ScopedStencilMask to use gl::Context instead of querying the OpenGL state.

---------

Co-authored-by: paulhoux <[email protected]>
  • Loading branch information
paulhoux and paulhoux authored Jan 8, 2024
1 parent b4eaa2f commit 18e1214
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
25 changes: 25 additions & 0 deletions include/cinder/gl/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,28 @@ class CI_API Context {
void popFrontFace( bool forceRestore = false );
//! Returns the winding order defining front-facing polygons, either \c GL_CW or \c GL_CCW (the default).
GLenum getFrontFace();

//! Set the current color mask, which enables and disables writing of frame buffer color components.
void colorMask( bool red, bool green, bool blue, bool alpha );
//! Push the current color mask, which enables and disables writing of frame buffer color components.
void pushColorMask( bool red, bool green, bool blue, bool alpha );
//! Pops the current color mask, which enables and disables writing of frame buffer color components.
void popColorMask( bool forceRestore = false );
//! Returns the current color mask, which enables and disables writing of frame buffer color components. Default is \c GL_TRUE for all 4 components (red, green, blue, alpha).
glm::bvec4 getColorMask();

//! Set the current stencil mask, which controls the front and back writing of individual bits in the stencil planes (front and back).
void stencilMask( GLuint mask );
//! Set the current stencil mask, which controls the front and back writing of individual bits in the stencil planes (front and back).
void stencilMask( GLuint front, GLuint back );
//! Push the current stencil mask, which controls the front and back writing of individual bits in the stencil planes (front and back).
void pushStencilMask( GLuint mask );
//! Push the current stencil mask, which controls the front and back writing of individual bits in the stencil planes (front and back).
void pushStencilMask( GLuint front, GLuint back );
//! Pops the current stencil mask, which controls the front and back writing of individual bits in the stencil planes (front and back).
void popStencilMask( bool forceRestore = false );
//! Returns the current stencil mask, which controls the front and back writing of individual bits in the stencil planes (front and back).
glm::u8vec2 getStencilMask();

#if ! defined( CINDER_GL_ES )
//! Analogous to glLogicOp( \a mode ). Valid arguments are \c GL_CLEAR, \c GL_SET, \c GL_COPY, \c GL_COPY_INVERTED, \c GL_NOOP, \c GL_INVERT, \c GL_AND, \c GL_NAND, \c GL_OR, \c GL_NOR, \c GL_XOR, \c GL_EQUIV, \c GL_AND_REVERSE, \c GL_AND_INVERTED, \c GL_OR_REVERSE, or \c GL_OR_INVERTED.
Expand Down Expand Up @@ -535,6 +557,9 @@ class CI_API Context {
std::vector<GLenum> mCullFaceStack;
std::vector<GLenum> mFrontFaceStack;

std::vector<glm::bvec4> mColorMaskStack;
std::vector<glm::u8vec2> mStencilMaskStack;

#if ! defined( CINDER_GL_ES )
std::vector<GLenum> mLogicOpStack;
std::vector<GLenum> mPolygonModeStack;
Expand Down
24 changes: 24 additions & 0 deletions include/cinder/gl/scoped.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,30 @@ struct CI_API ScopedFrontFace : private Noncopyable {
Context *mCtx;
};

//! Scopes writing of frame buffer color components
class ScopedColorMask : private Noncopyable {
public:
//! Values for \a red, \a green, \a blue and \a alpha may be \c GL_TRUE or \c GL_FALSE
ScopedColorMask( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha );
~ScopedColorMask();

private:
Context *mCtx;
};

//! Scopes the front and back writing of individual bits in the stencil planes (front and back)
class ScopedStencilMask : private Noncopyable {
public:
//! Values for \a mask may be between \c 0x00 and \c 0xFF
ScopedStencilMask( GLuint mask );
//! Values for \a front and \a back may be between \c 0x00 and \c 0xFF
ScopedStencilMask( GLuint front, GLuint back );
~ScopedStencilMask();

private:
Context *mCtx;
};

#if defined( CINDER_GL_HAS_KHR_DEBUG )

//! Scopes debug group message
Expand Down
101 changes: 101 additions & 0 deletions src/cinder/gl/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ Context::Context( const std::shared_ptr<PlatformData> &platformData )
#endif
mDefaultArrayVboIdx = 0;

// initial state for color mask is enabled
mColorMaskStack.emplace_back( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

// initial state for stencil mask is all bits enabled
mStencilMaskStack.emplace_back( 0xFF, 0xFF );

// initial state for depth mask is enabled
mBoolStateStack[GL_DEPTH_WRITEMASK] = vector<GLboolean>();
mBoolStateStack[GL_DEPTH_WRITEMASK].push_back( GL_TRUE );
Expand Down Expand Up @@ -470,6 +476,101 @@ GLenum Context::getFrontFace()
return mFrontFaceStack.back();
}

//////////////////////////////////////////////////////////////////
// ColorMask
void Context::colorMask( bool red, bool green, bool blue, bool alpha )
{
if( setStackState( mColorMaskStack, glm::bvec4( red, green, blue, alpha ) ) ) {
glColorMask( red, green, blue, alpha );
}
}

void Context::pushColorMask( bool red, bool green, bool blue, bool alpha )
{
if( pushStackState( mColorMaskStack, glm::bvec4( red, green, blue, alpha ) ) ) {
glColorMask( red, green, blue, alpha );
}
}

void Context::popColorMask( bool forceRestore )
{
if( mColorMaskStack.empty() )
CI_LOG_E( "Color mask stack underflow" );
else if( popStackState( mColorMaskStack ) || forceRestore ) {
const auto mask = getColorMask();
glColorMask( mask.r, mask.g, mask.b, mask.a );
}
}

glm::bvec4 Context::getColorMask()
{
if( mColorMaskStack.empty() ) {
GLboolean queriedBool[4];
glGetBooleanv( GL_COLOR_WRITEMASK, queriedBool );
mColorMaskStack.emplace_back( queriedBool[0], queriedBool[1], queriedBool[2], queriedBool[3] ); // push twice
mColorMaskStack.emplace_back( queriedBool[0], queriedBool[1], queriedBool[2], queriedBool[3] );
}

return mColorMaskStack.back();
}

//////////////////////////////////////////////////////////////////
// StencilMask
void Context::stencilMask( GLuint mask )
{
if( setStackState( mStencilMaskStack, glm::u8vec2( mask, mask ) ) ) {
glStencilMask( mask );
}
}

void Context::stencilMask( GLuint front, GLuint back )
{
if( setStackState( mStencilMaskStack, glm::u8vec2( front, back ) ) ) {
glStencilMaskSeparate( GL_FRONT, front );
glStencilMaskSeparate( GL_BACK, back );
}
}

void Context::pushStencilMask( GLuint mask )
{
if( pushStackState( mStencilMaskStack, glm::u8vec2( mask, mask ) ) ) {
glStencilMask( mask );
}
}

void Context::pushStencilMask( GLuint front, GLuint back )
{
if( pushStackState( mStencilMaskStack, glm::u8vec2( front, back ) ) ) {
glStencilMaskSeparate( GL_FRONT, front );
glStencilMaskSeparate( GL_BACK, back );
}
}

void Context::popStencilMask( bool forceRestore )
{
if( mStencilMaskStack.empty() )
CI_LOG_E( "Stencil mask stack underflow" );
else if( popStackState( mStencilMaskStack ) || forceRestore ) {
const auto mask = getStencilMask();
glStencilMaskSeparate( GL_FRONT, mask[0] );
glStencilMaskSeparate( GL_BACK, mask[1] );
}
}

glm::u8vec2 Context::getStencilMask()
{
if( mStencilMaskStack.empty() ) {
GLint queriedIntFront;
GLint queriedIntBack;
glGetIntegerv( GL_STENCIL_WRITEMASK, &queriedIntFront );
glGetIntegerv( GL_STENCIL_BACK_WRITEMASK, &queriedIntBack );
mStencilMaskStack.emplace_back( queriedIntFront, queriedIntBack ); // push twice
mStencilMaskStack.emplace_back( queriedIntFront, queriedIntBack );
}

return mStencilMaskStack.back();
}

//////////////////////////////////////////////////////////////////
// LogicOp
#if ! defined( CINDER_GL_ES )
Expand Down
32 changes: 32 additions & 0 deletions src/cinder/gl/scoped.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,38 @@ ScopedFrontFace::~ScopedFrontFace()
mCtx->popFrontFace();
}

///////////////////////////////////////////////////////////////////////////////////////////
// ScopedColorMask
ScopedColorMask::ScopedColorMask( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha )
: mCtx( gl::context() )
{
mCtx->pushColorMask( red, green, blue, alpha );
}

ScopedColorMask::~ScopedColorMask()
{
mCtx->popColorMask();
}

///////////////////////////////////////////////////////////////////////////////////////////
// ScopedStencilMask
ScopedStencilMask::ScopedStencilMask( GLuint mask )
: mCtx( gl::context() )
{
mCtx->pushStencilMask( mask );
}

ScopedStencilMask::ScopedStencilMask( GLuint front, GLuint back )
: mCtx( gl::context() )
{
mCtx->pushStencilMask( front, back );
}

ScopedStencilMask::~ScopedStencilMask()
{
mCtx->popStencilMask();
}

///////////////////////////////////////////////////////////////////////////////////////////
// ScopedDebugGroup
#if defined( CINDER_GL_HAS_KHR_DEBUG )
Expand Down

0 comments on commit 18e1214

Please sign in to comment.