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