blob: 036f73d40b6650b563cbe94b47ccb05fb2393989 [file] [log] [blame]
Brian Paul1399d762001-02-20 16:43:50 +00001/*
Brian Paulf204c9d2002-02-16 14:54:18 +00002 * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and
Brian Paul762c3612006-04-06 04:11:28 +00003 * GL_ARB_shadow_ambient extensions.
Brian Paul1399d762001-02-20 16:43:50 +00004 *
5 * Brian Paul
6 * 19 Feb 2001
7 *
Brian Paul3c70f6f2002-03-23 16:34:18 +00008 * Added GL_EXT_shadow_funcs support on 23 March 2002
Brian Paul762c3612006-04-06 04:11:28 +00009 * 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.
Ian Romanick359c6ea2007-06-07 12:12:14 -070012 * Added vertex / fragment program support on 7 June 2007 (Ian Romanick).
Brian Paul3c70f6f2002-03-23 16:34:18 +000013 *
Brian Paul762c3612006-04-06 04:11:28 +000014 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Brian Paul1399d762001-02-20 16:43:50 +000015 *
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
Brian Paul0221e4d2001-02-28 18:41:50 +000034#include <assert.h>
Brian Paul1399d762001-02-20 16:43:50 +000035#include <stdio.h>
36#include <stdlib.h>
Ian Romanick359c6ea2007-06-07 12:12:14 -070037#include <string.h>
Brian Paul1399d762001-02-20 16:43:50 +000038#include <math.h>
José Fonseca2e61d132009-01-24 16:39:49 +000039#include <GL/glew.h>
Brian Paul1399d762001-02-20 16:43:50 +000040#include <GL/glut.h>
Brian Paul92eddb02005-01-09 17:37:50 +000041#include "showbuffer.h"
Brian Paul1399d762001-02-20 16:43:50 +000042
Brian Paul1399d762001-02-20 16:43:50 +000043#define DEG_TO_RAD (3.14159 / 180.0)
44
45static GLint WindowWidth = 450, WindowHeight = 300;
46static GLfloat Xrot = 15, Yrot = 0, Zrot = 0;
47
48static GLfloat Red[4] = {1, 0, 0, 1};
49static GLfloat Green[4] = {0, 1, 0, 1};
50static GLfloat Blue[4] = {0, 0, 1, 1};
51static GLfloat Yellow[4] = {1, 1, 0, 1};
52
53static GLfloat LightDist = 10;
54static GLfloat LightLatitude = 45.0;
55static GLfloat LightLongitude = 45.0;
56static GLfloat LightPos[4];
57static GLfloat SpotDir[3];
58static GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
59static GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
60static GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
61
Brian Paul511378b2001-02-26 18:26:32 +000062static GLboolean LinearFilter = GL_FALSE;
Brian Paul1399d762001-02-20 16:43:50 +000063
Brian Paul1399d762001-02-20 16:43:50 +000064static GLfloat Bias = -0.06;
65
Brian Paule099ce82006-04-06 04:34:09 +000066static GLboolean Anim = GL_TRUE;
Brian Paul1399d762001-02-20 16:43:50 +000067
Brian Paul762c3612006-04-06 04:11:28 +000068static GLboolean NeedNewShadowMap = GL_FALSE;
69static GLuint ShadowTexture, GrayTexture;
70static GLuint ShadowFBO;
71
Ian Romanick2260c242007-06-07 12:09:44 -070072static GLfloat lightModelview[16];
73static GLfloat lightProjection[16];
74
Ian Romanick359c6ea2007-06-07 12:12:14 -070075static GLuint vert_prog;
76static GLuint frag_progs[3];
77static GLuint curr_frag = 0;
78static GLuint max_frag = 1;
79
80#define NUM_FRAG_MODES 3
81static const char *FragProgNames[] = {
82 "fixed-function",
83 "program without \"OPTION ARB_fragment_program_shadow\"",
84 "program with \"OPTION ARB_fragment_program_shadow\"",
85};
86
Ian Romanickb961ecc2007-10-17 12:05:55 -070087static GLboolean HaveShadow = GL_FALSE;
Brian Paul762c3612006-04-06 04:11:28 +000088static GLboolean HaveFBO = GL_FALSE;
89static GLboolean UseFBO = GL_FALSE;
Ian Romanick359c6ea2007-06-07 12:12:14 -070090static GLboolean HaveVP = GL_FALSE;
91static GLboolean HaveFP = GL_FALSE;
92static GLboolean HaveFP_Shadow = GL_FALSE;
93static GLboolean UseVP = GL_FALSE;
Brian Paul762c3612006-04-06 04:11:28 +000094static GLboolean HavePackedDepthStencil = GL_FALSE;
Brian Paul10f08cc2006-03-15 01:44:03 +000095static GLboolean UsePackedDepthStencil = GL_FALSE;
Brian Paul3c70f6f2002-03-23 16:34:18 +000096static GLboolean HaveEXTshadowFuncs = GL_FALSE;
Brian Paul762c3612006-04-06 04:11:28 +000097static GLboolean HaveShadowAmbient = GL_FALSE;
98
Brian Paul3c70f6f2002-03-23 16:34:18 +000099static GLint Operator = 0;
100static const GLenum OperatorFunc[8] = {
101 GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER,
102 GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER };
103static const char *OperatorName[8] = {
104 "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
105 "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
106
107
Brian Paul0221e4d2001-02-28 18:41:50 +0000108static GLuint DisplayMode;
Brian Paul762c3612006-04-06 04:11:28 +0000109#define SHOW_SHADOWS 0
Brian Paul0221e4d2001-02-28 18:41:50 +0000110#define SHOW_DEPTH_IMAGE 1
111#define SHOW_DEPTH_MAPPING 2
112#define SHOW_DISTANCE 3
113
114
Brian Paul1399d762001-02-20 16:43:50 +0000115
Ian Romanick359c6ea2007-06-07 12:12:14 -0700116#define MAT4_MUL(dest_vec, src_mat, src_vec) \
117 "DP4 " dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
118 "DP4 " dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
119 "DP4 " dest_vec ".z, " src_mat "[2], " src_vec ";\n" \
120 "DP4 " dest_vec ".w, " src_mat "[3], " src_vec ";\n"
121
122#define MAT3_MUL(dest_vec, src_mat, src_vec) \
123 "DP3 " dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
124 "DP3 " dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
125 "DP3 " dest_vec ".z, " src_mat "[2], " src_vec ";\n"
126
127#define NORMALIZE(dest, src) \
128 "DP3 " dest ".w, " src ", " src ";\n" \
129 "RSQ " dest ".w, " dest ".w;\n" \
130 "MUL " dest ", " src ", " dest ".w;\n"
131
132/**
133 * Vertex program for shadow mapping.
134 */
135static const char vert_code[] =
136 "!!ARBvp1.0\n"
137 "ATTRIB iPos = vertex.position;\n"
138 "ATTRIB iNorm = vertex.normal;\n"
139
140 "PARAM mvinv[4] = { state.matrix.modelview.invtrans };\n"
141 "PARAM mvp[4] = { state.matrix.mvp };\n"
142 "PARAM mv[4] = { state.matrix.modelview };\n"
143 "PARAM texmat[4] = { state.matrix.texture[0] };\n"
144 "PARAM lightPos = state.light[0].position;\n"
145 "PARAM ambientCol = state.lightprod[0].ambient;\n"
146 "PARAM diffuseCol = state.lightprod[0].diffuse;\n"
147
148 "TEMP n, lightVec;\n"
149 "ALIAS V = lightVec;\n"
150 "ALIAS NdotL = n;\n"
151
152 "OUTPUT oPos = result.position;\n"
153 "OUTPUT oColor = result.color;\n"
154 "OUTPUT oTex = result.texcoord[0];\n"
155
156 /* Transform the vertex to clip coordinates. */
157 MAT4_MUL("oPos", "mvp", "iPos")
158
159 /* Transform the vertex to eye coordinates. */
160 MAT4_MUL("V", "mv", "iPos")
161
162 /* Transform the vertex to projected light coordinates. */
163 MAT4_MUL("oTex", "texmat", "iPos")
164
165 /* Transform the normal to eye coordinates. */
166 MAT3_MUL("n", "mvinv", "iNorm")
167
168 /* Calculate the vector from the vertex to the light in eye
169 * coordinates.
170 */
171 "SUB lightVec, lightPos, V;\n"
172 NORMALIZE("lightVec", "lightVec")
173
174 /* Compute diffuse lighting coefficient.
175 */
176 "DP3 NdotL.x, n, lightVec;\n"
177 "MAX NdotL.x, NdotL.x, {0.0};\n"
178 "MIN NdotL.x, NdotL.x, {1.0};\n"
179
180 /* Accumulate color contributions.
181 */
182 "MOV oColor, diffuseCol;\n"
183 "MAD oColor.xyz, NdotL.x, diffuseCol, ambientCol;\n"
184 "END\n"
185 ;
186
187static const char frag_code[] =
188 "!!ARBfp1.0\n"
189
190 "TEMP shadow, temp;\n"
191
192 "TXP shadow, fragment.texcoord[0], texture[0], 2D;\n"
193 "RCP temp.x, fragment.texcoord[0].w;\n"
194 "MUL temp.x, temp.x, fragment.texcoord[0].z;\n"
195 "SGE shadow, shadow.x, temp.x;\n"
196 "MUL result.color.rgb, fragment.color, shadow.x;\n"
197 "MOV result.color.a, fragment.color;\n"
198 "END\n"
199 ;
200
201static const char frag_shadow_code[] =
202 "!!ARBfp1.0\n"
203 "OPTION ARB_fragment_program_shadow;\n"
204
205 "TEMP shadow;\n"
206
207 "TXP shadow, fragment.texcoord[0], texture[0], SHADOW2D;\n"
208 "MUL result.color.rgb, fragment.color, shadow.x;\n"
209 "MOV result.color.a, fragment.color.a;\n"
210 "END\n"
211 ;
212
Brian Paul1399d762001-02-20 16:43:50 +0000213static void
214DrawScene(void)
215{
216 GLfloat k = 6;
Brian Paul762c3612006-04-06 04:11:28 +0000217
Brian Paul1399d762001-02-20 16:43:50 +0000218 /* sphere */
219 glPushMatrix();
220 glTranslatef(1.6, 2.2, 2.7);
221 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green);
222 glColor4fv(Green);
223 glutSolidSphere(1.5, 15, 15);
224 glPopMatrix();
225 /* dodecahedron */
226 glPushMatrix();
227 glTranslatef(-2.0, 1.2, 2.1);
228 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
229 glColor4fv(Red);
230 glutSolidDodecahedron();
231 glPopMatrix();
232 /* icosahedron */
233 glPushMatrix();
234 glTranslatef(-0.6, 1.3, -0.5);
235 glScalef(1.5, 1.5, 1.5);
236 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow);
237 glColor4fv(Red);
238 glutSolidIcosahedron();
239 glPopMatrix();
240 /* a plane */
241 glPushMatrix();
242 glTranslatef(0, -1.1, 0);
243 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
244 glColor4fv(Blue);
245 glNormal3f(0, 1, 0);
246 glBegin(GL_POLYGON);
247 glVertex3f(-k, 0, -k);
248 glVertex3f( k, 0, -k);
249 glVertex3f( k, 0, k);
250 glVertex3f(-k, 0, k);
251 glEnd();
252 glPopMatrix();
253}
254
255
Ian Romanick2260c242007-06-07 12:09:44 -0700256/**
257 * Calculate modelview and project matrices for the light
258 *
259 * Stores the results in \c lightProjection (projection matrix) and
260 * \c lightModelview (modelview matrix).
Brian Paul1399d762001-02-20 16:43:50 +0000261 */
262static void
Brian Paul0221e4d2001-02-28 18:41:50 +0000263MakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
264 GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
Brian Paul1399d762001-02-20 16:43:50 +0000265{
Ian Romanick2260c242007-06-07 12:09:44 -0700266 /* compute frustum to enclose spot light cone */
267 const GLfloat d = shadowNear * tan(spotAngle);
268
269 glMatrixMode(GL_PROJECTION);
270 glPushMatrix();
Brian Paul1399d762001-02-20 16:43:50 +0000271 glLoadIdentity();
Brian Paul1399d762001-02-20 16:43:50 +0000272 glFrustum(-d, d, -d, d, shadowNear, shadowFar);
Ian Romanick2260c242007-06-07 12:09:44 -0700273 glGetFloatv(GL_PROJECTION_MATRIX, lightProjection);
274 glPopMatrix();
275
276 glMatrixMode(GL_MODELVIEW);
277 glPushMatrix();
278 glLoadIdentity();
Brian Paul1399d762001-02-20 16:43:50 +0000279 gluLookAt(lightPos[0], lightPos[1], lightPos[2],
280 lightPos[0] + spotDir[0],
281 lightPos[1] + spotDir[1],
282 lightPos[2] + spotDir[2],
Ian Romanick2260c242007-06-07 12:09:44 -0700283 0.0, 1.0, 0.0);
284 glGetFloatv(GL_MODELVIEW_MATRIX, lightModelview);
285 glPopMatrix();
286}
287
288
289/**
290 * Load \c GL_TEXTURE matrix with light's MVP matrix.
291 */
292static void SetShadowTextureMatrix(void)
293{
294 static const GLfloat biasMatrix[16] = {
295 0.5, 0.0, 0.0, 0.0,
296 0.0, 0.5, 0.0, 0.0,
297 0.0, 0.0, 0.5, 0.0,
298 0.5, 0.5, 0.5, 1.0,
299 };
300
301 glMatrixMode(GL_TEXTURE);
302 glLoadMatrixf(biasMatrix);
303 glTranslatef(0.0, 0.0, Bias);
304 glMultMatrixf(lightProjection);
305 glMultMatrixf(lightModelview);
Brian Paul1399d762001-02-20 16:43:50 +0000306 glMatrixMode(GL_MODELVIEW);
307}
308
309
310static void
Brian Paul0221e4d2001-02-28 18:41:50 +0000311EnableIdentityTexgen(void)
Brian Paul1399d762001-02-20 16:43:50 +0000312{
313 /* texgen so that texcoord = vertex coord */
314 static GLfloat sPlane[4] = { 1, 0, 0, 0 };
315 static GLfloat tPlane[4] = { 0, 1, 0, 0 };
316 static GLfloat rPlane[4] = { 0, 0, 1, 0 };
317 static GLfloat qPlane[4] = { 0, 0, 0, 1 };
318
319 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
320 glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
321 glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
322 glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
323 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
324 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
325 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
326 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
327
328 glEnable(GL_TEXTURE_GEN_S);
329 glEnable(GL_TEXTURE_GEN_T);
330 glEnable(GL_TEXTURE_GEN_R);
331 glEnable(GL_TEXTURE_GEN_Q);
332}
333
334
Brian Paul0221e4d2001-02-28 18:41:50 +0000335/*
336 * Setup 1-D texgen so that the distance from the light source, between
337 * the near and far planes maps to s=0 and s=1. When we draw the scene,
338 * the grayness will indicate the fragment's distance from the light
339 * source.
340 */
341static void
342EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
343 GLfloat lightNear, GLfloat lightFar)
344{
345 GLfloat m, d;
346 GLfloat sPlane[4];
347 GLfloat nearPoint[3];
348
349 m = sqrt(lightDir[0] * lightDir[0] +
350 lightDir[1] * lightDir[1] +
351 lightDir[2] * lightDir[2]);
352
353 d = lightFar - lightNear;
354
355 /* nearPoint = point on light direction vector which intersects the
356 * near plane of the light frustum.
357 */
Brian Paul762c3612006-04-06 04:11:28 +0000358 nearPoint[0] = lightPos[0] + lightDir[0] / m * lightNear;
359 nearPoint[1] = lightPos[1] + lightDir[1] / m * lightNear;
360 nearPoint[2] = lightPos[2] + lightDir[2] / m * lightNear;
Brian Paul0221e4d2001-02-28 18:41:50 +0000361
362 sPlane[0] = lightDir[0] / d / m;
363 sPlane[1] = lightDir[1] / d / m;
364 sPlane[2] = lightDir[2] / d / m;
365 sPlane[3] = -(sPlane[0] * nearPoint[0]
366 + sPlane[1] * nearPoint[1]
367 + sPlane[2] * nearPoint[2]);
368
369 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
370 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
371 glEnable(GL_TEXTURE_GEN_S);
372}
373
374
Brian Paul1399d762001-02-20 16:43:50 +0000375static void
376DisableTexgen(void)
377{
378 glDisable(GL_TEXTURE_GEN_S);
379 glDisable(GL_TEXTURE_GEN_T);
380 glDisable(GL_TEXTURE_GEN_R);
381 glDisable(GL_TEXTURE_GEN_Q);
382}
383
384
385static void
386ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
387 GLfloat pos[4], GLfloat dir[3])
388{
Brian Paul0221e4d2001-02-28 18:41:50 +0000389
Brian Paul1399d762001-02-20 16:43:50 +0000390 pos[0] = dist * sin(longitude * DEG_TO_RAD);
391 pos[1] = dist * sin(latitude * DEG_TO_RAD);
392 pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
393 pos[3] = 1;
394 dir[0] = -pos[0];
395 dir[1] = -pos[1];
396 dir[2] = -pos[2];
397}
398
399
Brian Paul762c3612006-04-06 04:11:28 +0000400/**
401 * Render the shadow map / depth texture.
402 * The result will be in the texture object named ShadowTexture.
403 */
Brian Paul1399d762001-02-20 16:43:50 +0000404static void
Brian Paul762c3612006-04-06 04:11:28 +0000405RenderShadowMap(void)
Brian Paul1399d762001-02-20 16:43:50 +0000406{
Brian Paul762c3612006-04-06 04:11:28 +0000407 GLenum depthFormat; /* GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT */
408 GLenum depthType; /* GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT */
Brian Paul1399d762001-02-20 16:43:50 +0000409
Brian Paul762c3612006-04-06 04:11:28 +0000410 if (WindowWidth >= 1024 && WindowHeight >= 1024) {
411 ShadowTexWidth = ShadowTexHeight = 1024;
412 }
413 else if (WindowWidth >= 512 && WindowHeight >= 512) {
414 ShadowTexWidth = ShadowTexHeight = 512;
415 }
416 else if (WindowWidth >= 256 && WindowHeight >= 256) {
417 ShadowTexWidth = ShadowTexHeight = 256;
418 }
419 else {
420 ShadowTexWidth = ShadowTexHeight = 128;
421 }
422 printf("Rendering %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
423
424 if (UsePackedDepthStencil) {
425 depthFormat = GL_DEPTH_STENCIL_EXT;
426 depthType = GL_UNSIGNED_INT_24_8_EXT;
427 }
428 else {
429 depthFormat = GL_DEPTH_COMPONENT;
430 depthType = GL_UNSIGNED_INT;
431 }
432
Brian Paul1399d762001-02-20 16:43:50 +0000433 glMatrixMode(GL_PROJECTION);
Ian Romanick2260c242007-06-07 12:09:44 -0700434 glLoadMatrixf(lightProjection);
435
Brian Paul1399d762001-02-20 16:43:50 +0000436 glMatrixMode(GL_MODELVIEW);
Ian Romanick2260c242007-06-07 12:09:44 -0700437 glLoadMatrixf(lightModelview);
Brian Paul1399d762001-02-20 16:43:50 +0000438
Brian Paul762c3612006-04-06 04:11:28 +0000439 if (UseFBO) {
Ian Romanickad3cc952007-04-21 10:47:54 -0700440 GLenum fbo_status;
441
Brian Paul762c3612006-04-06 04:11:28 +0000442 glTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
443 ShadowTexWidth, ShadowTexHeight, 0,
444 depthFormat, depthType, NULL);
Ian Romanickad3cc952007-04-21 10:47:54 -0700445
446 /* Set the filter mode so that the texture is texture-complete.
447 * Otherwise it will cause the framebuffer to fail the framebuffer
448 * completeness test.
449 */
450 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
451
Brian Paul762c3612006-04-06 04:11:28 +0000452 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
453 glDrawBuffer(GL_NONE);
454 glReadBuffer(GL_NONE);
Ian Romanickad3cc952007-04-21 10:47:54 -0700455
456 fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
457 if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
458 fprintf(stderr, "FBO not complete! status = 0x%04x\n", fbo_status);
459 assert(fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT);
460 }
Brian Paul762c3612006-04-06 04:11:28 +0000461 }
462
463 assert(!glIsEnabled(GL_TEXTURE_1D));
464 assert(!glIsEnabled(GL_TEXTURE_2D));
465
Brian Paul1399d762001-02-20 16:43:50 +0000466 glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
Brian Paul762c3612006-04-06 04:11:28 +0000467 glClear(GL_DEPTH_BUFFER_BIT);
468 glEnable(GL_DEPTH_TEST);
Brian Paul1399d762001-02-20 16:43:50 +0000469 DrawScene();
470
Brian Paul762c3612006-04-06 04:11:28 +0000471 if (UseFBO) {
472 /* all done! */
473 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
474 }
475 else {
476 /*
477 * copy depth buffer into the texture map
478 */
479 if (DisplayMode == SHOW_DEPTH_MAPPING) {
480 /* load depth image as gray-scale luminance texture */
481 GLuint *depth = (GLuint *)
482 malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint));
Brian Paul10f08cc2006-03-15 01:44:03 +0000483 assert(depth);
484 glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
Brian Paul762c3612006-04-06 04:11:28 +0000485 depthFormat, depthType, depth);
Brian Paul10f08cc2006-03-15 01:44:03 +0000486 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
487 ShadowTexWidth, ShadowTexHeight, 0,
488 GL_LUMINANCE, GL_UNSIGNED_INT, depth);
489 free(depth);
490 }
491 else {
Brian Paul762c3612006-04-06 04:11:28 +0000492 /* The normal shadow case - a real depth texture */
493 glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
494 0, 0, ShadowTexWidth, ShadowTexHeight, 0);
495 if (UsePackedDepthStencil) {
496 /* debug check */
497 GLint intFormat;
498 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
499 GL_TEXTURE_INTERNAL_FORMAT, &intFormat);
500 assert(intFormat == GL_DEPTH_STENCIL_EXT);
501 }
Brian Paul0221e4d2001-02-28 18:41:50 +0000502 }
503 }
Brian Paul762c3612006-04-06 04:11:28 +0000504}
505
506
507/**
508 * Show the shadow map as a grayscale image.
509 */
510static void
511ShowShadowMap(void)
512{
513 glClear(GL_COLOR_BUFFER_BIT);
514
515 glMatrixMode(GL_TEXTURE);
516 glLoadIdentity();
517
518 glMatrixMode(GL_PROJECTION);
519 glLoadIdentity();
520 glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1);
521
522 glMatrixMode(GL_MODELVIEW);
523 glLoadIdentity();
524
525 glDisable(GL_DEPTH_TEST);
526 glDisable(GL_LIGHTING);
527
528 glEnable(GL_TEXTURE_2D);
529
530 DisableTexgen();
531
532 /* interpret texture's depth values as luminance values */
Ian Romanickb961ecc2007-10-17 12:05:55 -0700533 if (HaveShadow) {
534 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
535 }
536
Brian Paul762c3612006-04-06 04:11:28 +0000537 glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
Brian Paul762c3612006-04-06 04:11:28 +0000538 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
539
540 glBegin(GL_POLYGON);
541 glTexCoord2f(0, 0); glVertex2f(0, 0);
542 glTexCoord2f(1, 0); glVertex2f(ShadowTexWidth, 0);
543 glTexCoord2f(1, 1); glVertex2f(ShadowTexWidth, ShadowTexHeight);
544 glTexCoord2f(0, 1); glVertex2f(0, ShadowTexHeight);
545 glEnd();
546
547 glDisable(GL_TEXTURE_2D);
548 glEnable(GL_DEPTH_TEST);
549 glEnable(GL_LIGHTING);
550}
551
552
553/**
554 * Redraw window image
555 */
556static void
557Display(void)
558{
559 GLenum error;
560
561 ComputeLightPos(LightDist, LightLatitude, LightLongitude,
562 LightPos, SpotDir);
563
564 if (NeedNewShadowMap) {
Ian Romanick2260c242007-06-07 12:09:44 -0700565 MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
Brian Paul762c3612006-04-06 04:11:28 +0000566 RenderShadowMap();
567 NeedNewShadowMap = GL_FALSE;
Brian Paul0221e4d2001-02-28 18:41:50 +0000568 }
Brian Paul1399d762001-02-20 16:43:50 +0000569
Brian Paul1399d762001-02-20 16:43:50 +0000570 glViewport(0, 0, WindowWidth, WindowHeight);
Brian Paul0221e4d2001-02-28 18:41:50 +0000571 if (DisplayMode == SHOW_DEPTH_IMAGE) {
Brian Paul762c3612006-04-06 04:11:28 +0000572 ShowShadowMap();
Brian Paul1399d762001-02-20 16:43:50 +0000573 }
574 else {
Brian Paul762c3612006-04-06 04:11:28 +0000575 /* prepare to draw scene from camera's view */
576 const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
577
Brian Paul511378b2001-02-26 18:26:32 +0000578 glMatrixMode(GL_PROJECTION);
579 glLoadIdentity();
580 glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
Brian Paul762c3612006-04-06 04:11:28 +0000581
Brian Paul511378b2001-02-26 18:26:32 +0000582 glMatrixMode(GL_MODELVIEW);
583 glLoadIdentity();
584 glTranslatef(0.0, 0.0, -22.0);
585 glRotatef(Xrot, 1, 0, 0);
586 glRotatef(Yrot, 0, 1, 0);
587 glRotatef(Zrot, 0, 0, 1);
Brian Paul762c3612006-04-06 04:11:28 +0000588
Brian Paul1399d762001-02-20 16:43:50 +0000589 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Brian Paul762c3612006-04-06 04:11:28 +0000590
Brian Paul1399d762001-02-20 16:43:50 +0000591 glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
Brian Paul762c3612006-04-06 04:11:28 +0000592
Brian Paul511378b2001-02-26 18:26:32 +0000593 if (LinearFilter) {
594 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
595 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
596 }
597 else {
598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
599 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
600 }
Brian Paul762c3612006-04-06 04:11:28 +0000601
Brian Paul0221e4d2001-02-28 18:41:50 +0000602 if (DisplayMode == SHOW_DEPTH_MAPPING) {
Ian Romanickb961ecc2007-10-17 12:05:55 -0700603 if (HaveShadow) {
604 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
605 }
Brian Paul0221e4d2001-02-28 18:41:50 +0000606 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
607 glEnable(GL_TEXTURE_2D);
Ian Romanick2260c242007-06-07 12:09:44 -0700608
609 SetShadowTextureMatrix();
Brian Paul0221e4d2001-02-28 18:41:50 +0000610 EnableIdentityTexgen();
611 }
612 else if (DisplayMode == SHOW_DISTANCE) {
613 glMatrixMode(GL_TEXTURE);
614 glLoadIdentity();
615 glMatrixMode(GL_MODELVIEW);
616 EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
617 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
618 glEnable(GL_TEXTURE_1D);
Brian Paul762c3612006-04-06 04:11:28 +0000619 assert(!glIsEnabled(GL_TEXTURE_2D));
Brian Paul0221e4d2001-02-28 18:41:50 +0000620 }
621 else {
Brian Paul762c3612006-04-06 04:11:28 +0000622 assert(DisplayMode == SHOW_SHADOWS);
Ian Romanickb961ecc2007-10-17 12:05:55 -0700623 if (HaveShadow) {
624 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
625 GL_COMPARE_R_TO_TEXTURE_ARB);
626 }
Ian Romanick359c6ea2007-06-07 12:12:14 -0700627
628 if (curr_frag > 0) {
629 glEnable(GL_FRAGMENT_PROGRAM_ARB);
630 }
631 else {
632 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
633 }
Brian Paul0221e4d2001-02-28 18:41:50 +0000634 glEnable(GL_TEXTURE_2D);
Ian Romanick2260c242007-06-07 12:09:44 -0700635
636 SetShadowTextureMatrix();
Ian Romanick359c6ea2007-06-07 12:12:14 -0700637
638 if (UseVP) {
639 glEnable(GL_VERTEX_PROGRAM_ARB);
640 }
641 else {
642 glEnable(GL_LIGHTING);
643 EnableIdentityTexgen();
644 }
Brian Paul0221e4d2001-02-28 18:41:50 +0000645 }
Brian Paul762c3612006-04-06 04:11:28 +0000646
Brian Paul1399d762001-02-20 16:43:50 +0000647 DrawScene();
Brian Paul762c3612006-04-06 04:11:28 +0000648
Ian Romanick359c6ea2007-06-07 12:12:14 -0700649 if (UseVP) {
650 glDisable(GL_VERTEX_PROGRAM_ARB);
651 }
652 else {
653 DisableTexgen();
654 glDisable(GL_LIGHTING);
655 }
656
657 if (curr_frag > 0) {
658 glDisable(GL_FRAGMENT_PROGRAM_ARB);
659 }
660
Brian Paulaef4ca62008-04-29 15:02:46 -0600661 glDisable(GL_TEXTURE_1D);
Brian Paul1399d762001-02-20 16:43:50 +0000662 glDisable(GL_TEXTURE_2D);
663 }
664
665 glutSwapBuffers();
Brian Paul3c70f6f2002-03-23 16:34:18 +0000666
667 error = glGetError();
668 if (error) {
Brian Paul95210bc2003-04-21 14:50:12 +0000669 printf("GL Error: %s\n", (char *) gluErrorString(error));
Brian Paul3c70f6f2002-03-23 16:34:18 +0000670 }
Brian Paul1399d762001-02-20 16:43:50 +0000671}
672
673
674static void
675Reshape(int width, int height)
676{
677 WindowWidth = width;
678 WindowHeight = height;
Brian Paul762c3612006-04-06 04:11:28 +0000679 NeedNewShadowMap = GL_TRUE;
Brian Paul1399d762001-02-20 16:43:50 +0000680}
681
682
683static void
684Idle(void)
685{
Brian Paul92eddb02005-01-09 17:37:50 +0000686 static double t0 = -1.;
687 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
688 if (t0 < 0.0)
689 t0 = t;
690 dt = t - t0;
691 t0 = t;
692 Yrot += 75.0 * dt;
Brian Paul1399d762001-02-20 16:43:50 +0000693 /*LightLongitude -= 5.0;*/
694 glutPostRedisplay();
695}
696
697
698static void
699Key(unsigned char key, int x, int y)
700{
701 const GLfloat step = 3.0;
702 (void) x;
703 (void) y;
704 switch (key) {
705 case 'a':
706 Anim = !Anim;
707 if (Anim)
708 glutIdleFunc(Idle);
709 else
710 glutIdleFunc(NULL);
711 break;
712 case 'b':
713 Bias -= 0.01;
Brian Paul511378b2001-02-26 18:26:32 +0000714 printf("Bias %g\n", Bias);
Brian Paul1399d762001-02-20 16:43:50 +0000715 break;
716 case 'B':
717 Bias += 0.01;
Brian Paul511378b2001-02-26 18:26:32 +0000718 printf("Bias %g\n", Bias);
Brian Paul1399d762001-02-20 16:43:50 +0000719 break;
720 case 'd':
Brian Paul0221e4d2001-02-28 18:41:50 +0000721 DisplayMode = SHOW_DISTANCE;
Brian Paul1399d762001-02-20 16:43:50 +0000722 break;
Brian Paul511378b2001-02-26 18:26:32 +0000723 case 'f':
724 LinearFilter = !LinearFilter;
725 printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
726 break;
Brian Paul0221e4d2001-02-28 18:41:50 +0000727 case 'i':
728 DisplayMode = SHOW_DEPTH_IMAGE;
729 break;
730 case 'm':
731 DisplayMode = SHOW_DEPTH_MAPPING;
732 break;
Ian Romanick359c6ea2007-06-07 12:12:14 -0700733 case 'M':
734 curr_frag = (1 + curr_frag) % max_frag;
Ian Romanickb961ecc2007-10-17 12:05:55 -0700735 if (!HaveShadow && (curr_frag == 0)) {
736 curr_frag = 1;
737 }
738
Ian Romanick359c6ea2007-06-07 12:12:14 -0700739 printf("Using fragment %s\n", FragProgNames[curr_frag]);
740
741 if (HaveFP) {
742 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, frag_progs[curr_frag]);
743 }
744 break;
Brian Paul0221e4d2001-02-28 18:41:50 +0000745 case 'n':
Brian Paul762c3612006-04-06 04:11:28 +0000746 case 's':
Brian Paul0221e4d2001-02-28 18:41:50 +0000747 case ' ':
Brian Paul762c3612006-04-06 04:11:28 +0000748 DisplayMode = SHOW_SHADOWS;
Brian Paul0221e4d2001-02-28 18:41:50 +0000749 break;
Brian Paul3c70f6f2002-03-23 16:34:18 +0000750 case 'o':
751 if (HaveEXTshadowFuncs) {
752 Operator++;
753 if (Operator >= 8)
754 Operator = 0;
755 printf("Operator: %s\n", OperatorName[Operator]);
Ian Romanickb961ecc2007-10-17 12:05:55 -0700756 if (HaveShadow) {
757 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
758 OperatorFunc[Operator]);
759 }
Brian Paul3c70f6f2002-03-23 16:34:18 +0000760 }
761 break;
Brian Paul10f08cc2006-03-15 01:44:03 +0000762 case 'p':
763 UsePackedDepthStencil = !UsePackedDepthStencil;
Brian Paul762c3612006-04-06 04:11:28 +0000764 if (UsePackedDepthStencil && !HavePackedDepthStencil) {
Brian Paul10f08cc2006-03-15 01:44:03 +0000765 printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
766 UsePackedDepthStencil = GL_FALSE;
767 }
768 else {
769 printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil);
Brian Paul762c3612006-04-06 04:11:28 +0000770 /* Don't really need to regenerate shadow map texture, but do so
771 * to exercise more code more often.
772 */
773 NeedNewShadowMap = GL_TRUE;
Brian Paul10f08cc2006-03-15 01:44:03 +0000774 }
775 break;
Ian Romanick359c6ea2007-06-07 12:12:14 -0700776 case 'v':
777 UseVP = !UseVP && HaveVP;
778 printf("Using vertex %s mode.\n",
779 UseVP ? "program" : "fixed-function");
780 break;
Brian Paul1399d762001-02-20 16:43:50 +0000781 case 'z':
782 Zrot -= step;
783 break;
784 case 'Z':
785 Zrot += step;
786 break;
787 case 27:
788 exit(0);
789 break;
790 }
Keith Whitwella86ef372009-04-24 12:16:29 +0100791 fflush(stdout);
Brian Paul1399d762001-02-20 16:43:50 +0000792 glutPostRedisplay();
Brian Paul1399d762001-02-20 16:43:50 +0000793}
794
795
796static void
797SpecialKey(int key, int x, int y)
798{
799 const GLfloat step = 3.0;
800 const int mod = glutGetModifiers();
801 (void) x;
802 (void) y;
803 switch (key) {
804 case GLUT_KEY_UP:
805 if (mod)
806 LightLatitude += step;
807 else
808 Xrot += step;
809 break;
810 case GLUT_KEY_DOWN:
811 if (mod)
812 LightLatitude -= step;
813 else
814 Xrot -= step;
815 break;
816 case GLUT_KEY_LEFT:
817 if (mod)
818 LightLongitude += step;
819 else
820 Yrot += step;
821 break;
822 case GLUT_KEY_RIGHT:
823 if (mod)
824 LightLongitude -= step;
825 else
826 Yrot -= step;
827 break;
828 }
Brian Paul762c3612006-04-06 04:11:28 +0000829 if (mod)
830 NeedNewShadowMap = GL_TRUE;
831
Brian Paul1399d762001-02-20 16:43:50 +0000832 glutPostRedisplay();
833}
834
835
Ian Romanick359c6ea2007-06-07 12:12:14 -0700836/* A helper for finding errors in program strings */
837static int FindLine( const char *program, int position )
838{
839 int i, line = 1;
840 for (i = 0; i < position; i++) {
841 if (program[i] == '\n')
842 line++;
843 }
844 return line;
845}
846
847
848static GLuint
849compile_program(GLenum target, const char *code)
850{
851 GLuint p;
852 GLint errorPos;
853
854
855 glGenProgramsARB(1, & p);
856
857 glBindProgramARB(target, p);
858 glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB,
859 strlen(code), code);
860 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
861 if (glGetError() != GL_NO_ERROR || errorPos != -1) {
862 int l = FindLine(code, errorPos);
863 printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
864 (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
865 exit(0);
866 }
867
868 glBindProgramARB(target, 0);
869 return p;
870}
871
Brian Paul1399d762001-02-20 16:43:50 +0000872static void
873Init(void)
874{
Brian Paul1979b6b2006-04-05 03:26:12 +0000875 static const GLfloat borderColor[4] = {1.0, 0.0, 0.0, 0.0};
876
Ian Romanickb961ecc2007-10-17 12:05:55 -0700877 if (!glutExtensionSupported("GL_ARB_depth_texture")) {
878 printf("Sorry, this demo requires the GL_ARB_depth_texture extension\n");
Brian Paulf204c9d2002-02-16 14:54:18 +0000879 exit(1);
880 }
Brian Paul762c3612006-04-06 04:11:28 +0000881
Ian Romanickb961ecc2007-10-17 12:05:55 -0700882 HaveShadow = glutExtensionSupported("GL_ARB_shadow");
Ian Romanick359c6ea2007-06-07 12:12:14 -0700883 HaveVP = glutExtensionSupported("GL_ARB_vertex_program");
884 HaveFP = glutExtensionSupported("GL_ARB_fragment_program");
885 HaveFP_Shadow = glutExtensionSupported("GL_ARB_fragment_program_shadow");
886
Ian Romanickb961ecc2007-10-17 12:05:55 -0700887 if (!HaveShadow && !HaveFP) {
888 printf("Sorry, this demo requires either the GL_ARB_shadow extension "
889 "or the GL_ARB_fragment_program extension\n");
890 exit(1);
891 }
892
893 printf("Using GL_ARB_depth_texture\n");
894 if (HaveShadow) {
895 printf("and GL_ARB_shadow\n");
896 }
897
898 if (HaveFP) {
899 printf("and GL_ARB_fragment_program\n");
900 }
901
Brian Paul762c3612006-04-06 04:11:28 +0000902 HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient");
903 if (HaveShadowAmbient) {
904 printf("and GL_ARB_shadow_ambient\n");
Brian Paul1399d762001-02-20 16:43:50 +0000905 }
Brian Paul762c3612006-04-06 04:11:28 +0000906
Brian Paul3c70f6f2002-03-23 16:34:18 +0000907 HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
Brian Paul1399d762001-02-20 16:43:50 +0000908
Brian Paul762c3612006-04-06 04:11:28 +0000909 HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil");
910 UsePackedDepthStencil = HavePackedDepthStencil;
Brian Paul1979b6b2006-04-05 03:26:12 +0000911
Brian Paul762c3612006-04-06 04:11:28 +0000912#if defined(GL_EXT_framebuffer_object)
913 HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object");
914 UseFBO = HaveFBO;
915 if (UseFBO) {
916 printf("Using GL_EXT_framebuffer_object\n");
917 }
918#endif
919
920 /*
921 * Set up the 2D shadow map texture
922 */
923 glGenTextures(1, &ShadowTexture);
924 glBindTexture(GL_TEXTURE_2D, ShadowTexture);
Brian Paul1979b6b2006-04-05 03:26:12 +0000925 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
Brian Paul1399d762001-02-20 16:43:50 +0000926 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
927 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
Ian Romanickb961ecc2007-10-17 12:05:55 -0700928
929 if (HaveShadow) {
930 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
931 GL_COMPARE_R_TO_TEXTURE_ARB);
932 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
933 }
Ian Romanickf575d4f2007-06-07 11:59:42 -0700934
Brian Paul762c3612006-04-06 04:11:28 +0000935 if (HaveShadowAmbient) {
Brian Paulf204c9d2002-02-16 14:54:18 +0000936 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
Brian Paulf204c9d2002-02-16 14:54:18 +0000937 }
Brian Paul762c3612006-04-06 04:11:28 +0000938
939#if defined(GL_EXT_framebuffer_object)
940 if (UseFBO) {
941 glGenFramebuffersEXT(1, &ShadowFBO);
942 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
943 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
944 GL_COLOR_ATTACHMENT0_EXT,
945 GL_RENDERBUFFER_EXT, 0);
946 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
947 GL_TEXTURE_2D, ShadowTexture, 0);
948
949 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
Brian Paulf204c9d2002-02-16 14:54:18 +0000950 }
Brian Paul0a0595f2001-02-20 17:06:35 +0000951#endif
Brian Paul1399d762001-02-20 16:43:50 +0000952
Brian Paul762c3612006-04-06 04:11:28 +0000953 /*
954 * Setup 1-D grayscale texture image for SHOW_DISTANCE mode
955 */
956 glGenTextures(1, &GrayTexture);
957 glBindTexture(GL_TEXTURE_1D, GrayTexture);
958 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
Brian Paul762c3612006-04-06 04:11:28 +0000959 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
960 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Brian Paul0221e4d2001-02-28 18:41:50 +0000961 {
962 GLuint i;
963 GLubyte image[256];
964 for (i = 0; i < 256; i++)
965 image[i] = i;
966 glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
967 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
968 }
969
Ian Romanick359c6ea2007-06-07 12:12:14 -0700970 if (HaveVP) {
971 vert_prog = compile_program(GL_VERTEX_PROGRAM_ARB, vert_code);
972 glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vert_prog);
973 }
974
975 max_frag = 1;
976 frag_progs[0] = 0;
977
978 if (HaveFP) {
979 frag_progs[1] = compile_program(GL_FRAGMENT_PROGRAM_ARB, frag_code);
980 max_frag = 2;
981 }
982
983 if (HaveFP && HaveFP_Shadow) {
984 frag_progs[2] = compile_program(GL_FRAGMENT_PROGRAM_ARB,
985 frag_shadow_code);
986 max_frag = 3;
987 }
988
Ian Romanickb961ecc2007-10-17 12:05:55 -0700989 if (!HaveShadow) {
990 curr_frag = 1;
991 glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, frag_progs[curr_frag]);
992 }
993
Brian Paul1399d762001-02-20 16:43:50 +0000994 glEnable(GL_DEPTH_TEST);
995 glEnable(GL_LIGHTING);
996 glEnable(GL_LIGHT0);
997}
998
999
1000static void
1001PrintHelp(void)
1002{
1003 printf("Keys:\n");
1004 printf(" a = toggle animation\n");
Brian Paul0221e4d2001-02-28 18:41:50 +00001005 printf(" i = show depth texture image\n");
1006 printf(" m = show depth texture mapping\n");
1007 printf(" d = show fragment distance from light source\n");
1008 printf(" n = show normal, shadowed image\n");
Brian Paul511378b2001-02-26 18:26:32 +00001009 printf(" f = toggle nearest/bilinear texture filtering\n");
Brian Paul1399d762001-02-20 16:43:50 +00001010 printf(" b/B = decrease/increase shadow map Z bias\n");
Brian Paul10f08cc2006-03-15 01:44:03 +00001011 printf(" p = toggle use of packed depth/stencil\n");
Ian Romanick359c6ea2007-06-07 12:12:14 -07001012 printf(" M = cycle through fragment program modes\n");
1013 printf(" v = toggle vertex program modes\n");
Brian Paul1399d762001-02-20 16:43:50 +00001014 printf(" cursor keys = rotate scene\n");
1015 printf(" <shift> + cursor keys = rotate light source\n");
Brian Paul3c70f6f2002-03-23 16:34:18 +00001016 if (HaveEXTshadowFuncs)
1017 printf(" o = cycle through comparison modes\n");
Keith Whitwella86ef372009-04-24 12:16:29 +01001018 fflush(stdout);
Brian Paul1399d762001-02-20 16:43:50 +00001019}
1020
1021
1022int
1023main(int argc, char *argv[])
1024{
Brian Paul1399d762001-02-20 16:43:50 +00001025 glutInitWindowSize(WindowWidth, WindowHeight);
Brian Paul263f4322009-12-18 08:12:55 -07001026 glutInit(&argc, argv);
Brian Paul10f08cc2006-03-15 01:44:03 +00001027 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
Brian Paul1399d762001-02-20 16:43:50 +00001028 glutCreateWindow(argv[0]);
José Fonseca2e61d132009-01-24 16:39:49 +00001029 glewInit();
Brian Paul1399d762001-02-20 16:43:50 +00001030 glutReshapeFunc(Reshape);
1031 glutKeyboardFunc(Key);
1032 glutSpecialFunc(SpecialKey);
1033 glutDisplayFunc(Display);
1034 if (Anim)
1035 glutIdleFunc(Idle);
1036 Init();
1037 PrintHelp();
1038 glutMainLoop();
1039 return 0;
1040}