2 * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and
3 * GL_ARB_shadow_ambient extensions (or the old SGIX extensions).
8 * Added GL_EXT_shadow_funcs support on 23 March 2002
10 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include "showbuffer.h"
38 #if 0 /* change to 1 if you want to use the old SGIX extensions */
39 #undef GL_ARB_depth_texture
41 #undef GL_ARB_shadow_ambient
44 #define DEG_TO_RAD (3.14159 / 180.0)
46 static GLint WindowWidth
= 450, WindowHeight
= 300;
47 static GLfloat Xrot
= 15, Yrot
= 0, Zrot
= 0;
49 static GLfloat Red
[4] = {1, 0, 0, 1};
50 static GLfloat Green
[4] = {0, 1, 0, 1};
51 static GLfloat Blue
[4] = {0, 0, 1, 1};
52 static GLfloat Yellow
[4] = {1, 1, 0, 1};
54 static GLfloat LightDist
= 10;
55 static GLfloat LightLatitude
= 45.0;
56 static GLfloat LightLongitude
= 45.0;
57 static GLfloat LightPos
[4];
58 static GLfloat SpotDir
[3];
59 static GLfloat SpotAngle
= 40.0 * DEG_TO_RAD
;
60 static GLfloat ShadowNear
= 4.0, ShadowFar
= 24.0;
61 static GLint ShadowTexWidth
= 256, ShadowTexHeight
= 256;
63 static GLboolean LinearFilter
= GL_FALSE
;
65 static GLfloat Bias
= -0.06;
67 static GLboolean Anim
= GL_TRUE
;
69 static GLboolean UsePackedDepthStencil
= GL_FALSE
;
70 static GLboolean HaveEXTshadowFuncs
= GL_FALSE
;
71 static GLint Operator
= 0;
72 static const GLenum OperatorFunc
[8] = {
73 GL_LEQUAL
, GL_LESS
, GL_GEQUAL
, GL_GREATER
,
74 GL_EQUAL
, GL_NOTEQUAL
, GL_ALWAYS
, GL_NEVER
};
75 static const char *OperatorName
[8] = {
76 "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
77 "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
80 static GLuint DisplayMode
;
82 #define SHOW_DEPTH_IMAGE 1
83 #define SHOW_DEPTH_MAPPING 2
84 #define SHOW_DISTANCE 3
94 glTranslatef(1.6, 2.2, 2.7);
95 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Green
);
97 glutSolidSphere(1.5, 15, 15);
101 glTranslatef(-2.0, 1.2, 2.1);
102 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Red
);
104 glutSolidDodecahedron();
108 glTranslatef(-0.6, 1.3, -0.5);
109 glScalef(1.5, 1.5, 1.5);
110 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Yellow
);
112 glutSolidIcosahedron();
116 glTranslatef(0, -1.1, 0);
117 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, Blue
);
121 glVertex3f(-k
, 0, -k
);
122 glVertex3f( k
, 0, -k
);
123 glVertex3f( k
, 0, k
);
124 glVertex3f(-k
, 0, k
);
131 * Load the GL_TEXTURE matrix with the projection from the light
132 * source's point of view.
135 MakeShadowMatrix(const GLfloat lightPos
[4], const GLfloat spotDir
[3],
136 GLfloat spotAngle
, GLfloat shadowNear
, GLfloat shadowFar
)
140 glMatrixMode(GL_TEXTURE
);
142 glTranslatef(0.5, 0.5, 0.5 + Bias
);
143 glScalef(0.5, 0.5, 0.5);
144 d
= shadowNear
* tan(spotAngle
);
145 glFrustum(-d
, d
, -d
, d
, shadowNear
, shadowFar
);
146 gluLookAt(lightPos
[0], lightPos
[1], lightPos
[2],
147 lightPos
[0] + spotDir
[0],
148 lightPos
[1] + spotDir
[1],
149 lightPos
[2] + spotDir
[2],
151 glMatrixMode(GL_MODELVIEW
);
156 EnableIdentityTexgen(void)
158 /* texgen so that texcoord = vertex coord */
159 static GLfloat sPlane
[4] = { 1, 0, 0, 0 };
160 static GLfloat tPlane
[4] = { 0, 1, 0, 0 };
161 static GLfloat rPlane
[4] = { 0, 0, 1, 0 };
162 static GLfloat qPlane
[4] = { 0, 0, 0, 1 };
164 glTexGenfv(GL_S
, GL_EYE_PLANE
, sPlane
);
165 glTexGenfv(GL_T
, GL_EYE_PLANE
, tPlane
);
166 glTexGenfv(GL_R
, GL_EYE_PLANE
, rPlane
);
167 glTexGenfv(GL_Q
, GL_EYE_PLANE
, qPlane
);
168 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
169 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
170 glTexGeni(GL_R
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
171 glTexGeni(GL_Q
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
173 glEnable(GL_TEXTURE_GEN_S
);
174 glEnable(GL_TEXTURE_GEN_T
);
175 glEnable(GL_TEXTURE_GEN_R
);
176 glEnable(GL_TEXTURE_GEN_Q
);
181 * Setup 1-D texgen so that the distance from the light source, between
182 * the near and far planes maps to s=0 and s=1. When we draw the scene,
183 * the grayness will indicate the fragment's distance from the light
187 EnableDistanceTexgen(const GLfloat lightPos
[4], const GLfloat lightDir
[3],
188 GLfloat lightNear
, GLfloat lightFar
)
192 GLfloat nearPoint
[3];
194 m
= sqrt(lightDir
[0] * lightDir
[0] +
195 lightDir
[1] * lightDir
[1] +
196 lightDir
[2] * lightDir
[2]);
198 d
= lightFar
- lightNear
;
200 /* nearPoint = point on light direction vector which intersects the
201 * near plane of the light frustum.
203 nearPoint
[0] = LightPos
[0] + lightDir
[0] / m
* lightNear
;
204 nearPoint
[1] = LightPos
[1] + lightDir
[1] / m
* lightNear
;
205 nearPoint
[2] = LightPos
[2] + lightDir
[2] / m
* lightNear
;
207 sPlane
[0] = lightDir
[0] / d
/ m
;
208 sPlane
[1] = lightDir
[1] / d
/ m
;
209 sPlane
[2] = lightDir
[2] / d
/ m
;
210 sPlane
[3] = -(sPlane
[0] * nearPoint
[0]
211 + sPlane
[1] * nearPoint
[1]
212 + sPlane
[2] * nearPoint
[2]);
214 glTexGenfv(GL_S
, GL_EYE_PLANE
, sPlane
);
215 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_EYE_LINEAR
);
216 glEnable(GL_TEXTURE_GEN_S
);
223 glDisable(GL_TEXTURE_GEN_S
);
224 glDisable(GL_TEXTURE_GEN_T
);
225 glDisable(GL_TEXTURE_GEN_R
);
226 glDisable(GL_TEXTURE_GEN_Q
);
231 ComputeLightPos(GLfloat dist
, GLfloat latitude
, GLfloat longitude
,
232 GLfloat pos
[4], GLfloat dir
[3])
235 pos
[0] = dist
* sin(longitude
* DEG_TO_RAD
);
236 pos
[1] = dist
* sin(latitude
* DEG_TO_RAD
);
237 pos
[2] = dist
* cos(latitude
* DEG_TO_RAD
) * cos(longitude
* DEG_TO_RAD
);
248 GLfloat ar
= (GLfloat
) WindowWidth
/ (GLfloat
) WindowHeight
;
252 ComputeLightPos(LightDist
, LightLatitude
, LightLongitude
,
255 * Step 1: render scene from point of view of the light source
257 /* compute frustum to enclose spot light cone */
258 d
= ShadowNear
* tan(SpotAngle
);
259 glMatrixMode(GL_PROJECTION
);
261 glFrustum(-d
, d
, -d
, d
, ShadowNear
, ShadowFar
);
262 glMatrixMode(GL_MODELVIEW
);
264 gluLookAt(LightPos
[0], LightPos
[1], LightPos
[2], /* from */
265 0, 0, 0, /* target */
268 glViewport(0, 0, ShadowTexWidth
, ShadowTexHeight
);
269 glClear(GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
273 * Step 2: copy depth buffer into texture map
275 if (DisplayMode
== SHOW_DEPTH_MAPPING
) {
276 /* load depth image as gray-scale luminance texture */
277 if (UsePackedDepthStencil
) {
278 GLuint
*depth
= (GLuint
*) malloc(ShadowTexWidth
* ShadowTexHeight
281 glReadPixels(0, 0, ShadowTexWidth
, ShadowTexHeight
,
282 GL_DEPTH_STENCIL_EXT
, GL_UNSIGNED_INT_24_8_EXT
, depth
);
283 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
,
284 ShadowTexWidth
, ShadowTexHeight
, 0,
285 GL_LUMINANCE
, GL_UNSIGNED_INT
, depth
);
289 GLfloat
*depth
= (GLfloat
*) malloc(ShadowTexWidth
* ShadowTexHeight
292 glReadPixels(0, 0, ShadowTexWidth
, ShadowTexHeight
,
293 GL_DEPTH_COMPONENT
, GL_FLOAT
, depth
);
294 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
,
295 ShadowTexWidth
, ShadowTexHeight
, 0,
296 GL_LUMINANCE
, GL_FLOAT
, depth
);
301 /* The normal shadow case */
302 if (UsePackedDepthStencil
) {
304 glCopyTexImage2D(GL_TEXTURE_2D
, 0, GL_DEPTH_STENCIL_EXT
,
305 0, 0, ShadowTexWidth
, ShadowTexHeight
, 0);
306 glGetTexLevelParameteriv(GL_TEXTURE_2D
, 0,
307 GL_TEXTURE_INTERNAL_FORMAT
, &intFormat
);
308 assert(intFormat
== GL_DEPTH_STENCIL_EXT
);
311 glCopyTexImage2D(GL_TEXTURE_2D
, 0, GL_DEPTH_COMPONENT
,
312 0, 0, ShadowTexWidth
, ShadowTexHeight
, 0);
317 * Step 3: render scene from point of view of the camera
319 glViewport(0, 0, WindowWidth
, WindowHeight
);
320 if (DisplayMode
== SHOW_DEPTH_IMAGE
) {
321 ShowDepthBuffer(WindowWidth
, WindowHeight
, 0, 1);
324 glMatrixMode(GL_PROJECTION
);
326 glFrustum(-ar
, ar
, -1.0, 1.0, 4.0, 50.0);
327 glMatrixMode(GL_MODELVIEW
);
329 glTranslatef(0.0, 0.0, -22.0);
330 glRotatef(Xrot
, 1, 0, 0);
331 glRotatef(Yrot
, 0, 1, 0);
332 glRotatef(Zrot
, 0, 0, 1);
333 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
334 glLightfv(GL_LIGHT0
, GL_POSITION
, LightPos
);
336 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
337 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
340 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
341 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
343 if (DisplayMode
== SHOW_DEPTH_MAPPING
) {
344 #if defined(GL_ARB_shadow)
345 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
346 #elif defined(GL_SGIX_shadow)
347 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_SGIX
, GL_FALSE
);
349 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
350 glEnable(GL_TEXTURE_2D
);
351 MakeShadowMatrix(LightPos
, SpotDir
, SpotAngle
, ShadowNear
, ShadowFar
);
352 EnableIdentityTexgen();
354 else if (DisplayMode
== SHOW_DISTANCE
) {
355 glMatrixMode(GL_TEXTURE
);
357 glMatrixMode(GL_MODELVIEW
);
358 EnableDistanceTexgen(LightPos
, SpotDir
, ShadowNear
+Bias
, ShadowFar
);
359 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
360 glEnable(GL_TEXTURE_1D
);
363 assert(DisplayMode
== SHOW_NORMAL
);
364 #if defined(GL_ARB_shadow)
365 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_MODE_ARB
,
366 GL_COMPARE_R_TO_TEXTURE_ARB
);
367 #elif defined(GL_SGIX_shadow)
368 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_SGIX
, GL_TRUE
);
370 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
371 glEnable(GL_TEXTURE_2D
);
372 MakeShadowMatrix(LightPos
, SpotDir
, SpotAngle
, ShadowNear
, ShadowFar
);
373 EnableIdentityTexgen();
377 glDisable(GL_TEXTURE_1D
);
378 glDisable(GL_TEXTURE_2D
);
383 error
= glGetError();
385 printf("GL Error: %s\n", (char *) gluErrorString(error
));
391 Reshape(int width
, int height
)
394 WindowHeight
= height
;
395 if (width
>= 512 && height
>= 512) {
396 ShadowTexWidth
= ShadowTexHeight
= 512;
398 else if (width
>= 256 && height
>= 256) {
399 ShadowTexWidth
= ShadowTexHeight
= 256;
402 ShadowTexWidth
= ShadowTexHeight
= 128;
404 printf("Using %d x %d depth texture\n", ShadowTexWidth
, ShadowTexHeight
);
411 static double t0
= -1.;
412 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
418 /*LightLongitude -= 5.0;*/
424 Key(unsigned char key
, int x
, int y
)
426 const GLfloat step
= 3.0;
439 printf("Bias %g\n", Bias
);
443 printf("Bias %g\n", Bias
);
446 DisplayMode
= SHOW_DISTANCE
;
449 LinearFilter
= !LinearFilter
;
450 printf("%s filtering\n", LinearFilter
? "Bilinear" : "Nearest");
453 DisplayMode
= SHOW_DEPTH_IMAGE
;
456 DisplayMode
= SHOW_DEPTH_MAPPING
;
460 DisplayMode
= SHOW_NORMAL
;
463 if (HaveEXTshadowFuncs
) {
467 printf("Operator: %s\n", OperatorName
[Operator
]);
468 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_FUNC_ARB
,
469 OperatorFunc
[Operator
]);
473 UsePackedDepthStencil
= !UsePackedDepthStencil
;
474 if (UsePackedDepthStencil
475 && !glutExtensionSupported("GL_EXT_packed_depth_stencil")) {
476 printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
477 UsePackedDepthStencil
= GL_FALSE
;
480 printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil
);
498 SpecialKey(int key
, int x
, int y
)
500 const GLfloat step
= 3.0;
501 const int mod
= glutGetModifiers();
507 LightLatitude
+= step
;
513 LightLatitude
-= step
;
519 LightLongitude
+= step
;
525 LightLongitude
-= step
;
537 #if defined(GL_ARB_depth_texture) && defined(GL_ARB_shadow)
538 if (!glutExtensionSupported("GL_ARB_depth_texture") ||
539 !glutExtensionSupported("GL_ARB_shadow")) {
540 printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
543 printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
544 #elif defined(GL_SGIX_depth_texture) && defined(GL_SGIX_shadow)
545 if (!glutExtensionSupported("GL_SGIX_depth_texture") ||
546 !glutExtensionSupported("GL_SGIX_shadow")) {
547 printf("Sorry, this demo requires the GL_SGIX_depth_texture and GL_SGIX_shadow extensions\n");
550 printf("Using GL_SGIX_depth_texture and GL_SGIX_shadow\n");
552 HaveEXTshadowFuncs
= glutExtensionSupported("GL_EXT_shadow_funcs");
554 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
555 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
556 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
557 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
558 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
559 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
560 #if defined(GL_ARB_shadow)
561 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_MODE_ARB
,
562 GL_COMPARE_R_TO_TEXTURE_ARB
);
563 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_FUNC_ARB
, GL_LEQUAL
);
564 #elif defined(GL_SGIX_shadow)
565 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_OPERATOR_SGIX
,
566 GL_TEXTURE_LEQUAL_R_SGIX
);
569 #if defined(GL_ARB_shadow_ambient)
570 if (glutExtensionSupported("GL_ARB_shadow_ambient")) {
571 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB
, 0.3);
572 printf("and GL_ARB_shadow_ambient\n");
574 #elif defined(GL_SGIX_shadow_ambient)
575 if (glutExtensionSupported("GL_SGIX_shadow_ambient")) {
576 glTexParameterf(GL_TEXTURE_2D
, GL_SHADOW_AMBIENT_SGIX
, 0.3);
577 printf("and GL_SGIX_shadow_ambient\n");
581 /* setup 1-D grayscale texture image for SHOW_DISTANCE mode */
585 for (i
= 0; i
< 256; i
++)
587 glTexImage1D(GL_TEXTURE_1D
, 0, GL_LUMINANCE
,
588 256, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, image
);
591 glEnable(GL_DEPTH_TEST
);
592 glEnable(GL_LIGHTING
);
601 printf(" a = toggle animation\n");
602 printf(" i = show depth texture image\n");
603 printf(" m = show depth texture mapping\n");
604 printf(" d = show fragment distance from light source\n");
605 printf(" n = show normal, shadowed image\n");
606 printf(" f = toggle nearest/bilinear texture filtering\n");
607 printf(" b/B = decrease/increase shadow map Z bias\n");
608 printf(" p = toggle use of packed depth/stencil\n");
609 printf(" cursor keys = rotate scene\n");
610 printf(" <shift> + cursor keys = rotate light source\n");
611 if (HaveEXTshadowFuncs
)
612 printf(" o = cycle through comparison modes\n");
617 main(int argc
, char *argv
[])
619 glutInit(&argc
, argv
);
620 glutInitWindowPosition(0, 0);
621 glutInitWindowSize(WindowWidth
, WindowHeight
);
622 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
| GLUT_STENCIL
);
623 glutCreateWindow(argv
[0]);
624 glutReshapeFunc(Reshape
);
625 glutKeyboardFunc(Key
);
626 glutSpecialFunc(SpecialKey
);
627 glutDisplayFunc(Display
);