132001f49Smrg#include <assert.h> 232001f49Smrg#include <string.h> 332001f49Smrg#include <stdio.h> 432001f49Smrg#include <stdlib.h> 532001f49Smrg#include <math.h> 632001f49Smrg#include <GL/glew.h> 732001f49Smrg#include "glut_wrap.h" 832001f49Smrg 932001f49Smrg#define windowSize 100 1032001f49SmrgGLfloat tolerance[5]; 1132001f49Smrgstruct ShaderProgram 1232001f49Smrg{ 1332001f49Smrg const char *name; 1432001f49Smrg const char *fragShaderString; 1532001f49Smrg GLfloat expectedColor[4]; 1632001f49Smrg} Programs[] = { 1732001f49Smrg { 1832001f49Smrg "shadow2D(): 1", "uniform sampler2DShadow texZ; \n" 1932001f49Smrg "void main() { \n" 2032001f49Smrg " vec3 coord = vec3(0.1, 0.1, 0.5); \n" 2132001f49Smrg " // shadow map value should be 0.25 \n" 2232001f49Smrg " gl_FragColor = shadow2D(texZ, coord) + vec4(0.25); \n" 2332001f49Smrg " // 0.5 <= 0.25 ? color = 1 : 0\n" "} \n", { 2432001f49Smrg 0.25, 0.25, 0.25, 1.0},}, { 2532001f49Smrg "shadow2D(): 2", "uniform sampler2DShadow texZ; \n" 2632001f49Smrg "void main() { \n" 2732001f49Smrg " vec3 coord = vec3(0.1, 0.1, 0.2); \n" 2832001f49Smrg " // shadow map value should be 0.25 \n" 2932001f49Smrg " gl_FragColor = shadow2D(texZ, coord); \n" 3032001f49Smrg " // 0.2 <= 0.25 ? color = 1 : 0\n" "} \n", { 3132001f49Smrg 1.0, 1.0, 1.0, 1.0},}, { 3232001f49Smrg "shadow2D(): 3", "uniform sampler2DShadow texZ; \n" 3332001f49Smrg "void main() { \n" 3432001f49Smrg " vec3 coord = vec3(0.9, 0.9, 0.95); \n" 3532001f49Smrg " // shadow map value should be 0.75 \n" 3632001f49Smrg " gl_FragColor = shadow2D(texZ, coord) + vec4(0.25); \n" 3732001f49Smrg " // 0.95 <= 0.75 ? color = 1 : 0\n" "} \n", { 3832001f49Smrg 0.25, 0.25, 0.25, 1.0},}, { 3932001f49Smrg "shadow2D(): 4", "uniform sampler2DShadow texZ; \n" 4032001f49Smrg "void main() { \n" 4132001f49Smrg " vec3 coord = vec3(0.9, 0.9, 0.65); \n" 4232001f49Smrg " // shadow map value should be 0.75 \n" 4332001f49Smrg " gl_FragColor = shadow2D(texZ, coord); \n" 4432001f49Smrg " // 0.65 <= 0.75 ? color = 1 : 0\n" "} \n", { 4532001f49Smrg 1.0, 1.0, 1.0, 1.0}}, { 4632001f49Smrg NULL, NULL, { 4732001f49Smrg0, 0, 0, 0}}}; 4832001f49Smrg 4932001f49Smrgstatic void 5032001f49SmrgsetupTextures(void) 5132001f49Smrg{ 5232001f49Smrg GLfloat teximageZ[16][16]; 5332001f49Smrg GLint i, j; 5432001f49Smrg GLuint objZ; 5532001f49Smrg glGenTextures(1, &objZ); 5632001f49Smrg 5732001f49Smrg /* 2D GL_DEPTH_COMPONENT texture (for shadow sampler tests) */ 5832001f49Smrg for (i = 0; i < 16; i++) { 5932001f49Smrg for (j = 0; j < 16; j++) { 6032001f49Smrg if (j < 8) 6132001f49Smrg teximageZ[i][j] = 0.25; 6232001f49Smrg 6332001f49Smrg else 6432001f49Smrg teximageZ[i][j] = 0.75; 6532001f49Smrg } 6632001f49Smrg } 6732001f49Smrg glBindTexture(GL_TEXTURE_2D, objZ); 6832001f49Smrg glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 16, 16, 0, 6932001f49Smrg GL_DEPTH_COMPONENT, GL_FLOAT, teximageZ); 7032001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 7132001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 7232001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, 7332001f49Smrg GL_COMPARE_R_TO_TEXTURE_ARB); 7432001f49Smrg} 7532001f49Smrg 7632001f49Smrgstatic void 7732001f49SmrgInit(void) 7832001f49Smrg{ 7932001f49Smrg 8032001f49Smrg /* check GLSL version */ 8132001f49Smrg GLenum err; 8232001f49Smrg int bufferBits[5]; 8332001f49Smrg const char *glslVersion = 8432001f49Smrg (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION); 8532001f49Smrg if (!glslVersion || glslVersion[0] != '1') { 8632001f49Smrg fprintf(stderr, "GLSL 1.x not supported\n"); 8732001f49Smrg return; 8832001f49Smrg } 8932001f49Smrg setupTextures(); 9032001f49Smrg err = glGetError(); 9132001f49Smrg assert(!err); /* should be OK */ 9232001f49Smrg 9332001f49Smrg /* setup vertex transform (we'll draw a quad in middle of window) */ 9432001f49Smrg glMatrixMode(GL_PROJECTION); 9532001f49Smrg glLoadIdentity(); 9632001f49Smrg glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0); 9732001f49Smrg glMatrixMode(GL_MODELVIEW); 9832001f49Smrg glLoadIdentity(); 9932001f49Smrg glDrawBuffer(GL_FRONT); 10032001f49Smrg glReadBuffer(GL_FRONT); 10132001f49Smrg 10232001f49Smrg /* compute error tolerances (may need fine-tuning) */ 10332001f49Smrg glGetIntegerv(GL_RED_BITS, &bufferBits[0]); 10432001f49Smrg glGetIntegerv(GL_GREEN_BITS, &bufferBits[1]); 10532001f49Smrg glGetIntegerv(GL_BLUE_BITS, &bufferBits[2]); 10632001f49Smrg glGetIntegerv(GL_ALPHA_BITS, &bufferBits[3]); 10732001f49Smrg glGetIntegerv(GL_DEPTH_BITS, &bufferBits[4]); 10832001f49Smrg tolerance[0] = 2.0 / (1 << bufferBits[0]); 10932001f49Smrg tolerance[1] = 2.0 / (1 << bufferBits[1]); 11032001f49Smrg tolerance[2] = 2.0 / (1 << bufferBits[2]); 11132001f49Smrg if (bufferBits[3]) 11232001f49Smrg tolerance[3] = 2.0 / (1 << bufferBits[3]); 11332001f49Smrg 11432001f49Smrg else 11532001f49Smrg tolerance[3] = 1.0; 11632001f49Smrg if (bufferBits[4]) 11732001f49Smrg tolerance[4] = 16.0 / (1 << bufferBits[4]); 11832001f49Smrg 11932001f49Smrg else 12032001f49Smrg tolerance[4] = 1.0; 12132001f49Smrg} 12232001f49Smrg 12332001f49Smrgstatic void 12432001f49SmrgreportFailure(const char *programName, const GLfloat expectedColor[4], 12532001f49Smrg const GLfloat actualColor[4]) 12632001f49Smrg{ 12732001f49Smrg fprintf(stdout, "FAILURE:\n"); 12832001f49Smrg fprintf(stdout, " Shader test: %s\n", programName); 12932001f49Smrg fprintf(stdout, " Expected color: [%1.3f, %1.3f, %1.3f, %1.3f]\n", 13032001f49Smrg expectedColor[0], expectedColor[1], expectedColor[2], 13132001f49Smrg expectedColor[3]); 13232001f49Smrg fprintf(stdout, " Observed color: [%1.3f, %1.3f, %1.3f, %1.3f]\n", 13332001f49Smrg actualColor[0], actualColor[1], actualColor[2], actualColor[3]); 13432001f49Smrg} static GLboolean 13532001f49Smrg 13632001f49SmrgequalColors(const GLfloat act[4], const GLfloat exp[4]) 13732001f49Smrg{ 13832001f49Smrg const GLfloat *tol = tolerance; 13932001f49Smrg if ((fabsf(act[0] - exp[0]) > tol[0]) || 14032001f49Smrg (fabsf(act[1] - exp[1]) > tol[1]) || 14132001f49Smrg (fabsf(act[2] - exp[2]) > tol[2]) || (fabsf(act[3] - exp[3]) > tol[3])) 14232001f49Smrg return GL_FALSE; 14332001f49Smrg 14432001f49Smrg else 14532001f49Smrg return GL_TRUE; 14632001f49Smrg} 14732001f49Smrg 14832001f49Smrgstatic GLuint 14932001f49SmrgloadAndCompileShader(GLenum target, const char *str) 15032001f49Smrg{ 15132001f49Smrg GLuint shader; 15232001f49Smrg shader = glCreateShader(target); 15332001f49Smrg glShaderSource(shader, 1, (const GLchar **) &str, NULL); 15432001f49Smrg glCompileShader(shader); 15532001f49Smrg return shader; 15632001f49Smrg} 15732001f49Smrg 15832001f49Smrgstatic GLboolean 15932001f49SmrgcheckCompileStatus(GLenum target, GLuint shader, struct ShaderProgram p) 16032001f49Smrg{ 16132001f49Smrg GLint stat; 16232001f49Smrg GLchar infoLog[1000]; 16332001f49Smrg GLsizei len; 16432001f49Smrg glGetShaderiv(shader, GL_COMPILE_STATUS, &stat); 16532001f49Smrg if (!stat) { 16632001f49Smrg glGetShaderInfoLog(shader, 1000, &len, infoLog); 16732001f49Smrg fprintf(stderr, "FAILURE:\n"); 16832001f49Smrg fprintf(stderr, " Shader test: %s\n", p.name); 16932001f49Smrg if (target == GL_FRAGMENT_SHADER) 17032001f49Smrg fprintf(stderr, "Fragment shader did not compile:\n"); 17132001f49Smrg 17232001f49Smrg else 17332001f49Smrg fprintf(stderr, "Vertex shader did not compile:\n");; 17432001f49Smrg fprintf(stderr, "%s\n", infoLog); 17532001f49Smrg return GL_FALSE; 17632001f49Smrg } 17732001f49Smrg return GL_TRUE; 17832001f49Smrg} 17932001f49Smrg 18032001f49Smrgstatic GLboolean 18132001f49SmrgtestProgram(struct ShaderProgram p) 18232001f49Smrg{ 18332001f49Smrg const GLfloat r = 0.62; /* XXX draw 16x16 pixel quad */ 18432001f49Smrg GLuint fragShader = 0, vertShader = 0, program = 0; 18532001f49Smrg GLint utexZ; 18632001f49Smrg GLboolean retVal = GL_FALSE; 18732001f49Smrg GLfloat pixel[4]; 18832001f49Smrg if (p.fragShaderString) { 18932001f49Smrg fragShader = 19032001f49Smrg loadAndCompileShader(GL_FRAGMENT_SHADER, p.fragShaderString); 19132001f49Smrg if (!checkCompileStatus(GL_FRAGMENT_SHADER, fragShader, p)) { 19232001f49Smrg retVal = GL_FALSE; 19332001f49Smrg goto cleanup; 19432001f49Smrg } 19532001f49Smrg } 19632001f49Smrg if (!fragShader && !vertShader) { 19732001f49Smrg 19832001f49Smrg /* must have had a compilation errror */ 19932001f49Smrg retVal = GL_FALSE; 20032001f49Smrg goto cleanup; 20132001f49Smrg } 20232001f49Smrg program = glCreateProgram(); 20332001f49Smrg if (fragShader) 20432001f49Smrg glAttachShader(program, fragShader); 20532001f49Smrg if (vertShader) 20632001f49Smrg glAttachShader(program, vertShader); 20732001f49Smrg glLinkProgram(program); 20832001f49Smrg 20932001f49Smrg /* check link */ 21032001f49Smrg { 21132001f49Smrg GLint stat; 21232001f49Smrg glGetProgramiv(program, GL_LINK_STATUS, &stat); 21332001f49Smrg if (!stat) { 21432001f49Smrg GLchar log[1000]; 21532001f49Smrg GLsizei len; 21632001f49Smrg glGetProgramInfoLog(program, 1000, &len, log); 21732001f49Smrg fprintf(stderr, "FAILURE:\n"); 21832001f49Smrg fprintf(stderr, " Shader test: %s\n", p.name);; 21932001f49Smrg fprintf(stderr, " Link error: ");; 22032001f49Smrg fprintf(stderr, "%s\n", log); 22132001f49Smrg retVal = GL_FALSE; 22232001f49Smrg goto cleanup; 22332001f49Smrg } 22432001f49Smrg } 22532001f49Smrg glUseProgram(program); 22632001f49Smrg 22732001f49Smrg /* load uniform vars */ 22832001f49Smrg utexZ = glGetUniformLocation(program, "texZ"); 22932001f49Smrg assert(utexZ >= 0); 23032001f49Smrg glUniform1i(utexZ, 0); /* bind to tex unit 0 */ 23132001f49Smrg 23232001f49Smrg /* to avoid potential issue with undefined result.depth.z */ 23332001f49Smrg glDisable(GL_DEPTH_TEST); 23432001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 23532001f49Smrg 23632001f49Smrg /* Counter Clockwise */ 23732001f49Smrg glBegin(GL_POLYGON); 23832001f49Smrg glTexCoord2f(0, 0); 23932001f49Smrg glVertex2f(-r, -r); 24032001f49Smrg glTexCoord2f(1, 0); 24132001f49Smrg glVertex2f(r, -r); 24232001f49Smrg glTexCoord2f(1, 1); 24332001f49Smrg glVertex2f(r, r); 24432001f49Smrg glTexCoord2f(0, 1); 24532001f49Smrg glVertex2f(-r, r); 24632001f49Smrg glEnd(); 24732001f49Smrg 24832001f49Smrg /* read a pixel from lower-left corder of rendered quad */ 24932001f49Smrg glReadPixels(windowSize / 2 - 2, windowSize / 2 - 2, 1, 1, GL_RGBA, 25032001f49Smrg GL_FLOAT, pixel); 25132001f49Smrg if (!equalColors(pixel, p.expectedColor)) { 25232001f49Smrg reportFailure(p.name, p.expectedColor, pixel); 25332001f49Smrg retVal = GL_FALSE; 25432001f49Smrg goto cleanup; 25532001f49Smrg } 25632001f49Smrg 25732001f49Smrg /* passed! */ 25832001f49Smrg retVal = GL_TRUE; 25932001f49Smrg 26032001f49Smrg cleanup: 26132001f49Smrg if (fragShader) 26232001f49Smrg glDeleteShader(fragShader); 26332001f49Smrg if (vertShader) 26432001f49Smrg glDeleteShader(vertShader); 26532001f49Smrg glDeleteProgram(program); 26632001f49Smrg return retVal; 26732001f49Smrg} 26832001f49Smrg 26932001f49Smrgstatic void 27032001f49SmrgDisplay(void) 27132001f49Smrg{ 27232001f49Smrg int i, numPassed = 0, numFailed = 0; 27332001f49Smrg for (i = 0; Programs[i].name; i++) { 27432001f49Smrg if (testProgram(Programs[i])) { 27532001f49Smrg numPassed++; 27632001f49Smrg } 27732001f49Smrg 27832001f49Smrg else { 27932001f49Smrg numFailed++; 28032001f49Smrg } 28132001f49Smrg glFinish(); 28232001f49Smrg } 28332001f49Smrg fprintf(stderr, "Total = %d. Passed = %d. Failed = %d\n", 28432001f49Smrg numPassed + numFailed, numPassed, numFailed); 28532001f49Smrg} 28632001f49Smrg 28732001f49Smrgstatic void 28832001f49SmrgReshape(int width, int height) 28932001f49Smrg{ 29032001f49Smrg} static void 29132001f49Smrg 29232001f49SmrgKey(unsigned char key, int x, int y) 29332001f49Smrg{ 29432001f49Smrg (void) x; 29532001f49Smrg (void) y; 29632001f49Smrg switch (key) { 29732001f49Smrg case 27: 29832001f49Smrg exit(0); 29932001f49Smrg break; 30032001f49Smrg } 30132001f49Smrg glutPostRedisplay(); 30232001f49Smrg} 30332001f49Smrg 30432001f49Smrgint 30532001f49Smrgmain(int argc, char *argv[]) 30632001f49Smrg{ 30732001f49Smrg glutInit(&argc, argv); 30832001f49Smrg glutInitWindowPosition(0, 0); 30932001f49Smrg glutInitWindowSize(windowSize, windowSize); 31032001f49Smrg glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA | GLUT_SINGLE | GLUT_ALPHA); 31132001f49Smrg glutCreateWindow(argv[0]); 31232001f49Smrg glewInit(); 31332001f49Smrg glutReshapeFunc(Reshape); 31432001f49Smrg glutKeyboardFunc(Key); 31532001f49Smrg glutDisplayFunc(Display); 31632001f49Smrg Init(); 31732001f49Smrg glutMainLoop(); 31832001f49Smrg return 0; 31932001f49Smrg} 320