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.
26 #include "glut_wrap.h"
29 #include "trackball.h"
32 #define SPECULAR_TEXTURE_FILE DEMOS_DATA_DIR "reflect.rgb"
33 #define BASE_TEXTURE_FILE DEMOS_DATA_DIR "tile.rgb"
36 #define DO_SPEC_TEXTURE 1
45 static GLint WinWidth
= 500, WinHeight
= 500;
46 static GLuint CylinderObj
= 0;
47 static GLuint TeapotObj
= 0;
48 static GLuint Object
= 0;
49 static GLboolean Animate
= GL_TRUE
;
51 static float CurQuat
[4] = { 0, 0, 0, 1 };
53 static GLfloat Black
[4] = { 0, 0, 0, 0 };
54 static GLfloat White
[4] = { 1, 1, 1, 1 };
55 static GLfloat Diffuse
[4] = { .3, .3, 1.0, 1.0 }; /* blue */
56 static GLfloat Shininess
= 6;
58 static GLuint BaseTexture
, SpecularTexture
;
59 static GLboolean DoSpecTexture
= GL_TRUE
;
61 static GLboolean ButtonDown
= GL_FALSE
;
62 static GLint ButtonX
, ButtonY
;
65 /* performance info */
67 static GLint Frames
= 0;
70 static void Idle( void )
72 static const float yAxis
[3] = {0, 1, 0};
73 static double t0
= -1.;
75 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
81 axis_to_quat(yAxis
, 2.0 * dt
, quat
);
82 add_quats(quat
, CurQuat
, CurQuat
);
88 static void Display( void )
92 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
95 build_rotmatrix(rot
, CurQuat
);
96 glMultMatrixf(&rot
[0][0]);
98 /* First pass: diffuse lighting with base texture */
99 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Diffuse
);
100 glMaterialfv(GL_FRONT
, GL_SPECULAR
, Black
);
101 glEnable(GL_TEXTURE_2D
);
102 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
105 /* Second pass: specular lighting with reflection texture */
106 glEnable(GL_POLYGON_OFFSET_FILL
);
107 glBlendFunc(GL_ONE
, GL_ONE
); /* add */
109 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Black
);
110 glMaterialfv(GL_FRONT
, GL_SPECULAR
, White
);
112 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
113 glEnable(GL_TEXTURE_GEN_S
);
114 glEnable(GL_TEXTURE_GEN_T
);
117 glDisable(GL_TEXTURE_2D
);
120 glDisable(GL_TEXTURE_GEN_S
);
121 glDisable(GL_TEXTURE_GEN_T
);
123 glDisable(GL_POLYGON_OFFSET_FILL
);
130 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
132 if (t
- T0
>= 5000) {
133 GLfloat seconds
= (t
- T0
) / 1000.0;
134 GLfloat fps
= Frames
/ seconds
;
135 printf("%d frames in %g seconds = %g FPS\n", Frames
, seconds
, fps
);
144 static void Reshape( int width
, int height
)
147 GLfloat w
= h
* width
/ height
;
150 glViewport( 0, 0, width
, height
);
151 glMatrixMode( GL_PROJECTION
);
153 glFrustum( -w
, w
, -h
, h
, 150.0, 500.0 );
154 glMatrixMode( GL_MODELVIEW
);
156 glTranslatef( 0.0, 0.0, -380.0 );
160 static void ToggleAnimate(void)
164 glutIdleFunc( Idle
);
165 T0
= glutGet(GLUT_ELAPSED_TIME
);
169 glutIdleFunc( NULL
);
174 static void ModeMenu(int entry
)
176 if (entry
==ANIMATE
) {
179 else if (entry
==DO_SPEC_TEXTURE
) {
180 DoSpecTexture
= !DoSpecTexture
;
182 else if (entry
==OBJECT
) {
183 if (Object
== TeapotObj
)
184 Object
= CylinderObj
;
188 else if (entry
==QUIT
) {
195 static void Key( unsigned char key
, int x
, int y
)
204 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
205 printf("Shininess = %g\n", Shininess
);
209 if (Shininess
> 128.0)
211 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
212 printf("Shininess = %g\n", Shininess
);
222 glutDestroyWindow(Win
);
231 MouseMotion(int x
, int y
)
234 float x0
= (2.0 * ButtonX
- WinWidth
) / WinWidth
;
235 float y0
= (WinHeight
- 2.0 * ButtonY
) / WinHeight
;
236 float x1
= (2.0 * x
- WinWidth
) / WinWidth
;
237 float y1
= (WinHeight
- 2.0 * y
) / WinHeight
;
240 trackball(q
, x0
, y0
, x1
, y1
);
243 add_quats(q
, CurQuat
, CurQuat
);
251 MouseButton(int button
, int state
, int x
, int y
)
253 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
254 ButtonDown
= GL_TRUE
;
258 else if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
259 ButtonDown
= GL_FALSE
;
264 static void Init( int argc
, char *argv
[] )
266 GLboolean convolve
= GL_FALSE
;
267 GLboolean fullscreen
= GL_FALSE
;
270 for (i
= 1; i
< argc
; i
++) {
271 if (strcmp(argv
[i
], "-info")==0) {
272 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
273 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
274 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
275 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
277 else if (strcmp(argv
[i
], "-c")==0) {
280 else if (strcmp(argv
[i
], "-f")==0) {
281 fullscreen
= GL_TRUE
;
285 if (convolve
&& !glutExtensionSupported("GL_ARB_imaging")) {
287 "GL_ARB_imaging is not supported, disabling convolution.\n");
295 /* Cylinder object */
297 static GLfloat height
= 100.0;
298 static GLfloat radius
= 40.0;
299 static GLint slices
= 24; /* pie slices around Z axis */
300 static GLint stacks
= 10; /* subdivisions along length of cylinder */
301 static GLint rings
= 4; /* rings in the end disks */
302 GLUquadricObj
*q
= gluNewQuadric();
304 gluQuadricTexture(q
, GL_TRUE
);
306 CylinderObj
= glGenLists(1);
307 glNewList(CylinderObj
, GL_COMPILE
);
310 glTranslatef(0.0, 0.0, -0.5 * height
);
312 glMatrixMode(GL_TEXTURE
);
314 /*glScalef(8.0, 4.0, 2.0);*/
315 glMatrixMode(GL_MODELVIEW
);
318 gluQuadricNormals(q
, GL_SMOOTH
);
319 gluQuadricTexture(q
, GL_TRUE
);
320 gluCylinder(q
, radius
, radius
, height
, slices
, stacks
);
323 glMatrixMode(GL_TEXTURE
);
325 glScalef(3.0, 3.0, 1.0);
326 glMatrixMode(GL_MODELVIEW
);
328 glTranslatef(0.0, 0.0, height
);
329 gluDisk(q
, 0.0, radius
, slices
, rings
);
332 glTranslatef(0.0, 0.0, -height
);
333 gluQuadricOrientation(q
, GLU_INSIDE
);
334 gluDisk(q
, 0.0, radius
, slices
, rings
);
338 glMatrixMode(GL_TEXTURE
);
340 glMatrixMode(GL_MODELVIEW
);
348 TeapotObj
= glGenLists(1);
349 glNewList(TeapotObj
, GL_COMPILE
);
352 glutSolidTeapot(40.0);
358 /* show cylinder by default */
359 Object
= CylinderObj
;
363 glEnable(GL_LIGHTING
);
365 GLfloat pos
[4] = { 3, 3, 3, 1 };
366 glLightfv(GL_LIGHT0
, GL_AMBIENT
, Black
);
367 glLightfv(GL_LIGHT0
, GL_DIFFUSE
, White
);
368 glLightfv(GL_LIGHT0
, GL_SPECULAR
, White
);
369 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
371 glMaterialfv(GL_FRONT
, GL_AMBIENT
, Black
);
372 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
373 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER
, 1);
377 glGenTextures(1, &BaseTexture
);
378 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
379 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
380 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
381 if (!LoadRGBMipmaps(BASE_TEXTURE_FILE
, GL_RGB
)) {
382 printf("Error: couldn't load texture image file %s\n", BASE_TEXTURE_FILE
);
386 /* Specular texture */
387 glGenTextures(1, &SpecularTexture
);
388 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
389 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
390 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
391 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
392 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
394 /* use convolution to blur the texture to simulate a dull finish
400 GLfloat filter
[FILTER_SIZE
][FILTER_SIZE
][4];
402 for (h
= 0; h
< FILTER_SIZE
; h
++) {
403 for (w
= 0; w
< FILTER_SIZE
; w
++) {
404 const GLfloat k
= 1.0 / (FILTER_SIZE
* FILTER_SIZE
);
412 glEnable(GL_CONVOLUTION_2D
);
413 glConvolutionParameteri(GL_CONVOLUTION_2D
,
414 GL_CONVOLUTION_BORDER_MODE
, GL_CONSTANT_BORDER
);
415 glConvolutionFilter2D(GL_CONVOLUTION_2D
, GL_RGBA
,
416 FILTER_SIZE
, FILTER_SIZE
,
417 GL_RGBA
, GL_FLOAT
, filter
);
419 img
= LoadRGBImage(SPECULAR_TEXTURE_FILE
, &w
, &h
, &format
);
421 printf("Error: couldn't load texture image file %s\n",
422 SPECULAR_TEXTURE_FILE
);
426 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
427 format
, GL_UNSIGNED_BYTE
, img
);
432 if (!LoadRGBMipmaps(SPECULAR_TEXTURE_FILE
, GL_RGB
)) {
433 printf("Error: couldn't load texture image file %s\n",
434 SPECULAR_TEXTURE_FILE
);
440 glEnable(GL_CULL_FACE
);
441 glEnable(GL_TEXTURE_2D
);
442 glEnable(GL_DEPTH_TEST
);
443 glEnable(GL_NORMALIZE
);
445 glPolygonOffset( -1, -1 );
449 int main( int argc
, char *argv
[] )
451 glutInitWindowSize(WinWidth
, WinHeight
);
452 glutInit( &argc
, argv
);
453 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
454 Win
= glutCreateWindow(argv
[0] );
456 glutReshapeFunc( Reshape
);
457 glutKeyboardFunc( Key
);
458 glutDisplayFunc( Display
);
459 glutMotionFunc(MouseMotion
);
460 glutMouseFunc(MouseButton
);
462 glutIdleFunc( Idle
);
464 glutCreateMenu(ModeMenu
);
465 glutAddMenuEntry("Toggle Highlight", DO_SPEC_TEXTURE
);
466 glutAddMenuEntry("Toggle Object", OBJECT
);
467 glutAddMenuEntry("Toggle Animate", ANIMATE
);
468 glutAddMenuEntry("Quit", QUIT
);
469 glutAttachMenu(GLUT_RIGHT_BUTTON
);