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 #include "trackball.h"
32 #define SPECULAR_TEXTURE_FILE "../images/reflect.rgb"
33 #define BASE_TEXTURE_FILE "../images/tile.rgb"
36 #define DO_SPEC_TEXTURE 1
44 static GLint WinWidth
= 500, WinHeight
= 500;
45 static GLuint CylinderObj
= 0;
46 static GLuint TeapotObj
= 0;
47 static GLuint Object
= 0;
48 static GLboolean Animate
= GL_TRUE
;
50 static float CurQuat
[4] = { 0, 0, 0, 1 };
52 static GLfloat Black
[4] = { 0, 0, 0, 0 };
53 static GLfloat White
[4] = { 1, 1, 1, 1 };
54 static GLfloat Diffuse
[4] = { .3, .3, 1.0, 1.0 }; /* blue */
55 static GLfloat Shininess
= 6;
57 static GLuint BaseTexture
, SpecularTexture
;
58 static GLboolean DoSpecTexture
= GL_TRUE
;
60 static GLboolean ButtonDown
= GL_FALSE
;
61 static GLint ButtonX
, ButtonY
;
64 /* performance info */
66 static GLint Frames
= 0;
69 static void Idle( void )
71 static const float yAxis
[3] = {0, 1, 0};
72 static double t0
= -1.;
74 double dt
, t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
80 axis_to_quat(yAxis
, 2.0 * dt
, quat
);
81 add_quats(quat
, CurQuat
, CurQuat
);
87 static void Display( void )
91 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
94 build_rotmatrix(rot
, CurQuat
);
95 glMultMatrixf(&rot
[0][0]);
97 /* First pass: diffuse lighting with base texture */
98 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Diffuse
);
99 glMaterialfv(GL_FRONT
, GL_SPECULAR
, Black
);
100 glEnable(GL_TEXTURE_2D
);
101 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
104 /* Second pass: specular lighting with reflection texture */
105 glEnable(GL_POLYGON_OFFSET_FILL
);
106 glBlendFunc(GL_ONE
, GL_ONE
); /* add */
108 glMaterialfv(GL_FRONT
, GL_DIFFUSE
, Black
);
109 glMaterialfv(GL_FRONT
, GL_SPECULAR
, White
);
111 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
112 glEnable(GL_TEXTURE_GEN_S
);
113 glEnable(GL_TEXTURE_GEN_T
);
116 glDisable(GL_TEXTURE_2D
);
119 glDisable(GL_TEXTURE_GEN_S
);
120 glDisable(GL_TEXTURE_GEN_T
);
122 glDisable(GL_POLYGON_OFFSET_FILL
);
129 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
131 if (t
- T0
>= 5000) {
132 GLfloat seconds
= (t
- T0
) / 1000.0;
133 GLfloat fps
= Frames
/ seconds
;
134 printf("%d frames in %g seconds = %g FPS\n", Frames
, seconds
, fps
);
143 static void Reshape( int width
, int height
)
146 GLfloat w
= h
* width
/ height
;
149 glViewport( 0, 0, width
, height
);
150 glMatrixMode( GL_PROJECTION
);
152 glFrustum( -w
, w
, -h
, h
, 150.0, 500.0 );
153 glMatrixMode( GL_MODELVIEW
);
155 glTranslatef( 0.0, 0.0, -380.0 );
159 static void ToggleAnimate(void)
163 glutIdleFunc( Idle
);
164 T0
= glutGet(GLUT_ELAPSED_TIME
);
168 glutIdleFunc( NULL
);
173 static void ModeMenu(int entry
)
175 if (entry
==ANIMATE
) {
178 else if (entry
==DO_SPEC_TEXTURE
) {
179 DoSpecTexture
= !DoSpecTexture
;
181 else if (entry
==OBJECT
) {
182 if (Object
== TeapotObj
)
183 Object
= CylinderObj
;
187 else if (entry
==QUIT
) {
194 static void Key( unsigned char key
, int x
, int y
)
203 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
204 printf("Shininess = %g\n", Shininess
);
208 if (Shininess
> 128.0)
210 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
211 printf("Shininess = %g\n", Shininess
);
226 MouseMotion(int x
, int y
)
229 float x0
= (2.0 * ButtonX
- WinWidth
) / WinWidth
;
230 float y0
= (WinHeight
- 2.0 * ButtonY
) / WinHeight
;
231 float x1
= (2.0 * x
- WinWidth
) / WinWidth
;
232 float y1
= (WinHeight
- 2.0 * y
) / WinHeight
;
235 trackball(q
, x0
, y0
, x1
, y1
);
238 add_quats(q
, CurQuat
, CurQuat
);
246 MouseButton(int button
, int state
, int x
, int y
)
248 if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_DOWN
) {
249 ButtonDown
= GL_TRUE
;
253 else if (button
== GLUT_LEFT_BUTTON
&& state
== GLUT_UP
) {
254 ButtonDown
= GL_FALSE
;
259 static void Init( int argc
, char *argv
[] )
261 GLboolean convolve
= GL_FALSE
;
262 GLboolean fullscreen
= GL_FALSE
;
265 for (i
= 1; i
< argc
; i
++) {
266 if (strcmp(argv
[i
], "-info")==0) {
267 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
268 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
269 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
270 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
272 else if (strcmp(argv
[i
], "-c")==0) {
275 else if (strcmp(argv
[i
], "-f")==0) {
276 fullscreen
= GL_TRUE
;
283 /* Cylinder object */
285 static GLfloat height
= 100.0;
286 static GLfloat radius
= 40.0;
287 static GLint slices
= 24; /* pie slices around Z axis */
288 static GLint stacks
= 10; /* subdivisions along length of cylinder */
289 static GLint rings
= 4; /* rings in the end disks */
290 GLUquadricObj
*q
= gluNewQuadric();
292 gluQuadricTexture(q
, GL_TRUE
);
294 CylinderObj
= glGenLists(1);
295 glNewList(CylinderObj
, GL_COMPILE
);
298 glTranslatef(0.0, 0.0, -0.5 * height
);
300 glMatrixMode(GL_TEXTURE
);
302 /*glScalef(8.0, 4.0, 2.0);*/
303 glMatrixMode(GL_MODELVIEW
);
306 gluQuadricNormals(q
, GL_SMOOTH
);
307 gluQuadricTexture(q
, GL_TRUE
);
308 gluCylinder(q
, radius
, radius
, height
, slices
, stacks
);
311 glMatrixMode(GL_TEXTURE
);
313 glScalef(3.0, 3.0, 1.0);
314 glMatrixMode(GL_MODELVIEW
);
316 glTranslatef(0.0, 0.0, height
);
317 gluDisk(q
, 0.0, radius
, slices
, rings
);
320 glTranslatef(0.0, 0.0, -height
);
321 gluQuadricOrientation(q
, GLU_INSIDE
);
322 gluDisk(q
, 0.0, radius
, slices
, rings
);
326 glMatrixMode(GL_TEXTURE
);
328 glMatrixMode(GL_MODELVIEW
);
336 TeapotObj
= glGenLists(1);
337 glNewList(TeapotObj
, GL_COMPILE
);
340 glutSolidTeapot(40.0);
346 /* show cylinder by default */
347 Object
= CylinderObj
;
351 glEnable(GL_LIGHTING
);
353 GLfloat pos
[4] = { 3, 3, 3, 1 };
354 glLightfv(GL_LIGHT0
, GL_AMBIENT
, Black
);
355 glLightfv(GL_LIGHT0
, GL_DIFFUSE
, White
);
356 glLightfv(GL_LIGHT0
, GL_SPECULAR
, White
);
357 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
359 glMaterialfv(GL_FRONT
, GL_AMBIENT
, Black
);
360 glMaterialf(GL_FRONT
, GL_SHININESS
, Shininess
);
361 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER
, 1);
365 glGenTextures(1, &BaseTexture
);
366 glBindTexture(GL_TEXTURE_2D
, BaseTexture
);
367 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
368 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
369 if (!LoadRGBMipmaps(BASE_TEXTURE_FILE
, GL_RGB
)) {
370 printf("Error: couldn't load texture image file %s\n", BASE_TEXTURE_FILE
);
374 /* Specular texture */
375 glGenTextures(1, &SpecularTexture
);
376 glBindTexture(GL_TEXTURE_2D
, SpecularTexture
);
377 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
378 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
379 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
380 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
382 /* use convolution to blur the texture to simulate a dull finish
388 GLfloat filter
[FILTER_SIZE
][FILTER_SIZE
][4];
390 for (h
= 0; h
< FILTER_SIZE
; h
++) {
391 for (w
= 0; w
< FILTER_SIZE
; w
++) {
392 const GLfloat k
= 1.0 / (FILTER_SIZE
* FILTER_SIZE
);
400 glEnable(GL_CONVOLUTION_2D
);
401 glConvolutionParameteri(GL_CONVOLUTION_2D
,
402 GL_CONVOLUTION_BORDER_MODE
, GL_CONSTANT_BORDER
);
403 glConvolutionFilter2D(GL_CONVOLUTION_2D
, GL_RGBA
,
404 FILTER_SIZE
, FILTER_SIZE
,
405 GL_RGBA
, GL_FLOAT
, filter
);
407 img
= LoadRGBImage(SPECULAR_TEXTURE_FILE
, &w
, &h
, &format
);
409 printf("Error: couldn't load texture image file %s\n",
410 SPECULAR_TEXTURE_FILE
);
414 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
415 format
, GL_UNSIGNED_BYTE
, img
);
420 if (!LoadRGBMipmaps(SPECULAR_TEXTURE_FILE
, GL_RGB
)) {
421 printf("Error: couldn't load texture image file %s\n",
422 SPECULAR_TEXTURE_FILE
);
428 glEnable(GL_CULL_FACE
);
429 glEnable(GL_TEXTURE_2D
);
430 glEnable(GL_DEPTH_TEST
);
431 glEnable(GL_NORMALIZE
);
433 glPolygonOffset( -1, -1 );
437 int main( int argc
, char *argv
[] )
439 glutInit( &argc
, argv
);
440 glutInitWindowSize(WinWidth
, WinHeight
);
441 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
442 glutCreateWindow(argv
[0] );
444 glutReshapeFunc( Reshape
);
445 glutKeyboardFunc( Key
);
446 glutDisplayFunc( Display
);
447 glutMotionFunc(MouseMotion
);
448 glutMouseFunc(MouseButton
);
450 glutIdleFunc( Idle
);
452 glutCreateMenu(ModeMenu
);
453 glutAddMenuEntry("Toggle Highlight", DO_SPEC_TEXTURE
);
454 glutAddMenuEntry("Toggle Object", OBJECT
);
455 glutAddMenuEntry("Toggle Animate", ANIMATE
);
456 glutAddMenuEntry("Quit", QUIT
);
457 glutAttachMenu(GLUT_RIGHT_BUTTON
);