【OpenGL】一个好用的 GL 环境状态存储类

作为带有渲染功能的 SDK ,在完成某些特定需求的情况下,需要在游戏引擎(Unity、Unreal、Native 等)的线程里进行绘制。同时,绘制某些物体需要特定的 OpenGL 环境,因此不得不改变 OpenGL Context 。

然而,在 SDK 进行切换 OpenGL Context 时,并不清楚之前在 游戏引擎 中的 OpenGL Context State。理论上,应该由游戏引擎每一帧开始绘制时重新重置 OpenGL Context 环境状态。但是,仍然会存在一些问题,而且,在某些其他的场景下,可能我们也想实现在我们的渲染命令执行完成后,恢复初始的 OpenGL 环境。因此,接下来这个 GlStateSave 类实在是很不错的设计。

#ifndef GLSTATESAVE_H
#define GLSTATESAVE_H
#include "GlUtils.h"

class GLStateSave
{
public:
	// If our code only uses VertexArrayObjects, we don't need to
	// save and restore all the buffer related state
	static const bool	exclusivelyVAO = true;

	GLStateSave()
	{
		glGetIntegerv( GL_BLEND, &Blend );
		glGetIntegerv( GL_BLEND_DST_ALPHA, &BlendDstAlpha );
		glGetIntegerv( GL_BLEND_DST_RGB, &BlendDstRGB );
		glGetIntegerv( GL_BLEND_EQUATION_ALPHA, &BlendEquationAlpha );
		glGetIntegerv( GL_BLEND_EQUATION_RGB, &BlendEquationRgb );
		glGetIntegerv( GL_BLEND_SRC_ALPHA, &BlendSrcAlpha );
		glGetIntegerv( GL_BLEND_SRC_RGB, &BlendSrcRGB );

		// We update an array for debug graphs, so this needs to
		// be saved even though we use VAO, because GL_ARRAY_BUFFER_BINDING
		// isn't part of the VAO state.
		glGetIntegerv( GL_ARRAY_BUFFER_BINDING, &ArrayBuffer );

		if ( !exclusivelyVAO ) {
			glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING, &ElementArrayBuffer );
			for ( int i = 0 ; i < MAX_ATTRIBS ; i++ ) {
				glGetVertexAttribiv( i,	GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertexAttribArrayEnabled[i] );
			}
		}

		glGetIntegerv( GL_SCISSOR_TEST, &ScissorTest );
		glGetIntegerv( GL_SCISSOR_BOX, ScissorBox );
		glGetIntegerv( GL_DEPTH_TEST, &DepthTest );
		glGetIntegerv( GL_DEPTH_FUNC, &DepthFunc );
		glGetIntegerv( GL_DEPTH_WRITEMASK, &DepthWriteMask );
		glGetIntegerv( GL_CULL_FACE, &CullFace );
	}

	~GLStateSave()
	{
		glBlendEquationSeparate( BlendEquationRgb, BlendEquationAlpha );
		glBlendFuncSeparate( BlendSrcRGB, BlendDstRGB, BlendSrcAlpha, BlendDstAlpha );
		GL_Enable( GL_BLEND, Blend );

		glBindBuffer( GL_ARRAY_BUFFER, ArrayBuffer );

		if ( exclusivelyVAO ) {
			glBindVertexArrayOES_( 0 );
		} else {
			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ElementArrayBuffer );
			for ( int i = 0 ; i < MAX_ATTRIBS ; i++ ) {
				if ( vertexAttribArrayEnabled[i] ) {
					glEnableVertexAttribArray(i);
				} else {
					glDisableVertexAttribArray(i);
				}
			}
		}

		GL_Enable( GL_SCISSOR_TEST, ScissorTest );
		glScissor( ScissorBox[0], ScissorBox[1], ScissorBox[2], ScissorBox[3] );

		GL_Enable( GL_DEPTH_TEST, DepthTest );
		glDepthFunc( DepthFunc );

		glDepthMask( DepthWriteMask );

		GL_Enable( GL_CULL_FACE, CullFace );
	}

	void GL_Enable( const GLenum feature, GLboolean enabled )
	{
		if ( enabled ) {
			glEnable( feature );
		} else {
			glDisable( feature );
		}
	}


	GLint	Blend;
	GLint	BlendDstAlpha;
	GLint	BlendDstRGB;
	GLint	BlendEquationAlpha;
	GLint	BlendEquationRgb;
	GLint	BlendSrcAlpha;
	GLint	BlendSrcRGB;

	GLint	ElementArrayBuffer;
	GLint	ArrayBuffer;
	static const int MAX_ATTRIBS = 4;
	GLint	vertexAttribArrayEnabled[MAX_ATTRIBS];

	GLint	ScissorTest;
	GLint	ScissorBox[4];

	GLint	DepthTest;
	GLint	DepthFunc;
	GLint	DepthWriteMask;

	GLint   CullFace;
};

#endif // GLSTATESAVE_H

这样一来,在渲染相关函数的中就可以这么写了:

void Boundary::DoRender(int eye, GLuint fbIdMid, GLuint texIdMid)
{
    GLStateSave glState;
    GL(glDepthMask(GL_FALSE));
    GL(glDisable(GL_CULL_FACE));
    bool needFlush = RenderSeeThrough(eye, 0, 0);
    needFlush |= RenderBoundary(eye);
    RenderBackGround(eye);
    RenderDialog(eye);
    if (needFlush)
        GL(glFlush());
    return ;
}

程序执行到 DoRender 之后,因为声明了 GLStateSave 类,所以会在执行 GL(glDepthMask(GL_FALSE)) 之前先调用 GLStateSave 类的构建函数,记录所有 OpenGL Context,当程序从 DoRender 返回时,由于 glState 是个局部变量,所以就会自动释放,自动调用 GLStateSave 类的析构函数,去还原所有的 GL Context。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深海Enoch

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值