// // 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. // #define HOOK #include #include "esUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "esTransform.h" #include "eglutil.h" #include "dump_gl_screen.h" #include "viv_hook.h" static EGLint const config_attribute_list[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_DEPTH_SIZE, 16, EGL_STENCIL_SIZE, 8, EGL_NONE }; static EGLint const pbuffer_attribute_list[] = { EGL_WIDTH, 400, EGL_HEIGHT, 240, EGL_LARGEST_PBUFFER, EGL_TRUE, EGL_NONE }; static const EGLint context_attribute_list[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; int main(int argc, char *argv[]) { EGLDisplay display; EGLint egl_major, egl_minor; EGLConfig config; EGLint num_config; EGLContext context; EGLSurface surface; GLuint vertex_shader; GLuint fragment_shader; GLuint program; GLint ret; GLint width, height; #ifdef HOOK the_hook("/mnt/sdcard/egl2.fdr"); #endif const char *vertex_shader_source = "attribute vec4 a_position; \n" "void main() \n" "{ \n" " gl_Position = a_position; \n" "} \n"; const char *fragment_shader_source = "precision mediump float; \n" "uniform vec4 u_color; \n" "void main() \n" "{ \n" " gl_FragColor = u_color; \n" "} \n"; 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 }; display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (display == EGL_NO_DISPLAY) { printf("Error: No display found!\n"); return -1; } if (!eglInitialize(display, &egl_major, &egl_minor)) { printf("Error: eglInitialise failed!\n"); return -1; } printf("Using display %p with EGL version %d.%d\n", display, egl_major, egl_minor); printf("EGL Version \"%s\"\n", eglQueryString(display, EGL_VERSION)); printf("EGL Vendor \"%s\"\n", eglQueryString(display, EGL_VENDOR)); printf("EGL Extensions \"%s\"\n", eglQueryString(display, EGL_EXTENSIONS)); /* get an appropriate EGL frame buffer configuration */ eglChooseConfig(display, config_attribute_list, &config, 1, &num_config); /* create an EGL rendering context */ context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attribute_list); if (context == EGL_NO_CONTEXT) { printf("Error: eglCreateContext failed: %d\n", eglGetError()); return -1; } surface = eglCreatePbufferSurface(display, config, pbuffer_attribute_list); if (surface == EGL_NO_SURFACE) { printf("Error: eglCreatePbufferSurface failed: %d (%s)\n", eglGetError(), eglStrError(eglGetError())); return -1; } if (!eglQuerySurface(display, surface, EGL_WIDTH, &width) || !eglQuerySurface(display, surface, EGL_HEIGHT, &height)) { printf("Error: eglQuerySurface failed: %d (%s)\n", eglGetError(), eglStrError(eglGetError())); return -1; } printf("PBuffer: %dx%d\n", width, height); printf("GL Extensions \"%s\"\n", glGetString(GL_EXTENSIONS)); /* connect the context to the surface */ if (!eglMakeCurrent(display, surface, surface, context)) { printf("Error: eglMakeCurrent() failed: %d (%s)\n", eglGetError(), eglStrError(eglGetError())); return -1; } vertex_shader = glCreateShader(GL_VERTEX_SHADER); if (!vertex_shader) { printf("Error: glCreateShader(GL_VERTEX_SHADER) failed: %d (%s)\n", eglGetError(), eglStrError(eglGetError())); return -1; } glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); glCompileShader(vertex_shader); glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &ret); if (!ret) { char *log; printf("Error: vertex shader compilation failed!:\n"); glGetShaderiv(vertex_shader, GL_INFO_LOG_LENGTH, &ret); if (ret > 1) { log = malloc(ret); glGetShaderInfoLog(vertex_shader, ret, NULL, log); printf("%s", log); } return -1; } else printf("Vertex shader compilation succeeded!\n"); fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); if (!fragment_shader) { printf("Error: glCreateShader(GL_FRAGMENT_SHADER) failed: %d (%s)\n", eglGetError(), eglStrError(eglGetError())); return -1; } glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); glCompileShader(fragment_shader); glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &ret); if (!ret) { char *log; printf("Error: fragment shader compilation failed!:\n"); glGetShaderiv(fragment_shader, GL_INFO_LOG_LENGTH, &ret); if (ret > 1) { log = malloc(ret); glGetShaderInfoLog(fragment_shader, ret, NULL, log); printf("%s", log); } return -1; } else printf("Fragment shader compilation succeeded!\n"); program = glCreateProgram(); if (!program) { printf("Error: failed to create program!\n"); return -1; } glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glBindAttribLocation(program, 0, "in_position"); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &ret); if (!ret) { char *log; printf("Error: program linking failed!:\n"); glGetProgramiv(program, GL_INFO_LOG_LENGTH, &ret); if (ret > 1) { log = malloc(ret); glGetProgramInfoLog(program, ret, NULL, log); printf("%s", log); } return -1; } else printf("program linking succeeded!\n"); GLint colorLoc = glGetUniformLocation(program, "u_color"); glUseProgram(program); glViewport(0, 0, width, height); // 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 ); /* clear the color buffer */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Load the vertex position glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices ); glEnableVertexAttribArray ( 0 ); // 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 & 0x3 ) // // 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 ); printf("num stencil bits: %i\n", 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 ( int i = 0; i < NumTests; ++i ) { glStencilFunc( GL_EQUAL, stencilValues[i], 0xff ); glUniform4fv( colorLoc, 1, colors[i] ); glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices[4] ); } glFlush(); fflush(stdout); dump_gl_screen("/sdcard/egl2.bmp", width, height); #ifdef HOOK close_hook(); #endif return 0; }