1//
2// Book:      OpenGL(R) ES 2.0 Programming Guide
3// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
4// ISBN-10:   0321502795
5// ISBN-13:   9780321502797
6// Publisher: Addison-Wesley Professional
7// URLs:      http://safari.informit.com/9780321563835
8//            http://www.opengles-book.com
9//
10
11// Stencil_Test.c
12//
13//    This example shows various stencil buffer
14//    operations.
15//
16#include <stdlib.h>
17#include "esUtil.h"
18
19typedef struct
20{
21   // Handle to a program object
22   GLuint programObject;
23
24   // Attribute locations
25   GLint  positionLoc;
26
27   // Uniform locations
28   GLint  colorLoc;
29
30} UserData;
31
32///
33// Initialize the shader and program object
34//
35int Init ( ESContext *esContext )
36{
37   UserData *userData = esContext->userData;
38   GLbyte vShaderStr[] =
39      "attribute vec4 a_position;   \n"
40      "void main()                  \n"
41      "{                            \n"
42      "   gl_Position = a_position; \n"
43      "}                            \n";
44
45   GLbyte fShaderStr[] =
46      "precision mediump float;  \n"
47      "uniform vec4  u_color;    \n"
48      "void main()               \n"
49      "{                         \n"
50      "  gl_FragColor = u_color; \n"
51      "}                         \n";
52
53   // Load the shaders and get a linked program object
54   userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
55
56   // Get the attribute locations
57   userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
58
59   // Get the sampler location
60   userData->colorLoc = glGetUniformLocation ( userData->programObject, "u_color" );
61
62   // Set the clear color
63   glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
64
65   // Set the stencil clear value
66   glClearStencil ( 0x1 );
67
68   // Set the depth clear value
69   glClearDepthf( 0.75f );
70
71   // Enable the depth and stencil tests
72   glEnable( GL_DEPTH_TEST );
73   glEnable( GL_STENCIL_TEST );
74
75   return TRUE;
76}
77
78///
79// Initialize the stencil buffer values, and then use those
80//   values to control rendering
81//
82void Draw ( ESContext *esContext )
83{
84   int  i;
85
86   UserData *userData = esContext->userData;
87
88   GLfloat vVertices[] = {
89       -0.75f,  0.25f,  0.50f, // Quad #0
90       -0.25f,  0.25f,  0.50f,
91       -0.25f,  0.75f,  0.50f,
92       -0.75f,  0.75f,  0.50f,
93	    0.25f,  0.25f,  0.90f, // Quad #1
94		0.75f,  0.25f,  0.90f,
95		0.75f,  0.75f,  0.90f,
96		0.25f,  0.75f,  0.90f,
97	   -0.75f, -0.75f,  0.50f, // Quad #2
98       -0.25f, -0.75f,  0.50f,
99       -0.25f, -0.25f,  0.50f,
100       -0.75f, -0.25f,  0.50f,
101        0.25f, -0.75f,  0.50f, // Quad #3
102        0.75f, -0.75f,  0.50f,
103        0.75f, -0.25f,  0.50f,
104        0.25f, -0.25f,  0.50f,
105       -1.00f, -1.00f,  0.00f, // Big Quad
106        1.00f, -1.00f,  0.00f,
107        1.00f,  1.00f,  0.00f,
108       -1.00f,  1.00f,  0.00f
109   };
110
111   GLubyte indices[][6] = {
112       {  0,  1,  2,  0,  2,  3 }, // Quad #0
113       {  4,  5,  6,  4,  6,  7 }, // Quad #1
114       {  8,  9, 10,  8, 10, 11 }, // Quad #2
115       { 12, 13, 14, 12, 14, 15 }, // Quad #3
116       { 16, 17, 18, 16, 18, 19 }  // Big Quad
117   };
118
119#define NumTests  4
120   GLfloat  colors[NumTests][4] = {
121       { 1.0f, 0.0f, 0.0f, 1.0f },
122       { 0.0f, 1.0f, 0.0f, 1.0f },
123       { 0.0f, 0.0f, 1.0f, 1.0f },
124       { 1.0f, 1.0f, 0.0f, 0.0f }
125   };
126
127   GLint   numStencilBits;
128   GLuint  stencilValues[NumTests] = {
129      0x7, // Result of test 0
130      0x0, // Result of test 1
131      0x2, // Result of test 2
132      0xff // Result of test 3.  We need to fill this
133           //  value in a run-time
134   };
135
136   // Set the viewport
137   glViewport ( 0, 0, esContext->width, esContext->height );
138
139   // Clear the color, depth, and stencil buffers.  At this
140   //   point, the stencil buffer will be 0x1 for all pixels
141   glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
142
143   // Use the program object
144   glUseProgram ( userData->programObject );
145
146   // Load the vertex position
147   glVertexAttribPointer ( userData->positionLoc, 3, GL_FLOAT,
148                           GL_FALSE, 0, vVertices );
149
150   glEnableVertexAttribArray ( userData->positionLoc );
151
152   // Test 0:
153   //
154   // Initialize upper-left region.  In this case, the
155   //   stencil-buffer values will be replaced because the
156   //   stencil test for the rendered pixels will fail the
157   //   stencil test, which is
158   //
159   //        ref   mask   stencil  mask
160   //      ( 0x7 & 0x3 ) < ( 0x1 & 0x7 )
161   //
162   //   The value in the stencil buffer for these pixels will
163   //   be 0x7.
164   //
165   glStencilFunc( GL_LESS, 0x7, 0x3 );
166   glStencilOp( GL_REPLACE, GL_DECR, GL_DECR );
167   glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[0] );
168
169   // Test 1:
170   //
171   // Initialize the upper-right region.  Here, we'll decrement
172   //   the stencil-buffer values where the stencil test passes
173   //   but the depth test fails.  The stencil test is
174   //
175   //        ref  mask    stencil  mask
176   //      ( 0x3 & 0x3 ) > ( 0x1 & 0x3 )
177   //
178   //    but where the geometry fails the depth test.  The
179   //    stencil values for these pixels will be 0x0.
180   //
181   glStencilFunc( GL_GREATER, 0x3, 0x3 );
182   glStencilOp( GL_KEEP, GL_DECR, GL_KEEP );
183   glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[1] );
184
185   // Test 2:
186   //
187   // Initialize the lower-left region.  Here we'll increment
188   //   (with saturation) the stencil value where both the
189   //   stencil and depth tests pass.  The stencil test for
190   //   these pixels will be
191   //
192   //        ref  mask     stencil  mask
193   //      ( 0x1 & 0x3 ) == ( 0x1 & 0x3 )
194   //
195   //   The stencil values for these pixels will be 0x2.
196   //
197   glStencilFunc( GL_EQUAL, 0x1, 0x3 );
198   glStencilOp( GL_KEEP, GL_INCR, GL_INCR );
199   glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[2] );
200
201   // Test 3:
202   //
203   // Finally, initialize the lower-right region.  We'll invert
204   //   the stencil value where the stencil tests fails.  The
205   //   stencil test for these pixels will be
206   //
207   //        ref   mask    stencil  mask
208   //      ( 0x2 & 0x1 ) == ( 0x1 & 0x1 )
209   //
210   //   The stencil value here will be set to ~((2^s-1) & 0x1),
211   //   (with the 0x1 being from the stencil clear value),
212   //   where 's' is the number of bits in the stencil buffer
213   //
214   glStencilFunc( GL_EQUAL, 0x2, 0x1 );
215   glStencilOp( GL_INVERT, GL_KEEP, GL_KEEP );
216   glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[3] );
217
218   // Since we don't know at compile time how many stecil bits are present,
219   //   we'll query, and update the value correct value in the
220   //   stencilValues arrays for the fourth tests.  We'll use this value
221   //   later in rendering.
222   glGetIntegerv( GL_STENCIL_BITS, &numStencilBits );
223
224   stencilValues[3] = ~(((1 << numStencilBits) - 1) & 0x1) & 0xff;
225
226   // Use the stencil buffer for controlling where rendering will
227   //   occur.  We diable writing to the stencil buffer so we
228   //   can test against them without modifying the values we
229   //   generated.
230   glStencilMask( 0x0 );
231
232   for ( i = 0; i < NumTests; ++i )
233   {
234      glStencilFunc( GL_EQUAL, stencilValues[i], 0xff );
235      glUniform4fv( userData->colorLoc, 1, colors[i] );
236      glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[4] );
237   }
238
239   eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
240}
241
242///
243// Cleanup
244//
245void ShutDown ( ESContext *esContext )
246{
247   UserData *userData = esContext->userData;
248
249   // Delete program object
250   glDeleteProgram ( userData->programObject );
251}
252
253
254int main ( int argc, char *argv[] )
255{
256   ESContext esContext;
257   UserData  userData;
258
259   esInitContext ( &esContext );
260   esContext.userData = &userData;
261
262   esCreateWindow ( &esContext, TEXT("Stencil Test"), 320, 240,
263                    ES_WINDOW_RGB | ES_WINDOW_DEPTH | ES_WINDOW_STENCIL );
264
265   if ( !Init ( &esContext ) )
266      return 0;
267
268   esRegisterDrawFunc ( &esContext, Draw );
269
270   esMainLoop ( &esContext );
271
272   ShutDown ( &esContext );
273}
274