diff options
Diffstat (limited to 'samples/gles2_book/Stencil_Test/Stencil_Test.c')
-rw-r--r-- | samples/gles2_book/Stencil_Test/Stencil_Test.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/samples/gles2_book/Stencil_Test/Stencil_Test.c b/samples/gles2_book/Stencil_Test/Stencil_Test.c new file mode 100644 index 00000000..4996ccfc --- /dev/null +++ b/samples/gles2_book/Stencil_Test/Stencil_Test.c @@ -0,0 +1,273 @@ +// +// Book: OpenGL(R) ES 2.0 Programming Guide +// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner +// ISBN-10: 0321502795 +// ISBN-13: 9780321502797 +// Publisher: Addison-Wesley Professional +// URLs: http://safari.informit.com/9780321563835 +// http://www.opengles-book.com +// + +// Stencil_Test.c +// +// This example shows various stencil buffer +// operations. +// +#include <stdlib.h> +#include "esUtil.h" + +typedef struct +{ + // Handle to a program object + GLuint programObject; + + // Attribute locations + GLint positionLoc; + + // Uniform locations + GLint colorLoc; + +} UserData; + +/// +// Initialize the shader and program object +// +int Init ( ESContext *esContext ) +{ + UserData *userData = esContext->userData; + GLbyte vShaderStr[] = + "attribute vec4 a_position; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + "} \n"; + + GLbyte fShaderStr[] = + "precision mediump float; \n" + "uniform vec4 u_color; \n" + "void main() \n" + "{ \n" + " gl_FragColor = u_color; \n" + "} \n"; + + // Load the shaders and get a linked program object + userData->programObject = esLoadProgram ( vShaderStr, fShaderStr ); + + // Get the attribute locations + userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" ); + + // Get the sampler location + userData->colorLoc = glGetUniformLocation ( userData->programObject, "u_color" ); + + // Set the clear color + glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); + + // Set the stencil clear value + glClearStencil ( 0x1 ); + + // Set the depth clear value + glClearDepthf( 0.75f ); + + // Enable the depth and stencil tests + glEnable( GL_DEPTH_TEST ); + glEnable( GL_STENCIL_TEST ); + + return TRUE; +} + +/// +// Initialize the stencil buffer values, and then use those +// values to control rendering +// +void Draw ( ESContext *esContext ) +{ + int i; + + UserData *userData = esContext->userData; + + GLfloat vVertices[] = { + -0.75f, 0.25f, 0.50f, // Quad #0 + -0.25f, 0.25f, 0.50f, + -0.25f, 0.75f, 0.50f, + -0.75f, 0.75f, 0.50f, + 0.25f, 0.25f, 0.90f, // Quad #1 + 0.75f, 0.25f, 0.90f, + 0.75f, 0.75f, 0.90f, + 0.25f, 0.75f, 0.90f, + -0.75f, -0.75f, 0.50f, // Quad #2 + -0.25f, -0.75f, 0.50f, + -0.25f, -0.25f, 0.50f, + -0.75f, -0.25f, 0.50f, + 0.25f, -0.75f, 0.50f, // Quad #3 + 0.75f, -0.75f, 0.50f, + 0.75f, -0.25f, 0.50f, + 0.25f, -0.25f, 0.50f, + -1.00f, -1.00f, 0.00f, // Big Quad + 1.00f, -1.00f, 0.00f, + 1.00f, 1.00f, 0.00f, + -1.00f, 1.00f, 0.00f + }; + + GLubyte indices[][6] = { + { 0, 1, 2, 0, 2, 3 }, // Quad #0 + { 4, 5, 6, 4, 6, 7 }, // Quad #1 + { 8, 9, 10, 8, 10, 11 }, // Quad #2 + { 12, 13, 14, 12, 14, 15 }, // Quad #3 + { 16, 17, 18, 16, 18, 19 } // Big Quad + }; + +#define NumTests 4 + GLfloat colors[NumTests][4] = { + { 1.0f, 0.0f, 0.0f, 1.0f }, + { 0.0f, 1.0f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 1.0f, 1.0f }, + { 1.0f, 1.0f, 0.0f, 0.0f } + }; + + GLint numStencilBits; + GLuint stencilValues[NumTests] = { + 0x7, // Result of test 0 + 0x0, // Result of test 1 + 0x2, // Result of test 2 + 0xff // Result of test 3. We need to fill this + // value in a run-time + }; + + // Set the viewport + glViewport ( 0, 0, esContext->width, esContext->height ); + + // Clear the color, depth, and stencil buffers. At this + // point, the stencil buffer will be 0x1 for all pixels + glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + + // Use the program object + glUseProgram ( userData->programObject ); + + // Load the vertex position + glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT, + GL_FALSE, 0, vVertices ); + + glEnableVertexAttribArray ( userData->positionLoc ); + + // Test 0: + // + // Initialize upper-left region. In this case, the + // stencil-buffer values will be replaced because the + // stencil test for the rendered pixels will fail the + // stencil test, which is + // + // ref mask stencil mask + // ( 0x7 & 0x3 ) < ( 0x1 & 0x7 ) + // + // The value in the stencil buffer for these pixels will + // be 0x7. + // + glStencilFunc( GL_LESS, 0x7, 0x3 ); + glStencilOp( GL_REPLACE, GL_DECR, GL_DECR ); + glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[0] ); + + // Test 1: + // + // Initialize the upper-right region. Here, we'll decrement + // the stencil-buffer values where the stencil test passes + // but the depth test fails. The stencil test is + // + // ref mask stencil mask + // ( 0x3 & 0x3 ) > ( 0x1 & 0x3 ) + // + // but where the geometry fails the depth test. The + // stencil values for these pixels will be 0x0. + // + glStencilFunc( GL_GREATER, 0x3, 0x3 ); + glStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); + glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[1] ); + + // Test 2: + // + // Initialize the lower-left region. Here we'll increment + // (with saturation) the stencil value where both the + // stencil and depth tests pass. The stencil test for + // these pixels will be + // + // ref mask stencil mask + // ( 0x1 & 0x3 ) == ( 0x1 & 0x3 ) + // + // The stencil values for these pixels will be 0x2. + // + glStencilFunc( GL_EQUAL, 0x1, 0x3 ); + glStencilOp( GL_KEEP, GL_INCR, GL_INCR ); + glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[2] ); + + // Test 3: + // + // Finally, initialize the lower-right region. We'll invert + // the stencil value where the stencil tests fails. The + // stencil test for these pixels will be + // + // ref mask stencil mask + // ( 0x2 & 0x1 ) == ( 0x1 & 0x1 ) + // + // The stencil value here will be set to ~((2^s-1) & 0x1), + // (with the 0x1 being from the stencil clear value), + // where 's' is the number of bits in the stencil buffer + // + glStencilFunc( GL_EQUAL, 0x2, 0x1 ); + glStencilOp( GL_INVERT, GL_KEEP, GL_KEEP ); + glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[3] ); + + // Since we don't know at compile time how many stecil bits are present, + // we'll query, and update the value correct value in the + // stencilValues arrays for the fourth tests. We'll use this value + // later in rendering. + glGetIntegerv( GL_STENCIL_BITS, &numStencilBits ); + + stencilValues[3] = ~(((1 << numStencilBits) - 1) & 0x1) & 0xff; + + // Use the stencil buffer for controlling where rendering will + // occur. We diable writing to the stencil buffer so we + // can test against them without modifying the values we + // generated. + glStencilMask( 0x0 ); + + for ( i = 0; i < NumTests; ++i ) + { + glStencilFunc( GL_EQUAL, stencilValues[i], 0xff ); + glUniform4fv( userData->colorLoc, 1, colors[i] ); + glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[4] ); + } + + eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface ); +} + +/// +// Cleanup +// +void ShutDown ( ESContext *esContext ) +{ + UserData *userData = esContext->userData; + + // Delete program object + glDeleteProgram ( userData->programObject ); +} + + +int main ( int argc, char *argv[] ) +{ + ESContext esContext; + UserData userData; + + esInitContext ( &esContext ); + esContext.userData = &userData; + + esCreateWindow ( &esContext, TEXT("Stencil Test"), 320, 240, + ES_WINDOW_RGB | ES_WINDOW_DEPTH | ES_WINDOW_STENCIL ); + + if ( !Init ( &esContext ) ) + return 0; + + esRegisterDrawFunc ( &esContext, Draw ); + + esMainLoop ( &esContext ); + + ShutDown ( &esContext ); +} |