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 "../util/showbuffer.c"
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
45 #define DEG_TO_RAD (3.14159 / 180.0)
47 static GLint WindowWidth
= 450, WindowHeight
= 300;
48 static GLfloat Xrot
= 15, Yrot
= 0, Zrot
= 0;
50 static GLfloat Red
[4] = {1, 0, 0, 1};
51 static GLfloat Green
[4] = {0, 1, 0, 1};
52 static GLfloat Blue
[4] = {0, 0, 1, 1};
53 static GLfloat Yellow
[4] = {1, 1, 0, 1};
55 static GLfloat LightDist
= 10;
56 static GLfloat LightLatitude
= 45.0;
57 static GLfloat LightLongitude
= 45.0;
58 static GLfloat LightPos
[4];
59 static GLfloat SpotDir
[3];
60 static GLfloat SpotAngle
= 40.0 * DEG_TO_RAD
;
61 static GLfloat ShadowNear
= 4.0, ShadowFar
= 24.0;
62 static GLint ShadowTexWidth
= 256, ShadowTexHeight
= 256;
64 static GLboolean LinearFilter
= GL_FALSE
;
66 static GLfloat Bias
= -0.06;
68 static GLboolean Anim
= GL_TRUE
;
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
);
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 GLfloat
*depth
= (GLfloat
*) malloc(ShadowTexWidth
* ShadowTexHeight
280 glReadPixels(0, 0, ShadowTexWidth
, ShadowTexHeight
,
281 GL_DEPTH_COMPONENT
, GL_FLOAT
, depth
);
282 glTexImage2D(GL_TEXTURE_2D
, 0, GL_LUMINANCE
,
283 ShadowTexWidth
, ShadowTexHeight
, 0,
284 GL_LUMINANCE
, GL_FLOAT
, depth
);
289 /* The normal shadow case */
290 glCopyTexImage2D(GL_TEXTURE_2D
, 0, GL_DEPTH_COMPONENT
,
291 0, 0, ShadowTexWidth
, ShadowTexHeight
, 0);
295 * Step 3: render scene from point of view of the camera
297 glViewport(0, 0, WindowWidth
, WindowHeight
);
298 if (DisplayMode
== SHOW_DEPTH_IMAGE
) {
299 ShowDepthBuffer(WindowWidth
, WindowHeight
, 0, 1);
302 glMatrixMode(GL_PROJECTION
);
304 glFrustum(-ar
, ar
, -1.0, 1.0, 4.0, 50.0);
305 glMatrixMode(GL_MODELVIEW
);
307 glTranslatef(0.0, 0.0, -22.0);
308 glRotatef(Xrot
, 1, 0, 0);
309 glRotatef(Yrot
, 0, 1, 0);
310 glRotatef(Zrot
, 0, 0, 1);
311 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
312 glLightfv(GL_LIGHT0
, GL_POSITION
, LightPos
);
314 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
315 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
318 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
319 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
321 if (DisplayMode
== SHOW_DEPTH_MAPPING
) {
322 #if defined(GL_ARB_shadow)
323 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_MODE_ARB
, GL_NONE
);
324 #elif defined(GL_SGIX_shadow)
325 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_SGIX
, GL_FALSE
);
327 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
328 glEnable(GL_TEXTURE_2D
);
329 MakeShadowMatrix(LightPos
, SpotDir
, SpotAngle
, ShadowNear
, ShadowFar
);
330 EnableIdentityTexgen();
332 else if (DisplayMode
== SHOW_DISTANCE
) {
333 glMatrixMode(GL_TEXTURE
);
335 glMatrixMode(GL_MODELVIEW
);
336 EnableDistanceTexgen(LightPos
, SpotDir
, ShadowNear
+Bias
, ShadowFar
);
337 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
338 glEnable(GL_TEXTURE_1D
);
341 assert(DisplayMode
== SHOW_NORMAL
);
342 #if defined(GL_ARB_shadow)
343 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_MODE_ARB
,
344 GL_COMPARE_R_TO_TEXTURE_ARB
);
345 #elif defined(GL_SGIX_shadow)
346 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_SGIX
, GL_TRUE
);
348 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
349 glEnable(GL_TEXTURE_2D
);
350 MakeShadowMatrix(LightPos
, SpotDir
, SpotAngle
, ShadowNear
, ShadowFar
);
351 EnableIdentityTexgen();
355 glDisable(GL_TEXTURE_1D
);
356 glDisable(GL_TEXTURE_2D
);
361 error
= glGetError();
363 printf("GL Error: %s\n", (char *) gluErrorString(error
));
369 Reshape(int width
, int height
)
372 WindowHeight
= height
;
373 if (width
>= 512 && height
>= 512) {
374 ShadowTexWidth
= ShadowTexHeight
= 512;
376 else if (width
>= 256 && height
>= 256) {
377 ShadowTexWidth
= ShadowTexHeight
= 256;
380 ShadowTexWidth
= ShadowTexHeight
= 128;
382 printf("Using %d x %d depth texture\n", ShadowTexWidth
, ShadowTexHeight
);
390 /*LightLongitude -= 5.0;*/
396 Key(unsigned char key
, int x
, int y
)
398 const GLfloat step
= 3.0;
411 printf("Bias %g\n", Bias
);
415 printf("Bias %g\n", Bias
);
418 DisplayMode
= SHOW_DISTANCE
;
421 LinearFilter
= !LinearFilter
;
422 printf("%s filtering\n", LinearFilter
? "Bilinear" : "Nearest");
425 DisplayMode
= SHOW_DEPTH_IMAGE
;
428 DisplayMode
= SHOW_DEPTH_MAPPING
;
432 DisplayMode
= SHOW_NORMAL
;
435 if (HaveEXTshadowFuncs
) {
439 printf("Operator: %s\n", OperatorName
[Operator
]);
440 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_FUNC_ARB
,
441 OperatorFunc
[Operator
]);
459 SpecialKey(int key
, int x
, int y
)
461 const GLfloat step
= 3.0;
462 const int mod
= glutGetModifiers();
468 LightLatitude
+= step
;
474 LightLatitude
-= step
;
480 LightLongitude
+= step
;
486 LightLongitude
-= step
;
498 #if defined(GL_ARB_depth_texture) && defined(GL_ARB_shadow)
499 if (!glutExtensionSupported("GL_ARB_depth_texture") ||
500 !glutExtensionSupported("GL_ARB_shadow")) {
501 printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
504 printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
505 #elif defined(GL_SGIX_depth_texture) && defined(GL_SGIX_shadow)
506 if (!glutExtensionSupported("GL_SGIX_depth_texture") ||
507 !glutExtensionSupported("GL_SGIX_shadow")) {
508 printf("Sorry, this demo requires the GL_SGIX_depth_texture and GL_SGIX_shadow extensions\n");
511 printf("Using GL_SGIX_depth_texture and GL_SGIX_shadow\n");
513 HaveEXTshadowFuncs
= glutExtensionSupported("GL_EXT_shadow_funcs");
515 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
516 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
517 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
518 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
519 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
520 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
521 #if defined(GL_ARB_shadow)
522 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_MODE_ARB
,
523 GL_COMPARE_R_TO_TEXTURE_ARB
);
524 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_FUNC_ARB
, GL_LEQUAL
);
525 #elif defined(GL_SGIX_shadow)
526 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_OPERATOR_SGIX
,
527 GL_TEXTURE_LEQUAL_R_SGIX
);
530 #if defined(GL_ARB_shadow_ambient)
531 if (glutExtensionSupported("GL_ARB_shadow_ambient")) {
532 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB
, 0.3);
533 printf("and GL_ARB_shadow_ambient\n");
535 #elif defined(GL_SGIX_shadow_ambient)
536 if (glutExtensionSupported("GL_SGIX_shadow_ambient")) {
537 glTexParameterf(GL_TEXTURE_2D
, GL_SHADOW_AMBIENT_SGIX
, 0.3);
538 printf("and GL_SGIX_shadow_ambient\n");
542 /* setup 1-D grayscale texture image for SHOW_DISTANCE mode */
546 for (i
= 0; i
< 256; i
++)
548 glTexImage1D(GL_TEXTURE_1D
, 0, GL_LUMINANCE
,
549 256, 0, GL_LUMINANCE
, GL_UNSIGNED_BYTE
, image
);
552 glEnable(GL_DEPTH_TEST
);
553 glEnable(GL_LIGHTING
);
562 printf(" a = toggle animation\n");
563 printf(" i = show depth texture image\n");
564 printf(" m = show depth texture mapping\n");
565 printf(" d = show fragment distance from light source\n");
566 printf(" n = show normal, shadowed image\n");
567 printf(" f = toggle nearest/bilinear texture filtering\n");
568 printf(" b/B = decrease/increase shadow map Z bias\n");
569 printf(" cursor keys = rotate scene\n");
570 printf(" <shift> + cursor keys = rotate light source\n");
571 if (HaveEXTshadowFuncs
)
572 printf(" o = cycle through comparison modes\n");
577 main(int argc
, char *argv
[])
579 glutInit(&argc
, argv
);
580 glutInitWindowPosition(0, 0);
581 glutInitWindowSize(WindowWidth
, WindowHeight
);
582 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
583 glutCreateWindow(argv
[0]);
584 glutReshapeFunc(Reshape
);
585 glutKeyboardFunc(Key
);
586 glutSpecialFunc(SpecialKey
);
587 glutDisplayFunc(Display
);