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