Demo of per-pixel lighting with a fragment program.
authorBrian Paul <brian.paul@tungstengraphics.com>
Mon, 7 Apr 2003 23:05:50 +0000 (23:05 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Mon, 7 Apr 2003 23:05:50 +0000 (23:05 +0000)
progs/demos/Makefile.X11
progs/demos/fplight.c [new file with mode: 0644]

index a388626..5862749 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile.X11,v 1.20 2001/08/21 05:42:11 gareth Exp $
+# $Id: Makefile.X11,v 1.21 2003/04/07 23:05:51 brianp Exp $
 
 # Mesa 3-D graphics library
 # Version:  3.5
@@ -23,6 +23,7 @@ PROGS = bounce \
        cubemap \
        drawpix \
        fire \
+       fplight \
        gamma \
        gears \
        geartrain \
diff --git a/progs/demos/fplight.c b/progs/demos/fplight.c
new file mode 100644 (file)
index 0000000..12a3e91
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Use GL_NV_fragment_program to implement per-pixel lighting.
+ *
+ * Brian Paul
+ * 7 April 2003
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#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;
+
+
+#define NAMED_PARAMETER4FV(prog, name, v)        \
+  glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
+
+
+static void Display( void )
+{
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   if (PixelLight) {
+      NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos);
+      glEnable(GL_FRAGMENT_PROGRAM_NV);
+      glEnable(GL_VERTEX_PROGRAM_NV);
+      glDisable(GL_LIGHTING);
+   }
+   else {
+      glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+      glDisable(GL_FRAGMENT_PROGRAM_NV);
+      glDisable(GL_VERTEX_PROGRAM_NV);
+      glEnable(GL_LIGHTING);
+   }
+
+   glPushMatrix();
+   glRotatef(Xrot, 1, 0, 0);
+   glRotatef(Yrot, 0, 1, 0);
+
+   glTexCoord2f(0, 0);
+#if 1
+   glutSolidSphere(2.0, 10, 5);
+#else
+   {
+      GLUquadricObj *q = gluNewQuadric();
+      gluQuadricNormals(q, GL_SMOOTH);
+      gluQuadricTexture(q, GL_TRUE);
+      glRotatef(90, 1, 0, 0);
+      glTranslatef(0, 0, -1);
+      gluCylinder(q, 1.0, 1.0, 2.0, 24, 1);
+      gluDeleteQuadric(q);
+   }
+#endif
+
+   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 );
+   /*glOrtho( -2.0, 2.0, -2.0, 2.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();
+}
+
+
+static void Init( void )
+{
+   static const char *fragProgramText =
+      "!!FP1.0\n"
+      "DECLARE Diffuse; \n"
+      "DECLARE Specular; \n"
+      "DECLARE LightPos; \n"
+
+      "# Compute normalized LightPos, put it in R0\n"
+      "DP3 R0.x, LightPos, LightPos;\n"
+      "RSQ R0.y, R0.x;\n"
+      "MUL R0, LightPos, R0.y;\n"
+
+      "# Compute normalized normal, put it in R1\n"
+      "DP3 R1, f[TEX0], f[TEX0]; \n"
+      "RSQ R1.y, R1.x;\n"
+      "MUL R1, f[TEX0], R1.y;\n"
+
+      "# Compute dot product of light direction and normal vector\n"
+      "DP3 R2, R0, R1;"
+
+      "MUL R3, Diffuse, R2;    # diffuse attenuation\n"
+
+      "POW R4, R2.x, {20.0}.x; # specular exponent\n"
+
+      "MUL R5, Specular, R4;   # specular attenuation\n"
+
+      "ADD o[COLR], R3, R5;    # add diffuse and specular colors\n"
+      "END \n"
+      ;
+
+   static const char *vertProgramText =
+      "!!VP1.0\n"
+      "# typical modelview/projection transform\n"
+      "DP4   o[HPOS].x, c[0], v[OPOS] ;\n"
+      "DP4   o[HPOS].y, c[1], v[OPOS] ;\n"
+      "DP4   o[HPOS].z, c[2], v[OPOS] ;\n"
+      "DP4   o[HPOS].w, c[3], v[OPOS] ;\n"
+      "# transform normal by inv transpose of modelview, put in tex0\n"
+      "DP4   o[TEX0].x, c[4], v[NRML] ;\n"
+      "DP4   o[TEX0].y, c[5], v[NRML] ;\n"
+      "DP4   o[TEX0].z, c[6], v[NRML] ;\n"
+      "DP4   o[TEX0].w, c[7], v[NRML] ;\n"
+      "END\n";
+   ;
+
+   if (!glutExtensionSupported("GL_NV_vertex_program")) {
+      printf("Sorry, this demo requires GL_NV_vertex_program\n");
+      exit(1);
+   }
+   if (!glutExtensionSupported("GL_NV_fragment_program")) {
+      printf("Sorry, this demo requires GL_NV_fragment_program\n");
+      exit(1);
+   }
+         
+   glGenProgramsNV(1, &FragProg);
+   glGenProgramsNV(1, &VertProg);
+
+   /*
+    * Fragment program
+    */
+   glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg,
+                   strlen(fragProgramText),
+                   (const GLubyte *) fragProgramText);
+   assert(glIsProgramNV(FragProg));
+   glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg);
+
+   NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse);
+   NAMED_PARAMETER4FV(FragProg, "Specular", Specular);
+
+   /*
+    * Vertex program
+    */
+   glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg,
+                   strlen(vertProgramText),
+                   (const GLubyte *) vertProgramText);
+   assert(glIsProgramNV(VertProg));
+   glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg);
+   glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV);
+   glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV);
+
+   /*
+    * Misc init
+    */
+   glClearColor(0.3, 0.3, 0.3, 0.0);
+   glEnable(GL_ALPHA_TEST); /* temporary hack */
+   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( Display );
+   if (Anim)
+      glutIdleFunc(Idle);
+   Init();
+   glutMainLoop();
+   return 0;
+}