132001f49Smrg/*
232001f49Smrg * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and
332001f49Smrg * GL_ARB_shadow_ambient extensions.
432001f49Smrg *
532001f49Smrg * Brian Paul
632001f49Smrg * 19 Feb 2001
732001f49Smrg *
832001f49Smrg * Added GL_EXT_shadow_funcs support on 23 March 2002
932001f49Smrg * Added GL_EXT_packed_depth_stencil support on 15 March 2006.
1032001f49Smrg * Added GL_EXT_framebuffer_object support on 27 March 2006.
1132001f49Smrg * Removed old SGIX extension support on 5 April 2006.
1232001f49Smrg * Added vertex / fragment program support on 7 June 2007 (Ian Romanick).
1332001f49Smrg *
1432001f49Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
1532001f49Smrg *
1632001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
1732001f49Smrg * copy of this software and associated documentation files (the "Software"),
1832001f49Smrg * to deal in the Software without restriction, including without limitation
1932001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
2032001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
2132001f49Smrg * Software is furnished to do so, subject to the following conditions:
2232001f49Smrg *
2332001f49Smrg * The above copyright notice and this permission notice shall be included
2432001f49Smrg * in all copies or substantial portions of the Software.
2532001f49Smrg *
2632001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2732001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2832001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2932001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
3032001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
3132001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3232001f49Smrg */
3332001f49Smrg
3432001f49Smrg#include <assert.h>
3532001f49Smrg#include <stdio.h>
3632001f49Smrg#include <stdlib.h>
3732001f49Smrg#include <string.h>
3832001f49Smrg#include <math.h>
3932001f49Smrg#include <GL/glew.h>
4032001f49Smrg#include "glut_wrap.h"
4132001f49Smrg
4232001f49Smrg#define DEG_TO_RAD (3.14159 / 180.0)
4332001f49Smrg
4432001f49Smrgstatic GLint WindowWidth = 450, WindowHeight = 300;
4532001f49Smrgstatic GLfloat Xrot = 15, Yrot = 0, Zrot = 0;
4632001f49Smrg
4732001f49Smrgstatic GLfloat Red[4] = {1, 0, 0, 1};
4832001f49Smrgstatic GLfloat Green[4] = {0, 1, 0, 1};
4932001f49Smrgstatic GLfloat Blue[4] = {0, 0, 1, 1};
5032001f49Smrgstatic GLfloat Yellow[4] = {1, 1, 0, 1};
5132001f49Smrg
5232001f49Smrgstatic GLfloat LightDist = 10;
5332001f49Smrgstatic GLfloat LightLatitude = 45.0;
5432001f49Smrgstatic GLfloat LightLongitude = 45.0;
5532001f49Smrgstatic GLfloat LightPos[4];
5632001f49Smrgstatic GLfloat SpotDir[3];
5732001f49Smrgstatic GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
5832001f49Smrgstatic GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
5932001f49Smrgstatic GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
6032001f49Smrg
6132001f49Smrgstatic GLboolean LinearFilter = GL_FALSE;
6232001f49Smrg
6332001f49Smrgstatic GLfloat Bias = -0.06;
6432001f49Smrg
6532001f49Smrgstatic GLboolean Anim = GL_TRUE;
6632001f49Smrg
6732001f49Smrgstatic GLboolean NeedNewShadowMap = GL_FALSE;
6832001f49Smrgstatic GLuint ShadowTexture, GrayTexture;
6932001f49Smrgstatic GLuint ShadowFBO;
7032001f49Smrg
7132001f49Smrgstatic GLfloat lightModelview[16];
7232001f49Smrgstatic GLfloat lightProjection[16];
7332001f49Smrg
7432001f49Smrgstatic GLuint vert_prog;
7532001f49Smrgstatic GLuint frag_progs[3];
7632001f49Smrgstatic GLuint curr_frag = 0;
7732001f49Smrgstatic GLuint max_frag = 1;
7832001f49Smrg
7932001f49Smrg#define NUM_FRAG_MODES 3
8032001f49Smrgstatic const char *FragProgNames[] = {
8132001f49Smrg   "fixed-function",
8232001f49Smrg   "program without \"OPTION ARB_fragment_program_shadow\"",
8332001f49Smrg   "program with \"OPTION ARB_fragment_program_shadow\"",
8432001f49Smrg};
8532001f49Smrg
8632001f49Smrgstatic GLboolean HaveShadow = GL_FALSE;
8732001f49Smrgstatic GLboolean HaveFBO = GL_FALSE;
8832001f49Smrgstatic GLboolean UseFBO = GL_FALSE;
8932001f49Smrgstatic GLboolean HaveVP = GL_FALSE;
9032001f49Smrgstatic GLboolean HaveFP = GL_FALSE;
9132001f49Smrgstatic GLboolean HaveFP_Shadow = GL_FALSE;
9232001f49Smrgstatic GLboolean UseVP = GL_FALSE;
9332001f49Smrgstatic GLboolean HavePackedDepthStencil = GL_FALSE;
9432001f49Smrgstatic GLboolean UsePackedDepthStencil = GL_FALSE;
9532001f49Smrgstatic GLboolean HaveEXTshadowFuncs = GL_FALSE;
9632001f49Smrgstatic GLboolean HaveShadowAmbient = GL_FALSE;
9732001f49Smrg
9832001f49Smrgstatic GLint Operator = 0;
9932001f49Smrgstatic const GLenum OperatorFunc[8] = {
10032001f49Smrg   GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER,
10132001f49Smrg   GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER };
10232001f49Smrgstatic const char *OperatorName[8] = {
10332001f49Smrg   "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
10432001f49Smrg   "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
10532001f49Smrg
10632001f49Smrg
10732001f49Smrgstatic GLuint DisplayMode;
10832001f49Smrg#define SHOW_SHADOWS        0
10932001f49Smrg#define SHOW_DEPTH_IMAGE    1
11032001f49Smrg#define SHOW_DEPTH_MAPPING  2
11132001f49Smrg#define SHOW_DISTANCE       3
11232001f49Smrg
11332001f49Smrg
11432001f49Smrg
11532001f49Smrg#define MAT4_MUL(dest_vec, src_mat, src_vec) \
11632001f49Smrg    "DP4	" dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
11732001f49Smrg    "DP4	" dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
11832001f49Smrg    "DP4	" dest_vec ".z, " src_mat "[2], " src_vec ";\n" \
11932001f49Smrg    "DP4	" dest_vec ".w, " src_mat "[3], " src_vec ";\n"
12032001f49Smrg
12132001f49Smrg#define MAT3_MUL(dest_vec, src_mat, src_vec) \
12232001f49Smrg    "DP3	" dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
12332001f49Smrg    "DP3	" dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
12432001f49Smrg    "DP3	" dest_vec ".z, " src_mat "[2], " src_vec ";\n"
12532001f49Smrg
12632001f49Smrg#define NORMALIZE(dest, src) \
12732001f49Smrg    "DP3	" dest ".w, " src ", " src ";\n" \
12832001f49Smrg    "RSQ	" dest ".w, " dest ".w;\n" \
12932001f49Smrg    "MUL	" dest ", " src ", " dest ".w;\n"
13032001f49Smrg
13132001f49Smrg/**
13232001f49Smrg * Vertex program for shadow mapping.
13332001f49Smrg */
13432001f49Smrgstatic const char vert_code[] =
13532001f49Smrg    "!!ARBvp1.0\n"
13632001f49Smrg    "ATTRIB iPos        = vertex.position;\n"
13732001f49Smrg    "ATTRIB iNorm       = vertex.normal;\n"
13832001f49Smrg
13932001f49Smrg    "PARAM  mvinv[4]    = { state.matrix.modelview.invtrans };\n"
14032001f49Smrg    "PARAM  mvp[4]      = { state.matrix.mvp };\n"
14132001f49Smrg    "PARAM  mv[4]       = { state.matrix.modelview };\n"
14232001f49Smrg    "PARAM  texmat[4]   = { state.matrix.texture[0] };\n"
14332001f49Smrg    "PARAM  lightPos    = state.light[0].position;\n"
14432001f49Smrg    "PARAM  ambientCol  = state.lightprod[0].ambient;\n"
14532001f49Smrg    "PARAM  diffuseCol  = state.lightprod[0].diffuse;\n"
14632001f49Smrg
14732001f49Smrg    "TEMP   n, lightVec;\n"
14832001f49Smrg    "ALIAS  V = lightVec;\n"
14932001f49Smrg    "ALIAS  NdotL = n;\n"
15032001f49Smrg
15132001f49Smrg    "OUTPUT oPos = result.position;\n"
15232001f49Smrg    "OUTPUT oColor = result.color;\n"
15332001f49Smrg    "OUTPUT oTex = result.texcoord[0];\n"
15432001f49Smrg
15532001f49Smrg    /* Transform the vertex to clip coordinates. */
15632001f49Smrg    MAT4_MUL("oPos", "mvp",    "iPos")
15732001f49Smrg
15832001f49Smrg    /* Transform the vertex to eye coordinates. */
15932001f49Smrg    MAT4_MUL("V",    "mv",     "iPos")
16032001f49Smrg
16132001f49Smrg    /* Transform the vertex to projected light coordinates. */
16232001f49Smrg    MAT4_MUL("oTex", "texmat", "iPos")
16332001f49Smrg
16432001f49Smrg    /* Transform the normal to eye coordinates. */
16532001f49Smrg    MAT3_MUL("n",    "mvinv",  "iNorm")
16632001f49Smrg
16732001f49Smrg    /* Calculate the vector from the vertex to the light in eye
16832001f49Smrg     * coordinates.
16932001f49Smrg     */
17032001f49Smrg    "SUB	lightVec, lightPos, V;\n"
17132001f49Smrg    NORMALIZE("lightVec", "lightVec")
17232001f49Smrg
17332001f49Smrg    /* Compute diffuse lighting coefficient.
17432001f49Smrg     */
17532001f49Smrg    "DP3	NdotL.x, n, lightVec;\n"
17632001f49Smrg    "MAX	NdotL.x, NdotL.x, {0.0};\n"
17732001f49Smrg    "MIN	NdotL.x, NdotL.x, {1.0};\n"
17832001f49Smrg
17932001f49Smrg    /* Accumulate color contributions.
18032001f49Smrg     */
18132001f49Smrg    "MOV	oColor, diffuseCol;\n"
18232001f49Smrg    "MAD	oColor.xyz, NdotL.x, diffuseCol, ambientCol;\n"
18332001f49Smrg    "END\n"
18432001f49Smrg    ;
18532001f49Smrg
18632001f49Smrgstatic const char frag_code[] =
18732001f49Smrg    "!!ARBfp1.0\n"
18832001f49Smrg
18932001f49Smrg    "TEMP   shadow, temp;\n"
19032001f49Smrg
19132001f49Smrg    "TXP	shadow, fragment.texcoord[0], texture[0], 2D;\n"
19232001f49Smrg    "RCP	temp.x, fragment.texcoord[0].w;\n"
19332001f49Smrg    "MUL	temp.x, temp.x, fragment.texcoord[0].z;\n"
19432001f49Smrg    "SGE	shadow, shadow.x, temp.x;\n"
19532001f49Smrg    "MUL	result.color.rgb, fragment.color, shadow.x;\n"
19632001f49Smrg    "MOV	result.color.a, fragment.color;\n"
19732001f49Smrg    "END\n"
19832001f49Smrg    ;
19932001f49Smrg
20032001f49Smrgstatic const char frag_shadow_code[] =
20132001f49Smrg    "!!ARBfp1.0\n"
20232001f49Smrg    "OPTION ARB_fragment_program_shadow;\n"
20332001f49Smrg
20432001f49Smrg    "TEMP   shadow;\n"
20532001f49Smrg
20632001f49Smrg    "TXP	shadow, fragment.texcoord[0], texture[0], SHADOW2D;\n"
20732001f49Smrg    "MUL	result.color.rgb, fragment.color, shadow.x;\n"
20832001f49Smrg    "MOV	result.color.a, fragment.color.a;\n"
20932001f49Smrg    "END\n"
21032001f49Smrg    ;
21132001f49Smrg
21232001f49Smrgstatic void
21332001f49SmrgDrawScene(void)
21432001f49Smrg{
21532001f49Smrg   GLfloat k = 6;
21632001f49Smrg
21732001f49Smrg   /* sphere */
21832001f49Smrg   glPushMatrix();
21932001f49Smrg   glTranslatef(1.6, 2.2, 2.7);
22032001f49Smrg   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green);
22132001f49Smrg   glColor4fv(Green);
22232001f49Smrg   glutSolidSphere(1.5, 15, 15);
22332001f49Smrg   glPopMatrix();
22432001f49Smrg   /* dodecahedron */
22532001f49Smrg   glPushMatrix();
22632001f49Smrg   glTranslatef(-2.0, 1.2, 2.1);
22732001f49Smrg   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
22832001f49Smrg   glColor4fv(Red);
22932001f49Smrg   glutSolidDodecahedron();
23032001f49Smrg   glPopMatrix();
23132001f49Smrg   /* icosahedron */
23232001f49Smrg   glPushMatrix();
23332001f49Smrg   glTranslatef(-0.6, 1.3, -0.5);
23432001f49Smrg   glScalef(1.5, 1.5, 1.5);
23532001f49Smrg   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow);
23632001f49Smrg   glColor4fv(Red);
23732001f49Smrg   glutSolidIcosahedron();
23832001f49Smrg   glPopMatrix();
23932001f49Smrg   /* a plane */
24032001f49Smrg   glPushMatrix();
24132001f49Smrg   glTranslatef(0, -1.1, 0);
24232001f49Smrg   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
24332001f49Smrg   glColor4fv(Blue);
24432001f49Smrg   glNormal3f(0, 1, 0);
24532001f49Smrg   glBegin(GL_POLYGON);
24632001f49Smrg   glVertex3f(-k, 0, -k);
24732001f49Smrg   glVertex3f( k, 0, -k);
24832001f49Smrg   glVertex3f( k, 0,  k);
24932001f49Smrg   glVertex3f(-k, 0,  k);
25032001f49Smrg   glEnd();
25132001f49Smrg   glPopMatrix();
25232001f49Smrg}
25332001f49Smrg
25432001f49Smrg
25532001f49Smrg/**
25632001f49Smrg * Calculate modelview and project matrices for the light
25732001f49Smrg *
25832001f49Smrg * Stores the results in \c lightProjection (projection matrix) and
25932001f49Smrg * \c lightModelview (modelview matrix).
26032001f49Smrg */
26132001f49Smrgstatic void
26232001f49SmrgMakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
26332001f49Smrg                 GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
26432001f49Smrg{
26532001f49Smrg   /* compute frustum to enclose spot light cone */
26632001f49Smrg   const GLfloat d = shadowNear * tan(spotAngle);
26732001f49Smrg
26832001f49Smrg   glMatrixMode(GL_PROJECTION);
26932001f49Smrg   glPushMatrix();
27032001f49Smrg   glLoadIdentity();
27132001f49Smrg   glFrustum(-d, d, -d, d, shadowNear, shadowFar);
27232001f49Smrg   glGetFloatv(GL_PROJECTION_MATRIX, lightProjection);
27332001f49Smrg   glPopMatrix();
27432001f49Smrg
27532001f49Smrg   glMatrixMode(GL_MODELVIEW);
27632001f49Smrg   glPushMatrix();
27732001f49Smrg   glLoadIdentity();
27832001f49Smrg   gluLookAt(lightPos[0], lightPos[1], lightPos[2],
27932001f49Smrg             lightPos[0] + spotDir[0],
28032001f49Smrg             lightPos[1] + spotDir[1],
28132001f49Smrg             lightPos[2] + spotDir[2],
28232001f49Smrg             0.0, 1.0, 0.0);
28332001f49Smrg   glGetFloatv(GL_MODELVIEW_MATRIX, lightModelview);
28432001f49Smrg   glPopMatrix();
28532001f49Smrg}
28632001f49Smrg
28732001f49Smrg
28832001f49Smrg/**
28932001f49Smrg * Load \c GL_TEXTURE matrix with light's MVP matrix.
29032001f49Smrg */
29132001f49Smrgstatic void SetShadowTextureMatrix(void)
29232001f49Smrg{
29332001f49Smrg   static const GLfloat biasMatrix[16] = {
29432001f49Smrg      0.5, 0.0, 0.0, 0.0,
29532001f49Smrg      0.0, 0.5, 0.0, 0.0,
29632001f49Smrg      0.0, 0.0, 0.5, 0.0,
29732001f49Smrg      0.5, 0.5, 0.5, 1.0,
29832001f49Smrg   };
29932001f49Smrg
30032001f49Smrg   glMatrixMode(GL_TEXTURE);
30132001f49Smrg   glLoadMatrixf(biasMatrix);
30232001f49Smrg   glTranslatef(0.0, 0.0, Bias);
30332001f49Smrg   glMultMatrixf(lightProjection);
30432001f49Smrg   glMultMatrixf(lightModelview);
30532001f49Smrg   glMatrixMode(GL_MODELVIEW);
30632001f49Smrg}
30732001f49Smrg
30832001f49Smrg
30932001f49Smrgstatic void
31032001f49SmrgEnableIdentityTexgen(void)
31132001f49Smrg{
31232001f49Smrg   /* texgen so that texcoord = vertex coord */
31332001f49Smrg   static GLfloat sPlane[4] = { 1, 0, 0, 0 };
31432001f49Smrg   static GLfloat tPlane[4] = { 0, 1, 0, 0 };
31532001f49Smrg   static GLfloat rPlane[4] = { 0, 0, 1, 0 };
31632001f49Smrg   static GLfloat qPlane[4] = { 0, 0, 0, 1 };
31732001f49Smrg
31832001f49Smrg   glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
31932001f49Smrg   glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
32032001f49Smrg   glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
32132001f49Smrg   glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
32232001f49Smrg   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
32332001f49Smrg   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
32432001f49Smrg   glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
32532001f49Smrg   glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
32632001f49Smrg
32732001f49Smrg   glEnable(GL_TEXTURE_GEN_S);
32832001f49Smrg   glEnable(GL_TEXTURE_GEN_T);
32932001f49Smrg   glEnable(GL_TEXTURE_GEN_R);
33032001f49Smrg   glEnable(GL_TEXTURE_GEN_Q);
33132001f49Smrg}
33232001f49Smrg
33332001f49Smrg
33432001f49Smrg/*
33532001f49Smrg * Setup 1-D texgen so that the distance from the light source, between
33632001f49Smrg * the near and far planes maps to s=0 and s=1.  When we draw the scene,
33732001f49Smrg * the grayness will indicate the fragment's distance from the light
33832001f49Smrg * source.
33932001f49Smrg */
34032001f49Smrgstatic void
34132001f49SmrgEnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
34232001f49Smrg                     GLfloat lightNear, GLfloat lightFar)
34332001f49Smrg{
34432001f49Smrg   GLfloat m, d;
34532001f49Smrg   GLfloat sPlane[4];
34632001f49Smrg   GLfloat nearPoint[3];
34732001f49Smrg
34832001f49Smrg   m = sqrt(lightDir[0] * lightDir[0] +
34932001f49Smrg            lightDir[1] * lightDir[1] +
35032001f49Smrg            lightDir[2] * lightDir[2]);
35132001f49Smrg
35232001f49Smrg   d = lightFar - lightNear;
35332001f49Smrg
35432001f49Smrg   /* nearPoint = point on light direction vector which intersects the
35532001f49Smrg    * near plane of the light frustum.
35632001f49Smrg    */
35732001f49Smrg   nearPoint[0] = lightPos[0] + lightDir[0] / m * lightNear;
35832001f49Smrg   nearPoint[1] = lightPos[1] + lightDir[1] / m * lightNear;
35932001f49Smrg   nearPoint[2] = lightPos[2] + lightDir[2] / m * lightNear;
36032001f49Smrg
36132001f49Smrg   sPlane[0] = lightDir[0] / d / m;
36232001f49Smrg   sPlane[1] = lightDir[1] / d / m;
36332001f49Smrg   sPlane[2] = lightDir[2] / d / m;
36432001f49Smrg   sPlane[3] = -(sPlane[0] * nearPoint[0]
36532001f49Smrg               + sPlane[1] * nearPoint[1]
36632001f49Smrg               + sPlane[2] * nearPoint[2]);
36732001f49Smrg
36832001f49Smrg   glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
36932001f49Smrg   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
37032001f49Smrg   glEnable(GL_TEXTURE_GEN_S);
37132001f49Smrg}
37232001f49Smrg
37332001f49Smrg
37432001f49Smrgstatic void
37532001f49SmrgDisableTexgen(void)
37632001f49Smrg{
37732001f49Smrg   glDisable(GL_TEXTURE_GEN_S);
37832001f49Smrg   glDisable(GL_TEXTURE_GEN_T);
37932001f49Smrg   glDisable(GL_TEXTURE_GEN_R);
38032001f49Smrg   glDisable(GL_TEXTURE_GEN_Q);
38132001f49Smrg}
38232001f49Smrg
38332001f49Smrg
38432001f49Smrgstatic void
38532001f49SmrgComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
38632001f49Smrg                GLfloat pos[4], GLfloat dir[3])
38732001f49Smrg{
38832001f49Smrg
38932001f49Smrg   pos[0] = dist * sin(longitude * DEG_TO_RAD);
39032001f49Smrg   pos[1] = dist * sin(latitude * DEG_TO_RAD);
39132001f49Smrg   pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
39232001f49Smrg   pos[3] = 1;
39332001f49Smrg   dir[0] = -pos[0];
39432001f49Smrg   dir[1] = -pos[1];
39532001f49Smrg   dir[2] = -pos[2];
39632001f49Smrg}
39732001f49Smrg
39832001f49Smrg
39932001f49Smrg/**
40032001f49Smrg * Render the shadow map / depth texture.
40132001f49Smrg * The result will be in the texture object named ShadowTexture.
40232001f49Smrg */
40332001f49Smrgstatic void
40432001f49SmrgRenderShadowMap(void)
40532001f49Smrg{
40632001f49Smrg   GLenum depthFormat; /* GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT */
40732001f49Smrg   GLenum depthType; /* GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT */
40832001f49Smrg
40932001f49Smrg   if (WindowWidth >= 1024 && WindowHeight >= 1024) {
41032001f49Smrg      ShadowTexWidth = ShadowTexHeight = 1024;
41132001f49Smrg   }
41232001f49Smrg   else if (WindowWidth >= 512 && WindowHeight >= 512) {
41332001f49Smrg      ShadowTexWidth = ShadowTexHeight = 512;
41432001f49Smrg   }
41532001f49Smrg   else if (WindowWidth >= 256 && WindowHeight >= 256) {
41632001f49Smrg      ShadowTexWidth = ShadowTexHeight = 256;
41732001f49Smrg   }
41832001f49Smrg   else {
41932001f49Smrg      ShadowTexWidth = ShadowTexHeight = 128;
42032001f49Smrg   }
42132001f49Smrg   printf("Rendering %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
42232001f49Smrg
42332001f49Smrg   if (UsePackedDepthStencil) {
42432001f49Smrg      depthFormat = GL_DEPTH_STENCIL_EXT;
42532001f49Smrg      depthType = GL_UNSIGNED_INT_24_8_EXT;
42632001f49Smrg   }
42732001f49Smrg   else {
42832001f49Smrg      depthFormat = GL_DEPTH_COMPONENT;
42932001f49Smrg      depthType = GL_UNSIGNED_INT;
43032001f49Smrg   }
43132001f49Smrg
43232001f49Smrg   glMatrixMode(GL_PROJECTION);
43332001f49Smrg   glLoadMatrixf(lightProjection);
43432001f49Smrg
43532001f49Smrg   glMatrixMode(GL_MODELVIEW);
43632001f49Smrg   glLoadMatrixf(lightModelview);
43732001f49Smrg
43832001f49Smrg   if (UseFBO) {
43932001f49Smrg      GLenum fbo_status;
44032001f49Smrg
44132001f49Smrg      glTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
44232001f49Smrg                   ShadowTexWidth, ShadowTexHeight, 0,
44332001f49Smrg                   depthFormat, depthType, NULL);
44432001f49Smrg
44532001f49Smrg      /* Set the filter mode so that the texture is texture-complete.
44632001f49Smrg       * Otherwise it will cause the framebuffer to fail the framebuffer
44732001f49Smrg       * completeness test.
44832001f49Smrg       */
44932001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
45032001f49Smrg
45132001f49Smrg      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
45232001f49Smrg      glDrawBuffer(GL_NONE);
45332001f49Smrg      glReadBuffer(GL_NONE);
45432001f49Smrg
45532001f49Smrg      fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
45632001f49Smrg      if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
45732001f49Smrg         fprintf(stderr, "FBO not complete!  status = 0x%04x\n", fbo_status);
45832001f49Smrg         assert(fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT);
45932001f49Smrg      }
46032001f49Smrg   }
46132001f49Smrg
46232001f49Smrg   assert(!glIsEnabled(GL_TEXTURE_1D));
46332001f49Smrg   assert(!glIsEnabled(GL_TEXTURE_2D));
46432001f49Smrg
46532001f49Smrg   glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
46632001f49Smrg   glClear(GL_DEPTH_BUFFER_BIT);
46732001f49Smrg   glEnable(GL_DEPTH_TEST);
46832001f49Smrg   DrawScene();
46932001f49Smrg
47032001f49Smrg   if (UseFBO) {
47132001f49Smrg      /* all done! */
47232001f49Smrg      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
47332001f49Smrg   }
47432001f49Smrg   else {
47532001f49Smrg      /*
47632001f49Smrg       * copy depth buffer into the texture map
47732001f49Smrg       */
47832001f49Smrg      if (DisplayMode == SHOW_DEPTH_MAPPING) {
47932001f49Smrg         /* load depth image as gray-scale luminance texture */
48032001f49Smrg         GLuint *depth = (GLuint *)
48132001f49Smrg            malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint));
48232001f49Smrg         assert(depth);
48332001f49Smrg         glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
48432001f49Smrg                      depthFormat, depthType, depth);
48532001f49Smrg         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
48632001f49Smrg                      ShadowTexWidth, ShadowTexHeight, 0,
48732001f49Smrg                      GL_LUMINANCE, GL_UNSIGNED_INT, depth);
48832001f49Smrg         free(depth);
48932001f49Smrg      }
49032001f49Smrg      else {
49132001f49Smrg         /* The normal shadow case - a real depth texture */
49232001f49Smrg         glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
49332001f49Smrg                          0, 0, ShadowTexWidth, ShadowTexHeight, 0);
49432001f49Smrg         if (UsePackedDepthStencil) {
49532001f49Smrg            /* debug check */
49632001f49Smrg            GLint intFormat;
49732001f49Smrg            glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
49832001f49Smrg                                     GL_TEXTURE_INTERNAL_FORMAT, &intFormat);
49932001f49Smrg            assert(intFormat == GL_DEPTH_STENCIL_EXT);
50032001f49Smrg         }
50132001f49Smrg      }
50232001f49Smrg   }
50332001f49Smrg}
50432001f49Smrg
50532001f49Smrg
50632001f49Smrg/**
50732001f49Smrg * Show the shadow map as a grayscale image.
50832001f49Smrg */
50932001f49Smrgstatic void
51032001f49SmrgShowShadowMap(void)
51132001f49Smrg{
51232001f49Smrg   glClear(GL_COLOR_BUFFER_BIT);
51332001f49Smrg
51432001f49Smrg   glMatrixMode(GL_TEXTURE);
51532001f49Smrg   glLoadIdentity();
51632001f49Smrg
51732001f49Smrg   glMatrixMode(GL_PROJECTION);
51832001f49Smrg   glLoadIdentity();
51932001f49Smrg   glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1);
52032001f49Smrg
52132001f49Smrg   glMatrixMode(GL_MODELVIEW);
52232001f49Smrg   glLoadIdentity();
52332001f49Smrg
52432001f49Smrg   glDisable(GL_DEPTH_TEST);
52532001f49Smrg   glDisable(GL_LIGHTING);
52632001f49Smrg
52732001f49Smrg   glEnable(GL_TEXTURE_2D);
52832001f49Smrg
52932001f49Smrg   DisableTexgen();
53032001f49Smrg
53132001f49Smrg   /* interpret texture's depth values as luminance values */
53232001f49Smrg   if (HaveShadow) {
53332001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
53432001f49Smrg   }
53532001f49Smrg
53632001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
53732001f49Smrg   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
53832001f49Smrg
53932001f49Smrg   glBegin(GL_POLYGON);
54032001f49Smrg   glTexCoord2f(0, 0);  glVertex2f(0, 0);
54132001f49Smrg   glTexCoord2f(1, 0);  glVertex2f(ShadowTexWidth, 0);
54232001f49Smrg   glTexCoord2f(1, 1);  glVertex2f(ShadowTexWidth, ShadowTexHeight);
54332001f49Smrg   glTexCoord2f(0, 1);  glVertex2f(0, ShadowTexHeight);
54432001f49Smrg   glEnd();
54532001f49Smrg
54632001f49Smrg   glDisable(GL_TEXTURE_2D);
54732001f49Smrg   glEnable(GL_DEPTH_TEST);
54832001f49Smrg   glEnable(GL_LIGHTING);
54932001f49Smrg}
55032001f49Smrg
55132001f49Smrg
55232001f49Smrg/**
55332001f49Smrg * Redraw window image
55432001f49Smrg */
55532001f49Smrgstatic void
55632001f49SmrgDisplay(void)
55732001f49Smrg{
55832001f49Smrg   GLenum error;
55932001f49Smrg
56032001f49Smrg   ComputeLightPos(LightDist, LightLatitude, LightLongitude,
56132001f49Smrg                   LightPos, SpotDir);
56232001f49Smrg
56332001f49Smrg   if (NeedNewShadowMap) {
56432001f49Smrg      MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
56532001f49Smrg      RenderShadowMap();
56632001f49Smrg      NeedNewShadowMap = GL_FALSE;
56732001f49Smrg   }
56832001f49Smrg
56932001f49Smrg   glViewport(0, 0, WindowWidth, WindowHeight);
57032001f49Smrg   if (DisplayMode == SHOW_DEPTH_IMAGE) {
57132001f49Smrg      ShowShadowMap();
57232001f49Smrg   }
57332001f49Smrg   else {
57432001f49Smrg      /* prepare to draw scene from camera's view */
57532001f49Smrg      const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
57632001f49Smrg
57732001f49Smrg      glMatrixMode(GL_PROJECTION);
57832001f49Smrg      glLoadIdentity();
57932001f49Smrg      glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
58032001f49Smrg
58132001f49Smrg      glMatrixMode(GL_MODELVIEW);
58232001f49Smrg      glLoadIdentity();
58332001f49Smrg      glTranslatef(0.0, 0.0, -22.0);
58432001f49Smrg      glRotatef(Xrot, 1, 0, 0);
58532001f49Smrg      glRotatef(Yrot, 0, 1, 0);
58632001f49Smrg      glRotatef(Zrot, 0, 0, 1);
58732001f49Smrg
58832001f49Smrg      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
58932001f49Smrg
59032001f49Smrg      glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
59132001f49Smrg
59232001f49Smrg      if (LinearFilter) {
59332001f49Smrg         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
59432001f49Smrg         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
59532001f49Smrg      }
59632001f49Smrg      else {
59732001f49Smrg         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
59832001f49Smrg         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
59932001f49Smrg      }
60032001f49Smrg
60132001f49Smrg      if (DisplayMode == SHOW_DEPTH_MAPPING) {
60232001f49Smrg         if (HaveShadow) {
60332001f49Smrg            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
60432001f49Smrg         }
60532001f49Smrg         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
60632001f49Smrg         glEnable(GL_TEXTURE_2D);
60732001f49Smrg
60832001f49Smrg         SetShadowTextureMatrix();
60932001f49Smrg         EnableIdentityTexgen();
61032001f49Smrg      }
61132001f49Smrg      else if (DisplayMode == SHOW_DISTANCE) {
61232001f49Smrg         glMatrixMode(GL_TEXTURE);
61332001f49Smrg         glLoadIdentity();
61432001f49Smrg         glMatrixMode(GL_MODELVIEW);
61532001f49Smrg         EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
61632001f49Smrg         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
61732001f49Smrg         glEnable(GL_TEXTURE_1D);
61832001f49Smrg         assert(!glIsEnabled(GL_TEXTURE_2D));
61932001f49Smrg      }
62032001f49Smrg      else {
62132001f49Smrg         assert(DisplayMode == SHOW_SHADOWS);
62232001f49Smrg         if (HaveShadow) {
62332001f49Smrg            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
62432001f49Smrg                            GL_COMPARE_R_TO_TEXTURE_ARB);
62532001f49Smrg         }
62632001f49Smrg
62732001f49Smrg         if (curr_frag > 0) {
62832001f49Smrg            glEnable(GL_FRAGMENT_PROGRAM_ARB);
62932001f49Smrg         }
63032001f49Smrg         else {
63132001f49Smrg            glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
63232001f49Smrg         }
63332001f49Smrg         glEnable(GL_TEXTURE_2D);
63432001f49Smrg
63532001f49Smrg         SetShadowTextureMatrix();
63632001f49Smrg
63732001f49Smrg         if (UseVP) {
63832001f49Smrg            glEnable(GL_VERTEX_PROGRAM_ARB);
63932001f49Smrg         }
64032001f49Smrg         else {
64132001f49Smrg            glEnable(GL_LIGHTING);
64232001f49Smrg            EnableIdentityTexgen();
64332001f49Smrg         }
64432001f49Smrg      }
64532001f49Smrg
64632001f49Smrg      DrawScene();
64732001f49Smrg
64832001f49Smrg      if (UseVP) {
64932001f49Smrg         glDisable(GL_VERTEX_PROGRAM_ARB);
65032001f49Smrg      }
65132001f49Smrg      else {
65232001f49Smrg         DisableTexgen();
65332001f49Smrg         glDisable(GL_LIGHTING);
65432001f49Smrg      }
65532001f49Smrg
65632001f49Smrg      if (curr_frag > 0) {
65732001f49Smrg         glDisable(GL_FRAGMENT_PROGRAM_ARB);
65832001f49Smrg      }
65932001f49Smrg
66032001f49Smrg      glDisable(GL_TEXTURE_1D);
66132001f49Smrg      glDisable(GL_TEXTURE_2D);
66232001f49Smrg   }
66332001f49Smrg
66432001f49Smrg   glutSwapBuffers();
66532001f49Smrg
66632001f49Smrg   error = glGetError();
66732001f49Smrg   if (error) {
66832001f49Smrg      printf("GL Error: %s\n", (char *) gluErrorString(error));
66932001f49Smrg   }
67032001f49Smrg}
67132001f49Smrg
67232001f49Smrg
67332001f49Smrgstatic void
67432001f49SmrgReshape(int width, int height)
67532001f49Smrg{
67632001f49Smrg   WindowWidth = width;
67732001f49Smrg   WindowHeight = height;
67832001f49Smrg   NeedNewShadowMap = GL_TRUE;
67932001f49Smrg}
68032001f49Smrg
68132001f49Smrg
68232001f49Smrgstatic void
68332001f49SmrgIdle(void)
68432001f49Smrg{
68532001f49Smrg   static double t0 = -1.;
68632001f49Smrg   double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
68732001f49Smrg   if (t0 < 0.0)
68832001f49Smrg      t0 = t;
68932001f49Smrg   dt = t - t0;
69032001f49Smrg   t0 = t;
69132001f49Smrg   Yrot += 75.0 * dt;
69232001f49Smrg   /*LightLongitude -= 5.0;*/
69332001f49Smrg   glutPostRedisplay();
69432001f49Smrg}
69532001f49Smrg
69632001f49Smrg
69732001f49Smrgstatic void
69832001f49SmrgKey(unsigned char key, int x, int y)
69932001f49Smrg{
70032001f49Smrg   const GLfloat step = 3.0;
70132001f49Smrg   (void) x;
70232001f49Smrg   (void) y;
70332001f49Smrg   switch (key) {
70432001f49Smrg      case 'a':
70532001f49Smrg         Anim = !Anim;
70632001f49Smrg         if (Anim)
70732001f49Smrg            glutIdleFunc(Idle);
70832001f49Smrg         else
70932001f49Smrg            glutIdleFunc(NULL);
71032001f49Smrg         break;
71132001f49Smrg      case 'b':
71232001f49Smrg         Bias -= 0.01;
71332001f49Smrg         printf("Bias %g\n", Bias);
71432001f49Smrg         break;
71532001f49Smrg      case 'B':
71632001f49Smrg         Bias += 0.01;
71732001f49Smrg         printf("Bias %g\n", Bias);
71832001f49Smrg         break;
71932001f49Smrg      case 'd':
72032001f49Smrg         DisplayMode = SHOW_DISTANCE;
72132001f49Smrg         break;
72232001f49Smrg      case 'f':
72332001f49Smrg         LinearFilter = !LinearFilter;
72432001f49Smrg         printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
72532001f49Smrg         break;
72632001f49Smrg      case 'i':
72732001f49Smrg         DisplayMode = SHOW_DEPTH_IMAGE;
72832001f49Smrg         break;
72932001f49Smrg      case 'm':
73032001f49Smrg         DisplayMode = SHOW_DEPTH_MAPPING;
73132001f49Smrg         break;
73232001f49Smrg      case 'M':
73332001f49Smrg         curr_frag = (1 + curr_frag) % max_frag;
73432001f49Smrg         if (!HaveShadow && (curr_frag == 0)) {
73532001f49Smrg            curr_frag = 1;
73632001f49Smrg         }
73732001f49Smrg
73832001f49Smrg         printf("Using fragment %s\n", FragProgNames[curr_frag]);
73932001f49Smrg
74032001f49Smrg         if (HaveFP) {
74132001f49Smrg            glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, frag_progs[curr_frag]);
74232001f49Smrg         }
74332001f49Smrg         break;
74432001f49Smrg      case 'n':
74532001f49Smrg      case 's':
74632001f49Smrg      case ' ':
74732001f49Smrg         DisplayMode = SHOW_SHADOWS;
74832001f49Smrg         break;
74932001f49Smrg      case 'o':
75032001f49Smrg         if (HaveEXTshadowFuncs) {
75132001f49Smrg            Operator++;
75232001f49Smrg            if (Operator >= 8)
75332001f49Smrg               Operator = 0;
75432001f49Smrg            printf("Operator: %s\n", OperatorName[Operator]);
75532001f49Smrg            if (HaveShadow) {
75632001f49Smrg               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
75732001f49Smrg                               OperatorFunc[Operator]);
75832001f49Smrg            }
75932001f49Smrg         }
76032001f49Smrg         break;
76132001f49Smrg      case 'p':
76232001f49Smrg         UsePackedDepthStencil = !UsePackedDepthStencil;
76332001f49Smrg         if (UsePackedDepthStencil && !HavePackedDepthStencil) {
76432001f49Smrg            printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
76532001f49Smrg            UsePackedDepthStencil = GL_FALSE;
76632001f49Smrg         }
76732001f49Smrg         else {
76832001f49Smrg            printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil);
76932001f49Smrg            /* Don't really need to regenerate shadow map texture, but do so
77032001f49Smrg             * to exercise more code more often.
77132001f49Smrg             */
77232001f49Smrg            NeedNewShadowMap = GL_TRUE;
77332001f49Smrg         }
77432001f49Smrg         break;
77532001f49Smrg      case 'v':
77632001f49Smrg         UseVP = !UseVP && HaveVP;
77732001f49Smrg         printf("Using vertex %s mode.\n",
77832001f49Smrg                UseVP ? "program" : "fixed-function");
77932001f49Smrg         break;
78032001f49Smrg      case 'z':
78132001f49Smrg         Zrot -= step;
78232001f49Smrg         break;
78332001f49Smrg      case 'Z':
78432001f49Smrg         Zrot += step;
78532001f49Smrg         break;
78632001f49Smrg      case 27:
78732001f49Smrg         exit(0);
78832001f49Smrg         break;
78932001f49Smrg   }
79032001f49Smrg   fflush(stdout);
79132001f49Smrg   glutPostRedisplay();
79232001f49Smrg}
79332001f49Smrg
79432001f49Smrg
79532001f49Smrgstatic void
79632001f49SmrgSpecialKey(int key, int x, int y)
79732001f49Smrg{
79832001f49Smrg   const GLfloat step = 3.0;
79932001f49Smrg   const int mod = glutGetModifiers();
80032001f49Smrg   (void) x;
80132001f49Smrg   (void) y;
80232001f49Smrg   switch (key) {
80332001f49Smrg      case GLUT_KEY_UP:
80432001f49Smrg         if (mod)
80532001f49Smrg            LightLatitude += step;
80632001f49Smrg         else
80732001f49Smrg            Xrot += step;
80832001f49Smrg         break;
80932001f49Smrg      case GLUT_KEY_DOWN:
81032001f49Smrg         if (mod)
81132001f49Smrg            LightLatitude -= step;
81232001f49Smrg         else
81332001f49Smrg            Xrot -= step;
81432001f49Smrg         break;
81532001f49Smrg      case GLUT_KEY_LEFT:
81632001f49Smrg         if (mod)
81732001f49Smrg            LightLongitude += step;
81832001f49Smrg         else
81932001f49Smrg            Yrot += step;
82032001f49Smrg         break;
82132001f49Smrg      case GLUT_KEY_RIGHT:
82232001f49Smrg         if (mod)
82332001f49Smrg            LightLongitude -= step;
82432001f49Smrg         else
82532001f49Smrg            Yrot -= step;
82632001f49Smrg         break;
82732001f49Smrg   }
82832001f49Smrg   if (mod)
82932001f49Smrg      NeedNewShadowMap = GL_TRUE;
83032001f49Smrg
83132001f49Smrg   glutPostRedisplay();
83232001f49Smrg}
83332001f49Smrg
83432001f49Smrg
83532001f49Smrg/* A helper for finding errors in program strings */
83632001f49Smrgstatic int FindLine( const char *program, int position )
83732001f49Smrg{
83832001f49Smrg   int i, line = 1;
83932001f49Smrg   for (i = 0; i < position; i++) {
84032001f49Smrg      if (program[i] == '\n')
84132001f49Smrg         line++;
84232001f49Smrg   }
84332001f49Smrg   return line;
84432001f49Smrg}
84532001f49Smrg
84632001f49Smrg
84732001f49Smrgstatic GLuint
84832001f49Smrgcompile_program(GLenum target, const char *code)
84932001f49Smrg{
85032001f49Smrg   GLuint p;
85132001f49Smrg   GLint errorPos;
85232001f49Smrg
85332001f49Smrg
85432001f49Smrg   glGenProgramsARB(1, & p);
85532001f49Smrg
85632001f49Smrg   glBindProgramARB(target, p);
85732001f49Smrg   glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB,
85832001f49Smrg                      strlen(code), code);
85932001f49Smrg   glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
86032001f49Smrg   if (glGetError() != GL_NO_ERROR || errorPos != -1) {
86132001f49Smrg      int l = FindLine(code, errorPos);
86232001f49Smrg      printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
86332001f49Smrg             (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
86432001f49Smrg      exit(0);
86532001f49Smrg   }
86632001f49Smrg
86732001f49Smrg   glBindProgramARB(target, 0);
86832001f49Smrg   return p;
86932001f49Smrg}
87032001f49Smrg
87132001f49Smrgstatic void
87232001f49SmrgInit(void)
87332001f49Smrg{
87432001f49Smrg   static const GLfloat borderColor[4] = {1.0, 0.0, 0.0, 0.0};
87532001f49Smrg
87632001f49Smrg   if (!glutExtensionSupported("GL_ARB_depth_texture")) {
87732001f49Smrg      printf("Sorry, this demo requires the GL_ARB_depth_texture extension\n");
87832001f49Smrg      exit(1);
87932001f49Smrg   }
88032001f49Smrg
88132001f49Smrg   HaveShadow = glutExtensionSupported("GL_ARB_shadow");
88232001f49Smrg   HaveVP = glutExtensionSupported("GL_ARB_vertex_program");
88332001f49Smrg   HaveFP = glutExtensionSupported("GL_ARB_fragment_program");
88432001f49Smrg   HaveFP_Shadow = glutExtensionSupported("GL_ARB_fragment_program_shadow");
88532001f49Smrg
88632001f49Smrg   if (!HaveShadow && !HaveFP) {
88732001f49Smrg      printf("Sorry, this demo requires either the GL_ARB_shadow extension "
88832001f49Smrg	     "or the GL_ARB_fragment_program extension\n");
88932001f49Smrg      exit(1);
89032001f49Smrg   }
89132001f49Smrg
89232001f49Smrg   printf("Using GL_ARB_depth_texture\n");
89332001f49Smrg   if (HaveShadow) {
89432001f49Smrg      printf("and GL_ARB_shadow\n");
89532001f49Smrg   }
89632001f49Smrg
89732001f49Smrg   if (HaveFP) {
89832001f49Smrg      printf("and GL_ARB_fragment_program\n");
89932001f49Smrg   }
90032001f49Smrg
90132001f49Smrg   HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient");
90232001f49Smrg   if (HaveShadowAmbient) {
90332001f49Smrg      printf("and GL_ARB_shadow_ambient\n");
90432001f49Smrg   }
90532001f49Smrg
90632001f49Smrg   HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
90732001f49Smrg
90832001f49Smrg   HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil");
90932001f49Smrg   UsePackedDepthStencil = HavePackedDepthStencil;
91032001f49Smrg
91132001f49Smrg#if defined(GL_EXT_framebuffer_object)
91232001f49Smrg   HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object");
91332001f49Smrg   UseFBO = HaveFBO;
91432001f49Smrg   if (UseFBO) {
91532001f49Smrg      printf("Using GL_EXT_framebuffer_object\n");
91632001f49Smrg   }
91732001f49Smrg#endif
91832001f49Smrg
91932001f49Smrg   /*
92032001f49Smrg    * Set up the 2D shadow map texture
92132001f49Smrg    */
92232001f49Smrg   glGenTextures(1, &ShadowTexture);
92332001f49Smrg   glBindTexture(GL_TEXTURE_2D, ShadowTexture);
92432001f49Smrg   glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
92532001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
92632001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
92732001f49Smrg
92832001f49Smrg   if (HaveShadow) {
92932001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
93032001f49Smrg                      GL_COMPARE_R_TO_TEXTURE_ARB);
93132001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
93232001f49Smrg   }
93332001f49Smrg
93432001f49Smrg   if (HaveShadowAmbient) {
93532001f49Smrg      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
93632001f49Smrg   }
93732001f49Smrg
93832001f49Smrg#if defined(GL_EXT_framebuffer_object)
93932001f49Smrg   if (UseFBO) {
94032001f49Smrg      glGenFramebuffersEXT(1, &ShadowFBO);
94132001f49Smrg      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
94232001f49Smrg      glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
94332001f49Smrg                                   GL_COLOR_ATTACHMENT0_EXT,
94432001f49Smrg                                   GL_RENDERBUFFER_EXT, 0);
94532001f49Smrg      glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
94632001f49Smrg                                GL_TEXTURE_2D, ShadowTexture, 0);
94732001f49Smrg
94832001f49Smrg      glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
94932001f49Smrg   }
95032001f49Smrg#endif
95132001f49Smrg
95232001f49Smrg   /*
95332001f49Smrg    * Setup 1-D grayscale texture image for SHOW_DISTANCE mode
95432001f49Smrg    */
95532001f49Smrg   glGenTextures(1, &GrayTexture);
95632001f49Smrg   glBindTexture(GL_TEXTURE_1D, GrayTexture);
95732001f49Smrg   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
95832001f49Smrg   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
95932001f49Smrg   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
96032001f49Smrg   {
96132001f49Smrg      GLuint i;
96232001f49Smrg      GLubyte image[256];
96332001f49Smrg      for (i = 0; i < 256; i++)
96432001f49Smrg         image[i] = i;
96532001f49Smrg      glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
96632001f49Smrg                   256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
96732001f49Smrg   }
96832001f49Smrg
96932001f49Smrg   if (HaveVP) {
97032001f49Smrg      vert_prog = compile_program(GL_VERTEX_PROGRAM_ARB, vert_code);
97132001f49Smrg      glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vert_prog);
97232001f49Smrg   }
97332001f49Smrg
97432001f49Smrg   max_frag = 1;
97532001f49Smrg   frag_progs[0] = 0;
97632001f49Smrg
97732001f49Smrg   if (HaveFP) {
97832001f49Smrg      frag_progs[1] = compile_program(GL_FRAGMENT_PROGRAM_ARB, frag_code);
97932001f49Smrg      max_frag = 2;
98032001f49Smrg   }
98132001f49Smrg
98232001f49Smrg   if (HaveFP && HaveFP_Shadow) {
98332001f49Smrg      frag_progs[2] = compile_program(GL_FRAGMENT_PROGRAM_ARB,
98432001f49Smrg                                      frag_shadow_code);
98532001f49Smrg      max_frag = 3;
98632001f49Smrg   }
98732001f49Smrg
98832001f49Smrg   if (!HaveShadow) {
98932001f49Smrg      curr_frag = 1;
99032001f49Smrg      glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, frag_progs[curr_frag]);
99132001f49Smrg   }
99232001f49Smrg
99332001f49Smrg   glEnable(GL_DEPTH_TEST);
99432001f49Smrg   glEnable(GL_LIGHTING);
99532001f49Smrg   glEnable(GL_LIGHT0);
99632001f49Smrg}
99732001f49Smrg
99832001f49Smrg
99932001f49Smrgstatic void
100032001f49SmrgPrintHelp(void)
100132001f49Smrg{
100232001f49Smrg   printf("Keys:\n");
100332001f49Smrg   printf("  a = toggle animation\n");
100432001f49Smrg   printf("  i = show depth texture image\n");
100532001f49Smrg   printf("  m = show depth texture mapping\n");
100632001f49Smrg   printf("  d = show fragment distance from light source\n");
100732001f49Smrg   printf("  n = show normal, shadowed image\n");
100832001f49Smrg   printf("  f = toggle nearest/bilinear texture filtering\n");
100932001f49Smrg   printf("  b/B = decrease/increase shadow map Z bias\n");
101032001f49Smrg   printf("  p = toggle use of packed depth/stencil\n");
101132001f49Smrg   printf("  M = cycle through fragment program modes\n");
101232001f49Smrg   printf("  v = toggle vertex program modes\n");
101332001f49Smrg   printf("  cursor keys = rotate scene\n");
101432001f49Smrg   printf("  <shift> + cursor keys = rotate light source\n");
101532001f49Smrg   if (HaveEXTshadowFuncs)
101632001f49Smrg      printf("  o = cycle through comparison modes\n");
101732001f49Smrg   fflush(stdout);
101832001f49Smrg}
101932001f49Smrg
102032001f49Smrg
102132001f49Smrgint
102232001f49Smrgmain(int argc, char *argv[])
102332001f49Smrg{
102432001f49Smrg   glutInitWindowSize(WindowWidth, WindowHeight);
102532001f49Smrg   glutInit(&argc, argv);
102632001f49Smrg   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
102732001f49Smrg   glutCreateWindow(argv[0]);
102832001f49Smrg   glewInit();
102932001f49Smrg   glutReshapeFunc(Reshape);
103032001f49Smrg   glutKeyboardFunc(Key);
103132001f49Smrg   glutSpecialFunc(SpecialKey);
103232001f49Smrg   glutDisplayFunc(Display);
103332001f49Smrg   if (Anim)
103432001f49Smrg      glutIdleFunc(Idle);
103532001f49Smrg   Init();
103632001f49Smrg   PrintHelp();
103732001f49Smrg   glutMainLoop();
103832001f49Smrg   return 0;
103932001f49Smrg}
1040