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