132001f49Smrg
232001f49Smrg/*
332001f49Smrg * GLUT demonstration of texturing with specular highlights.
432001f49Smrg *
532001f49Smrg * When drawing a lit, textured surface one usually wants the specular
632001f49Smrg * highlight to override the texture colors.  However, OpenGL applies
732001f49Smrg * texturing after lighting so the specular highlight is modulated by
832001f49Smrg * the texture.
932001f49Smrg *
1032001f49Smrg * The solution here shown here is a two-pass algorithm:
1132001f49Smrg *  1. Draw the textured surface without specular lighting.
1232001f49Smrg *  2. Enable blending to add the next pass:
1332001f49Smrg *  3. Redraw the surface with a matte white material and only the
1432001f49Smrg *     specular components of light sources enabled.
1532001f49Smrg *
1632001f49Smrg * Brian Paul  February 1997
1732001f49Smrg */
1832001f49Smrg
1932001f49Smrg#include <stdio.h>
2032001f49Smrg#include <stdlib.h>
2132001f49Smrg#include <math.h>
2232001f49Smrg#include "glut_wrap.h"
2332001f49Smrg
2432001f49Smrg
2532001f49Smrgstatic GLUquadricObj *Quadric;
2632001f49Smrgstatic GLuint Sphere;
2732001f49Smrgstatic GLfloat LightPos[4] = {10.0, 10.0, 10.0, 1.0};
2832001f49Smrgstatic GLfloat Delta = 20.0;
2932001f49Smrgstatic GLint Mode = 4;
3032001f49Smrg
3132001f49Smrg/*static GLfloat Blue[4] = {0.0, 0.0, 1.0, 1.0};*/
3232001f49Smrg/*static GLfloat Gray[4] = {0.5, 0.5, 0.5, 1.0};*/
3332001f49Smrgstatic GLfloat Black[4] = {0.0, 0.0, 0.0, 1.0};
3432001f49Smrgstatic GLfloat White[4] = {1.0, 1.0, 1.0, 1.0};
3532001f49Smrg
3632001f49Smrgstatic GLboolean smooth = 1;
3732001f49Smrg
3832001f49Smrgstatic void
3932001f49SmrgIdle(void)
4032001f49Smrg{
4132001f49Smrg   static double t0 = -1.;
4232001f49Smrg   double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;;
4332001f49Smrg   if (t0 < 0.0)
4432001f49Smrg      t0 = t;
4532001f49Smrg   dt = t - t0;
4632001f49Smrg   t0 = t;
4732001f49Smrg   LightPos[0] += Delta * dt;
4832001f49Smrg   if (LightPos[0]>15.0 || LightPos[0]<-15.0)
4932001f49Smrg      Delta = -Delta;
5032001f49Smrg
5132001f49Smrg   glutPostRedisplay();
5232001f49Smrg}
5332001f49Smrg
5432001f49Smrg
5532001f49Smrgstatic void Display( void )
5632001f49Smrg{
5732001f49Smrg   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
5832001f49Smrg
5932001f49Smrg   glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
6032001f49Smrg
6132001f49Smrg   glPushMatrix();
6232001f49Smrg   glRotatef(90.0, 1.0, 0.0, 0.0);
6332001f49Smrg
6432001f49Smrg   if (Mode==0) {
6532001f49Smrg      /* Typical method: diffuse + specular + texture */
6632001f49Smrg      glEnable(GL_TEXTURE_2D);
6732001f49Smrg      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
6832001f49Smrg      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
6932001f49Smrg#ifdef GL_VERSION_1_2
7032001f49Smrg      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
7132001f49Smrg#endif
7232001f49Smrg      glCallList(Sphere);
7332001f49Smrg   }
7432001f49Smrg   else if (Mode==1) {
7532001f49Smrg      /* just specular highlight */
7632001f49Smrg      glDisable(GL_TEXTURE_2D);
7732001f49Smrg      glLightfv(GL_LIGHT0, GL_DIFFUSE, Black);  /* disable diffuse */
7832001f49Smrg      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
7932001f49Smrg#ifdef GL_VERSION_1_2
8032001f49Smrg      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
8132001f49Smrg#endif
8232001f49Smrg      glCallList(Sphere);
8332001f49Smrg   }
8432001f49Smrg   else if (Mode==2) {
8532001f49Smrg      /* diffuse textured */
8632001f49Smrg      glEnable(GL_TEXTURE_2D);
8732001f49Smrg      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
8832001f49Smrg      glLightfv(GL_LIGHT0, GL_SPECULAR, Black);  /* disable specular */
8932001f49Smrg#ifdef GL_VERSION_1_2
9032001f49Smrg      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
9132001f49Smrg#endif
9232001f49Smrg      glCallList(Sphere);
9332001f49Smrg   }
9432001f49Smrg   else if (Mode==3) {
9532001f49Smrg      /* 2-pass: diffuse textured then add specular highlight*/
9632001f49Smrg      glEnable(GL_TEXTURE_2D);
9732001f49Smrg      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
9832001f49Smrg      glLightfv(GL_LIGHT0, GL_SPECULAR, Black);  /* disable specular */
9932001f49Smrg#ifdef GL_VERSION_1_2
10032001f49Smrg      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
10132001f49Smrg#endif
10232001f49Smrg      glCallList(Sphere);
10332001f49Smrg      /* specular highlight */
10432001f49Smrg      glDepthFunc(GL_EQUAL);  /* redraw same pixels */
10532001f49Smrg      glDisable(GL_TEXTURE_2D);
10632001f49Smrg      glEnable(GL_BLEND);  /* add */
10732001f49Smrg      glLightfv(GL_LIGHT0, GL_DIFFUSE, Black);  /* disable diffuse */
10832001f49Smrg      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
10932001f49Smrg      glCallList(Sphere);
11032001f49Smrg      glDepthFunc(GL_LESS);
11132001f49Smrg      glDisable(GL_BLEND);
11232001f49Smrg   }
11332001f49Smrg   else if (Mode==4) {
11432001f49Smrg      /* OpenGL 1.2's separate diffuse and specular color */
11532001f49Smrg      glEnable(GL_TEXTURE_2D);
11632001f49Smrg      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
11732001f49Smrg      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
11832001f49Smrg#ifdef GL_VERSION_1_2
11932001f49Smrg      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
12032001f49Smrg#endif
12132001f49Smrg      glCallList(Sphere);
12232001f49Smrg   }
12332001f49Smrg
12432001f49Smrg   glPopMatrix();
12532001f49Smrg
12632001f49Smrg   glutSwapBuffers();
12732001f49Smrg}
12832001f49Smrg
12932001f49Smrg
13032001f49Smrgstatic void Reshape( int width, int height )
13132001f49Smrg{
13232001f49Smrg   glViewport( 0, 0, width, height );
13332001f49Smrg   glMatrixMode( GL_PROJECTION );
13432001f49Smrg   glLoadIdentity();
13532001f49Smrg   glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
13632001f49Smrg   glMatrixMode( GL_MODELVIEW );
13732001f49Smrg   glLoadIdentity();
13832001f49Smrg   glTranslatef( 0.0, 0.0, -12.0 );
13932001f49Smrg}
14032001f49Smrg
14132001f49Smrg
14232001f49Smrgstatic void Key( unsigned char key, int x, int y )
14332001f49Smrg{
14432001f49Smrg   (void) x;
14532001f49Smrg   (void) y;
14632001f49Smrg   switch (key) {
14732001f49Smrg   case 27:
14832001f49Smrg      exit(0);
14932001f49Smrg      break;
15032001f49Smrg   case 's':
15132001f49Smrg      smooth = !smooth;
15232001f49Smrg      if (smooth)
15332001f49Smrg         glShadeModel(GL_SMOOTH);
15432001f49Smrg      else
15532001f49Smrg         glShadeModel(GL_FLAT);
15632001f49Smrg      break;
15732001f49Smrg   }
15832001f49Smrg   glutPostRedisplay();
15932001f49Smrg}
16032001f49Smrg
16132001f49Smrg
16232001f49Smrgstatic void SpecialKey( int key, int x, int y )
16332001f49Smrg{
16432001f49Smrg   (void) x;
16532001f49Smrg   (void) y;
16632001f49Smrg   switch (key) {
16732001f49Smrg      case GLUT_KEY_UP:
16832001f49Smrg         break;
16932001f49Smrg      case GLUT_KEY_DOWN:
17032001f49Smrg         break;
17132001f49Smrg   }
17232001f49Smrg   glutPostRedisplay();
17332001f49Smrg}
17432001f49Smrg
17532001f49Smrg
17632001f49Smrgstatic void Init( void )
17732001f49Smrg{
17832001f49Smrg   int i, j;
17932001f49Smrg   GLubyte texImage[64][64][3];
18032001f49Smrg
18132001f49Smrg   glEnable(GL_LIGHTING);
18232001f49Smrg   glEnable(GL_LIGHT0);
18332001f49Smrg   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
18432001f49Smrg   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Black);
18532001f49Smrg
18632001f49Smrg   glShadeModel(GL_SMOOTH);
18732001f49Smrg
18832001f49Smrg   glMaterialfv(GL_FRONT, GL_DIFFUSE, White);
18932001f49Smrg   glMaterialfv(GL_FRONT, GL_SPECULAR, White);
19032001f49Smrg   glMaterialf(GL_FRONT, GL_SHININESS, 20.0);
19132001f49Smrg
19232001f49Smrg   /* Actually, these are set again later */
19332001f49Smrg   glLightfv(GL_LIGHT0, GL_DIFFUSE, White);
19432001f49Smrg   glLightfv(GL_LIGHT0, GL_SPECULAR, White);
19532001f49Smrg
19632001f49Smrg   Quadric = gluNewQuadric();
19732001f49Smrg   gluQuadricTexture( Quadric, GL_TRUE );
19832001f49Smrg
19932001f49Smrg   Sphere= glGenLists(1);
20032001f49Smrg   glNewList( Sphere, GL_COMPILE );
20132001f49Smrg   gluSphere( Quadric, 1.0, 24, 24 );
20232001f49Smrg   glEndList();
20332001f49Smrg
20432001f49Smrg   glEnable(GL_DEPTH_TEST);
20532001f49Smrg   glEnable(GL_CULL_FACE);
20632001f49Smrg
20732001f49Smrg   for (i=0;i<64;i++) {
20832001f49Smrg      for (j=0;j<64;j++) {
20932001f49Smrg         int k = ((i>>3)&1) ^ ((j>>3)&1);
21032001f49Smrg         texImage[i][j][0] = 255*k;
21132001f49Smrg         texImage[i][j][1] = 255*(1-k);
21232001f49Smrg         texImage[i][j][2] = 0;
21332001f49Smrg      }
21432001f49Smrg   }
21532001f49Smrg
21632001f49Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
21732001f49Smrg   glTexImage2D( GL_TEXTURE_2D,
21832001f49Smrg                 0,
21932001f49Smrg                 3,
22032001f49Smrg                 64, 64,
22132001f49Smrg                 0,
22232001f49Smrg                 GL_RGB, GL_UNSIGNED_BYTE,
22332001f49Smrg                 texImage );
22432001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
22532001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
22632001f49Smrg   glEnable(GL_TEXTURE_2D);
22732001f49Smrg
22832001f49Smrg   glBlendFunc(GL_ONE, GL_ONE);
22932001f49Smrg}
23032001f49Smrg
23132001f49Smrg
23232001f49Smrgstatic void ModeMenu(int entry)
23332001f49Smrg{
23432001f49Smrg   if (entry==99)
23532001f49Smrg      exit(0);
23632001f49Smrg   Mode = entry;
23732001f49Smrg}
23832001f49Smrg
23932001f49Smrg
24032001f49Smrgint main( int argc, char *argv[] )
24132001f49Smrg{
24232001f49Smrg   glutInitWindowSize( 300, 300 );
24332001f49Smrg   glutInit( &argc, argv );
24432001f49Smrg   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
24532001f49Smrg   glutCreateWindow( "spectex" );
24632001f49Smrg
24732001f49Smrg   Init();
24832001f49Smrg
24932001f49Smrg   glutReshapeFunc( Reshape );
25032001f49Smrg   glutKeyboardFunc( Key );
25132001f49Smrg   glutSpecialFunc( SpecialKey );
25232001f49Smrg   glutDisplayFunc( Display );
25332001f49Smrg   glutIdleFunc( Idle );
25432001f49Smrg
25532001f49Smrg   glutCreateMenu( ModeMenu );
25632001f49Smrg   glutAddMenuEntry("1-pass lighting + texturing", 0);
25732001f49Smrg   glutAddMenuEntry("specular lighting", 1);
25832001f49Smrg   glutAddMenuEntry("diffuse lighting + texturing", 2);
25932001f49Smrg   glutAddMenuEntry("2-pass lighting + texturing", 3);
26032001f49Smrg#ifdef GL_VERSION_1_2
26132001f49Smrg   glutAddMenuEntry("OpenGL 1.2 separate specular", 4);
26232001f49Smrg#endif
26332001f49Smrg   glutAddMenuEntry("Quit", 99);
26432001f49Smrg   glutAttachMenu(GLUT_RIGHT_BUTTON);
26532001f49Smrg
26632001f49Smrg   glutMainLoop();
26732001f49Smrg   return 0;
26832001f49Smrg}
269