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.
28 #include "trackball.h"
31 #define SPECULAR_TEXTURE_FILE "../images/reflect.rgb"
32 #define BASE_TEXTURE_FILE "../images/tile.rgb"
35 #define DO_SPEC_TEXTURE 1
43 static GLint WinWidth
= 500, WinHeight
= 500;
44 static GLuint CylinderObj
= 0;
45 static GLuint TeapotObj
= 0;
46 static GLuint Object
= 0;
47 static GLboolean Animate
= GL_TRUE
;
49 static float CurQuat
[4] = { 0, 0, 0, 1 };
51 static GLfloat Black
[4] = { 0, 0, 0, 0 };
52 static GLfloat White
[4] = { 1, 1, 1, 1 };
53 static GLfloat Diffuse
[4] = { .3, .3, 1.0, 1.0 }; /* blue */
54 static GLfloat Shininess
= 6;
56 static GLuint BaseTexture
, SpecularTexture
;
57 static GLboolean DoSpecTexture
= GL_TRUE
;
59 static GLboolean ButtonDown
= GL_FALSE
;
60 static GLint ButtonX
, ButtonY
;
63 /* performance info */
65 static GLint Frames
= 0;
68 static void Idle( void )
70 static const float yAxis
[3] = {0, 1, 0};
71 static double t0
= -1.;
73 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
79 axis_to_quat(yAxis
, 2.0 * dt
, quat
);
80 add_quats(quat
, CurQuat
, CurQuat
);
86 static void Display( void )
90 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
93 build_rotmatrix(rot
, CurQuat
);
94 glMultMatrixf(&rot
[0][0]);
96 /* First pass: diffuse lighting with base texture */
97 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Diffuse
);
98 glMaterialfv(GL_FRONT
, GL_SPECULAR
, Black
);
99 glEnable(GL_TEXTURE_2D
);
100 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
103 /* Second pass: specular lighting with reflection texture */
104 glEnable(GL_POLYGON_OFFSET_FILL
);
105 glBlendFunc(GL_ONE
, GL_ONE
); /* add */
107 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Black
);
108 glMaterialfv(GL_FRONT
, GL_SPECULAR
, White
);
110 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
111 glEnable(GL_TEXTURE_GEN_S
);
112 glEnable(GL_TEXTURE_GEN_T
);
115 glDisable(GL_TEXTURE_2D
);
118 glDisable(GL_TEXTURE_GEN_S
);
119 glDisable(GL_TEXTURE_GEN_T
);
121 glDisable(GL_POLYGON_OFFSET_FILL
);
128 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
130 if (t
- T0
>= 5000) {
131 GLfloat seconds
= (t
- T0
) / 1000.0;
132 GLfloat fps
= Frames
/ seconds
;
133 printf("%d frames in %g seconds = %g FPS\n", Frames
, seconds
, fps
);
141 static void Reshape( int width
, int height
)
144 GLfloat w
= h
* width
/ height
;
147 glViewport( 0, 0, width
, height
);
148 glMatrixMode( GL_PROJECTION
);
150 glFrustum( -w
, w
, -h
, h
, 150.0, 500.0 );
151 glMatrixMode( GL_MODELVIEW
);
153 glTranslatef( 0.0, 0.0, -380.0 );
157 static void ToggleAnimate(void)
161 glutIdleFunc( Idle
);
162 T0
= glutGet(GLUT_ELAPSED_TIME
);
166 glutIdleFunc( NULL
);
171 static void ModeMenu(int entry
)
173 if (entry
==ANIMATE
) {
176 else if (entry
==DO_SPEC_TEXTURE
) {
177 DoSpecTexture
= !DoSpecTexture
;
179 else if (entry
==OBJECT
) {
180 if (Object
== TeapotObj
)
181 Object
= CylinderObj
;
185 else if (entry
==QUIT
) {
192 static void Key( unsigned char key
, int x
, int y
)
201 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
202 printf("Shininess = %g\n", Shininess
);
206 if (Shininess
> 128.0)
208 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
209 printf("Shininess = %g\n", Shininess
);
224 MouseMotion(int x
, int y
)
227 float x0
= (2.0 * ButtonX
- WinWidth
) / WinWidth
;
228 float y0
= (WinHeight
- 2.0 * ButtonY
) / WinHeight
;
229 float x1
= (2.0 * x
- WinWidth
) / WinWidth
;
230 float y1
= (WinHeight
- 2.0 * y
) / WinHeight
;
233 trackball(q
, x0
, y0
, x1
, y1
);
236 add_quats(q
, CurQuat
, CurQuat
);
244 MouseButton(int button
, int state
, int x
, int y
)
246 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
247 ButtonDown
= GL_TRUE
;
251 else if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
252 ButtonDown
= GL_FALSE
;
257 static void Init( int argc
, char *argv
[] )
259 GLboolean convolve
= GL_FALSE
;
260 GLboolean fullscreen
= GL_FALSE
;
263 for (i
= 1; i
< argc
; i
++) {
264 if (strcmp(argv
[i
], "-info")==0) {
265 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
266 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
267 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
268 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
270 else if (strcmp(argv
[i
], "-c")==0) {
273 else if (strcmp(argv
[i
], "-f")==0) {
274 fullscreen
= GL_TRUE
;
281 /* Cylinder object */
283 static GLfloat height
= 100.0;
284 static GLfloat radius
= 40.0;
285 static GLint slices
= 24; /* pie slices around Z axis */
286 static GLint stacks
= 10; /* subdivisions along length of cylinder */
287 static GLint rings
= 4; /* rings in the end disks */
288 GLUquadricObj
*q
= gluNewQuadric();
290 gluQuadricTexture(q
, GL_TRUE
);
292 CylinderObj
= glGenLists(1);
293 glNewList(CylinderObj
, GL_COMPILE
);
296 glTranslatef(0.0, 0.0, -0.5 * height
);
298 glMatrixMode(GL_TEXTURE
);
300 /*glScalef(8.0, 4.0, 2.0);*/
301 glMatrixMode(GL_MODELVIEW
);
304 gluQuadricNormals(q
, GL_SMOOTH
);
305 gluQuadricTexture(q
, GL_TRUE
);
306 gluCylinder(q
, radius
, radius
, height
, slices
, stacks
);
309 glMatrixMode(GL_TEXTURE
);
311 glScalef(3.0, 3.0, 1.0);
312 glMatrixMode(GL_MODELVIEW
);
314 glTranslatef(0.0, 0.0, height
);
315 gluDisk(q
, 0.0, radius
, slices
, rings
);
318 glTranslatef(0.0, 0.0, -height
);
319 gluQuadricOrientation(q
, GLU_INSIDE
);
320 gluDisk(q
, 0.0, radius
, slices
, rings
);
324 glMatrixMode(GL_TEXTURE
);
326 glMatrixMode(GL_MODELVIEW
);
334 TeapotObj
= glGenLists(1);
335 glNewList(TeapotObj
, GL_COMPILE
);
338 glutSolidTeapot(40.0);
344 /* show cylinder by default */
345 Object
= CylinderObj
;
349 glEnable(GL_LIGHTING
);
351 GLfloat pos
[4] = { 3, 3, 3, 1 };
352 glLightfv(GL_LIGHT0
, GL_AMBIENT
, Black
);
353 glLightfv(GL_LIGHT0
, GL_DIFFUSE
, White
);
354 glLightfv(GL_LIGHT0
, GL_SPECULAR
, White
);
355 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
357 glMaterialfv(GL_FRONT
, GL_AMBIENT
, Black
);
358 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
359 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER
, 1);
363 glGenTextures(1, &BaseTexture
);
364 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
365 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
366 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
367 if (!LoadRGBMipmaps(BASE_TEXTURE_FILE
, GL_RGB
)) {
368 printf("Error: couldn't load texture image file %s\n", BASE_TEXTURE_FILE
);
372 /* Specular texture */
373 glGenTextures(1, &SpecularTexture
);
374 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
375 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
376 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
377 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
378 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
380 /* use convolution to blur the texture to simulate a dull finish
386 GLfloat filter
[FILTER_SIZE
][FILTER_SIZE
][4];
388 for (h
= 0; h
< FILTER_SIZE
; h
++) {
389 for (w
= 0; w
< FILTER_SIZE
; w
++) {
390 const GLfloat k
= 1.0 / (FILTER_SIZE
* FILTER_SIZE
);
398 glEnable(GL_CONVOLUTION_2D
);
399 glConvolutionParameteri(GL_CONVOLUTION_2D
,
400 GL_CONVOLUTION_BORDER_MODE
, GL_CONSTANT_BORDER
);
401 glConvolutionFilter2D(GL_CONVOLUTION_2D
, GL_RGBA
,
402 FILTER_SIZE
, FILTER_SIZE
,
403 GL_RGBA
, GL_FLOAT
, filter
);
405 img
= LoadRGBImage(SPECULAR_TEXTURE_FILE
, &w
, &h
, &format
);
407 printf("Error: couldn't load texture image file %s\n",
408 SPECULAR_TEXTURE_FILE
);
412 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
413 format
, GL_UNSIGNED_BYTE
, img
);
418 if (!LoadRGBMipmaps(SPECULAR_TEXTURE_FILE
, GL_RGB
)) {
419 printf("Error: couldn't load texture image file %s\n",
420 SPECULAR_TEXTURE_FILE
);
426 glEnable(GL_CULL_FACE
);
427 glEnable(GL_TEXTURE_2D
);
428 glEnable(GL_DEPTH_TEST
);
429 glEnable(GL_NORMALIZE
);
431 glPolygonOffset( -1, -1 );
435 int main( int argc
, char *argv
[] )
437 glutInit( &argc
, argv
);
438 glutInitWindowSize(WinWidth
, WinHeight
);
439 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
440 glutCreateWindow(argv
[0] );
441 glutReshapeFunc( Reshape
);
442 glutKeyboardFunc( Key
);
443 glutDisplayFunc( Display
);
444 glutMotionFunc(MouseMotion
);
445 glutMouseFunc(MouseButton
);
447 glutIdleFunc( Idle
);
449 glutCreateMenu(ModeMenu
);
450 glutAddMenuEntry("Toggle Highlight", DO_SPEC_TEXTURE
);
451 glutAddMenuEntry("Toggle Object", OBJECT
);
452 glutAddMenuEntry("Toggle Animate", ANIMATE
);
453 glutAddMenuEntry("Quit", QUIT
);
454 glutAttachMenu(GLUT_RIGHT_BUTTON
);