Merge branch 'master' into i915-unification
[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 * Added vertex / fragment program support on 7 June 2007 (Ian Romanick).
13 *
14 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
22 *
23 * The above copyright notice and this permission notice shall be included
24 * in all copies or substantial portions of the Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
30 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 */
33
34 #define GL_GLEXT_PROTOTYPES
35 #include <assert.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <math.h>
40 #include <GL/glut.h>
41 #include "showbuffer.h"
42
43 #define DEG_TO_RAD (3.14159 / 180.0)
44
45 static GLint WindowWidth = 450, WindowHeight = 300;
46 static GLfloat Xrot = 15, Yrot = 0, Zrot = 0;
47
48 static GLfloat Red[4] = {1, 0, 0, 1};
49 static GLfloat Green[4] = {0, 1, 0, 1};
50 static GLfloat Blue[4] = {0, 0, 1, 1};
51 static GLfloat Yellow[4] = {1, 1, 0, 1};
52
53 static GLfloat LightDist = 10;
54 static GLfloat LightLatitude = 45.0;
55 static GLfloat LightLongitude = 45.0;
56 static GLfloat LightPos[4];
57 static GLfloat SpotDir[3];
58 static GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
59 static GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
60 static GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
61
62 static GLboolean LinearFilter = GL_FALSE;
63
64 static GLfloat Bias = -0.06;
65
66 static GLboolean Anim = GL_TRUE;
67
68 static GLboolean NeedNewShadowMap = GL_FALSE;
69 static GLuint ShadowTexture, GrayTexture;
70 static GLuint ShadowFBO;
71
72 static GLfloat lightModelview[16];
73 static GLfloat lightProjection[16];
74
75 static GLuint vert_prog;
76 static GLuint frag_progs[3];
77 static GLuint curr_frag = 0;
78 static GLuint max_frag = 1;
79
80 #define NUM_FRAG_MODES 3
81 static const char *FragProgNames[] = {
82 "fixed-function",
83 "program without \"OPTION ARB_fragment_program_shadow\"",
84 "program with \"OPTION ARB_fragment_program_shadow\"",
85 };
86
87 static GLboolean HaveFBO = GL_FALSE;
88 static GLboolean UseFBO = GL_FALSE;
89 static GLboolean HaveVP = GL_FALSE;
90 static GLboolean HaveFP = GL_FALSE;
91 static GLboolean HaveFP_Shadow = GL_FALSE;
92 static GLboolean UseVP = GL_FALSE;
93 static GLboolean HavePackedDepthStencil = GL_FALSE;
94 static GLboolean UsePackedDepthStencil = GL_FALSE;
95 static GLboolean HaveEXTshadowFuncs = GL_FALSE;
96 static GLboolean HaveShadowAmbient = GL_FALSE;
97
98 static GLint Operator = 0;
99 static const GLenum OperatorFunc[8] = {
100 GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER,
101 GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER };
102 static const char *OperatorName[8] = {
103 "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
104 "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
105
106
107 static GLuint DisplayMode;
108 #define SHOW_SHADOWS 0
109 #define SHOW_DEPTH_IMAGE 1
110 #define SHOW_DEPTH_MAPPING 2
111 #define SHOW_DISTANCE 3
112
113
114
115 #define MAT4_MUL(dest_vec, src_mat, src_vec) \
116 "DP4 " dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
117 "DP4 " dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
118 "DP4 " dest_vec ".z, " src_mat "[2], " src_vec ";\n" \
119 "DP4 " dest_vec ".w, " src_mat "[3], " src_vec ";\n"
120
121 #define MAT3_MUL(dest_vec, src_mat, src_vec) \
122 "DP3 " dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
123 "DP3 " dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
124 "DP3 " dest_vec ".z, " src_mat "[2], " src_vec ";\n"
125
126 #define NORMALIZE(dest, src) \
127 "DP3 " dest ".w, " src ", " src ";\n" \
128 "RSQ " dest ".w, " dest ".w;\n" \
129 "MUL " dest ", " src ", " dest ".w;\n"
130
131 /**
132 * Vertex program for shadow mapping.
133 */
134 static const char vert_code[] =
135 "!!ARBvp1.0\n"
136 "ATTRIB iPos = vertex.position;\n"
137 "ATTRIB iNorm = vertex.normal;\n"
138
139 "PARAM mvinv[4] = { state.matrix.modelview.invtrans };\n"
140 "PARAM mvp[4] = { state.matrix.mvp };\n"
141 "PARAM mv[4] = { state.matrix.modelview };\n"
142 "PARAM texmat[4] = { state.matrix.texture[0] };\n"
143 "PARAM lightPos = state.light[0].position;\n"
144 "PARAM ambientCol = state.lightprod[0].ambient;\n"
145 "PARAM diffuseCol = state.lightprod[0].diffuse;\n"
146
147 "TEMP n, lightVec;\n"
148 "ALIAS V = lightVec;\n"
149 "ALIAS NdotL = n;\n"
150
151 "OUTPUT oPos = result.position;\n"
152 "OUTPUT oColor = result.color;\n"
153 "OUTPUT oTex = result.texcoord[0];\n"
154
155 /* Transform the vertex to clip coordinates. */
156 MAT4_MUL("oPos", "mvp", "iPos")
157
158 /* Transform the vertex to eye coordinates. */
159 MAT4_MUL("V", "mv", "iPos")
160
161 /* Transform the vertex to projected light coordinates. */
162 MAT4_MUL("oTex", "texmat", "iPos")
163
164 /* Transform the normal to eye coordinates. */
165 MAT3_MUL("n", "mvinv", "iNorm")
166
167 /* Calculate the vector from the vertex to the light in eye
168 * coordinates.
169 */
170 "SUB lightVec, lightPos, V;\n"
171 NORMALIZE("lightVec", "lightVec")
172
173 /* Compute diffuse lighting coefficient.
174 */
175 "DP3 NdotL.x, n, lightVec;\n"
176 "MAX NdotL.x, NdotL.x, {0.0};\n"
177 "MIN NdotL.x, NdotL.x, {1.0};\n"
178
179 /* Accumulate color contributions.
180 */
181 "MOV oColor, diffuseCol;\n"
182 "MAD oColor.xyz, NdotL.x, diffuseCol, ambientCol;\n"
183 "END\n"
184 ;
185
186 static const char frag_code[] =
187 "!!ARBfp1.0\n"
188
189 "TEMP shadow, temp;\n"
190
191 "TXP shadow, fragment.texcoord[0], texture[0], 2D;\n"
192 "RCP temp.x, fragment.texcoord[0].w;\n"
193 "MUL temp.x, temp.x, fragment.texcoord[0].z;\n"
194 "SGE shadow, shadow.x, temp.x;\n"
195 "MUL result.color.rgb, fragment.color, shadow.x;\n"
196 "MOV result.color.a, fragment.color;\n"
197 "END\n"
198 ;
199
200 static const char frag_shadow_code[] =
201 "!!ARBfp1.0\n"
202 "OPTION ARB_fragment_program_shadow;\n"
203
204 "TEMP shadow;\n"
205
206 "TXP shadow, fragment.texcoord[0], texture[0], SHADOW2D;\n"
207 "MUL result.color.rgb, fragment.color, shadow.x;\n"
208 "MOV result.color.a, fragment.color.a;\n"
209 "END\n"
210 ;
211
212 static void
213 DrawScene(void)
214 {
215 GLfloat k = 6;
216
217 /* sphere */
218 glPushMatrix();
219 glTranslatef(1.6, 2.2, 2.7);
220 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green);
221 glColor4fv(Green);
222 glutSolidSphere(1.5, 15, 15);
223 glPopMatrix();
224 /* dodecahedron */
225 glPushMatrix();
226 glTranslatef(-2.0, 1.2, 2.1);
227 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
228 glColor4fv(Red);
229 glutSolidDodecahedron();
230 glPopMatrix();
231 /* icosahedron */
232 glPushMatrix();
233 glTranslatef(-0.6, 1.3, -0.5);
234 glScalef(1.5, 1.5, 1.5);
235 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow);
236 glColor4fv(Red);
237 glutSolidIcosahedron();
238 glPopMatrix();
239 /* a plane */
240 glPushMatrix();
241 glTranslatef(0, -1.1, 0);
242 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
243 glColor4fv(Blue);
244 glNormal3f(0, 1, 0);
245 glBegin(GL_POLYGON);
246 glVertex3f(-k, 0, -k);
247 glVertex3f( k, 0, -k);
248 glVertex3f( k, 0, k);
249 glVertex3f(-k, 0, k);
250 glEnd();
251 glPopMatrix();
252 }
253
254
255 /**
256 * Calculate modelview and project matrices for the light
257 *
258 * Stores the results in \c lightProjection (projection matrix) and
259 * \c lightModelview (modelview matrix).
260 */
261 static void
262 MakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
263 GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
264 {
265 /* compute frustum to enclose spot light cone */
266 const GLfloat d = shadowNear * tan(spotAngle);
267
268 glMatrixMode(GL_PROJECTION);
269 glPushMatrix();
270 glLoadIdentity();
271 glFrustum(-d, d, -d, d, shadowNear, shadowFar);
272 glGetFloatv(GL_PROJECTION_MATRIX, lightProjection);
273 glPopMatrix();
274
275 glMatrixMode(GL_MODELVIEW);
276 glPushMatrix();
277 glLoadIdentity();
278 gluLookAt(lightPos[0], lightPos[1], lightPos[2],
279 lightPos[0] + spotDir[0],
280 lightPos[1] + spotDir[1],
281 lightPos[2] + spotDir[2],
282 0.0, 1.0, 0.0);
283 glGetFloatv(GL_MODELVIEW_MATRIX, lightModelview);
284 glPopMatrix();
285 }
286
287
288 /**
289 * Load \c GL_TEXTURE matrix with light's MVP matrix.
290 */
291 static void SetShadowTextureMatrix(void)
292 {
293 static const GLfloat biasMatrix[16] = {
294 0.5, 0.0, 0.0, 0.0,
295 0.0, 0.5, 0.0, 0.0,
296 0.0, 0.0, 0.5, 0.0,
297 0.5, 0.5, 0.5, 1.0,
298 };
299
300 glMatrixMode(GL_TEXTURE);
301 glLoadMatrixf(biasMatrix);
302 glTranslatef(0.0, 0.0, Bias);
303 glMultMatrixf(lightProjection);
304 glMultMatrixf(lightModelview);
305 glMatrixMode(GL_MODELVIEW);
306 }
307
308
309 static void
310 EnableIdentityTexgen(void)
311 {
312 /* texgen so that texcoord = vertex coord */
313 static GLfloat sPlane[4] = { 1, 0, 0, 0 };
314 static GLfloat tPlane[4] = { 0, 1, 0, 0 };
315 static GLfloat rPlane[4] = { 0, 0, 1, 0 };
316 static GLfloat qPlane[4] = { 0, 0, 0, 1 };
317
318 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
319 glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
320 glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
321 glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
322 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
323 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
324 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
325 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
326
327 glEnable(GL_TEXTURE_GEN_S);
328 glEnable(GL_TEXTURE_GEN_T);
329 glEnable(GL_TEXTURE_GEN_R);
330 glEnable(GL_TEXTURE_GEN_Q);
331 }
332
333
334 /*
335 * Setup 1-D texgen so that the distance from the light source, between
336 * the near and far planes maps to s=0 and s=1. When we draw the scene,
337 * the grayness will indicate the fragment's distance from the light
338 * source.
339 */
340 static void
341 EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
342 GLfloat lightNear, GLfloat lightFar)
343 {
344 GLfloat m, d;
345 GLfloat sPlane[4];
346 GLfloat nearPoint[3];
347
348 m = sqrt(lightDir[0] * lightDir[0] +
349 lightDir[1] * lightDir[1] +
350 lightDir[2] * lightDir[2]);
351
352 d = lightFar - lightNear;
353
354 /* nearPoint = point on light direction vector which intersects the
355 * near plane of the light frustum.
356 */
357 nearPoint[0] = lightPos[0] + lightDir[0] / m * lightNear;
358 nearPoint[1] = lightPos[1] + lightDir[1] / m * lightNear;
359 nearPoint[2] = lightPos[2] + lightDir[2] / m * lightNear;
360
361 sPlane[0] = lightDir[0] / d / m;
362 sPlane[1] = lightDir[1] / d / m;
363 sPlane[2] = lightDir[2] / d / m;
364 sPlane[3] = -(sPlane[0] * nearPoint[0]
365 + sPlane[1] * nearPoint[1]
366 + sPlane[2] * nearPoint[2]);
367
368 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
369 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
370 glEnable(GL_TEXTURE_GEN_S);
371 }
372
373
374 static void
375 DisableTexgen(void)
376 {
377 glDisable(GL_TEXTURE_GEN_S);
378 glDisable(GL_TEXTURE_GEN_T);
379 glDisable(GL_TEXTURE_GEN_R);
380 glDisable(GL_TEXTURE_GEN_Q);
381 }
382
383
384 static void
385 ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
386 GLfloat pos[4], GLfloat dir[3])
387 {
388
389 pos[0] = dist * sin(longitude * DEG_TO_RAD);
390 pos[1] = dist * sin(latitude * DEG_TO_RAD);
391 pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
392 pos[3] = 1;
393 dir[0] = -pos[0];
394 dir[1] = -pos[1];
395 dir[2] = -pos[2];
396 }
397
398
399 /**
400 * Render the shadow map / depth texture.
401 * The result will be in the texture object named ShadowTexture.
402 */
403 static void
404 RenderShadowMap(void)
405 {
406 GLenum depthFormat; /* GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT */
407 GLenum depthType; /* GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT */
408
409 if (WindowWidth >= 1024 && WindowHeight >= 1024) {
410 ShadowTexWidth = ShadowTexHeight = 1024;
411 }
412 else if (WindowWidth >= 512 && WindowHeight >= 512) {
413 ShadowTexWidth = ShadowTexHeight = 512;
414 }
415 else if (WindowWidth >= 256 && WindowHeight >= 256) {
416 ShadowTexWidth = ShadowTexHeight = 256;
417 }
418 else {
419 ShadowTexWidth = ShadowTexHeight = 128;
420 }
421 printf("Rendering %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
422
423 if (UsePackedDepthStencil) {
424 depthFormat = GL_DEPTH_STENCIL_EXT;
425 depthType = GL_UNSIGNED_INT_24_8_EXT;
426 }
427 else {
428 depthFormat = GL_DEPTH_COMPONENT;
429 depthType = GL_UNSIGNED_INT;
430 }
431
432 glMatrixMode(GL_PROJECTION);
433 glLoadMatrixf(lightProjection);
434
435 glMatrixMode(GL_MODELVIEW);
436 glLoadMatrixf(lightModelview);
437
438 if (UseFBO) {
439 GLenum fbo_status;
440
441 glTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
442 ShadowTexWidth, ShadowTexHeight, 0,
443 depthFormat, depthType, NULL);
444
445 /* Set the filter mode so that the texture is texture-complete.
446 * Otherwise it will cause the framebuffer to fail the framebuffer
447 * completeness test.
448 */
449 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
450
451 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
452 glDrawBuffer(GL_NONE);
453 glReadBuffer(GL_NONE);
454
455 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
456 if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
457 fprintf(stderr, "FBO not complete! status = 0x%04x\n", fbo_status);
458 assert(fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT);
459 }
460 }
461
462 assert(!glIsEnabled(GL_TEXTURE_1D));
463 assert(!glIsEnabled(GL_TEXTURE_2D));
464
465 glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
466 glClear(GL_DEPTH_BUFFER_BIT);
467 glEnable(GL_DEPTH_TEST);
468 DrawScene();
469
470 if (UseFBO) {
471 /* all done! */
472 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
473 }
474 else {
475 /*
476 * copy depth buffer into the texture map
477 */
478 if (DisplayMode == SHOW_DEPTH_MAPPING) {
479 /* load depth image as gray-scale luminance texture */
480 GLuint *depth = (GLuint *)
481 malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint));
482 assert(depth);
483 glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
484 depthFormat, depthType, depth);
485 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
486 ShadowTexWidth, ShadowTexHeight, 0,
487 GL_LUMINANCE, GL_UNSIGNED_INT, depth);
488 free(depth);
489 }
490 else {
491 /* The normal shadow case - a real depth texture */
492 glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
493 0, 0, ShadowTexWidth, ShadowTexHeight, 0);
494 if (UsePackedDepthStencil) {
495 /* debug check */
496 GLint intFormat;
497 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
498 GL_TEXTURE_INTERNAL_FORMAT, &intFormat);
499 assert(intFormat == GL_DEPTH_STENCIL_EXT);
500 }
501 }
502 }
503 }
504
505
506 /**
507 * Show the shadow map as a grayscale image.
508 */
509 static void
510 ShowShadowMap(void)
511 {
512 glClear(GL_COLOR_BUFFER_BIT);
513
514 glMatrixMode(GL_TEXTURE);
515 glLoadIdentity();
516
517 glMatrixMode(GL_PROJECTION);
518 glLoadIdentity();
519 glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1);
520
521 glMatrixMode(GL_MODELVIEW);
522 glLoadIdentity();
523
524 glDisable(GL_DEPTH_TEST);
525 glDisable(GL_LIGHTING);
526
527 glEnable(GL_TEXTURE_2D);
528
529 DisableTexgen();
530
531 /* interpret texture's depth values as luminance values */
532 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
533 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
534 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
535
536 glBegin(GL_POLYGON);
537 glTexCoord2f(0, 0); glVertex2f(0, 0);
538 glTexCoord2f(1, 0); glVertex2f(ShadowTexWidth, 0);
539 glTexCoord2f(1, 1); glVertex2f(ShadowTexWidth, ShadowTexHeight);
540 glTexCoord2f(0, 1); glVertex2f(0, ShadowTexHeight);
541 glEnd();
542
543 glDisable(GL_TEXTURE_2D);
544 glEnable(GL_DEPTH_TEST);
545 glEnable(GL_LIGHTING);
546 }
547
548
549 /**
550 * Redraw window image
551 */
552 static void
553 Display(void)
554 {
555 GLenum error;
556
557 ComputeLightPos(LightDist, LightLatitude, LightLongitude,
558 LightPos, SpotDir);
559
560 if (NeedNewShadowMap) {
561 MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
562 RenderShadowMap();
563 NeedNewShadowMap = GL_FALSE;
564 }
565
566 glViewport(0, 0, WindowWidth, WindowHeight);
567 if (DisplayMode == SHOW_DEPTH_IMAGE) {
568 ShowShadowMap();
569 }
570 else {
571 /* prepare to draw scene from camera's view */
572 const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
573
574 glMatrixMode(GL_PROJECTION);
575 glLoadIdentity();
576 glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
577
578 glMatrixMode(GL_MODELVIEW);
579 glLoadIdentity();
580 glTranslatef(0.0, 0.0, -22.0);
581 glRotatef(Xrot, 1, 0, 0);
582 glRotatef(Yrot, 0, 1, 0);
583 glRotatef(Zrot, 0, 0, 1);
584
585 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
586
587 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
588
589 if (LinearFilter) {
590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
591 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
592 }
593 else {
594 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
595 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
596 }
597
598 if (DisplayMode == SHOW_DEPTH_MAPPING) {
599 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
600 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
601 glEnable(GL_TEXTURE_2D);
602
603 SetShadowTextureMatrix();
604 EnableIdentityTexgen();
605 }
606 else if (DisplayMode == SHOW_DISTANCE) {
607 glMatrixMode(GL_TEXTURE);
608 glLoadIdentity();
609 glMatrixMode(GL_MODELVIEW);
610 EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
611 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
612 glEnable(GL_TEXTURE_1D);
613 assert(!glIsEnabled(GL_TEXTURE_2D));
614 }
615 else {
616 assert(DisplayMode == SHOW_SHADOWS);
617 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
618 GL_COMPARE_R_TO_TEXTURE_ARB);
619
620 if (curr_frag > 0) {
621 glEnable(GL_FRAGMENT_PROGRAM_ARB);
622 }
623 else {
624 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
625 }
626 glEnable(GL_TEXTURE_2D);
627
628 SetShadowTextureMatrix();
629
630 if (UseVP) {
631 glEnable(GL_VERTEX_PROGRAM_ARB);
632 }
633 else {
634 glEnable(GL_LIGHTING);
635 EnableIdentityTexgen();
636 }
637 }
638
639 DrawScene();
640
641 if (UseVP) {
642 glDisable(GL_VERTEX_PROGRAM_ARB);
643 }
644 else {
645 DisableTexgen();
646 glDisable(GL_LIGHTING);
647 }
648
649 if (curr_frag > 0) {
650 glDisable(GL_FRAGMENT_PROGRAM_ARB);
651 }
652
653 glDisable(GL_TEXTURE_2D);
654 }
655
656 glutSwapBuffers();
657
658 error = glGetError();
659 if (error) {
660 printf("GL Error: %s\n", (char *) gluErrorString(error));
661 }
662 }
663
664
665 static void
666 Reshape(int width, int height)
667 {
668 WindowWidth = width;
669 WindowHeight = height;
670 NeedNewShadowMap = GL_TRUE;
671 }
672
673
674 static void
675 Idle(void)
676 {
677 static double t0 = -1.;
678 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
679 if (t0 < 0.0)
680 t0 = t;
681 dt = t - t0;
682 t0 = t;
683 Yrot += 75.0 * dt;
684 /*LightLongitude -= 5.0;*/
685 glutPostRedisplay();
686 }
687
688
689 static void
690 Key(unsigned char key, int x, int y)
691 {
692 const GLfloat step = 3.0;
693 (void) x;
694 (void) y;
695 switch (key) {
696 case 'a':
697 Anim = !Anim;
698 if (Anim)
699 glutIdleFunc(Idle);
700 else
701 glutIdleFunc(NULL);
702 break;
703 case 'b':
704 Bias -= 0.01;
705 printf("Bias %g\n", Bias);
706 break;
707 case 'B':
708 Bias += 0.01;
709 printf("Bias %g\n", Bias);
710 break;
711 case 'd':
712 DisplayMode = SHOW_DISTANCE;
713 break;
714 case 'f':
715 LinearFilter = !LinearFilter;
716 printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
717 break;
718 case 'i':
719 DisplayMode = SHOW_DEPTH_IMAGE;
720 break;
721 case 'm':
722 DisplayMode = SHOW_DEPTH_MAPPING;
723 break;
724 case 'M':
725 curr_frag = (1 + curr_frag) % max_frag;
726 printf("Using fragment %s\n", FragProgNames[curr_frag]);
727
728 if (HaveFP) {
729 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, frag_progs[curr_frag]);
730 }
731 break;
732 case 'n':
733 case 's':
734 case ' ':
735 DisplayMode = SHOW_SHADOWS;
736 break;
737 case 'o':
738 if (HaveEXTshadowFuncs) {
739 Operator++;
740 if (Operator >= 8)
741 Operator = 0;
742 printf("Operator: %s\n", OperatorName[Operator]);
743 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
744 OperatorFunc[Operator]);
745 }
746 break;
747 case 'p':
748 UsePackedDepthStencil = !UsePackedDepthStencil;
749 if (UsePackedDepthStencil && !HavePackedDepthStencil) {
750 printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
751 UsePackedDepthStencil = GL_FALSE;
752 }
753 else {
754 printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil);
755 /* Don't really need to regenerate shadow map texture, but do so
756 * to exercise more code more often.
757 */
758 NeedNewShadowMap = GL_TRUE;
759 }
760 break;
761 case 'v':
762 UseVP = !UseVP && HaveVP;
763 printf("Using vertex %s mode.\n",
764 UseVP ? "program" : "fixed-function");
765 break;
766 case 'z':
767 Zrot -= step;
768 break;
769 case 'Z':
770 Zrot += step;
771 break;
772 case 27:
773 exit(0);
774 break;
775 }
776 glutPostRedisplay();
777 }
778
779
780 static void
781 SpecialKey(int key, int x, int y)
782 {
783 const GLfloat step = 3.0;
784 const int mod = glutGetModifiers();
785 (void) x;
786 (void) y;
787 switch (key) {
788 case GLUT_KEY_UP:
789 if (mod)
790 LightLatitude += step;
791 else
792 Xrot += step;
793 break;
794 case GLUT_KEY_DOWN:
795 if (mod)
796 LightLatitude -= step;
797 else
798 Xrot -= step;
799 break;
800 case GLUT_KEY_LEFT:
801 if (mod)
802 LightLongitude += step;
803 else
804 Yrot += step;
805 break;
806 case GLUT_KEY_RIGHT:
807 if (mod)
808 LightLongitude -= step;
809 else
810 Yrot -= step;
811 break;
812 }
813 if (mod)
814 NeedNewShadowMap = GL_TRUE;
815
816 glutPostRedisplay();
817 }
818
819
820 /* A helper for finding errors in program strings */
821 static int FindLine( const char *program, int position )
822 {
823 int i, line = 1;
824 for (i = 0; i < position; i++) {
825 if (program[i] == '\n')
826 line++;
827 }
828 return line;
829 }
830
831
832 static GLuint
833 compile_program(GLenum target, const char *code)
834 {
835 GLuint p;
836 GLint errorPos;
837
838
839 glGenProgramsARB(1, & p);
840
841 glBindProgramARB(target, p);
842 glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB,
843 strlen(code), code);
844 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
845 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
846 int l = FindLine(code, errorPos);
847 printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
848 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
849 exit(0);
850 }
851
852 glBindProgramARB(target, 0);
853 return p;
854 }
855
856 static void
857 Init(void)
858 {
859 static const GLfloat borderColor[4] = {1.0, 0.0, 0.0, 0.0};
860
861 if (!glutExtensionSupported("GL_ARB_depth_texture") ||
862 !glutExtensionSupported("GL_ARB_shadow")) {
863 printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
864 exit(1);
865 }
866 printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
867
868 HaveVP = glutExtensionSupported("GL_ARB_vertex_program");
869 HaveFP = glutExtensionSupported("GL_ARB_fragment_program");
870 HaveFP_Shadow = glutExtensionSupported("GL_ARB_fragment_program_shadow");
871
872 HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient");
873 if (HaveShadowAmbient) {
874 printf("and GL_ARB_shadow_ambient\n");
875 }
876
877 HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
878
879 HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil");
880 UsePackedDepthStencil = HavePackedDepthStencil;
881
882 #if defined(GL_EXT_framebuffer_object)
883 HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object");
884 UseFBO = HaveFBO;
885 if (UseFBO) {
886 printf("Using GL_EXT_framebuffer_object\n");
887 }
888 #endif
889
890 /*
891 * Set up the 2D shadow map texture
892 */
893 glGenTextures(1, &ShadowTexture);
894 glBindTexture(GL_TEXTURE_2D, ShadowTexture);
895 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
896 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
897 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
898 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
899 GL_COMPARE_R_TO_TEXTURE_ARB);
900 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
901
902 if (HaveShadowAmbient) {
903 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
904 }
905
906 #if defined(GL_EXT_framebuffer_object)
907 if (UseFBO) {
908 glGenFramebuffersEXT(1, &ShadowFBO);
909 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
910 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
911 GL_COLOR_ATTACHMENT0_EXT,
912 GL_RENDERBUFFER_EXT, 0);
913 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
914 GL_TEXTURE_2D, ShadowTexture, 0);
915
916 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
917 }
918 #endif
919
920 /*
921 * Setup 1-D grayscale texture image for SHOW_DISTANCE mode
922 */
923 glGenTextures(1, &GrayTexture);
924 glBindTexture(GL_TEXTURE_1D, GrayTexture);
925 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
926 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
927 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
928 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
929 {
930 GLuint i;
931 GLubyte image[256];
932 for (i = 0; i < 256; i++)
933 image[i] = i;
934 glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
935 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
936 }
937
938 if (HaveVP) {
939 vert_prog = compile_program(GL_VERTEX_PROGRAM_ARB, vert_code);
940 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vert_prog);
941 }
942
943 max_frag = 1;
944 frag_progs[0] = 0;
945
946 if (HaveFP) {
947 frag_progs[1] = compile_program(GL_FRAGMENT_PROGRAM_ARB, frag_code);
948 max_frag = 2;
949 }
950
951 if (HaveFP && HaveFP_Shadow) {
952 frag_progs[2] = compile_program(GL_FRAGMENT_PROGRAM_ARB,
953 frag_shadow_code);
954 max_frag = 3;
955 }
956
957 glEnable(GL_DEPTH_TEST);
958 glEnable(GL_LIGHTING);
959 glEnable(GL_LIGHT0);
960 }
961
962
963 static void
964 PrintHelp(void)
965 {
966 printf("Keys:\n");
967 printf(" a = toggle animation\n");
968 printf(" i = show depth texture image\n");
969 printf(" m = show depth texture mapping\n");
970 printf(" d = show fragment distance from light source\n");
971 printf(" n = show normal, shadowed image\n");
972 printf(" f = toggle nearest/bilinear texture filtering\n");
973 printf(" b/B = decrease/increase shadow map Z bias\n");
974 printf(" p = toggle use of packed depth/stencil\n");
975 printf(" M = cycle through fragment program modes\n");
976 printf(" v = toggle vertex program modes\n");
977 printf(" cursor keys = rotate scene\n");
978 printf(" <shift> + cursor keys = rotate light source\n");
979 if (HaveEXTshadowFuncs)
980 printf(" o = cycle through comparison modes\n");
981 }
982
983
984 int
985 main(int argc, char *argv[])
986 {
987 glutInit(&argc, argv);
988 glutInitWindowPosition(0, 0);
989 glutInitWindowSize(WindowWidth, WindowHeight);
990 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
991 glutCreateWindow(argv[0]);
992 glutReshapeFunc(Reshape);
993 glutKeyboardFunc(Key);
994 glutSpecialFunc(SpecialKey);
995 glutDisplayFunc(Display);
996 if (Anim)
997 glutIdleFunc(Idle);
998 Init();
999 PrintHelp();
1000 glutMainLoop();
1001 return 0;
1002 }