Fix FBO completeness bug in shadowtex.
[mesa.git] / progs / demos / shadowtex.c
1 /*
2 * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and
3 * GL_ARB_shadow_ambient extensions.
4 *
5 * Brian Paul
6 * 19 Feb 2001
7 *
8 * Added GL_EXT_shadow_funcs support on 23 March 2002
9 * Added GL_EXT_packed_depth_stencil support on 15 March 2006.
10 * Added GL_EXT_framebuffer_object support on 27 March 2006.
11 * Removed old SGIX extension support on 5 April 2006.
12 *
13 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included
23 * in all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
29 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 */
32
33 #define GL_GLEXT_PROTOTYPES
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <math.h>
38 #include <GL/glut.h>
39 #include "showbuffer.h"
40
41 #define DEG_TO_RAD (3.14159 / 180.0)
42
43 static GLint WindowWidth = 450, WindowHeight = 300;
44 static GLfloat Xrot = 15, Yrot = 0, Zrot = 0;
45
46 static GLfloat Red[4] = {1, 0, 0, 1};
47 static GLfloat Green[4] = {0, 1, 0, 1};
48 static GLfloat Blue[4] = {0, 0, 1, 1};
49 static GLfloat Yellow[4] = {1, 1, 0, 1};
50
51 static GLfloat LightDist = 10;
52 static GLfloat LightLatitude = 45.0;
53 static GLfloat LightLongitude = 45.0;
54 static GLfloat LightPos[4];
55 static GLfloat SpotDir[3];
56 static GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
57 static GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
58 static GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
59
60 static GLboolean LinearFilter = GL_FALSE;
61
62 static GLfloat Bias = -0.06;
63
64 static GLboolean Anim = GL_TRUE;
65
66 static GLboolean NeedNewShadowMap = GL_FALSE;
67 static GLuint ShadowTexture, GrayTexture;
68 static GLuint ShadowFBO;
69
70 static GLboolean HaveFBO = GL_FALSE;
71 static GLboolean UseFBO = GL_FALSE;
72 static GLboolean HavePackedDepthStencil = GL_FALSE;
73 static GLboolean UsePackedDepthStencil = GL_FALSE;
74 static GLboolean HaveEXTshadowFuncs = GL_FALSE;
75 static GLboolean HaveShadowAmbient = GL_FALSE;
76
77 static GLint Operator = 0;
78 static const GLenum OperatorFunc[8] = {
79 GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER,
80 GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER };
81 static const char *OperatorName[8] = {
82 "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
83 "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
84
85
86 static GLuint DisplayMode;
87 #define SHOW_SHADOWS 0
88 #define SHOW_DEPTH_IMAGE 1
89 #define SHOW_DEPTH_MAPPING 2
90 #define SHOW_DISTANCE 3
91
92
93
94 static void
95 DrawScene(void)
96 {
97 GLfloat k = 6;
98
99 /* sphere */
100 glPushMatrix();
101 glTranslatef(1.6, 2.2, 2.7);
102 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green);
103 glColor4fv(Green);
104 glutSolidSphere(1.5, 15, 15);
105 glPopMatrix();
106 /* dodecahedron */
107 glPushMatrix();
108 glTranslatef(-2.0, 1.2, 2.1);
109 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
110 glColor4fv(Red);
111 glutSolidDodecahedron();
112 glPopMatrix();
113 /* icosahedron */
114 glPushMatrix();
115 glTranslatef(-0.6, 1.3, -0.5);
116 glScalef(1.5, 1.5, 1.5);
117 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow);
118 glColor4fv(Red);
119 glutSolidIcosahedron();
120 glPopMatrix();
121 /* a plane */
122 glPushMatrix();
123 glTranslatef(0, -1.1, 0);
124 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
125 glColor4fv(Blue);
126 glNormal3f(0, 1, 0);
127 glBegin(GL_POLYGON);
128 glVertex3f(-k, 0, -k);
129 glVertex3f( k, 0, -k);
130 glVertex3f( k, 0, k);
131 glVertex3f(-k, 0, k);
132 glEnd();
133 glPopMatrix();
134 }
135
136
137 /*
138 * Load the GL_TEXTURE matrix with the projection from the light
139 * source's point of view.
140 */
141 static void
142 MakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
143 GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
144 {
145 GLfloat d;
146
147 glMatrixMode(GL_TEXTURE);
148 glLoadIdentity();
149 glTranslatef(0.5, 0.5, 0.5 + Bias);
150 glScalef(0.5, 0.5, 0.5);
151 d = shadowNear * tan(spotAngle);
152 glFrustum(-d, d, -d, d, shadowNear, shadowFar);
153 gluLookAt(lightPos[0], lightPos[1], lightPos[2],
154 lightPos[0] + spotDir[0],
155 lightPos[1] + spotDir[1],
156 lightPos[2] + spotDir[2],
157 0, 1, 0);
158 glMatrixMode(GL_MODELVIEW);
159 }
160
161
162 static void
163 EnableIdentityTexgen(void)
164 {
165 /* texgen so that texcoord = vertex coord */
166 static GLfloat sPlane[4] = { 1, 0, 0, 0 };
167 static GLfloat tPlane[4] = { 0, 1, 0, 0 };
168 static GLfloat rPlane[4] = { 0, 0, 1, 0 };
169 static GLfloat qPlane[4] = { 0, 0, 0, 1 };
170
171 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
172 glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
173 glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
174 glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
175 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
176 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
177 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
178 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
179
180 glEnable(GL_TEXTURE_GEN_S);
181 glEnable(GL_TEXTURE_GEN_T);
182 glEnable(GL_TEXTURE_GEN_R);
183 glEnable(GL_TEXTURE_GEN_Q);
184 }
185
186
187 /*
188 * Setup 1-D texgen so that the distance from the light source, between
189 * the near and far planes maps to s=0 and s=1. When we draw the scene,
190 * the grayness will indicate the fragment's distance from the light
191 * source.
192 */
193 static void
194 EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
195 GLfloat lightNear, GLfloat lightFar)
196 {
197 GLfloat m, d;
198 GLfloat sPlane[4];
199 GLfloat nearPoint[3];
200
201 m = sqrt(lightDir[0] * lightDir[0] +
202 lightDir[1] * lightDir[1] +
203 lightDir[2] * lightDir[2]);
204
205 d = lightFar - lightNear;
206
207 /* nearPoint = point on light direction vector which intersects the
208 * near plane of the light frustum.
209 */
210 nearPoint[0] = lightPos[0] + lightDir[0] / m * lightNear;
211 nearPoint[1] = lightPos[1] + lightDir[1] / m * lightNear;
212 nearPoint[2] = lightPos[2] + lightDir[2] / m * lightNear;
213
214 sPlane[0] = lightDir[0] / d / m;
215 sPlane[1] = lightDir[1] / d / m;
216 sPlane[2] = lightDir[2] / d / m;
217 sPlane[3] = -(sPlane[0] * nearPoint[0]
218 + sPlane[1] * nearPoint[1]
219 + sPlane[2] * nearPoint[2]);
220
221 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
222 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
223 glEnable(GL_TEXTURE_GEN_S);
224 }
225
226
227 static void
228 DisableTexgen(void)
229 {
230 glDisable(GL_TEXTURE_GEN_S);
231 glDisable(GL_TEXTURE_GEN_T);
232 glDisable(GL_TEXTURE_GEN_R);
233 glDisable(GL_TEXTURE_GEN_Q);
234 }
235
236
237 static void
238 ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
239 GLfloat pos[4], GLfloat dir[3])
240 {
241
242 pos[0] = dist * sin(longitude * DEG_TO_RAD);
243 pos[1] = dist * sin(latitude * DEG_TO_RAD);
244 pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
245 pos[3] = 1;
246 dir[0] = -pos[0];
247 dir[1] = -pos[1];
248 dir[2] = -pos[2];
249 }
250
251
252 /**
253 * Render the shadow map / depth texture.
254 * The result will be in the texture object named ShadowTexture.
255 */
256 static void
257 RenderShadowMap(void)
258 {
259 GLenum depthFormat; /* GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT */
260 GLenum depthType; /* GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT */
261 float d;
262
263 if (WindowWidth >= 1024 && WindowHeight >= 1024) {
264 ShadowTexWidth = ShadowTexHeight = 1024;
265 }
266 else if (WindowWidth >= 512 && WindowHeight >= 512) {
267 ShadowTexWidth = ShadowTexHeight = 512;
268 }
269 else if (WindowWidth >= 256 && WindowHeight >= 256) {
270 ShadowTexWidth = ShadowTexHeight = 256;
271 }
272 else {
273 ShadowTexWidth = ShadowTexHeight = 128;
274 }
275 printf("Rendering %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
276
277 if (UsePackedDepthStencil) {
278 depthFormat = GL_DEPTH_STENCIL_EXT;
279 depthType = GL_UNSIGNED_INT_24_8_EXT;
280 }
281 else {
282 depthFormat = GL_DEPTH_COMPONENT;
283 depthType = GL_UNSIGNED_INT;
284 }
285
286 /* compute frustum to enclose spot light cone */
287 d = ShadowNear * tan(SpotAngle);
288
289 glMatrixMode(GL_PROJECTION);
290 glLoadIdentity();
291 glFrustum(-d, d, -d, d, ShadowNear, ShadowFar);
292 glMatrixMode(GL_MODELVIEW);
293 glLoadIdentity();
294 gluLookAt(LightPos[0], LightPos[1], LightPos[2], /* from */
295 0, 0, 0, /* target */
296 0, 1, 0); /* up */
297
298 if (UseFBO) {
299 GLenum fbo_status;
300
301 glTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
302 ShadowTexWidth, ShadowTexHeight, 0,
303 depthFormat, depthType, NULL);
304
305 /* Set the filter mode so that the texture is texture-complete.
306 * Otherwise it will cause the framebuffer to fail the framebuffer
307 * completeness test.
308 */
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
310
311 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
312 glDrawBuffer(GL_NONE);
313 glReadBuffer(GL_NONE);
314
315 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
316 if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
317 fprintf(stderr, "FBO not complete! status = 0x%04x\n", fbo_status);
318 assert(fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT);
319 }
320 }
321
322 assert(!glIsEnabled(GL_TEXTURE_1D));
323 assert(!glIsEnabled(GL_TEXTURE_2D));
324
325 glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
326 glClear(GL_DEPTH_BUFFER_BIT);
327 glEnable(GL_DEPTH_TEST);
328 DrawScene();
329
330 if (UseFBO) {
331 /* all done! */
332 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
333 }
334 else {
335 /*
336 * copy depth buffer into the texture map
337 */
338 if (DisplayMode == SHOW_DEPTH_MAPPING) {
339 /* load depth image as gray-scale luminance texture */
340 GLuint *depth = (GLuint *)
341 malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint));
342 assert(depth);
343 glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
344 depthFormat, depthType, depth);
345 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
346 ShadowTexWidth, ShadowTexHeight, 0,
347 GL_LUMINANCE, GL_UNSIGNED_INT, depth);
348 free(depth);
349 }
350 else {
351 /* The normal shadow case - a real depth texture */
352 glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
353 0, 0, ShadowTexWidth, ShadowTexHeight, 0);
354 if (UsePackedDepthStencil) {
355 /* debug check */
356 GLint intFormat;
357 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
358 GL_TEXTURE_INTERNAL_FORMAT, &intFormat);
359 assert(intFormat == GL_DEPTH_STENCIL_EXT);
360 }
361 }
362 }
363 }
364
365
366 /**
367 * Show the shadow map as a grayscale image.
368 */
369 static void
370 ShowShadowMap(void)
371 {
372 glClear(GL_COLOR_BUFFER_BIT);
373
374 glMatrixMode(GL_TEXTURE);
375 glLoadIdentity();
376
377 glMatrixMode(GL_PROJECTION);
378 glLoadIdentity();
379 glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1);
380
381 glMatrixMode(GL_MODELVIEW);
382 glLoadIdentity();
383
384 glDisable(GL_DEPTH_TEST);
385 glDisable(GL_LIGHTING);
386
387 glEnable(GL_TEXTURE_2D);
388
389 DisableTexgen();
390
391 /* interpret texture's depth values as luminance values */
392 #if defined(GL_ARB_shadow)
393 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
394 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
395 #endif
396 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
397
398 glBegin(GL_POLYGON);
399 glTexCoord2f(0, 0); glVertex2f(0, 0);
400 glTexCoord2f(1, 0); glVertex2f(ShadowTexWidth, 0);
401 glTexCoord2f(1, 1); glVertex2f(ShadowTexWidth, ShadowTexHeight);
402 glTexCoord2f(0, 1); glVertex2f(0, ShadowTexHeight);
403 glEnd();
404
405 glDisable(GL_TEXTURE_2D);
406 glEnable(GL_DEPTH_TEST);
407 glEnable(GL_LIGHTING);
408 }
409
410
411 /**
412 * Redraw window image
413 */
414 static void
415 Display(void)
416 {
417 GLenum error;
418
419 ComputeLightPos(LightDist, LightLatitude, LightLongitude,
420 LightPos, SpotDir);
421
422 if (NeedNewShadowMap) {
423 RenderShadowMap();
424 NeedNewShadowMap = GL_FALSE;
425 }
426
427 glViewport(0, 0, WindowWidth, WindowHeight);
428 if (DisplayMode == SHOW_DEPTH_IMAGE) {
429 ShowShadowMap();
430 }
431 else {
432 /* prepare to draw scene from camera's view */
433 const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
434
435 glMatrixMode(GL_PROJECTION);
436 glLoadIdentity();
437 glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
438
439 glMatrixMode(GL_MODELVIEW);
440 glLoadIdentity();
441 glTranslatef(0.0, 0.0, -22.0);
442 glRotatef(Xrot, 1, 0, 0);
443 glRotatef(Yrot, 0, 1, 0);
444 glRotatef(Zrot, 0, 0, 1);
445
446 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
447
448 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
449
450 if (LinearFilter) {
451 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
452 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
453 }
454 else {
455 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
456 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
457 }
458
459 if (DisplayMode == SHOW_DEPTH_MAPPING) {
460 #if defined(GL_ARB_shadow)
461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
462 #endif
463 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
464 glEnable(GL_TEXTURE_2D);
465 MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
466 EnableIdentityTexgen();
467 }
468 else if (DisplayMode == SHOW_DISTANCE) {
469 glMatrixMode(GL_TEXTURE);
470 glLoadIdentity();
471 glMatrixMode(GL_MODELVIEW);
472 EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
473 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
474 glEnable(GL_TEXTURE_1D);
475 assert(!glIsEnabled(GL_TEXTURE_2D));
476 }
477 else {
478 assert(DisplayMode == SHOW_SHADOWS);
479 #if defined(GL_ARB_shadow)
480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
481 GL_COMPARE_R_TO_TEXTURE_ARB);
482 #endif
483 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
484 glEnable(GL_TEXTURE_2D);
485 MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
486 EnableIdentityTexgen();
487 }
488
489 DrawScene();
490
491 DisableTexgen();
492 glDisable(GL_TEXTURE_1D);
493 glDisable(GL_TEXTURE_2D);
494 }
495
496 glutSwapBuffers();
497
498 error = glGetError();
499 if (error) {
500 printf("GL Error: %s\n", (char *) gluErrorString(error));
501 }
502 }
503
504
505 static void
506 Reshape(int width, int height)
507 {
508 WindowWidth = width;
509 WindowHeight = height;
510 NeedNewShadowMap = GL_TRUE;
511 }
512
513
514 static void
515 Idle(void)
516 {
517 static double t0 = -1.;
518 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
519 if (t0 < 0.0)
520 t0 = t;
521 dt = t - t0;
522 t0 = t;
523 Yrot += 75.0 * dt;
524 /*LightLongitude -= 5.0;*/
525 glutPostRedisplay();
526 }
527
528
529 static void
530 Key(unsigned char key, int x, int y)
531 {
532 const GLfloat step = 3.0;
533 (void) x;
534 (void) y;
535 switch (key) {
536 case 'a':
537 Anim = !Anim;
538 if (Anim)
539 glutIdleFunc(Idle);
540 else
541 glutIdleFunc(NULL);
542 break;
543 case 'b':
544 Bias -= 0.01;
545 printf("Bias %g\n", Bias);
546 break;
547 case 'B':
548 Bias += 0.01;
549 printf("Bias %g\n", Bias);
550 break;
551 case 'd':
552 DisplayMode = SHOW_DISTANCE;
553 break;
554 case 'f':
555 LinearFilter = !LinearFilter;
556 printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
557 break;
558 case 'i':
559 DisplayMode = SHOW_DEPTH_IMAGE;
560 break;
561 case 'm':
562 DisplayMode = SHOW_DEPTH_MAPPING;
563 break;
564 case 'n':
565 case 's':
566 case ' ':
567 DisplayMode = SHOW_SHADOWS;
568 break;
569 case 'o':
570 if (HaveEXTshadowFuncs) {
571 Operator++;
572 if (Operator >= 8)
573 Operator = 0;
574 printf("Operator: %s\n", OperatorName[Operator]);
575 #if defined(GL_ARB_shadow)
576 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
577 OperatorFunc[Operator]);
578 #endif
579 }
580 break;
581 case 'p':
582 UsePackedDepthStencil = !UsePackedDepthStencil;
583 if (UsePackedDepthStencil && !HavePackedDepthStencil) {
584 printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
585 UsePackedDepthStencil = GL_FALSE;
586 }
587 else {
588 printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil);
589 /* Don't really need to regenerate shadow map texture, but do so
590 * to exercise more code more often.
591 */
592 NeedNewShadowMap = GL_TRUE;
593 }
594 break;
595 case 'z':
596 Zrot -= step;
597 break;
598 case 'Z':
599 Zrot += step;
600 break;
601 case 27:
602 exit(0);
603 break;
604 }
605 glutPostRedisplay();
606 }
607
608
609 static void
610 SpecialKey(int key, int x, int y)
611 {
612 const GLfloat step = 3.0;
613 const int mod = glutGetModifiers();
614 (void) x;
615 (void) y;
616 switch (key) {
617 case GLUT_KEY_UP:
618 if (mod)
619 LightLatitude += step;
620 else
621 Xrot += step;
622 break;
623 case GLUT_KEY_DOWN:
624 if (mod)
625 LightLatitude -= step;
626 else
627 Xrot -= step;
628 break;
629 case GLUT_KEY_LEFT:
630 if (mod)
631 LightLongitude += step;
632 else
633 Yrot += step;
634 break;
635 case GLUT_KEY_RIGHT:
636 if (mod)
637 LightLongitude -= step;
638 else
639 Yrot -= step;
640 break;
641 }
642 if (mod)
643 NeedNewShadowMap = GL_TRUE;
644
645 glutPostRedisplay();
646 }
647
648
649 static void
650 Init(void)
651 {
652 static const GLfloat borderColor[4] = {1.0, 0.0, 0.0, 0.0};
653
654 #if defined(GL_ARB_depth_texture) && defined(GL_ARB_shadow)
655 if (!glutExtensionSupported("GL_ARB_depth_texture") ||
656 !glutExtensionSupported("GL_ARB_shadow")) {
657 #else
658 if (1) {
659 #endif
660 printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
661 exit(1);
662 }
663 printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
664
665 #if defined(GL_ARB_shadow_ambient)
666 HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient");
667 if (HaveShadowAmbient) {
668 printf("and GL_ARB_shadow_ambient\n");
669 }
670 #endif
671
672 HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
673
674 HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil");
675 UsePackedDepthStencil = HavePackedDepthStencil;
676
677 #if defined(GL_EXT_framebuffer_object)
678 HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object");
679 UseFBO = HaveFBO;
680 if (UseFBO) {
681 printf("Using GL_EXT_framebuffer_object\n");
682 }
683 #endif
684
685 /*
686 * Set up the 2D shadow map texture
687 */
688 glGenTextures(1, &ShadowTexture);
689 glBindTexture(GL_TEXTURE_2D, ShadowTexture);
690 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
691 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
692 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
693 #if defined(GL_ARB_shadow)
694 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
695 GL_COMPARE_R_TO_TEXTURE_ARB);
696 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
697 #endif
698 if (HaveShadowAmbient) {
699 #if defined(GL_ARB_shadow_ambient)
700 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
701 #endif
702 }
703
704 #if defined(GL_EXT_framebuffer_object)
705 if (UseFBO) {
706 glGenFramebuffersEXT(1, &ShadowFBO);
707 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
708 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
709 GL_COLOR_ATTACHMENT0_EXT,
710 GL_RENDERBUFFER_EXT, 0);
711 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
712 GL_TEXTURE_2D, ShadowTexture, 0);
713
714 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
715 }
716 #endif
717
718 /*
719 * Setup 1-D grayscale texture image for SHOW_DISTANCE mode
720 */
721 glGenTextures(1, &GrayTexture);
722 glBindTexture(GL_TEXTURE_1D, GrayTexture);
723 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
724 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
725 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
726 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
727 {
728 GLuint i;
729 GLubyte image[256];
730 for (i = 0; i < 256; i++)
731 image[i] = i;
732 glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
733 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
734 }
735
736 glEnable(GL_DEPTH_TEST);
737 glEnable(GL_LIGHTING);
738 glEnable(GL_LIGHT0);
739 }
740
741
742 static void
743 PrintHelp(void)
744 {
745 printf("Keys:\n");
746 printf(" a = toggle animation\n");
747 printf(" i = show depth texture image\n");
748 printf(" m = show depth texture mapping\n");
749 printf(" d = show fragment distance from light source\n");
750 printf(" n = show normal, shadowed image\n");
751 printf(" f = toggle nearest/bilinear texture filtering\n");
752 printf(" b/B = decrease/increase shadow map Z bias\n");
753 printf(" p = toggle use of packed depth/stencil\n");
754 printf(" cursor keys = rotate scene\n");
755 printf(" <shift> + cursor keys = rotate light source\n");
756 if (HaveEXTshadowFuncs)
757 printf(" o = cycle through comparison modes\n");
758 }
759
760
761 int
762 main(int argc, char *argv[])
763 {
764 glutInit(&argc, argv);
765 glutInitWindowPosition(0, 0);
766 glutInitWindowSize(WindowWidth, WindowHeight);
767 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
768 glutCreateWindow(argv[0]);
769 glutReshapeFunc(Reshape);
770 glutKeyboardFunc(Key);
771 glutSpecialFunc(SpecialKey);
772 glutDisplayFunc(Display);
773 if (Anim)
774 glutIdleFunc(Idle);
775 Init();
776 PrintHelp();
777 glutMainLoop();
778 return 0;
779 }