1
2/*
3 * GLUT demonstration of texturing with specular highlights.
4 *
5 * When drawing a lit, textured surface one usually wants the specular
6 * highlight to override the texture colors.  However, OpenGL applies
7 * texturing after lighting so the specular highlight is modulated by
8 * the texture.
9 *
10 * The solution here shown here is a two-pass algorithm:
11 *  1. Draw the textured surface without specular lighting.
12 *  2. Enable blending to add the next pass:
13 *  3. Redraw the surface with a matte white material and only the
14 *     specular components of light sources enabled.
15 *
16 * Brian Paul  February 1997
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <math.h>
22#include "glut_wrap.h"
23
24
25static GLUquadricObj *Quadric;
26static GLuint Sphere;
27static GLfloat LightPos[4] = {10.0, 10.0, 10.0, 1.0};
28static GLfloat Delta = 20.0;
29static GLint Mode = 4;
30
31/*static GLfloat Blue[4] = {0.0, 0.0, 1.0, 1.0};*/
32/*static GLfloat Gray[4] = {0.5, 0.5, 0.5, 1.0};*/
33static GLfloat Black[4] = {0.0, 0.0, 0.0, 1.0};
34static GLfloat White[4] = {1.0, 1.0, 1.0, 1.0};
35
36static GLboolean smooth = 1;
37
38static void
39Idle(void)
40{
41   static double t0 = -1.;
42   double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;;
43   if (t0 < 0.0)
44      t0 = t;
45   dt = t - t0;
46   t0 = t;
47   LightPos[0] += Delta * dt;
48   if (LightPos[0]>15.0 || LightPos[0]<-15.0)
49      Delta = -Delta;
50
51   glutPostRedisplay();
52}
53
54
55static void Display( void )
56{
57   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
58
59   glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
60
61   glPushMatrix();
62   glRotatef(90.0, 1.0, 0.0, 0.0);
63
64   if (Mode==0) {
65      /* Typical method: diffuse + specular + texture */
66      glEnable(GL_TEXTURE_2D);
67      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
68      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
69#ifdef GL_VERSION_1_2
70      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
71#endif
72      glCallList(Sphere);
73   }
74   else if (Mode==1) {
75      /* just specular highlight */
76      glDisable(GL_TEXTURE_2D);
77      glLightfv(GL_LIGHT0, GL_DIFFUSE, Black);  /* disable diffuse */
78      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
79#ifdef GL_VERSION_1_2
80      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
81#endif
82      glCallList(Sphere);
83   }
84   else if (Mode==2) {
85      /* diffuse textured */
86      glEnable(GL_TEXTURE_2D);
87      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
88      glLightfv(GL_LIGHT0, GL_SPECULAR, Black);  /* disable specular */
89#ifdef GL_VERSION_1_2
90      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
91#endif
92      glCallList(Sphere);
93   }
94   else if (Mode==3) {
95      /* 2-pass: diffuse textured then add specular highlight*/
96      glEnable(GL_TEXTURE_2D);
97      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
98      glLightfv(GL_LIGHT0, GL_SPECULAR, Black);  /* disable specular */
99#ifdef GL_VERSION_1_2
100      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
101#endif
102      glCallList(Sphere);
103      /* specular highlight */
104      glDepthFunc(GL_EQUAL);  /* redraw same pixels */
105      glDisable(GL_TEXTURE_2D);
106      glEnable(GL_BLEND);  /* add */
107      glLightfv(GL_LIGHT0, GL_DIFFUSE, Black);  /* disable diffuse */
108      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
109      glCallList(Sphere);
110      glDepthFunc(GL_LESS);
111      glDisable(GL_BLEND);
112   }
113   else if (Mode==4) {
114      /* OpenGL 1.2's separate diffuse and specular color */
115      glEnable(GL_TEXTURE_2D);
116      glLightfv(GL_LIGHT0, GL_DIFFUSE, White);  /* enable diffuse */
117      glLightfv(GL_LIGHT0, GL_SPECULAR, White);  /* enable specular */
118#ifdef GL_VERSION_1_2
119      glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
120#endif
121      glCallList(Sphere);
122   }
123
124   glPopMatrix();
125
126   glutSwapBuffers();
127}
128
129
130static void Reshape( int width, int height )
131{
132   glViewport( 0, 0, width, height );
133   glMatrixMode( GL_PROJECTION );
134   glLoadIdentity();
135   glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
136   glMatrixMode( GL_MODELVIEW );
137   glLoadIdentity();
138   glTranslatef( 0.0, 0.0, -12.0 );
139}
140
141
142static void Key( unsigned char key, int x, int y )
143{
144   (void) x;
145   (void) y;
146   switch (key) {
147   case 27:
148      exit(0);
149      break;
150   case 's':
151      smooth = !smooth;
152      if (smooth)
153         glShadeModel(GL_SMOOTH);
154      else
155         glShadeModel(GL_FLAT);
156      break;
157   }
158   glutPostRedisplay();
159}
160
161
162static void SpecialKey( int key, int x, int y )
163{
164   (void) x;
165   (void) y;
166   switch (key) {
167      case GLUT_KEY_UP:
168         break;
169      case GLUT_KEY_DOWN:
170         break;
171   }
172   glutPostRedisplay();
173}
174
175
176static void Init( void )
177{
178   int i, j;
179   GLubyte texImage[64][64][3];
180
181   glEnable(GL_LIGHTING);
182   glEnable(GL_LIGHT0);
183   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
184   glLightModelfv(GL_LIGHT_MODEL_AMBIENT, Black);
185
186   glShadeModel(GL_SMOOTH);
187
188   glMaterialfv(GL_FRONT, GL_DIFFUSE, White);
189   glMaterialfv(GL_FRONT, GL_SPECULAR, White);
190   glMaterialf(GL_FRONT, GL_SHININESS, 20.0);
191
192   /* Actually, these are set again later */
193   glLightfv(GL_LIGHT0, GL_DIFFUSE, White);
194   glLightfv(GL_LIGHT0, GL_SPECULAR, White);
195
196   Quadric = gluNewQuadric();
197   gluQuadricTexture( Quadric, GL_TRUE );
198
199   Sphere= glGenLists(1);
200   glNewList( Sphere, GL_COMPILE );
201   gluSphere( Quadric, 1.0, 24, 24 );
202   glEndList();
203
204   glEnable(GL_DEPTH_TEST);
205   glEnable(GL_CULL_FACE);
206
207   for (i=0;i<64;i++) {
208      for (j=0;j<64;j++) {
209         int k = ((i>>3)&1) ^ ((j>>3)&1);
210         texImage[i][j][0] = 255*k;
211         texImage[i][j][1] = 255*(1-k);
212         texImage[i][j][2] = 0;
213      }
214   }
215
216   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
217   glTexImage2D( GL_TEXTURE_2D,
218                 0,
219                 3,
220                 64, 64,
221                 0,
222                 GL_RGB, GL_UNSIGNED_BYTE,
223                 texImage );
224   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
225   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
226   glEnable(GL_TEXTURE_2D);
227
228   glBlendFunc(GL_ONE, GL_ONE);
229}
230
231
232static void ModeMenu(int entry)
233{
234   if (entry==99)
235      exit(0);
236   Mode = entry;
237}
238
239
240int main( int argc, char *argv[] )
241{
242   glutInitWindowSize( 300, 300 );
243   glutInit( &argc, argv );
244   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
245   glutCreateWindow( "spectex" );
246
247   Init();
248
249   glutReshapeFunc( Reshape );
250   glutKeyboardFunc( Key );
251   glutSpecialFunc( SpecialKey );
252   glutDisplayFunc( Display );
253   glutIdleFunc( Idle );
254
255   glutCreateMenu( ModeMenu );
256   glutAddMenuEntry("1-pass lighting + texturing", 0);
257   glutAddMenuEntry("specular lighting", 1);
258   glutAddMenuEntry("diffuse lighting + texturing", 2);
259   glutAddMenuEntry("2-pass lighting + texturing", 3);
260#ifdef GL_VERSION_1_2
261   glutAddMenuEntry("OpenGL 1.2 separate specular", 4);
262#endif
263   glutAddMenuEntry("Quit", 99);
264   glutAttachMenu(GLUT_RIGHT_BUTTON);
265
266   glutMainLoop();
267   return 0;
268}
269