Porting NV_vertex_program tests to ARB_vertex_program
authorKarl Rasche <karlrasche@gmail.com>
Sun, 23 Nov 2003 17:44:02 +0000 (17:44 +0000)
committerKarl Rasche <karlrasche@gmail.com>
Sun, 23 Nov 2003 17:44:02 +0000 (17:44 +0000)
progs/tests/arbvptest1.c [new file with mode: 0644]
progs/tests/arbvptest3.c [new file with mode: 0644]
progs/tests/arbvptorus.c [new file with mode: 0644]
progs/tests/arbvpwarpmesh.c [new file with mode: 0644]

diff --git a/progs/tests/arbvptest1.c b/progs/tests/arbvptest1.c
new file mode 100644 (file)
index 0000000..65f693a
--- /dev/null
@@ -0,0 +1,167 @@
+/* Test glGenProgramsNV(), glIsProgramNV(), glLoadProgramNV() */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static void Display( void )
+{
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   glPushMatrix();
+
+   glBegin(GL_POLYGON);
+   glVertexAttrib2fNV(0, -1, -1);
+   glVertexAttrib2fNV(0, 1, -1);
+   glVertexAttrib2fNV(0, 0,  1);
+   glEnd();
+
+   glPopMatrix();
+
+   glutSwapBuffers();
+}
+
+
+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 27:
+         exit(0);
+         break;
+   }
+   glutPostRedisplay();
+}
+
+static void load_program(const char *prog, GLuint prognum)
+{
+   int a;      
+   GLint errorpos, errno;
+   
+   glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+   glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+                        strlen(prog), (const GLubyte *) prog);
+
+   assert(glIsProgramARB(prognum));
+   errno = glGetError();
+   printf("glGetError = %d\n", errno);
+   if (errno != GL_NO_ERROR)
+   {
+      glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+      printf("errorpos: %d\n", errorpos);
+      printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+
+      for (a=-10; a<10; a++)
+      {
+         if ((errorpos+a < 0) || (errorpos+a >= strlen(prog))) continue;             
+         printf("%c", prog[errorpos+a]);
+      }          
+      printf("\n");      
+      exit(1);
+   }
+}
+
+static void Init( void )
+{
+   GLuint prognum[4];
+   
+   static const char *prog1 =
+      "!!ARBvp1.0\n"
+      "TEMP R0;\n"      
+      "MUL   result.color.primary.xyz, R0, program.local[35]; \n"
+      "END\n";
+   static const char *prog2 =
+      "!!ARBvp1.0\n"
+      "#\n"
+      "# c[0-3]  = modelview projection (composite) matrix\n"
+      "# c[32]   = normalized light direction in object-space\n"
+      "# c[35]   = yellow diffuse material, (1.0, 1.0, 0.0, 1.0)\n"
+      "# c[64].x = 0.0\n"
+      "# c[64].z = 0.125, a scaling factor\n"
+      "TEMP R0, R1;\n"      
+      "#\n"
+      "# outputs diffuse illumination for color and perturbed position\n"
+      "#\n"
+      "DP3   R0, program.local[32], vertex.normal;  # light direction DOT normal\n"
+      "MUL   result.color.primary.xyz, R0, program.local[35]; \n"
+      "MAX   R0, program.local[64].x, R0; \n"
+      "MUL   R0, R0, vertex.normal; \n"
+      "MUL   R0, R0, program.local[64].z;  \n"
+      "ADD   R1, vertex.position, -R0;       # perturb object space position\n"
+      "DP4   result.position.x, state.matrix.mvp.row[0], R1; \n"
+      "DP4   result.position.y, state.matrix.mvp.row[1], R1; \n"
+      "DP4   result.position.z, state.matrix.mvp.row[2], R1; \n"
+      "DP4   result.position.w, state.matrix.mvp.row[3], R1; \n"
+      "END\n";
+   static const char *prog3 = 
+      "!!ARBvp1.0\n"
+      "TEMP R0, R1, R2, R3;\n"      
+      "DP4   result.position.x, state.matrix.mvp.row[0], vertex.position;\n"
+      "DP4   result.position.y, state.matrix.mvp.row[1], vertex.position;\n"
+      "DP4   result.position.z, state.matrix.mvp.row[2], vertex.position;\n"
+      "DP4   result.position.w, state.matrix.mvp.row[3], vertex.position;\n"
+      "DP3   R0.x, state.matrix.modelview.inverse.row[0], vertex.normal;\n"
+      "DP3   R0.y, state.matrix.modelview.inverse.row[1], vertex.normal;\n"
+      "DP3   R0.z, state.matrix.modelview.inverse.row[2], vertex.normal;\n" 
+      "DP3   R1.x, program.env[32], R0;               # R1.x = Lpos DOT n'\n"
+      "DP3   R1.y, program.env[33], R0;               # R1.y = hHat DOT n'\n"
+      "MOV   R1.w, program.local[38].x;               # R1.w = specular power\n"
+      "LIT   R2, R1;                                  # Compute lighting values\n"
+      "MAD   R3, program.env[35].x, R2.y, program.env[35].y;       # diffuse + emissive\n"
+      "MAD   result.color.primary.xyz, program.env[36], R2.z, R3;  # + specular\n"
+      "END\n";
+   static const char *prog4 = 
+      "!!ARBvp1.0\n"
+      "TEMP R2, R3\n"
+      "DP4   R2, R3, program.local[A0.x];\n"
+#if 0
+      "DP4   R2, R3, program.local[A0.x + 5];\n"
+      "DP4   result.position, R3, program.local[A0.x - 4];\n"
+#else
+      "END\n";
+#endif
+
+   glGenProgramsNV(4, prognum);
+
+   load_program(prog1, prognum[0]);   
+   load_program(prog2, prognum[1]);   
+   load_program(prog3, prognum[2]);   
+   
+   /*
+    * XXX: Don't have relative offsets working yet 
+   load_program(prog4, prognum[3]);   
+   */
+}
+
+
+int main( int argc, char *argv[] )
+{
+   glutInit( &argc, argv );
+   glutInitWindowPosition( 0, 0 );
+   glutInitWindowSize( 250, 250 );
+   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+   glutCreateWindow(argv[0]);
+   glutReshapeFunc( Reshape );
+   glutKeyboardFunc( Key );
+   glutDisplayFunc( Display );
+   Init();
+   glutMainLoop();
+   return 0;
+}
diff --git a/progs/tests/arbvptest3.c b/progs/tests/arbvptest3.c
new file mode 100644 (file)
index 0000000..a3e6aab
--- /dev/null
@@ -0,0 +1,128 @@
+/* Test glGenProgramsNV(), glIsProgramNV(), glLoadProgramNV() */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Zrot = 0.0;
+
+
+static void Display( void )
+{
+   glClearColor(0.3, 0.3, 0.3, 1);
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   glEnable(GL_VERTEX_PROGRAM_NV);
+
+   glLoadIdentity();
+   glRotatef(Zrot, 0, 0, 1);
+
+   glPushMatrix();
+
+   glVertexAttrib3fARB(3, 1, 0.5, 0.25);
+   glBegin(GL_TRIANGLES);
+#if 1
+   glVertexAttrib3fARB(3, 1.0, 0.0, 0.0);
+   glVertexAttrib2fARB(0, -0.5, -0.5);
+   glVertexAttrib3fARB(3, 0.0, 1.0, 0.0);
+   glVertexAttrib2fARB(0, 0.5, -0.5);
+   glVertexAttrib3fARB(3, 0.0, 0.0, 1.0);
+   glVertexAttrib2fARB(0, 0,  0.5);
+#else
+   glVertex2f( -1, -1);
+   glVertex2f( 1, -1);
+   glVertex2f( 0,  1);
+#endif
+   glEnd();
+
+   glPopMatrix();
+
+   glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+   glViewport( 0, 0, width, height );
+   glMatrixMode( GL_PROJECTION );
+   glLoadIdentity();
+   /*   glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
+   glOrtho(-2.0, 2.0, -2.0, 2.0, -2.0, 2.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 'z':
+         Zrot -= 5.0;
+         break;
+      case 'Z':
+         Zrot += 5.0;
+         break;
+      case 27:
+         exit(0);
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+   GLint errno;
+   GLuint prognum;
+   
+   static const char *prog1 =
+      "!!ARBvp1.0\n"
+      "MOV  result.color, vertex.color;\n"
+
+      "DP4  result.position.x, vertex.position, state.matrix.modelview.row[0];\n"
+      "DP4  result.position.y, vertex.position, state.matrix.modelview.row[1];\n"
+      "DP4  result.position.z, vertex.position, state.matrix.modelview.row[2];\n"
+      "DP4  result.position.w, vertex.position, state.matrix.modelview.row[3];\n"
+      "END\n";
+
+   glGenProgramsARB(1, &prognum);
+
+   glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+   glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+                        strlen(prog1), (const GLubyte *) prog1);
+
+   assert(glIsProgramARB(prognum));
+   errno = glGetError();
+   printf("glGetError = %d\n", errno);
+   if (errno != GL_NO_ERROR)
+   {
+      GLint errorpos;
+
+      glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+      printf("errorpos: %d\n", errorpos);
+      printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+   }
+}
+
+
+int main( int argc, char *argv[] )
+{
+   glutInit( &argc, argv );
+   glutInitWindowPosition( 0, 0 );
+   glutInitWindowSize( 250, 250 );
+   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+   glutCreateWindow(argv[0]);
+   glutReshapeFunc( Reshape );
+   glutKeyboardFunc( Key );
+   glutDisplayFunc( Display );
+   Init();
+   glutMainLoop();
+   return 0;
+}
diff --git a/progs/tests/arbvptorus.c b/progs/tests/arbvptorus.c
new file mode 100644 (file)
index 0000000..29fd461
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * A lit, rotating torus via vertex program
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+
+
+static void Idle( void )
+{
+   Xrot += .3;
+   Yrot += .4;
+   Zrot += .2;
+   glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   glPushMatrix();
+      glRotatef(Xrot, 1, 0, 0);
+      glRotatef(Yrot, 0, 1, 0);
+      glRotatef(Zrot, 0, 0, 1);
+      glutSolidTorus(0.75, 2.0, 10, 20);
+   glPopMatrix();
+
+   glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+   glViewport( 0, 0, width, height );
+   glMatrixMode( GL_PROJECTION );
+   glLoadIdentity();
+   glFrustum( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );
+   glMatrixMode( GL_MODELVIEW );
+   glLoadIdentity();
+   glTranslatef( 0.0, 0.0, -12.0 );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+      case ' ':
+         Xrot = Yrot = Zrot = 0;
+         break;
+      case 'a':
+         Anim = !Anim;
+         if (Anim)
+            glutIdleFunc(Idle);
+         else
+            glutIdleFunc(NULL);
+         break;
+      case 'z':
+         Zrot -= 5.0;
+         break;
+      case 'Z':
+         Zrot += 5.0;
+         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 )
+{
+   GLint errno;
+   GLuint prognum;
+       
+   /* borrowed from an nvidia demo:
+    * c[0..3] = modelview matrix
+    * c[4..7] = inverse modelview matrix
+    * c[32] = light pos
+    * c[35] = diffuse color
+    */
+   static const char prog[] = 
+      "!!ARBvp1.0\n"
+      "TEMP R0, R1; \n"
+      "#Simple transform and diffuse lighting\n"
+      "# object x MVP -> clip\n"
+      "DP4   result.position.x, state.matrix.mvp.row[0], vertex.position ;\n"
+      "DP4   result.position.y, state.matrix.mvp.row[1], vertex.position ;\n"
+      "DP4   result.position.z, state.matrix.mvp.row[2], vertex.position ;\n"
+      "DP4   result.position.w, state.matrix.mvp.row[3], vertex.position ;\n"
+
+      "# normal x MV-1T -> lighting normal\n"          
+      "DP3   R1.x, state.matrix.modelview.inverse.row[0], vertex.normal ;\n"
+      "DP3   R1.y, state.matrix.modelview.inverse.row[1], vertex.normal;\n"
+      "DP3   R1.z, state.matrix.modelview.inverse.row[2], vertex.normal;\n"
+
+      "DP3   R0, program.local[32], R1;                  # L.N\n"
+#if 0
+      "MUL   result.color.xyz, R0, program.local[35] ;   # col = L.N * diffuse\n"
+#else
+      "MUL   result.color.primary.xyz, R0, program.local[35] ;   # col = L.N * diffuse\n"
+#endif
+      "MOV   result.texcoord, vertex.texcoord;\n"
+      "END";
+
+   if (!glutExtensionSupported("GL_ARB_vertex_program")) {
+      printf("Sorry, this program requires GL_ARB_vertex_program");
+      exit(1);
+   }
+
+       
+   glGenProgramsARB(1, &prognum);
+
+   glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+   glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+                        strlen(prog), (const GLubyte *) prog);
+
+   assert(glIsProgramARB(prognum));
+   errno = glGetError();
+   printf("glGetError = %d\n", errno);
+   if (errno != GL_NO_ERROR)
+   {
+      GLint errorpos;
+
+      glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+      printf("errorpos: %d\n", errorpos);
+      printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+   }
+
+   /* Light position */
+   glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 32, 2, 2, 4, 1);
+   /* Diffuse material color */
+   glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 35, 0.25, 0, 0.25, 1);
+
+   glEnable(GL_VERTEX_PROGRAM_ARB);
+   glEnable(GL_DEPTH_TEST);
+   glClearColor(0.3, 0.3, 0.3, 1);
+}
+
+
+int main( int argc, char *argv[] )
+{
+   glutInit( &argc, argv );
+   glutInitWindowPosition( 0, 0 );
+   glutInitWindowSize( 250, 250 );
+   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;
+}
diff --git a/progs/tests/arbvpwarpmesh.c b/progs/tests/arbvpwarpmesh.c
new file mode 100644 (file)
index 0000000..a9e2564
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Warp a triangle mesh with a vertex program.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GL/glut.h>
+
+static float Xrot = -60.0, Yrot = 0.0, Zrot = 0.0;
+static GLboolean Anim = GL_TRUE;
+static GLfloat Phi = 0.0;
+
+
+static void Idle( void )
+{
+   Phi += 0.01;
+   glutPostRedisplay();
+}
+
+
+static void DrawMesh( int rows, int cols )
+{
+   static const GLfloat colorA[3] = { 0, 1, 0 };
+   static const GLfloat colorB[3] = { 0, 0, 1 };
+   const float dx = 2.0 / (cols - 1);
+   const float dy = 2.0 / (rows - 1);
+   float x, y;
+   int i, j;
+
+#if 1
+#define COLOR3FV(c)     glVertexAttrib3fvARB(3, c)
+#define VERTEX2F(x, y)  glVertexAttrib2fARB(0, x, y)
+#else
+#define COLOR3FV(c)     glColor3fv(c)
+#define VERTEX2F(x, y)  glVertex2f(x, y)
+#endif
+
+   y = -1.0;
+   for (i = 0; i < rows - 1; i++) {
+      glBegin(GL_QUAD_STRIP);
+      x = -1.0;
+      for (j = 0; j < cols; j++) {
+         if ((i + j) & 1)
+            COLOR3FV(colorA);
+         else
+            COLOR3FV(colorB);
+         VERTEX2F(x, y);
+         VERTEX2F(x, y + dy);
+         x += dx;
+      }
+      glEnd();
+      y += dy;
+   }
+}
+
+
+static void Display( void )
+{
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   glPushMatrix();
+      glRotatef(Xrot, 1, 0, 0);
+      glRotatef(Yrot, 0, 1, 0);
+      glRotatef(Zrot, 0, 0, 1);
+
+      /* Position the gravity source */
+      {
+         GLfloat x, y, z, r = 0.5;
+         x = r * cos(Phi);
+         y = r * sin(Phi);
+         z = 1.0;
+         glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 30, x, y, z, 1);
+         glDisable(GL_VERTEX_PROGRAM_ARB);
+         glBegin(GL_POINTS);
+         glColor3f(1,1,1);
+         glVertex3f(x, y, z);
+         glEnd();
+      }
+
+      glEnable(GL_VERTEX_PROGRAM_ARB);
+      DrawMesh(8, 8);
+   glPopMatrix();
+
+   glutSwapBuffers();
+}
+
+
+static void Reshape( int width, int height )
+{
+   float ar = (float) width / (float) height;
+   glViewport( 0, 0, width, height );
+   glMatrixMode( GL_PROJECTION );
+   glLoadIdentity();
+   glFrustum( -1.0 * ar, 1.0 * ar, -1.0, 1.0, 5.0, 25.0 );
+   glMatrixMode( GL_MODELVIEW );
+   glLoadIdentity();
+   glTranslatef( 0.0, 0.0, -12.0 );
+   glScalef(2, 2, 2);
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+      case 'a':
+         Anim = !Anim;
+         if (Anim)
+            glutIdleFunc(Idle);
+         else
+            glutIdleFunc(NULL);
+         break;
+      case 'p':
+         Phi += 0.2;
+         break;
+      case 'z':
+         Zrot -= 5.0;
+         break;
+      case 'Z':
+         Zrot += 5.0;
+         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 )
+{
+   GLuint prognum;
+   GLint errno;
+       
+   /*
+    * c[0..3] = modelview matrix
+    * c[4..7] = inverse modelview matrix
+    * c[30] = gravity source location
+    * c[31] = gravity source strength
+    * c[32] = light pos
+    * c[35] = diffuse color
+    */
+   static const char prog[] = 
+      "!!ARBvp1.0\n"
+      "TEMP R1, R2, R3; "
+       
+      "# Compute distance from vertex to gravity source\n"
+      "ADD   R1, program.local[30], -vertex.position; # vector from vertex to gravity\n"
+      "DP3   R2, R1, R1;                              # dot product\n"
+      "RSQ   R2, R2.x;                                # square root = distance\n"
+      "MUL   R2, R2, program.local[31].xxxx;          # scale by the gravity factor\n"
+
+      "# Displace vertex by gravity factor along R1 vector\n"
+      "MAD   R3, R1, R2, vertex.position;\n"
+
+      "# Continue with typical modelview/projection\n"
+      "DP4   result.position.x, state.matrix.mvp.row[0], R3 ;  # object x MVP -> clip\n"
+      "DP4   result.position.y, state.matrix.mvp.row[1], R3 ;\n"
+      "DP4   result.position.z, state.matrix.mvp.row[2], R3 ;\n"
+      "DP4   result.position.w, state.matrix.mvp.row[3], R3 ;\n"
+
+      "MOV   result.color, vertex.color;\n       # copy input color to output color\n"
+
+      "END";
+
+   if (!glutExtensionSupported("GL_ARB_vertex_program")) {
+      printf("Sorry, this program requires GL_ARB_vertex_program\n");
+      exit(1);
+   }
+
+   glGenProgramsARB(1, &prognum);
+   glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prognum);
+   glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+            strlen(prog), (const GLubyte *)prog);
+   errno = glGetError();       
+   printf("glGetError = %d\n", errno);
+
+       if (errno != GL_NO_ERROR) 
+       {
+               GLint errorpos;
+
+               glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorpos);
+               printf("errorpos: %d\n", errorpos);
+               printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB));
+       }
+                         
+   /* Light position */
+   glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 32, 2, 2, 4, 1);
+   /* Diffuse material color */
+   glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 35, 0.25, 0, 0.25, 1);
+
+   /* Gravity strength */
+   glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, 31, .5, 0, 0, 0);
+
+   glEnable(GL_DEPTH_TEST);
+   glClearColor(0.3, 0.3, 0.3, 1);
+   glShadeModel(GL_FLAT);
+   glPointSize(3);
+}
+
+
+int main( int argc, char *argv[] )
+{
+   glutInit( &argc, argv );
+   glutInitWindowPosition( 0, 0 );
+   glutInitWindowSize( 250, 250 );
+   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;
+}