1#include <assert.h> 2#include <string.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <math.h> 6#include <GL/glew.h> 7#include "glut_wrap.h" 8 9#define windowSize 100 10GLfloat tolerance[5]; 11struct ShaderProgram 12{ 13 const char *name; 14 const char *fragShaderString; 15 GLfloat expectedColor[4]; 16} Programs[] = { 17 { 18 "shadow2D(): 1", "uniform sampler2DShadow texZ; \n" 19 "void main() { \n" 20 " vec3 coord = vec3(0.1, 0.1, 0.5); \n" 21 " // shadow map value should be 0.25 \n" 22 " gl_FragColor = shadow2D(texZ, coord) + vec4(0.25); \n" 23 " // 0.5 <= 0.25 ? color = 1 : 0\n" "} \n", { 24 0.25, 0.25, 0.25, 1.0},}, { 25 "shadow2D(): 2", "uniform sampler2DShadow texZ; \n" 26 "void main() { \n" 27 " vec3 coord = vec3(0.1, 0.1, 0.2); \n" 28 " // shadow map value should be 0.25 \n" 29 " gl_FragColor = shadow2D(texZ, coord); \n" 30 " // 0.2 <= 0.25 ? color = 1 : 0\n" "} \n", { 31 1.0, 1.0, 1.0, 1.0},}, { 32 "shadow2D(): 3", "uniform sampler2DShadow texZ; \n" 33 "void main() { \n" 34 " vec3 coord = vec3(0.9, 0.9, 0.95); \n" 35 " // shadow map value should be 0.75 \n" 36 " gl_FragColor = shadow2D(texZ, coord) + vec4(0.25); \n" 37 " // 0.95 <= 0.75 ? color = 1 : 0\n" "} \n", { 38 0.25, 0.25, 0.25, 1.0},}, { 39 "shadow2D(): 4", "uniform sampler2DShadow texZ; \n" 40 "void main() { \n" 41 " vec3 coord = vec3(0.9, 0.9, 0.65); \n" 42 " // shadow map value should be 0.75 \n" 43 " gl_FragColor = shadow2D(texZ, coord); \n" 44 " // 0.65 <= 0.75 ? color = 1 : 0\n" "} \n", { 45 1.0, 1.0, 1.0, 1.0}}, { 46 NULL, NULL, { 470, 0, 0, 0}}}; 48 49static void 50setupTextures(void) 51{ 52 GLfloat teximageZ[16][16]; 53 GLint i, j; 54 GLuint objZ; 55 glGenTextures(1, &objZ); 56 57 /* 2D GL_DEPTH_COMPONENT texture (for shadow sampler tests) */ 58 for (i = 0; i < 16; i++) { 59 for (j = 0; j < 16; j++) { 60 if (j < 8) 61 teximageZ[i][j] = 0.25; 62 63 else 64 teximageZ[i][j] = 0.75; 65 } 66 } 67 glBindTexture(GL_TEXTURE_2D, objZ); 68 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 16, 16, 0, 69 GL_DEPTH_COMPONENT, GL_FLOAT, teximageZ); 70 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 71 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 72 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, 73 GL_COMPARE_R_TO_TEXTURE_ARB); 74} 75 76static void 77Init(void) 78{ 79 80 /* check GLSL version */ 81 GLenum err; 82 int bufferBits[5]; 83 const char *glslVersion = 84 (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); 85 if (!glslVersion || glslVersion[0] != '1') { 86 fprintf(stderr, "GLSL 1.x not supported\n"); 87 return; 88 } 89 setupTextures(); 90 err = glGetError(); 91 assert(!err); /* should be OK */ 92 93 /* setup vertex transform (we'll draw a quad in middle of window) */ 94 glMatrixMode(GL_PROJECTION); 95 glLoadIdentity(); 96 glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0); 97 glMatrixMode(GL_MODELVIEW); 98 glLoadIdentity(); 99 glDrawBuffer(GL_FRONT); 100 glReadBuffer(GL_FRONT); 101 102 /* compute error tolerances (may need fine-tuning) */ 103 glGetIntegerv(GL_RED_BITS, &bufferBits[0]); 104 glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]); 105 glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]); 106 glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]); 107 glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]); 108 tolerance[0] = 2.0 / (1 << bufferBits[0]); 109 tolerance[1] = 2.0 / (1 << bufferBits[1]); 110 tolerance[2] = 2.0 / (1 << bufferBits[2]); 111 if (bufferBits[3]) 112 tolerance[3] = 2.0 / (1 << bufferBits[3]); 113 114 else 115 tolerance[3] = 1.0; 116 if (bufferBits[4]) 117 tolerance[4] = 16.0 / (1 << bufferBits[4]); 118 119 else 120 tolerance[4] = 1.0; 121} 122 123static void 124reportFailure(const char *programName, const GLfloat expectedColor[4], 125 const GLfloat actualColor[4]) 126{ 127 fprintf(stdout, "FAILURE:\n"); 128 fprintf(stdout, " Shader test: %s\n", programName); 129 fprintf(stdout, " Expected color: [%1.3f, %1.3f, %1.3f, %1.3f]\n", 130 expectedColor[0], expectedColor[1], expectedColor[2], 131 expectedColor[3]); 132 fprintf(stdout, " Observed color: [%1.3f, %1.3f, %1.3f, %1.3f]\n", 133 actualColor[0], actualColor[1], actualColor[2], actualColor[3]); 134} static GLboolean 135 136equalColors(const GLfloat act[4], const GLfloat exp[4]) 137{ 138 const GLfloat *tol = tolerance; 139 if ((fabsf(act[0] - exp[0]) > tol[0]) || 140 (fabsf(act[1] - exp[1]) > tol[1]) || 141 (fabsf(act[2] - exp[2]) > tol[2]) || (fabsf(act[3] - exp[3]) > tol[3])) 142 return GL_FALSE; 143 144 else 145 return GL_TRUE; 146} 147 148static GLuint 149loadAndCompileShader(GLenum target, const char *str) 150{ 151 GLuint shader; 152 shader = glCreateShader(target); 153 glShaderSource(shader, 1, (const GLchar **) &str, NULL); 154 glCompileShader(shader); 155 return shader; 156} 157 158static GLboolean 159checkCompileStatus(GLenum target, GLuint shader, struct ShaderProgram p) 160{ 161 GLint stat; 162 GLchar infoLog[1000]; 163 GLsizei len; 164 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); 165 if (!stat) { 166 glGetShaderInfoLog(shader, 1000, &len, infoLog); 167 fprintf(stderr, "FAILURE:\n"); 168 fprintf(stderr, " Shader test: %s\n", p.name); 169 if (target == GL_FRAGMENT_SHADER) 170 fprintf(stderr, "Fragment shader did not compile:\n"); 171 172 else 173 fprintf(stderr, "Vertex shader did not compile:\n");; 174 fprintf(stderr, "%s\n", infoLog); 175 return GL_FALSE; 176 } 177 return GL_TRUE; 178} 179 180static GLboolean 181testProgram(struct ShaderProgram p) 182{ 183 const GLfloat r = 0.62; /* XXX draw 16x16 pixel quad */ 184 GLuint fragShader = 0, vertShader = 0, program = 0; 185 GLint utexZ; 186 GLboolean retVal = GL_FALSE; 187 GLfloat pixel[4]; 188 if (p.fragShaderString) { 189 fragShader = 190 loadAndCompileShader(GL_FRAGMENT_SHADER, p.fragShaderString); 191 if (!checkCompileStatus(GL_FRAGMENT_SHADER, fragShader, p)) { 192 retVal = GL_FALSE; 193 goto cleanup; 194 } 195 } 196 if (!fragShader && !vertShader) { 197 198 /* must have had a compilation errror */ 199 retVal = GL_FALSE; 200 goto cleanup; 201 } 202 program = glCreateProgram(); 203 if (fragShader) 204 glAttachShader(program, fragShader); 205 if (vertShader) 206 glAttachShader(program, vertShader); 207 glLinkProgram(program); 208 209 /* check link */ 210 { 211 GLint stat; 212 glGetProgramiv(program, GL_LINK_STATUS, &stat); 213 if (!stat) { 214 GLchar log[1000]; 215 GLsizei len; 216 glGetProgramInfoLog(program, 1000, &len, log); 217 fprintf(stderr, "FAILURE:\n"); 218 fprintf(stderr, " Shader test: %s\n", p.name);; 219 fprintf(stderr, " Link error: ");; 220 fprintf(stderr, "%s\n", log); 221 retVal = GL_FALSE; 222 goto cleanup; 223 } 224 } 225 glUseProgram(program); 226 227 /* load uniform vars */ 228 utexZ = glGetUniformLocation(program, "texZ"); 229 assert(utexZ >= 0); 230 glUniform1i(utexZ, 0); /* bind to tex unit 0 */ 231 232 /* to avoid potential issue with undefined result.depth.z */ 233 glDisable(GL_DEPTH_TEST); 234 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 235 236 /* Counter Clockwise */ 237 glBegin(GL_POLYGON); 238 glTexCoord2f(0, 0); 239 glVertex2f(-r, -r); 240 glTexCoord2f(1, 0); 241 glVertex2f(r, -r); 242 glTexCoord2f(1, 1); 243 glVertex2f(r, r); 244 glTexCoord2f(0, 1); 245 glVertex2f(-r, r); 246 glEnd(); 247 248 /* read a pixel from lower-left corder of rendered quad */ 249 glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1, GL_RGBA, 250 GL_FLOAT, pixel); 251 if (!equalColors(pixel, p.expectedColor)) { 252 reportFailure(p.name, p.expectedColor, pixel); 253 retVal = GL_FALSE; 254 goto cleanup; 255 } 256 257 /* passed! */ 258 retVal = GL_TRUE; 259 260 cleanup: 261 if (fragShader) 262 glDeleteShader(fragShader); 263 if (vertShader) 264 glDeleteShader(vertShader); 265 glDeleteProgram(program); 266 return retVal; 267} 268 269static void 270Display(void) 271{ 272 int i, numPassed = 0, numFailed = 0; 273 for (i = 0; Programs[i].name; i++) { 274 if (testProgram(Programs[i])) { 275 numPassed++; 276 } 277 278 else { 279 numFailed++; 280 } 281 glFinish(); 282 } 283 fprintf(stderr, "Total = %d. Passed = %d. Failed = %d\n", 284 numPassed + numFailed, numPassed, numFailed); 285} 286 287static void 288Reshape(int width, int height) 289{ 290} static void 291 292Key(unsigned char key, int x, int y) 293{ 294 (void) x; 295 (void) y; 296 switch (key) { 297 case 27: 298 exit(0); 299 break; 300 } 301 glutPostRedisplay(); 302} 303 304int 305main(int argc, char *argv[]) 306{ 307 glutInit(&argc, argv); 308 glutInitWindowPosition(0, 0); 309 glutInitWindowSize(windowSize, windowSize); 310 glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_SINGLE | GLUT_ALPHA); 311 glutCreateWindow(argv[0]); 312 glewInit(); 313 glutReshapeFunc(Reshape); 314 glutKeyboardFunc(Key); 315 glutDisplayFunc(Display); 316 Init(); 317 glutMainLoop(); 318 return 0; 319} 320