re-enable animation
[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 glTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
300 ShadowTexWidth, ShadowTexHeight, 0,
301 depthFormat, depthType, NULL);
302 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
303 glDrawBuffer(GL_NONE);
304 glReadBuffer(GL_NONE);
305 assert(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)
306 == GL_FRAMEBUFFER_COMPLETE_EXT);
307 }
308
309 assert(!glIsEnabled(GL_TEXTURE_1D));
310 assert(!glIsEnabled(GL_TEXTURE_2D));
311
312 glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
313 glClear(GL_DEPTH_BUFFER_BIT);
314 glEnable(GL_DEPTH_TEST);
315 DrawScene();
316
317 if (UseFBO) {
318 /* all done! */
319 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
320 }
321 else {
322 /*
323 * copy depth buffer into the texture map
324 */
325 if (DisplayMode == SHOW_DEPTH_MAPPING) {
326 /* load depth image as gray-scale luminance texture */
327 GLuint *depth = (GLuint *)
328 malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint));
329 assert(depth);
330 glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
331 depthFormat, depthType, depth);
332 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
333 ShadowTexWidth, ShadowTexHeight, 0,
334 GL_LUMINANCE, GL_UNSIGNED_INT, depth);
335 free(depth);
336 }
337 else {
338 /* The normal shadow case - a real depth texture */
339 glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
340 0, 0, ShadowTexWidth, ShadowTexHeight, 0);
341 if (UsePackedDepthStencil) {
342 /* debug check */
343 GLint intFormat;
344 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
345 GL_TEXTURE_INTERNAL_FORMAT, &intFormat);
346 assert(intFormat == GL_DEPTH_STENCIL_EXT);
347 }
348 }
349 }
350 }
351
352
353 /**
354 * Show the shadow map as a grayscale image.
355 */
356 static void
357 ShowShadowMap(void)
358 {
359 glClear(GL_COLOR_BUFFER_BIT);
360
361 glMatrixMode(GL_TEXTURE);
362 glLoadIdentity();
363
364 glMatrixMode(GL_PROJECTION);
365 glLoadIdentity();
366 glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1);
367
368 glMatrixMode(GL_MODELVIEW);
369 glLoadIdentity();
370
371 glDisable(GL_DEPTH_TEST);
372 glDisable(GL_LIGHTING);
373
374 glEnable(GL_TEXTURE_2D);
375
376 DisableTexgen();
377
378 /* interpret texture's depth values as luminance values */
379 #if defined(GL_ARB_shadow)
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
381 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
382 #endif
383 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
384
385 glBegin(GL_POLYGON);
386 glTexCoord2f(0, 0); glVertex2f(0, 0);
387 glTexCoord2f(1, 0); glVertex2f(ShadowTexWidth, 0);
388 glTexCoord2f(1, 1); glVertex2f(ShadowTexWidth, ShadowTexHeight);
389 glTexCoord2f(0, 1); glVertex2f(0, ShadowTexHeight);
390 glEnd();
391
392 glDisable(GL_TEXTURE_2D);
393 glEnable(GL_DEPTH_TEST);
394 glEnable(GL_LIGHTING);
395 }
396
397
398 /**
399 * Redraw window image
400 */
401 static void
402 Display(void)
403 {
404 GLenum error;
405
406 ComputeLightPos(LightDist, LightLatitude, LightLongitude,
407 LightPos, SpotDir);
408
409 if (NeedNewShadowMap) {
410 RenderShadowMap();
411 NeedNewShadowMap = GL_FALSE;
412 }
413
414 glViewport(0, 0, WindowWidth, WindowHeight);
415 if (DisplayMode == SHOW_DEPTH_IMAGE) {
416 ShowShadowMap();
417 }
418 else {
419 /* prepare to draw scene from camera's view */
420 const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
421
422 glMatrixMode(GL_PROJECTION);
423 glLoadIdentity();
424 glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
425
426 glMatrixMode(GL_MODELVIEW);
427 glLoadIdentity();
428 glTranslatef(0.0, 0.0, -22.0);
429 glRotatef(Xrot, 1, 0, 0);
430 glRotatef(Yrot, 0, 1, 0);
431 glRotatef(Zrot, 0, 0, 1);
432
433 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
434
435 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
436
437 if (LinearFilter) {
438 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
439 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
440 }
441 else {
442 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
443 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
444 }
445
446 if (DisplayMode == SHOW_DEPTH_MAPPING) {
447 #if defined(GL_ARB_shadow)
448 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
449 #endif
450 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
451 glEnable(GL_TEXTURE_2D);
452 MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
453 EnableIdentityTexgen();
454 }
455 else if (DisplayMode == SHOW_DISTANCE) {
456 glMatrixMode(GL_TEXTURE);
457 glLoadIdentity();
458 glMatrixMode(GL_MODELVIEW);
459 EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
460 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
461 glEnable(GL_TEXTURE_1D);
462 assert(!glIsEnabled(GL_TEXTURE_2D));
463 }
464 else {
465 assert(DisplayMode == SHOW_SHADOWS);
466 #if defined(GL_ARB_shadow)
467 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
468 GL_COMPARE_R_TO_TEXTURE_ARB);
469 #endif
470 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
471 glEnable(GL_TEXTURE_2D);
472 MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
473 EnableIdentityTexgen();
474 }
475
476 DrawScene();
477
478 DisableTexgen();
479 glDisable(GL_TEXTURE_1D);
480 glDisable(GL_TEXTURE_2D);
481 }
482
483 glutSwapBuffers();
484
485 error = glGetError();
486 if (error) {
487 printf("GL Error: %s\n", (char *) gluErrorString(error));
488 }
489 }
490
491
492 static void
493 Reshape(int width, int height)
494 {
495 WindowWidth = width;
496 WindowHeight = height;
497 NeedNewShadowMap = GL_TRUE;
498 }
499
500
501 static void
502 Idle(void)
503 {
504 static double t0 = -1.;
505 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
506 if (t0 < 0.0)
507 t0 = t;
508 dt = t - t0;
509 t0 = t;
510 Yrot += 75.0 * dt;
511 /*LightLongitude -= 5.0;*/
512 glutPostRedisplay();
513 }
514
515
516 static void
517 Key(unsigned char key, int x, int y)
518 {
519 const GLfloat step = 3.0;
520 (void) x;
521 (void) y;
522 switch (key) {
523 case 'a':
524 Anim = !Anim;
525 if (Anim)
526 glutIdleFunc(Idle);
527 else
528 glutIdleFunc(NULL);
529 break;
530 case 'b':
531 Bias -= 0.01;
532 printf("Bias %g\n", Bias);
533 break;
534 case 'B':
535 Bias += 0.01;
536 printf("Bias %g\n", Bias);
537 break;
538 case 'd':
539 DisplayMode = SHOW_DISTANCE;
540 break;
541 case 'f':
542 LinearFilter = !LinearFilter;
543 printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
544 break;
545 case 'i':
546 DisplayMode = SHOW_DEPTH_IMAGE;
547 break;
548 case 'm':
549 DisplayMode = SHOW_DEPTH_MAPPING;
550 break;
551 case 'n':
552 case 's':
553 case ' ':
554 DisplayMode = SHOW_SHADOWS;
555 break;
556 case 'o':
557 if (HaveEXTshadowFuncs) {
558 Operator++;
559 if (Operator >= 8)
560 Operator = 0;
561 printf("Operator: %s\n", OperatorName[Operator]);
562 #if defined(GL_ARB_shadow)
563 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
564 OperatorFunc[Operator]);
565 #endif
566 }
567 break;
568 case 'p':
569 UsePackedDepthStencil = !UsePackedDepthStencil;
570 if (UsePackedDepthStencil && !HavePackedDepthStencil) {
571 printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
572 UsePackedDepthStencil = GL_FALSE;
573 }
574 else {
575 printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil);
576 /* Don't really need to regenerate shadow map texture, but do so
577 * to exercise more code more often.
578 */
579 NeedNewShadowMap = GL_TRUE;
580 }
581 break;
582 case 'z':
583 Zrot -= step;
584 break;
585 case 'Z':
586 Zrot += step;
587 break;
588 case 27:
589 exit(0);
590 break;
591 }
592 glutPostRedisplay();
593 }
594
595
596 static void
597 SpecialKey(int key, int x, int y)
598 {
599 const GLfloat step = 3.0;
600 const int mod = glutGetModifiers();
601 (void) x;
602 (void) y;
603 switch (key) {
604 case GLUT_KEY_UP:
605 if (mod)
606 LightLatitude += step;
607 else
608 Xrot += step;
609 break;
610 case GLUT_KEY_DOWN:
611 if (mod)
612 LightLatitude -= step;
613 else
614 Xrot -= step;
615 break;
616 case GLUT_KEY_LEFT:
617 if (mod)
618 LightLongitude += step;
619 else
620 Yrot += step;
621 break;
622 case GLUT_KEY_RIGHT:
623 if (mod)
624 LightLongitude -= step;
625 else
626 Yrot -= step;
627 break;
628 }
629 if (mod)
630 NeedNewShadowMap = GL_TRUE;
631
632 glutPostRedisplay();
633 }
634
635
636 static void
637 Init(void)
638 {
639 static const GLfloat borderColor[4] = {1.0, 0.0, 0.0, 0.0};
640
641 #if defined(GL_ARB_depth_texture) && defined(GL_ARB_shadow)
642 if (!glutExtensionSupported("GL_ARB_depth_texture") ||
643 !glutExtensionSupported("GL_ARB_shadow")) {
644 #else
645 if (1) {
646 #endif
647 printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
648 exit(1);
649 }
650 printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
651
652 #if defined(GL_ARB_shadow_ambient)
653 HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient");
654 if (HaveShadowAmbient) {
655 printf("and GL_ARB_shadow_ambient\n");
656 }
657 #endif
658
659 HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
660
661 HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil");
662 UsePackedDepthStencil = HavePackedDepthStencil;
663
664 #if defined(GL_EXT_framebuffer_object)
665 HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object");
666 UseFBO = HaveFBO;
667 if (UseFBO) {
668 printf("Using GL_EXT_framebuffer_object\n");
669 }
670 #endif
671
672 /*
673 * Set up the 2D shadow map texture
674 */
675 glGenTextures(1, &ShadowTexture);
676 glBindTexture(GL_TEXTURE_2D, ShadowTexture);
677 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
678 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
679 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
680 #if defined(GL_ARB_shadow)
681 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
682 GL_COMPARE_R_TO_TEXTURE_ARB);
683 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
684 #endif
685 if (HaveShadowAmbient) {
686 #if defined(GL_ARB_shadow_ambient)
687 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
688 #endif
689 }
690
691 #if defined(GL_EXT_framebuffer_object)
692 if (UseFBO) {
693 glGenFramebuffersEXT(1, &ShadowFBO);
694 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
695 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
696 GL_COLOR_ATTACHMENT0_EXT,
697 GL_RENDERBUFFER_EXT, 0);
698 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
699 GL_TEXTURE_2D, ShadowTexture, 0);
700
701 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
702 }
703 #endif
704
705 /*
706 * Setup 1-D grayscale texture image for SHOW_DISTANCE mode
707 */
708 glGenTextures(1, &GrayTexture);
709 glBindTexture(GL_TEXTURE_1D, GrayTexture);
710 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
711 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
712 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
713 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
714 {
715 GLuint i;
716 GLubyte image[256];
717 for (i = 0; i < 256; i++)
718 image[i] = i;
719 glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
720 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
721 }
722
723 glEnable(GL_DEPTH_TEST);
724 glEnable(GL_LIGHTING);
725 glEnable(GL_LIGHT0);
726 }
727
728
729 static void
730 PrintHelp(void)
731 {
732 printf("Keys:\n");
733 printf(" a = toggle animation\n");
734 printf(" i = show depth texture image\n");
735 printf(" m = show depth texture mapping\n");
736 printf(" d = show fragment distance from light source\n");
737 printf(" n = show normal, shadowed image\n");
738 printf(" f = toggle nearest/bilinear texture filtering\n");
739 printf(" b/B = decrease/increase shadow map Z bias\n");
740 printf(" p = toggle use of packed depth/stencil\n");
741 printf(" cursor keys = rotate scene\n");
742 printf(" <shift> + cursor keys = rotate light source\n");
743 if (HaveEXTshadowFuncs)
744 printf(" o = cycle through comparison modes\n");
745 }
746
747
748 int
749 main(int argc, char *argv[])
750 {
751 glutInit(&argc, argv);
752 glutInitWindowPosition(0, 0);
753 glutInitWindowSize(WindowWidth, WindowHeight);
754 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
755 glutCreateWindow(argv[0]);
756 glutReshapeFunc(Reshape);
757 glutKeyboardFunc(Key);
758 glutSpecialFunc(SpecialKey);
759 glutDisplayFunc(Display);
760 if (Anim)
761 glutIdleFunc(Idle);
762 Init();
763 PrintHelp();
764 glutMainLoop();
765 return 0;
766 }