Initial revision
diff --git a/progs/demos/spectex.c b/progs/demos/spectex.c
new file mode 100644
index 0000000..412f442
--- /dev/null
+++ b/progs/demos/spectex.c
@@ -0,0 +1,277 @@
+/* $Id: spectex.c,v 1.1 1999/08/19 00:55:40 jtg Exp $ */
+
+/*
+ * GLUT demonstration of texturing with specular highlights.
+ *
+ * When drawing a lit, textured surface one usually wants the specular
+ * highlight to override the texture colors.  However, OpenGL applies
+ * texturing after lighting so the specular highlight is modulated by
+ * the texture.
+ *
+ * The solution here shown here is a two-pass algorithm:
+ *  1. Draw the textured surface without specular lighting.
+ *  2. Enable blending to add the next pass:
+ *  3. Redraw the surface with a matte white material and only the
+ *     specular components of light sources enabled.
+ *
+ * Brian Paul  February 1997
+ */
+
+
+/*
+ * $Log: spectex.c,v $
+ * Revision 1.1  1999/08/19 00:55:40  jtg
+ * Initial revision
+ *
+ * Revision 3.2  1999/03/28 18:22:05  brianp
+ * minor clean-up
+ *
+ * Revision 3.1  1998/02/14 18:47:48  brianp
+ * added OpenGL 1.2 separate specular interpolation support
+ *
+ * Revision 3.0  1998/02/14 18:42:29  brianp
+ * initial rev
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+
+
+static GLUquadricObj *Quadric;
+static GLuint Sphere;
+static GLfloat LightPos[4] = {10.0, 10.0, 10.0, 1.0};
+static GLfloat Delta = 1.0;
+static GLint Mode = 0;
+
+/*static GLfloat Blue[4] = {0.0, 0.0, 1.0, 1.0};*/
+/*static GLfloat Gray[4] = {0.5, 0.5, 0.5, 1.0};*/
+static GLfloat Black[4] = {0.0, 0.0, 0.0, 1.0};
+static GLfloat White[4] = {1.0, 1.0, 1.0, 1.0};
+
+
+
+static void Idle( void )
+{
+   LightPos[0] += Delta;
+   if (LightPos[0]>15.0)
+      Delta = -1.0;
+   else if (LightPos[0]<-15.0)
+      Delta = 1.0;
+
+   glutPostRedisplay();
+}
+
+
+static void Display( void )
+{
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
+
+   glPushMatrix();
+   glRotatef(90.0, 1.0, 0.0, 0.0);
+
+   if (Mode==0) {
+      /* Typical method: diffuse + specular + texture */
+      glEnable(GL_TEXTURE_2D);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
+      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
+#ifdef GL_VERSION_1_2
+      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
+#endif
+      glCallList(Sphere);
+   }
+   else if (Mode==1) {
+      /* just specular highlight */
+      glDisable(GL_TEXTURE_2D);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE, Black);  /* disable diffuse */
+      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
+#ifdef GL_VERSION_1_2
+      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
+#endif
+      glCallList(Sphere);
+   }
+   else if (Mode==2) {
+      /* diffuse textured */
+      glEnable(GL_TEXTURE_2D);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
+      glLightfv(GL_LIGHT0, GL_SPECULAR, Black);  /* disable specular */
+#ifdef GL_VERSION_1_2
+      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
+#endif
+      glCallList(Sphere);
+   }
+   else if (Mode==3) {
+      /* 2-pass: diffuse textured then add specular highlight*/
+      glEnable(GL_TEXTURE_2D);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
+      glLightfv(GL_LIGHT0, GL_SPECULAR, Black);  /* disable specular */
+#ifdef GL_VERSION_1_2
+      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
+#endif
+      glCallList(Sphere);
+      /* specular highlight */
+      glDepthFunc(GL_EQUAL);  /* redraw same pixels */
+      glDisable(GL_TEXTURE_2D);
+      glEnable(GL_BLEND);  /* add */
+      glLightfv(GL_LIGHT0, GL_DIFFUSE, Black);  /* disable diffuse */
+      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
+      glCallList(Sphere);
+      glDepthFunc(GL_LESS);
+      glDisable(GL_BLEND);
+   }
+   else if (Mode==4) {
+      /* OpenGL 1.2's separate diffuse and specular color */
+      glEnable(GL_TEXTURE_2D);
+      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
+      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
+#ifdef GL_VERSION_1_2
+      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+#endif
+      glCallList(Sphere);
+   }
+
+   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, -12.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 SpecialKey( int key, int x, int y )
+{
+   (void) x;
+   (void) y;
+   switch (key) {
+      case GLUT_KEY_UP:
+         break;
+      case GLUT_KEY_DOWN:
+         break;
+   }
+   glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+   int i, j;
+   GLubyte texImage[64][64][3];
+
+   glEnable(GL_LIGHTING);
+   glEnable(GL_LIGHT0);
+   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Black);
+
+   glMaterialfv(GL_FRONT, GL_DIFFUSE, White);
+   glMaterialfv(GL_FRONT, GL_SPECULAR, White);
+   glMaterialf(GL_FRONT, GL_SHININESS, 20.0);
+
+   /* Actually, these are set again later */
+   glLightfv(GL_LIGHT0, GL_DIFFUSE, White);
+   glLightfv(GL_LIGHT0, GL_SPECULAR, White);
+
+   Quadric = gluNewQuadric();
+   gluQuadricTexture( Quadric, GL_TRUE );
+
+   Sphere= glGenLists(1);
+   glNewList( Sphere, GL_COMPILE );
+   gluSphere( Quadric, 1.0, 24, 24 );
+   glEndList();
+
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_CULL_FACE);
+
+   for (i=0;i<64;i++) {
+      for (j=0;j<64;j++) {
+         int k = ((i>>3)&1) ^ ((j>>3)&1);
+         texImage[i][j][0] = 255*k;
+         texImage[i][j][1] = 255*(1-k);
+         texImage[i][j][2] = 0;
+      }
+   }
+
+   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+   glTexImage2D( GL_TEXTURE_2D,
+                 0,
+                 3,
+                 64, 64,
+                 0,
+                 GL_RGB, GL_UNSIGNED_BYTE,
+                 texImage );
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   glEnable(GL_TEXTURE_2D);
+
+   glBlendFunc(GL_ONE, GL_ONE);
+}
+
+
+static void ModeMenu(int entry)
+{
+   if (entry==99)
+      exit(0);
+   Mode = entry;
+}
+
+
+int main( int argc, char *argv[] )
+{
+
+   glutInit( &argc, argv );
+   glutInitWindowPosition( 0, 0 );
+   glutInitWindowSize( 300, 300 );
+
+   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+
+   glutCreateWindow( "spectex" );
+
+   Init();
+
+   glutReshapeFunc( Reshape );
+   glutKeyboardFunc( Key );
+   glutSpecialFunc( SpecialKey );
+   glutDisplayFunc( Display );
+   glutIdleFunc( Idle );
+
+   glutCreateMenu( ModeMenu );
+   glutAddMenuEntry("1-pass lighting + texturing", 0);
+   glutAddMenuEntry("specular lighting", 1);
+   glutAddMenuEntry("diffuse lighting + texturing", 2);
+   glutAddMenuEntry("2-pass lighting + texturing", 3);
+#ifdef GL_VERSION_1_2
+   glutAddMenuEntry("OpenGL 1.2 separate specular", 4);
+#endif
+   glutAddMenuEntry("Quit", 99);
+   glutAttachMenu(GLUT_RIGHT_BUTTON);
+
+   glutMainLoop();
+   return 0;
+}