3 * Specular reflection demo. The specular highlight is modulated by
4 * a sphere-mapped texture. The result is a high-gloss surface.
5 * NOTE: you really need hardware acceleration for this.
6 * Also note, this technique can't be implemented with multi-texture
7 * and separate specular color interpolation because there's no way
8 * to indicate that the second texture unit (the reflection map)
9 * should modulate the specular color and not the base color.
10 * A future multi-texture extension could fix that.
12 * Command line options:
13 * -info print GL implementation information
16 * Brian Paul October 22, 1999 This program is in the public domain.
29 #define SPECULAR_TEXTURE_FILE "../images/reflect.rgb"
30 #define BASE_TEXTURE_FILE "../images/tile.rgb"
33 #define DO_SPEC_TEXTURE 1
41 static GLuint CylinderObj
= 0;
42 static GLuint TeapotObj
= 0;
43 static GLuint Object
= 0;
44 static GLboolean Animate
= GL_TRUE
;
46 static GLfloat Xrot
= 0.0, Yrot
= 0.0, Zrot
= 0.0;
47 static GLfloat DXrot
= 20.0, DYrot
= 50.;
49 static GLfloat Black
[4] = { 0, 0, 0, 0 };
50 static GLfloat White
[4] = { 1, 1, 1, 1 };
51 static GLfloat Diffuse
[4] = { .3, .3, 1.0, 1.0 }; /* blue */
52 static GLfloat Shininess
= 6;
54 static GLuint BaseTexture
, SpecularTexture
;
55 static GLboolean DoSpecTexture
= GL_TRUE
;
57 /* performance info */
59 static GLint Frames
= 0;
62 static void Idle( void )
64 static double t0
= -1.;
65 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
79 static void Display( void )
81 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
84 glRotatef(Xrot
, 1.0, 0.0, 0.0);
85 glRotatef(Yrot
, 0.0, 1.0, 0.0);
86 glRotatef(Zrot
, 0.0, 0.0, 1.0);
88 /* First pass: diffuse lighting with base texture */
89 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Diffuse
);
90 glMaterialfv(GL_FRONT
, GL_SPECULAR
, Black
);
91 glEnable(GL_TEXTURE_2D
);
92 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
95 /* Second pass: specular lighting with reflection texture */
96 glEnable(GL_POLYGON_OFFSET_FILL
);
97 glBlendFunc(GL_ONE
, GL_ONE
); /* add */
99 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Black
);
100 glMaterialfv(GL_FRONT
, GL_SPECULAR
, White
);
102 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
103 glEnable(GL_TEXTURE_GEN_S
);
104 glEnable(GL_TEXTURE_GEN_T
);
107 glDisable(GL_TEXTURE_2D
);
110 glDisable(GL_TEXTURE_GEN_S
);
111 glDisable(GL_TEXTURE_GEN_T
);
113 glDisable(GL_POLYGON_OFFSET_FILL
);
120 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
122 if (t
- T0
>= 5000) {
123 GLfloat seconds
= (t
- T0
) / 1000.0;
124 GLfloat fps
= Frames
/ seconds
;
125 printf("%d frames in %g seconds = %g FPS\n", Frames
, seconds
, fps
);
133 static void Reshape( int width
, int height
)
136 GLfloat w
= h
* width
/ height
;
137 glViewport( 0, 0, width
, height
);
138 glMatrixMode( GL_PROJECTION
);
140 glFrustum( -w
, w
, -h
, h
, 150.0, 500.0 );
141 glMatrixMode( GL_MODELVIEW
);
143 glTranslatef( 0.0, 0.0, -380.0 );
147 static void ToggleAnimate(void)
151 glutIdleFunc( Idle
);
152 T0
= glutGet(GLUT_ELAPSED_TIME
);
156 glutIdleFunc( NULL
);
161 static void ModeMenu(int entry
)
163 if (entry
==ANIMATE
) {
166 else if (entry
==DO_SPEC_TEXTURE
) {
167 DoSpecTexture
= !DoSpecTexture
;
169 else if (entry
==OBJECT
) {
170 if (Object
== TeapotObj
)
171 Object
= CylinderObj
;
175 else if (entry
==QUIT
) {
182 static void Key( unsigned char key
, int x
, int y
)
191 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
192 printf("Shininess = %g\n", Shininess
);
196 if (Shininess
> 128.0)
198 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
199 printf("Shininess = %g\n", Shininess
);
212 static void SpecialKey( int key
, int x
, int y
)
236 static void Init( int argc
, char *argv
[] )
238 GLboolean convolve
= GL_FALSE
;
239 GLboolean fullscreen
= GL_FALSE
;
242 for (i
= 1; i
< argc
; i
++) {
243 if (strcmp(argv
[i
], "-info")==0) {
244 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
245 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
246 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
247 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
249 else if (strcmp(argv
[i
], "-c")==0) {
252 else if (strcmp(argv
[i
], "-f")==0) {
253 fullscreen
= GL_TRUE
;
260 /* Cylinder object */
262 static GLfloat height
= 100.0;
263 static GLfloat radius
= 40.0;
264 static GLint slices
= 24; /* pie slices around Z axis */
265 static GLint stacks
= 10; /* subdivisions along length of cylinder */
266 static GLint rings
= 4; /* rings in the end disks */
267 GLUquadricObj
*q
= gluNewQuadric();
269 gluQuadricTexture(q
, GL_TRUE
);
271 CylinderObj
= glGenLists(1);
272 glNewList(CylinderObj
, GL_COMPILE
);
275 glTranslatef(0.0, 0.0, -0.5 * height
);
277 glMatrixMode(GL_TEXTURE
);
279 /*glScalef(8.0, 4.0, 2.0);*/
280 glMatrixMode(GL_MODELVIEW
);
283 gluQuadricNormals(q
, GL_SMOOTH
);
284 gluQuadricTexture(q
, GL_TRUE
);
285 gluCylinder(q
, radius
, radius
, height
, slices
, stacks
);
288 glMatrixMode(GL_TEXTURE
);
290 glScalef(3.0, 3.0, 1.0);
291 glMatrixMode(GL_MODELVIEW
);
293 glTranslatef(0.0, 0.0, height
);
294 gluDisk(q
, 0.0, radius
, slices
, rings
);
297 glTranslatef(0.0, 0.0, -height
);
298 gluQuadricOrientation(q
, GLU_INSIDE
);
299 gluDisk(q
, 0.0, radius
, slices
, rings
);
303 glMatrixMode(GL_TEXTURE
);
305 glMatrixMode(GL_MODELVIEW
);
313 TeapotObj
= glGenLists(1);
314 glNewList(TeapotObj
, GL_COMPILE
);
317 glutSolidTeapot(40.0);
323 /* show cylinder by default */
324 Object
= CylinderObj
;
328 glEnable(GL_LIGHTING
);
330 GLfloat pos
[4] = { 3, 3, 3, 1 };
331 glLightfv(GL_LIGHT0
, GL_AMBIENT
, Black
);
332 glLightfv(GL_LIGHT0
, GL_DIFFUSE
, White
);
333 glLightfv(GL_LIGHT0
, GL_SPECULAR
, White
);
334 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
336 glMaterialfv(GL_FRONT
, GL_AMBIENT
, Black
);
337 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
338 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER
, 1);
342 glGenTextures(1, &BaseTexture
);
343 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
344 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
345 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
346 if (!LoadRGBMipmaps(BASE_TEXTURE_FILE
, GL_RGB
)) {
347 printf("Error: couldn't load texture image file %s\n", BASE_TEXTURE_FILE
);
351 /* Specular texture */
352 glGenTextures(1, &SpecularTexture
);
353 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
354 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
355 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
356 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
357 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
359 /* use convolution to blur the texture to simulate a dull finish
365 GLfloat filter
[FILTER_SIZE
][FILTER_SIZE
][4];
367 for (h
= 0; h
< FILTER_SIZE
; h
++) {
368 for (w
= 0; w
< FILTER_SIZE
; w
++) {
369 const GLfloat k
= 1.0 / (FILTER_SIZE
* FILTER_SIZE
);
377 glEnable(GL_CONVOLUTION_2D
);
378 glConvolutionParameteri(GL_CONVOLUTION_2D
,
379 GL_CONVOLUTION_BORDER_MODE
, GL_CONSTANT_BORDER
);
380 glConvolutionFilter2D(GL_CONVOLUTION_2D
, GL_RGBA
,
381 FILTER_SIZE
, FILTER_SIZE
,
382 GL_RGBA
, GL_FLOAT
, filter
);
384 img
= LoadRGBImage(SPECULAR_TEXTURE_FILE
, &w
, &h
, &format
);
386 printf("Error: couldn't load texture image file %s\n",
387 SPECULAR_TEXTURE_FILE
);
391 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
392 format
, GL_UNSIGNED_BYTE
, img
);
397 if (!LoadRGBMipmaps(SPECULAR_TEXTURE_FILE
, GL_RGB
)) {
398 printf("Error: couldn't load texture image file %s\n",
399 SPECULAR_TEXTURE_FILE
);
405 glEnable(GL_CULL_FACE
);
406 glEnable(GL_TEXTURE_2D
);
407 glEnable(GL_DEPTH_TEST
);
408 glEnable(GL_NORMALIZE
);
410 glPolygonOffset( -1, -1 );
414 int main( int argc
, char *argv
[] )
416 glutInit( &argc
, argv
);
417 glutInitWindowPosition(0, 0);
418 glutInitWindowSize( 500, 500 );
420 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
422 glutCreateWindow(argv
[0] );
426 glutReshapeFunc( Reshape
);
427 glutKeyboardFunc( Key
);
428 glutSpecialFunc( SpecialKey
);
429 glutDisplayFunc( Display
);
431 glutIdleFunc( Idle
);
433 glutCreateMenu(ModeMenu
);
434 glutAddMenuEntry("Toggle Highlight", DO_SPEC_TEXTURE
);
435 glutAddMenuEntry("Toggle Object", OBJECT
);
436 glutAddMenuEntry("Toggle Animate", ANIMATE
);
437 glutAddMenuEntry("Quit", QUIT
);
438 glutAttachMenu(GLUT_RIGHT_BUTTON
);