This is an OpenGL shadowtex demo by Brian Paul, ported from C to Qore.
Screenshot:

#!/usr/bin/env qore %require-our # the glut module automatically loads the opengl module %requires glut #/* # * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and # * GL_ARB_shadow_ambient extensions. # * # * Brian Paul # * 19 Feb 2001 # * # * Added GL_EXT_shadow_funcs support on 23 March 2002 # * Added GL_EXT_packed_depth_stencil support on 15 March 2006. # * Added GL_EXT_framebuffer_object support on 27 March 2006. # * Removed old SGIX extension support on 5 April 2006. # * Added vertex / fragment program support on 7 June 2007 (Ian Romanick). # * # * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. # * # * Permission is hereby granted, free of charge, to any person obtaining a # * copy of this software and associated documentation files (the "Software"), # * to deal in the Software without restriction, including without limitation # * the rights to use, copy, modify, merge, publish, distribute, sublicense, # * and/or sell copies of the Software, and to permit persons to whom the # * Software is furnished to do so, subject to the following conditions: # * # * The above copyright notice and this permission notice shall be included # * in all copies or substantial portions of the Software. # * # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # */ const DEG_TO_RAD = (3.1415927 / 180.0); our $WindowWidth = 450; our $WindowHeight = 300; our $Xrot = 15; our $Yrot = 0.0; our $Zrot = 0.0; const Red = (1, 0, 0, 1); const Green = (0, 1, 0, 1); const Blue = (0, 0, 1, 1); const Yellow = (1, 1, 0, 1); const LightDist = 10; our $LightLatitude = 45.0; our $LightLongitude = 45.0; our $LightPos; our $SpotDir; const SpotAngle = 40.0 * DEG_TO_RAD; const ShadowNear = 4.0; const ShadowFar = 24.0; our $ShadowTexWidth = 256; our $ShadowTexHeight = 256; our $LinearFilter = GL_FALSE; our $Bias = -0.06; our $Anim = GL_TRUE; our $NeedNewShadowMap = GL_TRUE; our $ShadowTexture; our $GrayTexture; our $ShadowFBO; our $lightModelview; our $lightProjection; our $vert_prog; our $frag_progs; our $curr_frag = 0; our $max_frag = 1; const NUM_FRAG_MODES = 3; const FragProgNames = ( "fixed-function", "program without \"OPTION ARB_fragment_program_shadow\"", "program with \"OPTION ARB_fragment_program_shadow\"", ); our $HaveShadow = GL_FALSE; our $HaveFBO = GL_FALSE; our $UseFBO = GL_FALSE; our $HaveVP = GL_FALSE; our $HaveFP = GL_FALSE; our $HaveFP_Shadow = GL_FALSE; our $UseVP = GL_FALSE; our $HavePackedDepthStencil = GL_FALSE; our $UsePackedDepthStencil = GL_FALSE; our $HaveEXTshadowFuncs = GL_FALSE; our $HaveShadowAmbient = GL_FALSE; our $Operator = 0; const OperatorFunc = ( GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER, GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER ); const OperatorName = ( "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER", "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" ); our $DisplayMode; const SHOW_SHADOWS = 0; const SHOW_DEPTH_IMAGE = 1; const SHOW_DEPTH_MAPPING = 2; const SHOW_DISTANCE = 3; const biasMatrix = ( 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0, ); our $t0 = -1.0; const step = 3.0; const borderColor = (1.0, 0.0, 0.0, 0.0); sub MAT4_MUL($dest_vec, $src_mat, $src_vec) { return "DP4 " + $dest_vec + ".x, " + $src_mat + "[0], " + $src_vec + ";\n" "DP4 " + $dest_vec + ".y, " + $src_mat + "[1], " + $src_vec + ";\n" "DP4 " + $dest_vec + ".z, " + $src_mat + "[2], " + $src_vec + ";\n" "DP4 " + $dest_vec + ".w, " + $src_mat + "[3], " + $src_vec + ";\n"; } sub MAT3_MUL($dest_vec, $src_mat, $src_vec) { return "DP3 " + $dest_vec + ".x, " + $src_mat + "[0], " + $src_vec + ";\n" "DP3 " + $dest_vec + ".y, " + $src_mat + "[1], " + $src_vec + ";\n" "DP3 " + $dest_vec + ".z, " + $src_mat + "[2], " + $src_vec + ";\n"; } sub NORMALIZE($dest, $src) { return "DP3 " + $dest + ".w, " + $src + ", " + $src + ";\n" "RSQ " + $dest + ".w, " + $dest + ".w;\n" "MUL " + $dest + ", " + $src + ", " + $dest + ".w;\n"; } # Vertex program for shadow mapping. our $vert_code = "!!ARBvp1.0\n" "ATTRIB iPos = vertex.position;\n" "ATTRIB iNorm = vertex.normal;\n" "PARAM mvinv[4] = { state.matrix.modelview.invtrans };\n" "PARAM mvp[4] = { state.matrix.mvp };\n" "PARAM mv[4] = { state.matrix.modelview };\n" "PARAM texmat[4] = { state.matrix.texture[0] };\n" "PARAM $lightPos = state.light[0].position;\n" "PARAM ambientCol = state.lightprod[0].ambient;\n" "PARAM diffuseCol = state.lightprod[0].diffuse;\n" "TEMP n, lightVec;\n" "ALIAS V = lightVec;\n" "ALIAS NdotL = n;\n" "OUTPUT oPos = result.position;\n" "OUTPUT oColor = result.color;\n" "OUTPUT oTex = result.texcoord[0];\n" # Transform the vertex to clip coordinates. */ + MAT4_MUL("oPos", "mvp", "iPos") #/* Transform the vertex to eye coordinates. */ + MAT4_MUL("V", "mv", "iPos") #/* Transform the vertex to projected light coordinates. */ + MAT4_MUL("oTex", "texmat", "iPos") #/* Transform the normal to eye coordinates. */ + MAT3_MUL("n", "mvinv", "iNorm") # Calculate the vector from the vertex to the light in eye # coordinates. + "SUB lightVec, $lightPos, V;\n" + NORMALIZE("lightVec", "lightVec") + # Compute diffuse lighting coefficient. "DP3 NdotL.x, n, lightVec;\n" "MAX NdotL.x, NdotL.x, {0.0};\n" "MIN NdotL.x, NdotL.x, {1.0};\n" # Accumulate color contributions. "MOV oColor, diffuseCol;\n" "MAD oColor.xyz, NdotL.x, diffuseCol, ambientCol;\n" "END\n" ; const frag_code = "!!ARBfp1.0\n" "TEMP shadow, temp;\n" "TXP shadow, fragment.texcoord[0], texture[0], 2D;\n" "RCP temp.x, fragment.texcoord[0].w;\n" "MUL temp.x, temp.x, fragment.texcoord[0].z;\n" "SGE shadow, shadow.x, temp.x;\n" "MUL result.color.rgb, fragment.color, shadow.x;\n" "MOV result.color.a, fragment.color;\n" "END\n" ; const frag_shadow_code = "!!ARBfp1.0\n" "OPTION ARB_fragment_program_shadow;\n" "TEMP shadow;\n" "TXP shadow, fragment.texcoord[0], texture[0], SHADOW2D;\n" "MUL result.color.rgb, fragment.color, shadow.x;\n" "MOV result.color.a, fragment.color.a;\n" "END\n" ; const sPlane = ( 1, 0, 0, 0 ); const tPlane = ( 0, 1, 0, 0 ); const rPlane = ( 0, 0, 1, 0 ); const qPlane = ( 0, 0, 0, 1 ); sub assert($str) { stderr.vprintf("ASSERT: " + $str, $argv); stderr.printf("\n"); exit(1); } sub DrawScene() { my $k = 6.0; # sphere glPushMatrix(); glTranslatef(1.6, 2.2, 2.7); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green); glColor4fv(Green); glutSolidSphere(1.5, 15, 15); glPopMatrix(); /* dodecahedron */ glPushMatrix(); glTranslatef(-2.0, 1.2, 2.1); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red); glColor4fv(Red); glutSolidDodecahedron(); glPopMatrix(); /* icosahedron */ glPushMatrix(); glTranslatef(-0.6, 1.3, -0.5); glScalef(1.5, 1.5, 1.5); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow); glColor4fv(Red); glutSolidIcosahedron(); glPopMatrix(); /* a plane */ glPushMatrix(); glTranslatef(0, -1.1, 0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue); glColor4fv(Blue); glNormal3f(0, 1, 0); glBegin(GL_POLYGON); glVertex3f(-$k, 0, -$k); glVertex3f( $k, 0, -$k); glVertex3f( $k, 0, $k); glVertex3f(-$k, 0, $k); glEnd(); glPopMatrix(); } # Calculate modelview and project matrices for the light # Stores the results in \c $lightProjection (projection matrix) and # \c $lightModelview (modelview matrix). sub MakeShadowMatrix($lightPos, $spotDir, $spotAngle, $shadowNear, $shadowFar) { # compute frustum to enclose spot light cone my $d = $shadowNear * tan($spotAngle); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glFrustum(-$d, $d, -$d, $d, $shadowNear, $shadowFar); $lightProjection = glGetFloatv(GL_PROJECTION_MATRIX); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); gluLookAt($lightPos[0], $lightPos[1], $lightPos[2], $lightPos[0] + $spotDir[0], $lightPos[1] + $spotDir[1], $lightPos[2] + $spotDir[2], 0.0, 1.0, 0.0); $lightModelview = glGetFloatv(GL_MODELVIEW_MATRIX); glPopMatrix(); } # Load \c GL_TEXTURE matrix with light's MVP matrix. sub SetShadowTextureMatrix() { glMatrixMode(GL_TEXTURE); glLoadMatrixf(biasMatrix); glTranslatef(0.0, 0.0, $Bias); glMultMatrixf($lightProjection); glMultMatrixf($lightModelview); glMatrixMode(GL_MODELVIEW); } sub EnableIdentityTexgen() { # texgen so that texcoord = vertex coord glTexGenfv(GL_S, GL_EYE_PLANE, sPlane); glTexGenfv(GL_T, GL_EYE_PLANE, tPlane); glTexGenfv(GL_R, GL_EYE_PLANE, rPlane); glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); glEnable(GL_TEXTURE_GEN_R); glEnable(GL_TEXTURE_GEN_Q); } # * Setup 1-D texgen so that the distance from the light source, between # * the near and far planes maps to s=0 and s=1. When we draw the scene, # * the grayness will indicate the fragment's distance from the light # * source. sub EnableDistanceTexgen($lightPos, $lightDir, $lightNear, $lightFar) { my ($m, $d); my $sPlane; my $nearPoint; $m = sqrt($lightDir[0] * $lightDir[0] + $lightDir[1] * $lightDir[1] + $lightDir[2] * $lightDir[2]); $d = $lightFar - $lightNear; # $nearPoint = point on light direction vector which intersects the # near plane of the light frustum. $nearPoint[0] = $lightPos[0] + $lightDir[0] / $m * $lightNear; $nearPoint[1] = $lightPos[1] + $lightDir[1] / $m * $lightNear; $nearPoint[2] = $lightPos[2] + $lightDir[2] / $m * $lightNear; $sPlane[0] = $lightDir[0] / $d / $m; $sPlane[1] = $lightDir[1] / $d / $m; $sPlane[2] = $lightDir[2] / $d / $m; $sPlane[3] = -($sPlane[0] * $nearPoint[0] + $sPlane[1] * $nearPoint[1] + $sPlane[2] * $nearPoint[2]); glTexGenfv(GL_S, GL_EYE_PLANE, $sPlane); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); glEnable(GL_TEXTURE_GEN_S); } sub DisableTexgen() { glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); glDisable(GL_TEXTURE_GEN_R); glDisable(GL_TEXTURE_GEN_Q); } sub ComputeLightPos($dist, $latitude, $longitude, $pos, $dir) { $pos[0] = $dist * sin($longitude * DEG_TO_RAD); $pos[1] = $dist * sin($latitude * DEG_TO_RAD); $pos[2] = $dist * cos($latitude * DEG_TO_RAD) * cos($longitude * DEG_TO_RAD); $pos[3] = 1; $dir[0] = -$pos[0]; $dir[1] = -$pos[1]; $dir[2] = -$pos[2]; } # * Render the shadow map / depth texture. # * The result will be in the texture object named $ShadowTexture. sub RenderShadowMap() { my $depthFormat; # GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT my $depthType; # GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT if ($WindowWidth >= 1024 && $WindowHeight >= 1024) { $ShadowTexWidth = $ShadowTexHeight = 1024; } else if ($WindowWidth >= 512 && $WindowHeight >= 512) { $ShadowTexWidth = $ShadowTexHeight = 512; } else if ($WindowWidth >= 256 && $WindowHeight >= 256) { $ShadowTexWidth = $ShadowTexHeight = 256; } else { $ShadowTexWidth = $ShadowTexHeight = 128; } printf("Rendering %d x %d depth texture\n", $ShadowTexWidth, $ShadowTexHeight); if ($UsePackedDepthStencil) { $depthFormat = GL_DEPTH_STENCIL_EXT; $depthType = GL_UNSIGNED_INT_24_8_EXT; } else { $depthFormat = GL_DEPTH_COMPONENT; $depthType = GL_UNSIGNED_INT; } glMatrixMode(GL_PROJECTION); glLoadMatrixf($lightProjection); glMatrixMode(GL_MODELVIEW); glLoadMatrixf($lightModelview); if ($UseFBO) { my $fbo_status; glTexImage2D(GL_TEXTURE_2D, 0, $depthFormat, $ShadowTexWidth, $ShadowTexHeight, 0, $depthFormat, $depthType); # Set the filter mode so that the texture is texture-complete. # Otherwise it will cause the framebuffer to fail the framebuffer # completeness test. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, $ShadowFBO); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); $fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if ($fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) { stderr.printf("FBO not complete! status = 0x%04x\n", $fbo_status); if (GL_FRAMEBUFFER_UNSUPPORTED_EXT) assert("unsupported framebuffer extension"); assert("framebuffer not complete"); } } if (glIsEnabled(GL_TEXTURE_1D)) assert("GL_TEXTURE_1D"); if (glIsEnabled(GL_TEXTURE_2D)) assert("GL_TEXTURE_2D"); glViewport(0, 0, $ShadowTexWidth, $ShadowTexHeight); glClear(GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); DrawScene(); if ($UseFBO) { # all done! glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } else { # copy depth buffer into the texture map if ($DisplayMode == SHOW_DEPTH_MAPPING) { # load depth image as gray-scale luminance texture my $depth = glReadPixels(0, 0, $ShadowTexWidth, $ShadowTexHeight, $depthFormat, $depthType); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, $ShadowTexWidth, $ShadowTexHeight, 0, GL_LUMINANCE, GL_UNSIGNED_INT, $depth); } else { # The normal shadow case - a real depth texture glCopyTexImage2D(GL_TEXTURE_2D, 0, $depthFormat, 0, 0, $ShadowTexWidth, $ShadowTexHeight, 0); if ($UsePackedDepthStencil) { # debug check my $intFormat = glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT); if ($intFormat != GL_DEPTH_STENCIL_EXT) stderr.printf("texture format not set to GL_DEPTH_STENCIL_EXT (%d) internal format=%d\n", $depthFormat, $intFormat); } } } } # Show the shadow map as a grayscale image. sub ShowShadowMap() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, $WindowWidth, 0, $WindowHeight, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); DisableTexgen(); # interpret texture's depth values as luminance values if ($HaveShadow) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); } glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBegin(GL_POLYGON); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f($ShadowTexWidth, 0); glTexCoord2f(1, 1); glVertex2f($ShadowTexWidth, $ShadowTexHeight); glTexCoord2f(0, 1); glVertex2f(0, $ShadowTexHeight); glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); } # Redraw window image sub Display() { my $error; ComputeLightPos(LightDist, $LightLatitude, $LightLongitude, \$LightPos, \$SpotDir); if ($NeedNewShadowMap) { MakeShadowMatrix($LightPos, $SpotDir, SpotAngle, ShadowNear, ShadowFar); RenderShadowMap(); $NeedNewShadowMap = GL_FALSE; } glViewport(0, 0, $WindowWidth, $WindowHeight); if ($DisplayMode == SHOW_DEPTH_IMAGE) { ShowShadowMap(); } else { # prepare to draw scene from camera's view */ my $ar = float($WindowWidth) / $WindowHeight; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-$ar, $ar, -1.0, 1.0, 4.0, 50.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -22.0); glRotatef($Xrot, 1, 0, 0); glRotatef($Yrot, 0, 1, 0); glRotatef($Zrot, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0, GL_POSITION, $LightPos); if ($LinearFilter) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } if ($DisplayMode == SHOW_DEPTH_MAPPING) { if ($HaveShadow) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE); } glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable(GL_TEXTURE_2D); SetShadowTextureMatrix(); EnableIdentityTexgen(); } else if ($DisplayMode == SHOW_DISTANCE) { glMatrixMode(GL_TEXTURE); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); EnableDistanceTexgen($LightPos, $SpotDir, ShadowNear+$Bias, ShadowFar); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glEnable(GL_TEXTURE_1D); if (glIsEnabled(GL_TEXTURE_2D)) throw "ASSERT"; } else { if ($DisplayMode != SHOW_SHADOWS) throw "ASSERT"; if ($HaveShadow) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); } if ($curr_frag > 0) { glEnable(GL_FRAGMENT_PROGRAM_ARB); } else { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } glEnable(GL_TEXTURE_2D); SetShadowTextureMatrix(); if ($UseVP) { glEnable(GL_VERTEX_PROGRAM_ARB); } else { glEnable(GL_LIGHTING); EnableIdentityTexgen(); } } DrawScene(); if ($UseVP) { glDisable(GL_VERTEX_PROGRAM_ARB); } else { DisableTexgen(); glDisable(GL_LIGHTING); } if ($curr_frag > 0) { glDisable(GL_FRAGMENT_PROGRAM_ARB); } glDisable(GL_TEXTURE_2D); } glutSwapBuffers(); $error = glGetError(); if ($error) { printf("GL Error: %s\n", gluErrorString($error)); } } sub Reshape($width, $height) { $WindowWidth = $width; $WindowHeight = $height; $NeedNewShadowMap = GL_TRUE; } sub Idle() { our $dt; our $t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; if ($t0 < 0.0) $t0 = $t; $dt = $t - $t0; $t0 = $t; $Yrot += 75.0 * $dt; # $LightLongitude -= 5.0; glutPostRedisplay(); } sub Key($key, $x, $y) { if ($key > 27) $key = chr($key); switch ($key) { case 'a': $Anim = !$Anim; if ($Anim) glutIdleFunc(\Idle()); else glutIdleFunc(); break; case 'b': $Bias -= 0.01; printf("Bias %n\n", $Bias); break; case 'B': $Bias += 0.01; printf("Bias %n\n", $Bias); break; case 'd': $DisplayMode = SHOW_DISTANCE; break; case 'f': $LinearFilter = !$LinearFilter; printf("%s filtering\n", $LinearFilter ? "Bilinear" : "Nearest"); break; case 'i': $DisplayMode = SHOW_DEPTH_IMAGE; break; case 'm': $DisplayMode = SHOW_DEPTH_MAPPING; break; case 'M': $curr_frag = (1 + $curr_frag) % $max_frag; if (!$HaveShadow && ($curr_frag == 0)) { $curr_frag = 1; } printf("Using fragment %s\n", FragProgNames[$curr_frag]); if ($HaveFP) { glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, $frag_progs[$curr_frag]); } break; case 'n': case 's': case ' ': $DisplayMode = SHOW_SHADOWS; break; case 'o': if ($HaveEXTshadowFuncs) { $Operator++; if ($Operator >= 8) $Operator = 0; printf("Operator: %s\n", OperatorName[$Operator]); if ($HaveShadow) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, OperatorFunc[$Operator]); } } break; case 'p': $UsePackedDepthStencil = !$UsePackedDepthStencil; if ($UsePackedDepthStencil && !$HavePackedDepthStencil) { printf("Sorry, GL_EXT_packed_depth_stencil not supported\n"); $UsePackedDepthStencil = GL_FALSE; } else { printf("use GL_DEPTH_STENCIL_EXT: %d\n", $UsePackedDepthStencil); /* Don't really need to regenerate shadow map texture, but do so * to exercise more code more often. */ $NeedNewShadowMap = GL_TRUE; } break; case 'v': $UseVP = !$UseVP && $HaveVP; printf("Using vertex %s mode.\n", $UseVP ? "program" : "fixed-function"); break; case 'z': $Zrot -= step; break; case 'Z': $Zrot += step; break; case 27: exit(0); break; } glutPostRedisplay(); } sub SpecialKey($key, $x, $y) { my $mod = glutGetModifiers(); switch ($key) { case GLUT_KEY_UP: if ($mod) $LightLatitude += step; else $Xrot += step; break; case GLUT_KEY_DOWN: if ($mod) $LightLatitude -= step; else $Xrot -= step; break; case GLUT_KEY_LEFT: if ($mod) $LightLongitude += step; else $Yrot += step; break; case GLUT_KEY_RIGHT: if ($mod) $LightLongitude -= step; else $Yrot -= step; break; } if ($mod) $NeedNewShadowMap = GL_TRUE; glutPostRedisplay(); } # A helper for finding errors in program strings sub FindLine($program, $position) { my $l = split("\n", substr($program, 0, $position)); return elements $l; } sub compile_program($target, $code) { my $errorPos; my $p = glGenProgramsARB(1); glBindProgramARB($target, $p); glProgramStringARB($target, GL_PROGRAM_FORMAT_ASCII_ARB, $code); my $errorPos = glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB); if (glGetError() != GL_NO_ERROR || $errorPos != -1) { my $l = FindLine($code, $errorPos); printf("Fragment Program Error (pos=%d line=%d): %s\n", $errorPos, $l, glGetString(GL_PROGRAM_ERROR_STRING_ARB)); exit(0); } glBindProgramARB($target, 0); return $p; } sub Init() { if (!glutExtensionSupported("GL_ARB_depth_texture")) { printf("Sorry, this demo requires the GL_ARB_depth_texture extension\n"); exit(1); } $HaveShadow = glutExtensionSupported("GL_ARB_shadow"); $HaveVP = glutExtensionSupported("GL_ARB_vertex_program"); $HaveFP = glutExtensionSupported("GL_ARB_fragment_program"); $HaveFP_Shadow = glutExtensionSupported("GL_ARB_fragment_program_shadow"); if (!$HaveShadow && !$HaveFP) { printf("Sorry, this demo requires either the GL_ARB_shadow extension " "or the GL_ARB_fragment_program extension\n"); exit(1); } printf("Using GL_ARB_depth_texture\n"); if ($HaveShadow) { printf("and GL_ARB_shadow\n"); } if ($HaveFP) { printf("and GL_ARB_fragment_program\n"); } $HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient"); if ($HaveShadowAmbient) { printf("and GL_ARB_shadow_ambient\n"); } $HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs"); $HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil"); $UsePackedDepthStencil = $HavePackedDepthStencil; if (GL_EXT_framebuffer_object) { $HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object"); # disable framebuffer on Darwin initially - why doesn't it work? I have no clue :-( $UseFBO = PlatformOS == "Darwin" ? False : $HaveFBO; if ($UseFBO) { printf("Using GL_EXT_framebuffer_object\n"); } } # Set up the 2D shadow map texture glGenTextures(1, \$ShadowTexture); glBindTexture(GL_TEXTURE_2D, $ShadowTexture); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); if ($HaveShadow) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); } if ($HaveShadowAmbient) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3); } if (GL_EXT_framebuffer_object) { if ($UseFBO) { $ShadowFBO = glGenFramebuffersEXT(1); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, $ShadowFBO); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, $ShadowTexture, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } } #* Setup 1-D grayscale texture image for SHOW_DISTANCE mode $GrayTexture = glGenTextures(1); glBindTexture(GL_TEXTURE_1D, $GrayTexture); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); { my $i; my $image = ""; for ($i = 0; $i < 256; $i++) $image += chr($i); glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE, 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, binary($image)); } if ($HaveVP) { $vert_prog = compile_program(GL_VERTEX_PROGRAM_ARB, $vert_code); glBindProgramARB(GL_VERTEX_PROGRAM_ARB, $vert_prog); } $max_frag = 1; $frag_progs[0] = 0; if ($HaveFP) { $frag_progs[1] = compile_program(GL_FRAGMENT_PROGRAM_ARB, frag_code); $max_frag = 2; } if ($HaveFP && $HaveFP_Shadow) { $frag_progs[2] = compile_program(GL_FRAGMENT_PROGRAM_ARB, frag_shadow_code); $max_frag = 3; } if (!$HaveShadow) { $curr_frag = 1; glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, $frag_progs[$curr_frag]); } glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } sub PrintHelp() { printf("Keys:\n"); printf(" a = toggle animation\n"); printf(" i = show depth texture image\n"); printf(" m = show depth texture mapping\n"); printf(" d = show fragment distance from light source\n"); printf(" n = show normal, shadowed image\n"); printf(" f = toggle nearest/bilinear texture filtering\n"); printf(" b/B = decrease/increase shadow map Z bias\n"); printf(" p = toggle use of packed depth/stencil\n"); printf(" M = cycle through fragment program modes\n"); printf(" v = toggle vertex program modes\n"); printf(" cursor keys = rotate scene\n"); printf(" <shift> + cursor keys = rotate light source\n"); if ($HaveEXTshadowFuncs) printf(" o = cycle through comparison modes\n"); } sub main() { glutInit(\$ARGV); glutInitWindowPosition(0, 0); glutInitWindowSize($WindowWidth, $WindowHeight); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); glutCreateWindow("shadowtex.q"); glutReshapeFunc(\Reshape()); glutKeyboardFunc(\Key()); glutSpecialFunc(\SpecialKey()); glutDisplayFunc(\Display()); if ($Anim) glutIdleFunc(\Idle()); Init(); PrintHelp(); glutMainLoop(); return 0; } main();
| < Prev |
|---|





