include readtex.h
[mesa.git] / progs / demos / shadowtex.c
index a68ad77a1f8bdaa1ba577a68854ec26f57553086..e918751a7ad668195801b0dfa171ef3ece4f7f8d 100644 (file)
@@ -1,12 +1,12 @@
-/* $Id: shadowtex.c,v 1.1 2001/02/20 16:43:50 brianp Exp $ */
-
 /*
- * Shadow demo using the GL_SGIX_depth_texture, GL_SGIX_shadow and
- * GL_SGIX_shadow_ambient extensions.
+ * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and
+ * GL_ARB_shadow_ambient extensions (or the old SGIX extensions).
  *
  * Brian Paul
  * 19 Feb 2001
  *
+ * Added GL_EXT_shadow_funcs support on 23 March 2002
+ *
  * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  */
 
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
 #include <GL/glut.h>
-#include "../util/showbuffer.c"
+#include "showbuffer.h"
+
+#if 0 /* change to 1 if you want to use the old SGIX extensions */
+#undef GL_ARB_depth_texture
+#undef GL_ARB_shadow
+#undef GL_ARB_shadow_ambient
+#endif
 
 
 #define DEG_TO_RAD (3.14159 / 180.0)
@@ -54,14 +61,29 @@ static GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
 static GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
 static GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
 
-static GLboolean ShowDepth = GL_FALSE;
-
-static GLfloat ShadowImage[256*256];
+static GLboolean LinearFilter = GL_FALSE;
 
 static GLfloat Bias = -0.06;
 
 static GLboolean Anim = GL_TRUE;
 
+static GLboolean HaveEXTshadowFuncs = GL_FALSE;
+static GLint Operator = 0;
+static const GLenum OperatorFunc[8] = {
+   GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER,
+   GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER };
+static const char *OperatorName[8] = {
+   "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
+   "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
+
+
+static GLuint DisplayMode;
+#define SHOW_NORMAL         0
+#define SHOW_DEPTH_IMAGE    1
+#define SHOW_DEPTH_MAPPING  2
+#define SHOW_DISTANCE       3
+
+
 
 static void
 DrawScene(void)
@@ -110,8 +132,8 @@ DrawScene(void)
  * source's point of view.
  */
 static void
-ShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
-             GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
+MakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
+                 GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
 {
    GLfloat d;
    
@@ -131,7 +153,7 @@ ShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
 
 
 static void
-EnableTexgen(void)
+EnableIdentityTexgen(void)
 {
    /* texgen so that texcoord = vertex coord */
    static GLfloat sPlane[4] = { 1, 0, 0, 0 };
@@ -155,6 +177,46 @@ EnableTexgen(void)
 }
 
 
+/*
+ * 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.
+ */
+static void
+EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
+                     GLfloat lightNear, GLfloat lightFar)
+{
+   GLfloat m, d;
+   GLfloat sPlane[4];
+   GLfloat nearPoint[3];
+
+   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);
+}
+
+
 static void
 DisableTexgen(void)
 {
@@ -169,6 +231,7 @@ static void
 ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
                 GLfloat pos[4], GLfloat dir[3])
 {
+
    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);
@@ -184,6 +247,7 @@ Display(void)
 {
    GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
    GLfloat d;
+   GLenum error;
 
    ComputeLightPos(LightDist, LightLatitude, LightLongitude,
                    LightPos, SpotDir);
@@ -208,37 +272,96 @@ Display(void)
    /*
     * Step 2: copy depth buffer into texture map
     */
-   glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
-                    0, 0, ShadowTexWidth, ShadowTexHeight, 0);
+   if (DisplayMode == SHOW_DEPTH_MAPPING) {
+      /* load depth image as gray-scale luminance texture */
+      GLfloat *depth = (GLfloat *) malloc(ShadowTexWidth * ShadowTexHeight
+                                          * sizeof(GLfloat));
+      if (depth) {
+         glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
+                      GL_DEPTH_COMPONENT, GL_FLOAT, depth);
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
+                      ShadowTexWidth, ShadowTexHeight, 0,
+                      GL_LUMINANCE, GL_FLOAT, depth);
+         free(depth);
+      }
+   }
+   else {
+      /* The normal shadow case */
+      glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
+                       0, 0, ShadowTexWidth, ShadowTexHeight, 0);
+   }
 
    /*
     * Step 3: render scene from point of view of the camera
     */
    glViewport(0, 0, 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);
