better animate rate (Marcelo Magallon)
[mesa.git] / progs / demos / reflect.c
1
2 /*
3 * Demo of a reflective, texture-mapped surface with OpenGL.
4 * Brian Paul August 14, 1995 This file is in the public domain.
5 *
6 * Hardware texture mapping is highly recommended!
7 *
8 * The basic steps are:
9 * 1. Render the reflective object (a polygon) from the normal viewpoint,
10 * setting the stencil planes = 1.
11 * 2. Render the scene from a special viewpoint: the viewpoint which
12 * is on the opposite side of the reflective plane. Only draw where
13 * stencil = 1. This draws the objects in the reflective surface.
14 * 3. Render the scene from the original viewpoint. This draws the
15 * objects in the normal fashion. Use blending when drawing
16 * the reflective, textured surface.
17 *
18 * This is a very crude demo. It could be much better.
19 */
20
21 /*
22 * Authors:
23 * Brian Paul
24 * Dirk Reiners (reiners@igd.fhg.de) made some modifications to this code.
25 * Mark Kilgard (April 1997)
26 * Brian Paul (April 2000 - added keyboard d/s options)
27 */
28
29
30 #include <math.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include "GL/glut.h"
34 #include "showbuffer.h"
35 #include "readtex.h"
36
37
38 #define DEG2RAD (3.14159/180.0)
39
40 #define TABLE_TEXTURE "../images/tile.rgb"
41
42 static GLint ImgWidth, ImgHeight;
43 static GLenum ImgFormat;
44 static GLubyte *Image = NULL;
45
46 #define MAX_OBJECTS 2
47 static GLint table_list;
48 static GLint objects_list[MAX_OBJECTS];
49
50 static GLfloat xrot, yrot;
51 static GLfloat spin;
52
53 static GLint Width = 400, Height = 300;
54 static GLenum ShowBuffer = GL_NONE;
55 static GLboolean Anim = GL_TRUE;
56
57 /* performance info */
58 static GLint T0 = 0;
59 static GLint Frames = 0;
60
61
62 static void make_table( void )
63 {
64 static GLfloat table_mat[] = { 1.0, 1.0, 1.0, 0.6 };
65 static GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 };
66
67 table_list = glGenLists(1);
68 glNewList( table_list, GL_COMPILE );
69
70 /* load table's texture */
71 glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_mat );
72 /* glMaterialfv( GL_FRONT, GL_EMISSION, gray );*/
73 glMaterialfv( GL_FRONT, GL_DIFFUSE, table_mat );
74 glMaterialfv( GL_FRONT, GL_AMBIENT, gray );
75
76 /* draw textured square for the table */
77 glPushMatrix();
78 glScalef( 4.0, 4.0, 4.0 );
79 glBegin( GL_POLYGON );
80 glNormal3f( 0.0, 1.0, 0.0 );
81 glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 0.0, 1.0 );
82 glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, 0.0, 1.0 );
83 glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 0.0, -1.0 );
84 glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 0.0, -1.0 );
85 glEnd();
86 glPopMatrix();
87
88 glDisable( GL_TEXTURE_2D );
89
90 glEndList();
91 }
92
93
94 static void make_objects( void )
95 {
96 GLUquadricObj *q;
97
98 static GLfloat cyan[] = { 0.0, 1.0, 1.0, 1.0 };
99 static GLfloat green[] = { 0.2, 1.0, 0.2, 1.0 };
100 static GLfloat black[] = { 0.0, 0.0, 0.0, 0.0 };
101
102 q = gluNewQuadric();
103 gluQuadricDrawStyle( q, GLU_FILL );
104 gluQuadricNormals( q, GLU_SMOOTH );
105
106 objects_list[0] = glGenLists(1);
107 glNewList( objects_list[0], GL_COMPILE );
108 glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cyan );
109 glMaterialfv( GL_FRONT, GL_EMISSION, black );
110 gluCylinder( q, 0.5, 0.5, 1.0, 15, 1 );
111 glEndList();
112
113 objects_list[1] = glGenLists(1);
114 glNewList( objects_list[1], GL_COMPILE );
115 glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green );
116 glMaterialfv( GL_FRONT, GL_EMISSION, black );
117 gluCylinder( q, 1.5, 0.0, 2.5, 15, 1 );
118 glEndList();
119 }
120
121
122 static void init( void )
123 {
124 make_table();
125 make_objects();
126
127 Image = LoadRGBImage( TABLE_TEXTURE, &ImgWidth, &ImgHeight, &ImgFormat );
128 if (!Image) {
129 printf("Couldn't read %s\n", TABLE_TEXTURE);
130 exit(0);
131 }
132
133 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, ImgWidth, ImgHeight,
134 ImgFormat, GL_UNSIGNED_BYTE, Image);
135
136 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
137 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
138 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
139 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
140
141 xrot = 30.0;
142 yrot = 50.0;
143 spin = 0.0;
144
145 glShadeModel( GL_FLAT );
146
147 glEnable( GL_LIGHT0 );
148 glEnable( GL_LIGHTING );
149
150 glClearColor( 0.5, 0.5, 0.9, 0.0 );
151
152 glEnable( GL_NORMALIZE );
153 }
154
155
156
157 static void reshape(int w, int h)
158 {
159 GLfloat yAspect = 2.5;
160 GLfloat xAspect = yAspect * (float) w / (float) h;
161 Width = w;
162 Height = h;
163 glViewport(0, 0, w, h);
164 glMatrixMode(GL_PROJECTION);
165 glLoadIdentity();
166 glFrustum( -xAspect, xAspect, -yAspect, yAspect, 10.0, 30.0 );
167 glMatrixMode(GL_MODELVIEW);
168 glLoadIdentity();
169 }
170
171
172
173 static void draw_objects( GLfloat eyex, GLfloat eyey, GLfloat eyez )
174 {
175 (void) eyex;
176 (void) eyey;
177 (void) eyez;
178 #ifndef USE_ZBUFFER
179 if (eyex<0.5) {
180 #endif
181 glPushMatrix();
182 glTranslatef( 1.0, 1.5, 0.0 );
183 glRotatef( spin, 1.0, 0.5, 0.0 );
184 glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
185 glCallList( objects_list[0] );
186 glPopMatrix();
187
188 glPushMatrix();
189 glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*spin) ), 0.0 );
190 glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
191 glRotatef( spin, 1.0, 0.5, 0.0 );
192 glScalef( 0.5, 0.5, 0.5 );
193 glCallList( objects_list[1] );
194 glPopMatrix();
195 #ifndef USE_ZBUFFER
196 }
197 else {
198 glPushMatrix();
199 glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*spin) ), 0.0 );
200 glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
201 glRotatef( spin, 1.0, 0.5, 0.0 );
202 glScalef( 0.5, 0.5, 0.5 );
203 glCallList( objects_list[1] );
204 glPopMatrix();
205
206 glPushMatrix();
207 glTranslatef( 1.0, 1.5, 0.0 );
208 glRotatef( spin, 1.0, 0.5, 0.0 );
209 glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
210 glCallList( objects_list[0] );
211 glPopMatrix();
212 }
213 #endif
214 }
215
216
217
218 static void draw_table( void )
219 {
220 glCallList( table_list );
221 }
222
223
224
225 static void draw_scene( void )
226 {
227 static GLfloat light_pos[] = { 0.0, 20.0, 0.0, 1.0 };
228 GLfloat dist = 20.0;
229 GLfloat eyex, eyey, eyez;
230
231 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
232
233
234 eyex = dist * cos(yrot*DEG2RAD) * cos(xrot*DEG2RAD);
235 eyez = dist * sin(yrot*DEG2RAD) * cos(xrot*DEG2RAD);
236 eyey = dist * sin(xrot*DEG2RAD);
237
238 /* view from top */
239 glPushMatrix();
240 gluLookAt( eyex, eyey, eyez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );
241
242 glLightfv( GL_LIGHT0, GL_POSITION, light_pos );
243
244 /* draw table into stencil planes */
245 glDisable( GL_DEPTH_TEST );
246 glEnable( GL_STENCIL_TEST );
247 glStencilFunc( GL_ALWAYS, 1, 0xffffffff );
248 glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
249 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
250 draw_table();
251 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
252
253 glEnable( GL_DEPTH_TEST );
254
255 /* render view from below (reflected viewport) */
256 /* only draw where stencil==1 */
257 if (eyey>0.0) {
258 glPushMatrix();
259
260 glStencilFunc( GL_EQUAL, 1, 0xffffffff ); /* draw if ==1 */
261 glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
262 glScalef( 1.0, -1.0, 1.0 );
263
264 /* Reposition light in reflected space. */
265 glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
266
267 draw_objects(eyex, eyey, eyez);
268 glPopMatrix();
269
270 /* Restore light's original unreflected position. */
271 glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
272 }
273
274 glDisable( GL_STENCIL_TEST );
275
276 glEnable( GL_BLEND );
277 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
278
279 glEnable( GL_TEXTURE_2D );
280 draw_table();
281 glDisable( GL_TEXTURE_2D );
282 glDisable( GL_BLEND );
283
284 /* view from top */
285 glPushMatrix();
286
287 draw_objects(eyex, eyey, eyez);
288
289 glPopMatrix();
290
291 glPopMatrix();
292
293 if (ShowBuffer == GL_DEPTH) {
294 ShowDepthBuffer(Width, Height, 1.0, 0.0);
295 }
296 else if (ShowBuffer == GL_STENCIL) {
297 ShowStencilBuffer(Width, Height, 255.0, 0.0);
298 }
299 else if (ShowBuffer == GL_ALPHA) {
300 ShowAlphaBuffer(Width, Height);
301 }
302
303 glutSwapBuffers();
304
305 {
306 GLint t = glutGet(GLUT_ELAPSED_TIME);
307 Frames++;
308 if (t - T0 >= 5000) {
309 GLfloat seconds = (t - T0) / 1000.0;
310 GLfloat fps = Frames / seconds;
311 printf("%d frames in %g seconds = %g FPS\n", Frames, seconds, fps);
312 T0 = t;
313 Frames = 0;
314 }
315 }
316 }
317
318
319 static void idle( void )
320 {
321 static double t0 = -1.;
322 double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
323 if (t0 < 0.0)
324 t0 = t;
325 dt = t - t0;
326 t0 = t;
327 spin += 60.0 * dt;
328 yrot += 90.0 * dt;
329 glutPostRedisplay();
330 }
331
332
333 static void Key( unsigned char key, int x, int y )
334 {
335 (void) x;
336 (void) y;
337 if (key == 'd') {
338 ShowBuffer = GL_DEPTH;
339 }
340 else if (key == 's') {
341 ShowBuffer = GL_STENCIL;
342 }
343 else if (key == 'a') {
344 ShowBuffer = GL_ALPHA;
345 }
346 else if (key == ' ') {
347 Anim = !Anim;
348 if (Anim)
349 glutIdleFunc(idle);
350 else
351 glutIdleFunc(NULL);
352 }
353 else if (key==27) {
354 exit(0);
355 }
356 else {
357 ShowBuffer = GL_NONE;
358 }
359 glutPostRedisplay();
360 }
361
362
363 static void SpecialKey( int key, int x, int y )
364 {
365 (void) x;
366 (void) y;
367 switch (key) {
368 case GLUT_KEY_UP:
369 xrot += 3.0;
370 if ( xrot > 85 )
371 xrot = 85;
372 break;
373 case GLUT_KEY_DOWN:
374 xrot -= 3.0;
375 if ( xrot < 5 )
376 xrot = 5;
377 break;
378 case GLUT_KEY_LEFT:
379 yrot += 3.0;
380 break;
381 case GLUT_KEY_RIGHT:
382 yrot -= 3.0;
383 break;
384 }
385 glutPostRedisplay();
386 }
387
388
389 int main( int argc, char *argv[] )
390 {
391 glutInit(&argc, argv);
392 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL);
393 glutInitWindowPosition( 0, 0 );
394 glutInitWindowSize( Width, Height );
395 glutCreateWindow(argv[0]);
396 glutReshapeFunc(reshape);
397 glutDisplayFunc(draw_scene);
398 glutKeyboardFunc(Key);
399 glutSpecialFunc(SpecialKey);
400 glutIdleFunc(idle);
401 init();
402 glutMainLoop();
403 return 0;
404 }