1// 2// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6 7// Based on Stencil_Test.c from 8// Book: OpenGL(R) ES 2.0 Programming Guide 9// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 10// ISBN-10: 0321502795 11// ISBN-13: 9780321502797 12// Publisher: Addison-Wesley Professional 13// URLs: http://safari.informit.com/9780321563835 14// http://www.opengles-book.com 15 16#include "SampleApplication.h" 17#include "shader_utils.h" 18 19class StencilOperationsSample : public SampleApplication 20{ 21 public: 22 StencilOperationsSample::StencilOperationsSample() 23 : SampleApplication("StencilOperations", 1280, 720) 24 { 25 } 26 27 virtual bool initialize() 28 { 29 const std::string vs = SHADER_SOURCE 30 ( 31 attribute vec4 a_position; 32 void main() 33 { 34 gl_Position = a_position; 35 } 36 ); 37 38 const std::string fs = SHADER_SOURCE 39 ( 40 precision mediump float; 41 uniform vec4 u_color; 42 void main() 43 { 44 gl_FragColor = u_color; 45 } 46 ); 47 48 mProgram = CompileProgram(vs, fs); 49 if (!mProgram) 50 { 51 return false; 52 } 53 54 // Get the attribute locations 55 mPositionLoc = glGetAttribLocation(mProgram, "a_position"); 56 57 // Get the sampler location 58 mColorLoc = glGetUniformLocation(mProgram, "u_color"); 59 60 // Set the clear color 61 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 62 63 // Set the stencil clear value 64 glClearStencil(0x01); 65 66 // Set the depth clear value 67 glClearDepthf(0.75f); 68 69 // Enable the depth and stencil tests 70 glEnable(GL_DEPTH_TEST); 71 glEnable(GL_STENCIL_TEST); 72 73 return true; 74 } 75 76 virtual void destroy() 77 { 78 glDeleteProgram(mProgram); 79 } 80 81 virtual void draw() 82 { 83 GLfloat vertices[] = 84 { 85 -0.75f, 0.25f, 0.50f, // Quad #0 86 -0.25f, 0.25f, 0.50f, 87 -0.25f, 0.75f, 0.50f, 88 -0.75f, 0.75f, 0.50f, 89 0.25f, 0.25f, 0.90f, // Quad #1 90 0.75f, 0.25f, 0.90f, 91 0.75f, 0.75f, 0.90f, 92 0.25f, 0.75f, 0.90f, 93 -0.75f, -0.75f, 0.50f, // Quad #2 94 -0.25f, -0.75f, 0.50f, 95 -0.25f, -0.25f, 0.50f, 96 -0.75f, -0.25f, 0.50f, 97 0.25f, -0.75f, 0.50f, // Quad #3 98 0.75f, -0.75f, 0.50f, 99 0.75f, -0.25f, 0.50f, 100 0.25f, -0.25f, 0.50f, 101 -1.00f, -1.00f, 0.00f, // Big Quad 102 1.00f, -1.00f, 0.00f, 103 1.00f, 1.00f, 0.00f, 104 -1.00f, 1.00f, 0.00f, 105 }; 106 107 GLubyte indices[][6] = 108 { 109 { 0, 1, 2, 0, 2, 3 }, // Quad #0 110 { 4, 5, 6, 4, 6, 7 }, // Quad #1 111 { 8, 9, 10, 8, 10, 11 }, // Quad #2 112 { 12, 13, 14, 12, 14, 15 }, // Quad #3 113 { 16, 17, 18, 16, 18, 19 }, // Big Quad 114 }; 115 116 static const size_t testCount = 4; 117 GLfloat colors[testCount][4] = 118 { 119 { 1.0f, 0.0f, 0.0f, 1.0f }, 120 { 0.0f, 1.0f, 0.0f, 1.0f }, 121 { 0.0f, 0.0f, 1.0f, 1.0f }, 122 { 1.0f, 1.0f, 0.0f, 0.0f }, 123 }; 124 125 GLuint stencilValues[testCount] = 126 { 127 0x7, // Result of test 0 128 0x0, // Result of test 1 129 0x2, // Result of test 2 130 0xff // Result of test 3. We need to fill this value in at run-time 131 }; 132 133 // Set the viewport 134 glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight()); 135 136 // Clear the color, depth, and stencil buffers. At this point, the stencil 137 // buffer will be 0x1 for all pixels 138 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 139 140 // Use the program object 141 glUseProgram(mProgram); 142 143 // Load the vertex data 144 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, vertices); 145 glEnableVertexAttribArray(mPositionLoc); 146 147 // Test 0: 148 // 149 // Initialize upper-left region. In this case, the stencil-buffer values will 150 // be replaced because the stencil test for the rendered pixels will fail the 151 // stencil test, which is 152 // 153 // ref mask stencil mask 154 // ( 0x7 & 0x3 ) < ( 0x1 & 0x7 ) 155 // 156 // The value in the stencil buffer for these pixels will be 0x7. 157 glStencilFunc(GL_LESS, 0x7, 0x3); 158 glStencilOp(GL_REPLACE, GL_DECR, GL_DECR); 159 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[0]); 160 161 // Test 1: 162 // 163 // Initialize the upper-right region. Here, we'll decrement the stencil-buffer 164 // values where the stencil test passes but the depth test fails. The stencil test is 165 // 166 // ref mask stencil mask 167 // ( 0x3 & 0x3 ) > ( 0x1 & 0x3 ) 168 // 169 // but where the geometry fails the depth test. The stencil values for these pixels 170 // will be 0x0. 171 glStencilFunc(GL_GREATER, 0x3, 0x3); 172 glStencilOp(GL_KEEP, GL_DECR, GL_KEEP); 173 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[1]); 174 175 // Test 2: 176 // 177 // Initialize the lower-left region. Here we'll increment (with saturation) the 178 // stencil value where both the stencil and depth tests pass. The stencil test for 179 // these pixels will be 180 // 181 // ref mask stencil mask 182 // ( 0x1 & 0x3 ) == ( 0x1 & 0x3 ) 183 // 184 // The stencil values for these pixels will be 0x2. 185 glStencilFunc(GL_EQUAL, 0x1, 0x3); 186 glStencilOp(GL_KEEP, GL_INCR, GL_INCR); 187 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[2]); 188 189 // Test 3: 190 // 191 // Finally, initialize the lower-right region. We'll invert the stencil value 192 // where the stencil tests fails. The stencil test for these pixels will be 193 // 194 // ref mask stencil mask 195 // ( 0x2 & 0x1 ) == ( 0x1 & 0x1 ) 196 // 197 // The stencil value here will be set to ~((2^s-1) & 0x1), (with the 0x1 being 198 // from the stencil clear value), where 's' is the number of bits in the stencil 199 // buffer 200 glStencilFunc(GL_EQUAL, 0x2, 0x1); 201 glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP); 202 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[3]); 203 204 // Since we don't know at compile time how many stencil bits are present, we'll 205 // query, and update the value correct value in the stencilValues arrays for the 206 // fourth tests. We'll use this value later in rendering. 207 GLint stencilBitCount; 208 glGetIntegerv(GL_STENCIL_BITS, &stencilBitCount); 209 stencilValues[3] = ~(((1 << stencilBitCount) - 1) & 0x1) & 0xff; 210 211 // Use the stencil buffer for controlling where rendering will occur. We disable 212 // writing to the stencil buffer so we can test against them without modifying 213 // the values we generated. 214 glStencilMask(0x0); 215 216 for (size_t i = 0; i < testCount; ++i) 217 { 218 glStencilFunc(GL_EQUAL, stencilValues[i], 0xff); 219 glUniform4fv(mColorLoc, 1, colors[i]); 220 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[4]); 221 } 222 223 // Reset the stencil mask 224 glStencilMask(0xFF); 225 } 226 227 private: 228 // Handle to a program object 229 GLuint mProgram; 230 231 // Attribute locations 232 GLint mPositionLoc; 233 234 // Uniform locations 235 GLint mColorLoc; 236}; 237 238int main(int argc, char **argv) 239{ 240 StencilOperationsSample app; 241 return app.run(); 242} 243