Compile a simple 2D rendering framework based on OpenGL-10 reconstruction Renderer-Pass, Renderer-pass
Pass, rendering path. A rendering path refers to one pixel processing and one vertex processing, that is, one painting. Simply put, the vertex data is finally drawn in the rendering pipeline.
When rendering particles in the particle system, you must enable the OpenGL hybrid mode and add the two colors. If you draw multiple images at the same time, and the rendering of these images does not need to enable the hybrid mode. At this time, the final result of rendering is the problem of image rendering, which is not what we want. One solution is to perform draw twice. For the first time, enable the mixed mode to render the particles of the particle system, and for the second time, disable the mixed mode to render the image.
The above solution can be implemented through two Pass rendering, the first Pass setting enables the mixed mode, and the second Pass disables the mixed mode to render the two Pass.
Simple2D's Pass design is relatively simple and mainly implemented
1. Set cropping test, Alpha test, template test, deep test, and hybrid mode.
2. Fill mode, face removal mode, and vertices frontend setting.
The Pass member attribute adds the switch quantity enabled for these tests:
Bool bEnableScissor;/* cropping test */bool bEnableAlphaTest;/* Alpha test */bool bEnableStencilTest;/* template test */bool bEnableDepthTest;/* Deep test */bool bEnableBlend; /* Mixed Mode */bool bEnableCullFace;
The following are the property variables for various tests:
/* Remove Mode */enum CullMode {CULL_MODE_BACK,/* remove only the back */CULL_MODE_FRONT,/* remove only the front */CULL_MODE_FRONT_AND_BACK/* remove the back and front */}; /* frontend vertex sequence */enum FrontFace {FRONT_FACE_CLOCK_WISE,/* clockwise for the front */FRONT_FACE_COUNTER_CLOCK_WISE,/* clockwise for the front */}; /* fill mode */enum FillMode {FILL_LINE,/* box */FILL_POINT,/* point */FILL_FILL/* object */}; /* Mixed equation */enum BlendEquation {BLEND_ADD,/* add each other's elements */BLEND_SUNTRACT,/* subtract each other's elements */BLEND_REVERSE_SUBTRACT/* subtract each other's elements, however, the order is the opposite: */};/* Mixed factor */enum BlendFunc {BLEND_ZERO, BLEND_ONE, BLEND_SRC_COLOR, weight, BLEND_CONSTANT_COLOR, weight, weight, BLEND_CONSTANT_ALPHA, BLEND_ONE_MINUS_CONSTANT_ALPHA};/* comparison function */enum CompareFunction {COMPARE_LESS,/* test when the segment depth value is smaller than the buffer depth */COMPARE_LEQUAL, /* test the fragment depth value when it is less than or equal to the buffer depth */COMPARE_GREATER,/* test the fragment depth value when it is greater than the buffer depth */COMPARE_GEQUAL, /* test when the part depth value is greater than or equal to the buffer depth */COMPARE_EQUAL,/* test when the part depth value is equal to the buffer depth */COMPARE_NOT_EQUAL, /* test */COMPARE_ALWAYS when the fragment depth value is not equal to the buffer depth,/* always pass test */COMPARE_NEVER/* never pass test */}; /* template operation */enum StencilOp {STENCIL_OP_KEEP,/* does not change, which is also the default value */STENCIL_OP_ZERO,/* returns 0 */STENCIL_OP_REPLACE, /* use the set value in the test condition to replace the current template value */STENCIL_OP_INCR,/* increase by 1, but if it is already the maximum value, it will remain unchanged */STENCIL_OP_INCR_WRAP,/* increase by 1, but if it is already the maximum value, it will start from scratch */STENCIL_OP_DECR,/* will decrease 1, but if it is already zero, it will remain unchanged */STENCIL_OP_DECR_WRAP,/* will decrease 1, however, if it is already zero, You can reset it to the maximum value */STENCIL_OP_INVERT/* bitwise inversion */};
/* Cropping test: the area where pixels can be drawn */int nScissorX, nScissorY, nScissorW, and nScissorH;/* Alpha test */CompareFunction alphaCompareFunction; float fClampRef; /* template test */CompareFunction limit; unsigned int nStencilMask; int nStencilRef; StencilOp limit;/* Deep test, comparison function */CompareFunction limit; /* Mixed equation and mixed factor */BlendEquation blendEquation; BlendFunc blendSrc, blendDst, blendSrcAlpha, blendDstAlpha;
Next, set the variable values for each test:
Void enableScissor (bool enable) {bEnableScissor = enable;} void enableAlphaTest (bool enable) {bEnableAlphaTest = enable;} void Merge (bool enable) {bEnableStencilTest = enable ;} void Merge (bool enable) {bEnableDepthTest = enable;} void enableBlend (bool enable) {bEnableBlend = enable;} void enableCullFace (bool enable) {bEnableCullFace = enable ;} void setFillMode (FillMode fm) {fillMode = fm;} void setCullMode (CullMode cm) {cullMode = cm;} void setFrontFace (FrontFace ff) {frontFace = ff ;} /* set the cropping area */void setScissorRect (int x, int y, int w, int h) {nScissorX = x; nScissorY = y; nScissorW = w; nScissorH = h ;} void compute (CompareFunction compare) {alphaCompareFunction = compare;} void setAlphaClamf (float clamf) {fClampRef = clamf;} void compute (CompareFunction compare) {comparison = compare ;} void Merge (unsigned int mask) {merge = mask;} void setStencilRef (int ref) {nStencilRef = ref;}/* update template buffer operation */void setStencilOp (StencilOp sfail, stencilOp dpfail, StencilOp dppass) {strong = sfail; strong = dpfail; passStencilPassDepth = dppass;}/* set the deep test comparison function */void comparison (CompareFunction compare) {depthCompareFunction = compare;}/* set the mixed equation of the hybrid operation */void setBlendEquation (BlendEquation equation) {blendEquation = equation ;} /* set the mixed factor */void Merge (BlendFunc srcColor, BlendFunc dstColor, BlendFunc srcAlpha, BlendFunc dstAlpha) {blendSrc = srcColor; blendDst = dstColor; priority = srcAlpha; blendDstAlpha = dstAlpha ;}
There is nothing to say above. The key point is how to set the OpenGL status,
static int toEnum(CullMode cullmode) { switch ( cullmode ) { case Simple2D::CULL_MODE_BACK: return GL_BACK; case Simple2D::CULL_MODE_FRONT: return GL_FRONT; case Simple2D::CULL_MODE_FRONT_AND_BACK: return GL_FRONT_AND_BACK; } return GL_BACK; } static int toEnum(FrontFace frontface) { switch ( frontface ) { case Simple2D::FRONT_FACE_CLOCK_WISE: return GL_CW; case Simple2D::FRONT_FACE_COUNTER_CLOCK_WISE: return GL_CCW; } return GL_CCW; } static int toEnum(FillMode fillmode) { switch ( fillmode ) { case Simple2D::FILL_LINE: return GL_LINE; case Simple2D::FILL_POINT: return GL_POINT; case Simple2D::FILL_FILL: return GL_FILL; } return GL_FILL; } static int toEnum(BlendEquation equation) { switch ( equation ) { case Simple2D::BLEND_ADD: return GL_FUNC_ADD; case Simple2D::BLEND_SUNTRACT: return GL_FUNC_SUBTRACT; case Simple2D::BLEND_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT; } return GL_FUNC_ADD; } static int toEnum(BlendFunc func) { switch ( func ) { case Simple2D::BLEND_ZERO: return GL_ZERO; case Simple2D::BLEND_ONE: return GL_ONE; case Simple2D::BLEND_SRC_COLOR: return GL_SRC_COLOR; case Simple2D::BLEND_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR; case Simple2D::BLEND_DST_COLOR: return GL_DST_COLOR; case Simple2D::BLEND_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR; case Simple2D::BLEND_SRC_ALPHA: return GL_SRC_ALPHA; case Simple2D::BLEND_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA; case Simple2D::BLEND_DST_ALPHA: return GL_DST_ALPHA; case Simple2D::BLEND_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; case Simple2D::BLEND_CONSTANT_COLOR: return GL_CONSTANT_COLOR; case Simple2D::BLEND_ONE_MINUS_CONSTANT_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR; case Simple2D::BLEND_CONSTANT_ALPHA: return GL_CONSTANT_ALPHA; case Simple2D::BLEND_ONE_MINUS_CONSTANT_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA; } return GL_ONE; } static int toEnum(CompareFunction compare) { switch ( compare ) { case Simple2D::COMPARE_LESS: return GL_LESS; case Simple2D::COMPARE_LEQUAL: return GL_LEQUAL; case Simple2D::COMPARE_GREATER: return GL_GREATER; case Simple2D::COMPARE_GEQUAL: return GL_GEQUAL; case Simple2D::COMPARE_EQUAL: return GL_EQUAL; case Simple2D::COMPARE_NOT_EQUAL: return GL_NOTEQUAL; case Simple2D::COMPARE_ALWAYS: return GL_ALWAYS; case Simple2D::COMPARE_NEVER: return GL_NEVER; } return GL_LESS; } static int toEnum(StencilOp stencilOp) { switch ( stencilOp ) { case Simple2D::STENCIL_OP_KEEP: return GL_KEEP; case Simple2D::STENCIL_OP_ZERO: return GL_ZERO; case Simple2D::STENCIL_OP_REPLACE: return GL_REPLACE; case Simple2D::STENCIL_OP_INCR: return GL_INCR; case Simple2D::STENCIL_OP_INCR_WRAP: return GL_INCR_WRAP; case Simple2D::STENCIL_OP_DECR: return GL_DECR; case Simple2D::STENCIL_OP_DECR_WRAP: return GL_DECR_WRAP; case Simple2D::STENCIL_OP_INVERT: return GL_INVERT; } return GL_KEEP; }
Void Pass: setOpenGLState () {/* surface removal */if (bEnableCullFace) {glable (GL_CULL_FACE); glCullFace (toEnum (cullMode )); glFrontFace (toEnum (frontFace);} else {glDisable (GL_CULL_FACE);}/* fill mode */glPolygonMode (GL_FRONT_AND_BACK, toEnum (fillMode )); /* crop test */if (bEnableScissor) {glable (GL_SCISSOR_TEST);/* coordinate origin in the lower left corner */glScissor (nScissorX, nScissorY, nScissorW, nScissorH );} else {glDisable (GL_SCISSOR_TEST);}/* Alpha test */if (bEnableAlphaTest) {GL_ALPHA_TEST); glAlphaFunc (toEnum (alphaCompareFunction), fClampRef );} else {glDisable (GL_ALPHA_TEST);}/* template test */if (bEnableStencilTest) {glable (latency); glStencilFunc (toEnum (latency), nStencilRef, nStencilMask ); glStencilOp (toEnum (batch), toEnum (batch), toEnum (passStencilPassDepth);} else {glDisable (batch);}/* Deep test */if (bEnableDepthTest) {GL_DEPTH_TEST); glDepthFunc (toEnum (token);} else {glDisable (GL_DEPTH_TEST);}/* Mixed Mode */if (bEnableBlend) {glable (GL_BLEND ); glBlendEquation (toEnum (blendEquation); then (toEnum (blendSrc), toEnum (blendDst), toEnum (blendSrcAlpha), toEnum (blendDstAlpha ));} else {glDisable (GL_BLEND );}}
According to the previously designed class diagram
Each Pass has a Shader member variable, so the Pass class also needs to add the Shader member variable. In addition, the primitive type during painting is also designed in the Pass:
PrimType primType;Shader* pShader;
The design of the entire Pass class is relatively simple, and the source code is provided after the reconstruction Renderer is completed.