-   if (ShowDepth) {
-      ShowDepthBuffer(WindowWidth, WindowHeight, 1, 0);
+   if (DisplayMode == SHOW_DEPTH_IMAGE) {
+      ShowDepthBuffer(WindowWidth, WindowHeight, 0, 1);
    }
    else {
+      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);
-      glEnable(GL_TEXTURE_2D);
-      ShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
-      EnableTexgen();
+      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 defined(GL_ARB_shadow)
+         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+#elif defined(GL_SGIX_shadow)
+         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_FALSE);
+#endif
+         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+         glEnable(GL_TEXTURE_2D);
+         MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
+         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);
+      }
+      else {
+         assert(DisplayMode == SHOW_NORMAL);
+#if defined(GL_ARB_shadow)
+         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
+                         GL_COMPARE_R_TO_TEXTURE_ARB);
+#elif defined(GL_SGIX_shadow)
+         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
+#endif
+         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+         glEnable(GL_TEXTURE_2D);
+         MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
+         EnableIdentityTexgen();
+      }
       DrawScene();
       DisableTexgen();
+      glDisable(GL_TEXTURE_1D);
       glDisable(GL_TEXTURE_2D);
    }
 
    glutSwapBuffers();
+
+   error = glGetError();
+   if (error) {
+      printf("GL Error: %s\n", (char *) gluErrorString(error));
+   }
 }
 
 
@@ -247,13 +370,29 @@ Reshape(int width, int height)
 {
    WindowWidth = width;
    WindowHeight = height;
+   if (width >= 512 && height >= 512) {
+      ShadowTexWidth = ShadowTexHeight = 512;
+   }
+   else if (width >= 256 && height >= 256) {
+      ShadowTexWidth = ShadowTexHeight = 256;
+   }
+   else {
+      ShadowTexWidth = ShadowTexHeight = 128;
+   }
+   printf("Using %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
 }
 
 
 static void
 Idle(void)
 {
-   Yrot += 5.0;
+   static double t0 = -1.;
+   double dt, 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();
 }
@@ -275,12 +414,38 @@ Key(unsigned char key, int x, int y)
          break;
       case 'b':
          Bias -= 0.01;
+         printf("Bias %g\n", Bias);
          break;
       case 'B':
          Bias += 0.01;
+         printf("Bias %g\n", Bias);
          break;
       case 'd':
-         ShowDepth = !ShowDepth;
+         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 'n':
+      case ' ':
+         DisplayMode = SHOW_NORMAL;
+         break;
+      case 'o':
+         if (HaveEXTshadowFuncs) {
+            Operator++;
+            if (Operator >= 8)
+               Operator = 0;
+            printf("Operator: %s\n", OperatorName[Operator]);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
+                            OperatorFunc[Operator]);
+         }
          break;
       case 'z':
          Zrot -= step;
@@ -293,7 +458,6 @@ Key(unsigned char key, int x, int y)
          break;
    }
    glutPostRedisplay();
-   printf("Bias %g\n", Bias);
 }
 
 
@@ -337,22 +501,59 @@ SpecialKey(int key, int x, int y)
 static void
 Init(void)
 {
+#if defined(GL_ARB_depth_texture) && defined(GL_ARB_shadow)
+   if (!glutExtensionSupported("GL_ARB_depth_texture") ||
+       !glutExtensionSupported("GL_ARB_shadow")) {
+      printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
+      exit(1);
+   }
+   printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
+#elif defined(GL_SGIX_depth_texture) && defined(GL_SGIX_shadow)
    if (!glutExtensionSupported("GL_SGIX_depth_texture") ||
        !glutExtensionSupported("GL_SGIX_shadow")) {
       printf("Sorry, this demo requires the GL_SGIX_depth_texture and GL_SGIX_shadow extensions\n");
       exit(1);
    }
-
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   printf("Using GL_SGIX_depth_texture and GL_SGIX_shadow\n");
+#endif
+   HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
+
+   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+   glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
+#if defined(GL_ARB_shadow)
+   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);
+#elif defined(GL_SGIX_shadow)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_OPERATOR_SGIX,
                    GL_TEXTURE_LEQUAL_R_SGIX);
+#endif
 
-   if (glutExtensionSupported("GL_SGIX_shadow_ambient"))
+#if defined(GL_ARB_shadow_ambient)
+   if (glutExtensionSupported("GL_ARB_shadow_ambient")) {
+      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
+      printf("and GL_ARB_shadow_ambient\n");
+   }
+#elif defined(GL_SGIX_shadow_ambient)
+   if (glutExtensionSupported("GL_SGIX_shadow_ambient")) {
       glTexParameterf(GL_TEXTURE_2D, GL_SHADOW_AMBIENT_SGIX, 0.3);
+      printf("and GL_SGIX_shadow_ambient\n");
+   }
+#endif
+
+   /* setup 1-D grayscale texture image for SHOW_DISTANCE mode */
+   {
+      GLuint i;
+      GLubyte image[256];
+      for (i = 0; i < 256; i++)
+         image[i] = i;
+      glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
+                   256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
+   }
 
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
@@ -365,10 +566,16 @@ PrintHelp(void)
 {
    printf("Keys:\n");
    printf("  a = toggle animation\n");
-   printf("  d = toggle display of depth texture\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("  cursor keys = rotate scene\n");
    printf("  <shift> + cursor keys = rotate light source\n");
+   if (HaveEXTshadowFuncs)
+      printf("  o = cycle through comparison modes\n");
 }