Demo of using GL_ARB_vertex/fragment_program to do per-pixel lighting.
authorBrian Paul <brian.paul@tungstengraphics.com>
Thu, 17 Apr 2003 19:20:54 +0000 (19:20 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Thu, 17 Apr 2003 19:20:54 +0000 (19:20 +0000)
progs/demos/Makefile.BeOS-R4
progs/demos/Makefile.X11
progs/demos/Makefile.win
progs/demos/arbfplight.c [new file with mode: 0644]

index 23d270f81e916bc4f9db7ecfbad166d1dff78b5d..8511409a464a0b02d59ae72d664c3ed88154a357 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.BeOS-R4,v 1.14 2001/02/20 17:04:52 brianp Exp $
+# $Id: Makefile.BeOS-R4,v 1.15 2003/04/17 19:20:54 brianp Exp $
 
 # Mesa 3-D graphics library
 # Version:  3.5
@@ -17,11 +17,14 @@ GL_LIBS = -L$(LIBDIR) -L/boot/home/config/lib -Xlinker -rpath $(LIBDIR) -lbe -lg
 
 LIB_DEP = $(LIBDIR)/$(GL_LIB) $(LIBDIR)/$(GLU_LIB) $(LIBDIR)/$(GLUT_LIB)
 
-PROGS = bounce \
+PROGS = \
+       arbfplight \
+       bounce \
        clearspd \
        cubemap \
        drawpix \
        fire \
+       fplight \
        gamma \
        gears \
        geartrain \
index 5862749b5fa2360a9ea9fae494ca07b113496fbd..f34cde07e6de2c3e6d72e4ad83c562a55c076c94 100644 (file)
@@ -1,8 +1,8 @@
-# $Id: Makefile.X11,v 1.21 2003/04/07 23:05:51 brianp Exp $
+# $Id: Makefile.X11,v 1.22 2003/04/17 19:20:55 brianp Exp $
 
 # Mesa 3-D graphics library
-# Version:  3.5
-# Copyright (C) 1995-2001  Brian Paul
+# Version:  5.1
+# Copyright (C) 1995-2003  Brian Paul
 
 # Makefile for GLUT-based demo programs for Unix/X11
 
@@ -18,7 +18,9 @@ OSMESA_LIBS = -L$(LIBDIR) -lglut -lOSMesa -lGLU -lGL $(APP_LIB_DEPS)
 
 LIB_DEP = $(LIBDIR)/$(GL_LIB) $(LIBDIR)/$(GLU_LIB) $(LIBDIR)/$(GLUT_LIB)
 
-PROGS = bounce \
+PROGS = \
+       arbfplight \
+       bounce \
        clearspd \
        cubemap \
        drawpix \
index 18372b05dba4355f724ae0c96f30053be80a58d7..188ca2f6734666093acbbd33fa1db93e56cbd838 100644 (file)
@@ -1,8 +1,8 @@
-# $Id: Makefile.win,v 1.7 2002/01/16 00:48:43 kschultz Exp $
+# $Id: Makefile.win,v 1.8 2003/04/17 19:20:55 brianp Exp $
 
 # Mesa 3-D graphics library
-# Version:  3.5
-# Copyright (C) 1995-2001  Brian Paul
+# Version:  5.1
+# Copyright (C) 1995-2003  Brian Paul
 
 # Makefile for GLUT-based demo programs for Windows
 
@@ -14,12 +14,14 @@ TOP    = ..
 INCDIR = ..\include
 LIBDIR = ..\lib
 
-PROGS = anisotropic \
+PROGS = \
+       arbfplight \
        bounce \
        clearspd \
        cubemap \
        drawpix \
        fire \
+       fplight \
        gamma \
        gears \
        geartrain \
diff --git a/progs/demos/arbfplight.c b/progs/demos/arbfplight.c
new file mode 100644 (file)
index 0000000..fcdc114
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Use GL_ARB_fragment_program and GL_ARB_vertex_program to implement
+ * simple per-pixel lighting.
+ *
+ * Brian Paul
+ * 17 April 2003
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 };
+static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 };
+static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 };
+static GLfloat Delta = 1.0;
+
+static GLuint FragProg;
+static GLuint VertProg;
+static GLboolean Anim = GL_TRUE;
+static GLboolean Wire = GL_FALSE;
+static GLboolean PixelLight = GL_TRUE;
+
+static GLfloat Xrot = 0, Yrot = 0;
+
+static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func;
+static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func;
+static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func;
+static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func;
+static PFNGLISPROGRAMARBPROC glIsProgramARB_func;
+
+/* These must match the indexes used in the fragment program */
+#define DIFFUSE 1
+#define SPECULAR 2
+#define LIGHTPOS 3
+
+
+
+static void Redisplay( void )
+{
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   if (PixelLight) {
+      glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB,
+                                    LIGHTPOS, LightPos);
+      glEnable(GL_FRAGMENT_PROGRAM_ARB);
+      glEnable(GL_VERTEX_PROGRAM_ARB);
+      glDisable(GL_LIGHTING);
+   }
+   else {
+      glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+      glDisable(GL_FRAGMENT_PROGRAM_ARB);
+      glDisable(GL_VERTEX_PROGRAM_ARB);
+      glEnable(GL_LIGHTING);
+   }
+
+   glPushMatrix();
+   glRotatef(Xrot, 1, 0, 0);
+   glRotatef(Yrot, 0, 1, 0);
+   glutSolidSphere(2.0, 10, 5);
+   glPopMatrix();
+
+   glutSwapBuffers();
+}
+
+
+static void Idle(void)
+{
+   LightPos[0] += Delta;
+   if (LightPos[0] > 25.0)
+      Delta = -1.0;
+   else if (LightPos[0] <- 25.0)
+      Delta = 1.0;
+   glutPostRedisplay();
+}
+
+
+static void Reshape( int width, int height )
+{
+   glViewport( 0, 0, width, height );
+   glMatrixMode( GL_PROJECTION );
+   glLoadIdentity();
+   glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
+   glMatrixMode( GL_MODELVIEW );
+   glLoadIdentity();
+   glTranslatef( 0.0, 0.0, -15.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+     case ' ':
+        Anim = !Anim;
+        if (Anim)
+           glutIdleFunc(Idle);
+        else
+           glutIdleFunc(NULL);
+        break;
+      case 'x':
+         LightPos[0] -= 1.0;
+         break;
+      case 'X':
+         LightPos[0] += 1.0;
+         break;
+      case 'w':
+         Wire = !Wire;
+         if (Wire)
+            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+         else
+            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+         break;
+      case 'p':
+         PixelLight = !PixelLight;
+         if (PixelLight) {
+            printf("Per-pixel lighting\n");
+         }
+         else {
+            printf("Conventional lighting\n");
+         }
+         break;
+      case 27:
+         exit(0);
+         break;
+   }
+   glutPostRedisplay();
+}
+
+static void SpecialKey( int key, int x, int y )
+{
+   const GLfloat step = 3.0;
+   (void) x;
+   (void) y;
+   switch (key) {
+      case GLUT_KEY_UP:
+         Xrot -= step;
+         break;
+      case GLUT_KEY_DOWN:
+         Xrot += step;
+         break;
+      case GLUT_KEY_LEFT:
+         Yrot -= step;
+         break;
+      case GLUT_KEY_RIGHT:
+         Yrot += step;
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+/* A helper for finding errors in program strings */
+static int FindLine( const char *program, int position )
+{
+   int i, line = 1;
+   for (i = 0; i < position; i++) {
+      if (program[i] == '\n')
+         line++;
+   }
+   return line;
+}
+
+
+static void Init( void )
+{
+   GLint errorPos;
+
+   /* Yes, this could be expressed more efficiently */
+   static const char *fragProgramText =
+      "!!ARBfp1.0\n"
+      "PARAM Diffuse = program.local[1]; \n"
+      "PARAM Specular = program.local[2]; \n"
+      "PARAM LightPos = program.local[3]; \n"
+      "TEMP lightDir, normal, len; \n"
+      "TEMP dotProd, specAtten; \n"
+      "TEMP diffuseColor, specularColor; \n"
+
+      "# Compute normalized light direction \n"
+      "DP3 len.x, LightPos, LightPos; \n"
+      "RSQ len.y, len.x; \n"
+      "MUL lightDir, LightPos, len.y; \n"
+
+      "# Compute normalized normal \n"
+      "DP3 len.x, fragment.texcoord[0], fragment.texcoord[0]; \n"
+      "RSQ len.y, len.x; \n"
+      "MUL normal, fragment.texcoord[0], len.y; \n"
+
+      "# Compute dot product of light direction and normal vector\n"
+      "DP3 dotProd, lightDir, normal;"
+
+      "MUL diffuseColor, Diffuse, dotProd;            # diffuse attenuation\n"
+
+      "POW specAtten.x, dotProd.x, {20.0}.x;          # specular exponent\n"
+
+      "MUL specularColor, Specular, specAtten.x;      # specular attenuation\n"
+
+      "ADD result.color, diffuseColor, specularColor; # add colors\n"
+      "END \n"
+      ;
+
+   static const char *vertProgramText =
+      "!!ARBvp1.0\n"
+      "ATTRIB pos = vertex.position; \n"
+      "ATTRIB norm = vertex.normal; \n"
+      "PARAM modelviewProj[4] = { state.matrix.mvp }; \n"
+      "PARAM invModelview[4] = { state.matrix.modelview.invtrans }; \n"
+
+      "# typical modelview/projection transform \n"
+      "DP4 result.position.x, pos, modelviewProj[0]; \n"
+      "DP4 result.position.y, pos, modelviewProj[1]; \n"
+      "DP4 result.position.z, pos, modelviewProj[2]; \n"
+      "DP4 result.position.w, pos, modelviewProj[3]; \n"
+
+      "# transform normal by inv transpose of modelview, put in tex0 \n"
+      "DP4 result.texcoord[0].x, norm, invModelview[0]; \n"
+      "DP4 result.texcoord[0].y, norm, invModelview[1]; \n"
+      "DP4 result.texcoord[0].z, norm, invModelview[2]; \n"
+      "DP4 result.texcoord[0].w, norm, invModelview[3]; \n"
+
+      "END\n";
+      ;
+
+   if (!glutExtensionSupported("GL_ARB_vertex_program")) {
+      printf("Sorry, this demo requires GL_ARB_vertex_program\n");
+      exit(1);
+   }
+   if (!glutExtensionSupported("GL_ARB_fragment_program")) {
+      printf("Sorry, this demo requires GL_ARB_fragment_program\n");
+      exit(1);
+   }
+         
+   /*
+    * Get extension function pointers.
+    */
+   glProgramLocalParameter4fvARB_func = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) glutGetProcAddress("glProgramLocalParameter4fvARB");
+   assert(glProgramLocalParameter4fvARB_func);
+
+   glGenProgramsARB_func = (PFNGLGENPROGRAMSARBPROC) glutGetProcAddress("glGenProgramsARB");
+   assert(glGenProgramsARB_func);
+
+   glProgramStringARB_func = (PFNGLPROGRAMSTRINGARBPROC) glutGetProcAddress("glProgramStringARB");
+   assert(glProgramStringARB_func);
+
+   glBindProgramARB_func = (PFNGLBINDPROGRAMARBPROC) glutGetProcAddress("glBindProgramARB");
+   assert(glBindProgramARB_func);
+
+   glIsProgramARB_func = (PFNGLISPROGRAMARBPROC) glutGetProcAddress("glIsProgramARB");
+   assert(glIsProgramARB_func);
+
+   /*
+    * Fragment program
+    */
+   glGenProgramsARB_func(1, &FragProg);
+   assert(FragProg > 0);
+   glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB, FragProg);
+   glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB,
+                           GL_PROGRAM_FORMAT_ASCII_ARB,
+                           strlen(fragProgramText),
+                           (const GLubyte *) fragProgramText);
+   glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+   if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+      int l = FindLine(fragProgramText, errorPos);
+      printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
+             (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+      exit(0);
+   }
+   assert(glIsProgramARB_func(FragProg));
+
+   glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, DIFFUSE, Diffuse);
+   glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, SPECULAR, Specular);
+
+   /*
+    * Do some sanity tests
+    */
+   {
+      GLdouble v[4];
+      glProgramLocalParameter4dARB(GL_FRAGMENT_PROGRAM_ARB, 8,
+                                   10.0, 20.0, 30.0, 40.0);
+      glGetProgramLocalParameterdvARB(GL_FRAGMENT_PROGRAM_ARB, 8, v);
+      assert(v[0] == 10.0);
+      assert(v[1] == 20.0);
+      assert(v[2] == 30.0);
+      assert(v[3] == 40.0);
+      glGetProgramLocalParameterdvARB(GL_FRAGMENT_PROGRAM_ARB, DIFFUSE, v);
+      assert(v[0] == Diffuse[0]);
+      assert(v[1] == Diffuse[1]);
+      assert(v[2] == Diffuse[2]);
+      assert(v[3] == Diffuse[3]);
+   }
+
+   /*
+    * Vertex program
+    */
+   glGenProgramsARB_func(1, &VertProg);
+   assert(VertProg > 0);
+   glBindProgramARB_func(GL_VERTEX_PROGRAM_ARB, VertProg);
+   glProgramStringARB_func(GL_VERTEX_PROGRAM_ARB,
+                           GL_PROGRAM_FORMAT_ASCII_ARB,
+                           strlen(vertProgramText),
+                           (const GLubyte *) vertProgramText);
+   glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
+   if (glGetError() != GL_NO_ERROR || errorPos != -1) {
+      int l = FindLine(fragProgramText, errorPos);
+      printf("Vertex Program Error (pos=%d line=%d): %s\n", errorPos, l,
+             (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+      exit(0);
+   }
+   assert(glIsProgramARB_func(VertProg));
+
+   /*
+    * Misc init
+    */
+   glClearColor(0.3, 0.3, 0.3, 0.0);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_LIGHTING);
+   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse);
+   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular);
+   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0);
+
+   printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+   printf("Press p to toggle between per-pixel and per-vertex lighting\n");
+}
+
+
+int main( int argc, char *argv[] )
+{
+   glutInit( &argc, argv );
+   glutInitWindowPosition( 0, 0 );
+   glutInitWindowSize( 200, 200 );
+   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+   glutCreateWindow(argv[0]);
+   glutReshapeFunc( Reshape );
+   glutKeyboardFunc( Key );
+   glutSpecialFunc( SpecialKey );
+   glutDisplayFunc( Redisplay );
+   if (Anim)
+      glutIdleFunc(Idle);
+   Init();
+   glutMainLoop();
+   return 0;
+}