blob: 4996ccfcaac29278e0d9dd45135900b33f3dc824 [file] [log] [blame]
//
// 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 );
}