2 * Demo of a reflective, texture-mapped surface with OpenGL.
3 * Brian Paul August 14, 1995 This file is in the public domain.
5 * Hardware texture mapping is highly recommended!
8 * 1. Render the reflective object (a polygon) from the normal viewpoint,
9 * setting the stencil planes = 1.
10 * 2. Render the scene from a special viewpoint: the viewpoint which
11 * is on the opposite side of the reflective plane. Only draw where
12 * stencil = 1. This draws the objects in the reflective surface.
13 * 3. Render the scene from the original viewpoint. This draws the
14 * objects in the normal fashion. Use blending when drawing
15 * the reflective, textured surface.
17 * This is a very crude demo. It could be much better.
23 * Dirk Reiners (reiners@igd.fhg.de) made some modifications to this code.
24 * Mark Kilgard (April 1997)
25 * Brian Paul (April 2000 - added keyboard d/s options)
26 * Brian Paul (August 2005 - added multi window feature)
35 #include "showbuffer.h"
39 #define DEG2RAD (3.14159/180.0)
40 #define TABLE_TEXTURE "PROGDIR:images/tile.rgb"
42 #define INIT_WIDTH 400
43 #define INIT_HEIGHT 300
50 int id
; /* returned by glutCreateWindow() */
58 GLuint objects_list
[MAX_OBJECTS
];
64 static struct window
*FirstWindow
= NULL
;
71 static struct window
*
74 int id
= glutGetWindow();
76 for (w
= FirstWindow
; w
; w
= w
->next
) {
88 for (w
= FirstWindow
; w
; w
= w
->next
) {
97 KillWindow(struct window
*w
)
99 struct window
*win
, *prev
= NULL
;
100 for (win
= FirstWindow
; win
; win
= win
->next
) {
103 prev
->next
= win
->next
;
106 FirstWindow
= win
->next
;
108 glutDestroyWindow(win
->id
);
122 KillWindow(FirstWindow
);
129 static GLfloat table_mat
[] = { 1.0, 1.0, 1.0, 0.6 };
130 static GLfloat gray
[] = { 0.4, 0.4, 0.4, 1.0 };
133 table_list
= glGenLists(1);
134 glNewList( table_list
, GL_COMPILE
);
136 /* load table's texture */
137 glMaterialfv( GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, table_mat
);
138 /*glMaterialfv( GL_FRONT, GL_EMISSION, gray );*/
139 glMaterialfv( GL_FRONT
, GL_DIFFUSE
, table_mat
);
140 glMaterialfv( GL_FRONT
, GL_AMBIENT
, gray
);
142 /* draw textured square for the table */
144 glScalef( 4.0, 4.0, 4.0 );
145 glBegin( GL_POLYGON
);
146 glNormal3f( 0.0, 1.0, 0.0 );
147 glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 0.0, 1.0 );
148 glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, 0.0, 1.0 );
149 glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 0.0, -1.0 );
150 glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 0.0, -1.0 );
154 glDisable( GL_TEXTURE_2D
);
162 MakeObjects(GLuint
*objects_list
)
166 static GLfloat cyan
[] = { 0.0, 1.0, 1.0, 1.0 };
167 static GLfloat green
[] = { 0.2, 1.0, 0.2, 1.0 };
168 static GLfloat black
[] = { 0.0, 0.0, 0.0, 0.0 };
171 gluQuadricDrawStyle( q
, GLU_FILL
);
172 gluQuadricNormals( q
, GLU_SMOOTH
);
174 objects_list
[0] = glGenLists(1);
175 glNewList( objects_list
[0], GL_COMPILE
);
176 glMaterialfv( GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, cyan
);
177 glMaterialfv( GL_FRONT
, GL_EMISSION
, black
);
178 gluCylinder( q
, 0.5, 0.5, 1.0, 15, 1 );
181 objects_list
[1] = glGenLists(1);
182 glNewList( objects_list
[1], GL_COMPILE
);
183 glMaterialfv( GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
184 glMaterialfv( GL_FRONT
, GL_EMISSION
, black
);
185 gluCylinder( q
, 1.5, 0.0, 2.5, 15, 1 );
193 InitWindow(struct window
*w
)
195 GLint imgWidth
, imgHeight
;
197 GLubyte
*image
= NULL
;
199 w
->table_list
= MakeTable();
200 MakeObjects(w
->objects_list
);
202 image
= LoadRGBImage( TABLE_TEXTURE
, &imgWidth
, &imgHeight
, &imgFormat
);
204 printf("Couldn't read %s\n", TABLE_TEXTURE
);
208 gluBuild2DMipmaps(GL_TEXTURE_2D
, 3, imgWidth
, imgHeight
,
209 imgFormat
, GL_UNSIGNED_BYTE
, image
);
212 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
213 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
214 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
215 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
217 glShadeModel( GL_FLAT
);
219 glEnable( GL_LIGHT0
);
220 glEnable( GL_LIGHTING
);
222 glClearColor( 0.5, 0.5, 0.9, 0.0 );
224 glEnable( GL_NORMALIZE
);
229 Reshape(int width
, int height
)
231 struct window
*w
= CurrentWindow();
232 GLfloat yAspect
= 2.5;
233 GLfloat xAspect
= yAspect
* (float) width
/ (float) height
;
236 glViewport(0, 0, width
, height
);
237 glMatrixMode(GL_PROJECTION
);
239 glFrustum( -xAspect
, xAspect
, -yAspect
, yAspect
, 10.0, 30.0 );
240 glMatrixMode(GL_MODELVIEW
);
246 DrawObjects(struct window
*w
, GLfloat eyex
, GLfloat eyey
, GLfloat eyez
)
255 glTranslatef( 1.0, 1.5, 0.0 );
256 glRotatef( w
->spin
, 1.0, 0.5, 0.0 );
257 glRotatef( 0.5*w
->spin
, 0.0, 0.5, 1.0 );
258 glCallList( w
->objects_list
[0] );
262 glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w
->spin
) ), 0.0 );
263 glRotatef( 0.5*w
->spin
, 0.0, 0.5, 1.0 );
264 glRotatef( w
->spin
, 1.0, 0.5, 0.0 );
265 glScalef( 0.5, 0.5, 0.5 );
266 glCallList( w
->objects_list
[1] );
272 glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w
->spin
) ), 0.0 );
273 glRotatef( 0.5*w
->spin
, 0.0, 0.5, 1.0 );
274 glRotatef( w
->spin
, 1.0, 0.5, 0.0 );
275 glScalef( 0.5, 0.5, 0.5 );
276 glCallList( w
->objects_list
[1] );
280 glTranslatef( 1.0, 1.5, 0.0 );
281 glRotatef( w
->spin
, 1.0, 0.5, 0.0 );
282 glRotatef( 0.5*w
->spin
, 0.0, 0.5, 1.0 );
283 glCallList( w
->objects_list
[0] );
291 DrawTable(struct window
*w
)
293 glCallList(w
->table_list
);
300 struct window
*w
= CurrentWindow();
301 static GLfloat light_pos
[] = { 0.0, 20.0, 0.0, 1.0 };
303 GLfloat eyex
, eyey
, eyez
;
305 if (w
->drawBuffer
== GL_NONE
) {
306 glDrawBuffer(GL_BACK
);
307 glReadBuffer(GL_BACK
);
310 glDrawBuffer(w
->drawBuffer
);
311 glReadBuffer(w
->drawBuffer
);
314 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
316 if (w
->drawBuffer
== GL_NONE
) {
317 glDrawBuffer(GL_NONE
);
320 eyex
= dist
* cos(w
->yrot
* DEG2RAD
) * cos(w
->xrot
* DEG2RAD
);
321 eyez
= dist
* sin(w
->yrot
* DEG2RAD
) * cos(w
->xrot
* DEG2RAD
);
322 eyey
= dist
* sin(w
->xrot
* DEG2RAD
);
326 gluLookAt( eyex
, eyey
, eyez
, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );
328 glLightfv( GL_LIGHT0
, GL_POSITION
, light_pos
);
330 /* draw table into stencil planes */
331 glDisable( GL_DEPTH_TEST
);
332 glEnable( GL_STENCIL_TEST
);
333 glStencilFunc( GL_ALWAYS
, 1, 0xffffffff );
334 glStencilOp( GL_REPLACE
, GL_REPLACE
, GL_REPLACE
);
335 glColorMask( GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
337 glColorMask( GL_TRUE
, GL_TRUE
, GL_TRUE
, GL_TRUE
);
339 glEnable( GL_DEPTH_TEST
);
341 /* render view from below (reflected viewport) */
342 /* only draw where stencil==1 */
346 glStencilFunc( GL_EQUAL
, 1, 0xffffffff ); /* draw if ==1 */
347 glStencilOp( GL_KEEP
, GL_KEEP
, GL_KEEP
);
348 glScalef( 1.0, -1.0, 1.0 );
350 /* Reposition light in reflected space. */
351 glLightfv(GL_LIGHT0
, GL_POSITION
, light_pos
);
353 DrawObjects(w
, eyex
, eyey
, eyez
);
356 /* Restore light's original unreflected position. */
357 glLightfv(GL_LIGHT0
, GL_POSITION
, light_pos
);
360 glDisable( GL_STENCIL_TEST
);
362 glEnable( GL_BLEND
);
363 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
365 glEnable( GL_TEXTURE_2D
);
367 glDisable( GL_TEXTURE_2D
);
368 glDisable( GL_BLEND
);
373 DrawObjects(w
, eyex
, eyey
, eyez
);
379 if (w
->showBuffer
== GL_DEPTH
) {
380 ShowDepthBuffer(w
->width
, w
->height
, 1.0, 0.0);
382 else if (w
->showBuffer
== GL_STENCIL
) {
383 ShowStencilBuffer(w
->width
, w
->height
, 255.0, 0.0);
385 else if (w
->showBuffer
== GL_ALPHA
) {
386 ShowAlphaBuffer(w
->width
, w
->height
);
389 if (w
->drawBuffer
== GL_FRONT
)
394 /* calc/show frame rate */
397 static GLint frames
= 0;
398 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
400 if (t
- t0
>= 5000) {
401 GLfloat seconds
= (t
- t0
) / 1000.0;
402 GLfloat fps
= frames
/ seconds
;
403 printf("%d frames in %g seconds = %g FPS\n", frames
, seconds
, fps
);
415 double t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
417 for (w
= FirstWindow
; w
; w
= w
->next
) {
424 w
->spin
+= 60.0 * dt
;
425 w
->yrot
+= 90.0 * dt
;
427 glutSetWindow(w
->id
);
444 Key(unsigned char key
, int x
, int y
)
446 struct window
*w
= CurrentWindow();
452 w
->showBuffer
= GL_DEPTH
;
456 w
->showBuffer
= GL_STENCIL
;
460 w
->showBuffer
= GL_ALPHA
;
464 w
->showBuffer
= GL_NONE
;
468 if (w
->drawBuffer
== GL_FRONT
)
469 w
->drawBuffer
= GL_BACK
;
471 w
->drawBuffer
= GL_FRONT
;
475 w
->drawBuffer
= GL_NONE
;
492 if (FirstWindow
== NULL
)
506 SpecialKey(int key
, int x
, int y
)
508 struct window
*w
= CurrentWindow();
539 printf(" a - show alpha buffer\n");
540 printf(" d - show depth buffer\n");
541 printf(" s - show stencil buffer\n");
542 printf(" c - show color buffer\n");
543 printf(" f - toggle rendering to front/back color buffer\n");
545 printf(" n - create new window\n");
547 printf(" k - kill window\n");
548 printf(" SPACE - toggle animation\n");
549 printf(" ARROWS - rotate scene\n");
552 #include <proto/exec.h>
553 #include <proto/dos.h>
555 #define ARG_TEMPLATE "WINPOSX=X/N/K,WINPOSY=Y/N/K"
560 static IPTR args
[NUM_ARGS
];
561 WORD winx
= -1, winy
= -1;
565 static void correctpos(void)
567 if (winx
== -1) winx
= 100;
568 if (winy
== -1) winy
= 100;
571 static void getarguments(void)
573 struct RDArgs
*myargs
;
575 if ((myargs
= ReadArgs(ARG_TEMPLATE
, args
, NULL
)))
578 if (args
[ARG_X
]) winx
= *(IPTR
*)args
[ARG_X
];
579 if (args
[ARG_Y
]) winy
= *(IPTR
*)args
[ARG_Y
];
590 struct window
*w
= (struct window
*) calloc(1, sizeof(struct window
));
592 glutInitWindowPosition(winx
, winy
);
593 glutInitWindowSize(W
, H
);
594 w
->id
= glutCreateWindow("Reflect");
595 sprintf(title
, "Reflect %d", w
->id
);
596 glutSetWindowTitle(title
);
598 w
->width
= INIT_WIDTH
;
599 w
->height
= INIT_HEIGHT
;
604 w
->showBuffer
= GL_NONE
;
605 w
->drawBuffer
= GL_BACK
;
609 glutReshapeFunc(Reshape
);
610 glutDisplayFunc(DrawWindow
);
611 glutKeyboardFunc(Key
);
612 glutSpecialFunc(SpecialKey
);
614 /* insert at head of list */
615 w
->next
= FirstWindow
;
620 main(int argc
, char *argv
[])
625 glutInit(&argc
, argv
);
626 glutInitDisplayMode(GLUT_DOUBLE
| GLUT_RGB
| GLUT_DEPTH
|
627 GLUT_STENCIL
| GLUT_ALPHA
);