132001f49Smrg/*
232001f49Smrg * Demo of a reflective, texture-mapped surface with OpenGL.
332001f49Smrg * Brian Paul   August 14, 1995   This file is in the public domain.
432001f49Smrg *
532001f49Smrg * Hardware texture mapping is highly recommended!
632001f49Smrg *
732001f49Smrg * The basic steps are:
832001f49Smrg *    1. Render the reflective object (a polygon) from the normal viewpoint,
932001f49Smrg *       setting the stencil planes = 1.
1032001f49Smrg *    2. Render the scene from a special viewpoint:  the viewpoint which
1132001f49Smrg *       is on the opposite side of the reflective plane.  Only draw where
1232001f49Smrg *       stencil = 1.  This draws the objects in the reflective surface.
1332001f49Smrg *    3. Render the scene from the original viewpoint.  This draws the
1432001f49Smrg *       objects in the normal fashion.  Use blending when drawing
1532001f49Smrg *       the reflective, textured surface.
1632001f49Smrg *
1732001f49Smrg * This is a very crude demo.  It could be much better.
1832001f49Smrg */
1932001f49Smrg
2032001f49Smrg/*
2132001f49Smrg * Authors:
2232001f49Smrg *   Brian Paul
2332001f49Smrg *   Dirk Reiners (reiners@igd.fhg.de) made some modifications to this code.
2432001f49Smrg *   Mark Kilgard (April 1997)
2532001f49Smrg *   Brian Paul (April 2000 - added keyboard d/s options)
2632001f49Smrg *   Brian Paul (August 2005 - added multi window feature)
2732001f49Smrg */
2832001f49Smrg
2932001f49Smrg
3032001f49Smrg#include <assert.h>
3132001f49Smrg#include <math.h>
3232001f49Smrg#include <stdio.h>
3332001f49Smrg#include <stdlib.h>
3432001f49Smrg#include "glut_wrap.h"
3532001f49Smrg#include "showbuffer.h"
3632001f49Smrg#include "readtex.h"
3732001f49Smrg
3832001f49Smrg
3932001f49Smrg#define DEG2RAD (3.14159/180.0)
4032001f49Smrg#define TABLE_TEXTURE DEMOS_DATA_DIR "tile.rgb"
4132001f49Smrg#define MAX_OBJECTS 2
4232001f49Smrg#define INIT_WIDTH 400
4332001f49Smrg#define INIT_HEIGHT 300
4432001f49Smrg
4532001f49Smrg#ifdef _WIN32
4632001f49Smrg#undef CreateWindowA
4732001f49Smrg#endif
4832001f49Smrg
4932001f49Smrgstruct window {
5032001f49Smrg   int id;               /* returned by glutCreateWindow() */
5132001f49Smrg   int width, height;
5232001f49Smrg   GLboolean anim;
5332001f49Smrg   GLfloat xrot, yrot;
5432001f49Smrg   GLfloat spin;
5532001f49Smrg   GLenum showBuffer;
5632001f49Smrg   GLenum drawBuffer;
5732001f49Smrg   GLuint table_list;
5832001f49Smrg   GLuint objects_list[MAX_OBJECTS];
5932001f49Smrg   double t0;
6032001f49Smrg   struct window *next;
6132001f49Smrg};
6232001f49Smrg
6332001f49Smrg
6432001f49Smrgstatic struct window *FirstWindow = NULL;
6532001f49Smrg
6632001f49Smrg
6732001f49Smrgstatic void
6832001f49SmrgCreateWindow(void);
6932001f49Smrg
7032001f49Smrg
7132001f49Smrgstatic struct window *
7232001f49SmrgCurrentWindow(void)
7332001f49Smrg{
7432001f49Smrg   int id = glutGetWindow();
7532001f49Smrg   struct window *w;
7632001f49Smrg   for (w = FirstWindow; w; w = w->next) {
7732001f49Smrg      if (w->id == id)
7832001f49Smrg         return w;
7932001f49Smrg   }
8032001f49Smrg   return NULL;
8132001f49Smrg}
8232001f49Smrg
8332001f49Smrg
8432001f49Smrgstatic GLboolean
8532001f49SmrgAnyAnimating(void)
8632001f49Smrg{
8732001f49Smrg   struct window *w;
8832001f49Smrg   for (w = FirstWindow; w; w = w->next) {
8932001f49Smrg      if (w->anim)
9032001f49Smrg         return 1;
9132001f49Smrg   }
9232001f49Smrg   return 0;
9332001f49Smrg}
9432001f49Smrg
9532001f49Smrg
9632001f49Smrgstatic void
9732001f49SmrgKillWindow(struct window *w)
9832001f49Smrg{
9932001f49Smrg   struct window *win, *prev = NULL;
10032001f49Smrg   for (win = FirstWindow; win; win = win->next) {
10132001f49Smrg      if (win == w) {
10232001f49Smrg         if (prev) {
10332001f49Smrg            prev->next = win->next;
10432001f49Smrg         }
10532001f49Smrg         else {
10632001f49Smrg            FirstWindow = win->next;
10732001f49Smrg         }
10832001f49Smrg         glutDestroyWindow(win->id);
10932001f49Smrg         win->next = NULL;
11032001f49Smrg         free(win);
11132001f49Smrg         return;
11232001f49Smrg      }
11332001f49Smrg      prev = win;
11432001f49Smrg   }
11532001f49Smrg}
11632001f49Smrg
11732001f49Smrg
11832001f49Smrgstatic void
11932001f49SmrgKillAllWindows(void)
12032001f49Smrg{
12132001f49Smrg   while (FirstWindow)
12232001f49Smrg      KillWindow(FirstWindow);
12332001f49Smrg}
12432001f49Smrg
12532001f49Smrg
12632001f49Smrgstatic GLuint
12732001f49SmrgMakeTable(void)
12832001f49Smrg{
12932001f49Smrg   static GLfloat table_mat[] = { 1.0, 1.0, 1.0, 0.6 };
13032001f49Smrg   static GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 };
13132001f49Smrg   GLuint table_list;
13232001f49Smrg
13332001f49Smrg   table_list = glGenLists(1);
13432001f49Smrg   glNewList( table_list, GL_COMPILE );
13532001f49Smrg
13632001f49Smrg   /* load table's texture */
13732001f49Smrg   glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_mat );
13832001f49Smrg   /*glMaterialfv( GL_FRONT, GL_EMISSION, gray );*/
13932001f49Smrg   glMaterialfv( GL_FRONT, GL_DIFFUSE, table_mat );
14032001f49Smrg   glMaterialfv( GL_FRONT, GL_AMBIENT, gray );
14132001f49Smrg
14232001f49Smrg   /* draw textured square for the table */
14332001f49Smrg   glPushMatrix();
14432001f49Smrg   glScalef( 4.0, 4.0, 4.0 );
14532001f49Smrg   glBegin( GL_POLYGON );
14632001f49Smrg   glNormal3f( 0.0, 1.0, 0.0 );
14732001f49Smrg   glTexCoord2f( 0.0, 0.0 );   glVertex3f( -1.0, 0.0,  1.0 );
14832001f49Smrg   glTexCoord2f( 1.0, 0.0 );   glVertex3f(  1.0, 0.0,  1.0 );
14932001f49Smrg   glTexCoord2f( 1.0, 1.0 );   glVertex3f(  1.0, 0.0, -1.0 );
15032001f49Smrg   glTexCoord2f( 0.0, 1.0 );   glVertex3f( -1.0, 0.0, -1.0 );
15132001f49Smrg   glEnd();
15232001f49Smrg   glPopMatrix();
15332001f49Smrg
15432001f49Smrg   glDisable( GL_TEXTURE_2D );
15532001f49Smrg
15632001f49Smrg   glEndList();
15732001f49Smrg   return table_list;
15832001f49Smrg}
15932001f49Smrg
16032001f49Smrg
16132001f49Smrgstatic void
16232001f49SmrgMakeObjects(GLuint *objects_list)
16332001f49Smrg{
16432001f49Smrg   GLUquadricObj *q;
16532001f49Smrg
16632001f49Smrg   static GLfloat cyan[] = { 0.0, 1.0, 1.0, 1.0 };
16732001f49Smrg   static GLfloat green[] = { 0.2, 1.0, 0.2, 1.0 };
16832001f49Smrg   static GLfloat black[] = { 0.0, 0.0, 0.0, 0.0 };
16932001f49Smrg
17032001f49Smrg   q = gluNewQuadric();
17132001f49Smrg   gluQuadricDrawStyle( q, GLU_FILL );
17232001f49Smrg   gluQuadricNormals( q, GLU_SMOOTH );
17332001f49Smrg
17432001f49Smrg   objects_list[0] = glGenLists(1);
17532001f49Smrg   glNewList( objects_list[0], GL_COMPILE );
17632001f49Smrg   glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cyan );
17732001f49Smrg   glMaterialfv( GL_FRONT, GL_EMISSION, black );
17832001f49Smrg   gluCylinder( q, 0.5, 0.5,  1.0, 15, 1 );
17932001f49Smrg   glEndList();
18032001f49Smrg
18132001f49Smrg   objects_list[1] = glGenLists(1);
18232001f49Smrg   glNewList( objects_list[1], GL_COMPILE );
18332001f49Smrg   glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green );
18432001f49Smrg   glMaterialfv( GL_FRONT, GL_EMISSION, black );
18532001f49Smrg   gluCylinder( q, 1.5, 0.0,  2.5, 15, 1 );
18632001f49Smrg   glEndList();
18732001f49Smrg
18832001f49Smrg   gluDeleteQuadric(q);
18932001f49Smrg}
19032001f49Smrg
19132001f49Smrg
19232001f49Smrgstatic void
19332001f49SmrgInitWindow(struct window *w)
19432001f49Smrg{
19532001f49Smrg   GLint imgWidth, imgHeight;
19632001f49Smrg   GLenum imgFormat;
19732001f49Smrg   GLubyte *image = NULL;
19832001f49Smrg
19932001f49Smrg   w->table_list = MakeTable();
20032001f49Smrg   MakeObjects(w->objects_list);
20132001f49Smrg
20232001f49Smrg   image = LoadRGBImage( TABLE_TEXTURE, &imgWidth, &imgHeight, &imgFormat );
20332001f49Smrg   if (!image) {
20432001f49Smrg      printf("Couldn't read %s\n", TABLE_TEXTURE);
20532001f49Smrg      exit(0);
20632001f49Smrg   }
20732001f49Smrg
20832001f49Smrg   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight,
20932001f49Smrg                     imgFormat, GL_UNSIGNED_BYTE, image);
21032001f49Smrg   free(image);
21132001f49Smrg
21232001f49Smrg   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
21332001f49Smrg   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
21432001f49Smrg   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
21532001f49Smrg   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
21632001f49Smrg
21732001f49Smrg   glShadeModel( GL_FLAT );
21832001f49Smrg
21932001f49Smrg   glEnable( GL_LIGHT0 );
22032001f49Smrg   glEnable( GL_LIGHTING );
22132001f49Smrg
22232001f49Smrg   glClearColor( 0.5, 0.5, 0.9, 0.0 );
22332001f49Smrg
22432001f49Smrg   glEnable( GL_NORMALIZE );
22532001f49Smrg}
22632001f49Smrg
22732001f49Smrg
22832001f49Smrgstatic void
22932001f49SmrgReshape(int width, int height)
23032001f49Smrg{
23132001f49Smrg   struct window *w = CurrentWindow();
23232001f49Smrg   GLfloat yAspect = 2.5;
23332001f49Smrg   GLfloat xAspect = yAspect * (float) width / (float) height;
23432001f49Smrg   w->width = width;
23532001f49Smrg   w->height = height;
23632001f49Smrg   glViewport(0, 0, width, height);
23732001f49Smrg   glMatrixMode(GL_PROJECTION);
23832001f49Smrg   glLoadIdentity();
23932001f49Smrg   glFrustum( -xAspect, xAspect, -yAspect, yAspect, 10.0, 30.0 );
24032001f49Smrg   glMatrixMode(GL_MODELVIEW);
24132001f49Smrg   glLoadIdentity();
24232001f49Smrg}
24332001f49Smrg
24432001f49Smrg
24532001f49Smrgstatic void
24632001f49SmrgDrawObjects(struct window *w, GLfloat eyex, GLfloat eyey, GLfloat eyez)
24732001f49Smrg{
24832001f49Smrg   (void) eyex;
24932001f49Smrg   (void) eyey;
25032001f49Smrg   (void) eyez;
25132001f49Smrg#ifndef USE_ZBUFFER
25232001f49Smrg   if (eyex<0.5) {
25332001f49Smrg#endif
25432001f49Smrg      glPushMatrix();
25532001f49Smrg      glTranslatef( 1.0, 1.5, 0.0 );
25632001f49Smrg      glRotatef( w->spin, 1.0, 0.5, 0.0 );
25732001f49Smrg      glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
25832001f49Smrg      glCallList( w->objects_list[0] );
25932001f49Smrg      glPopMatrix();
26032001f49Smrg
26132001f49Smrg      glPushMatrix();
26232001f49Smrg      glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w->spin) ), 0.0 );
26332001f49Smrg      glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
26432001f49Smrg      glRotatef( w->spin, 1.0, 0.5, 0.0 );
26532001f49Smrg      glScalef( 0.5, 0.5, 0.5 );
26632001f49Smrg      glCallList( w->objects_list[1] );
26732001f49Smrg      glPopMatrix();
26832001f49Smrg#ifndef USE_ZBUFFER
26932001f49Smrg   }
27032001f49Smrg   else {
27132001f49Smrg      glPushMatrix();
27232001f49Smrg      glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w->spin) ), 0.0 );
27332001f49Smrg      glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
27432001f49Smrg      glRotatef( w->spin, 1.0, 0.5, 0.0 );
27532001f49Smrg      glScalef( 0.5, 0.5, 0.5 );
27632001f49Smrg      glCallList( w->objects_list[1] );
27732001f49Smrg      glPopMatrix();
27832001f49Smrg
27932001f49Smrg      glPushMatrix();
28032001f49Smrg      glTranslatef( 1.0, 1.5, 0.0 );
28132001f49Smrg      glRotatef( w->spin, 1.0, 0.5, 0.0 );
28232001f49Smrg      glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
28332001f49Smrg      glCallList( w->objects_list[0] );
28432001f49Smrg      glPopMatrix();
28532001f49Smrg   }
28632001f49Smrg#endif
28732001f49Smrg}
28832001f49Smrg
28932001f49Smrg
29032001f49Smrgstatic void
29132001f49SmrgDrawTable(struct window *w)
29232001f49Smrg{
29332001f49Smrg   glCallList(w->table_list);
29432001f49Smrg}
29532001f49Smrg
29632001f49Smrg
29732001f49Smrgstatic void
29832001f49SmrgDrawWindow(void)
29932001f49Smrg{
30032001f49Smrg   struct window *w = CurrentWindow();
30132001f49Smrg   static GLfloat light_pos[] = { 0.0, 20.0, 0.0, 1.0 };
30232001f49Smrg   GLfloat dist = 20.0;
30332001f49Smrg   GLfloat eyex, eyey, eyez;
30432001f49Smrg
30532001f49Smrg   if (w->drawBuffer == GL_NONE) {
30632001f49Smrg      glDrawBuffer(GL_BACK);
30732001f49Smrg      glReadBuffer(GL_BACK);
30832001f49Smrg   }
30932001f49Smrg   else {
31032001f49Smrg      glDrawBuffer(w->drawBuffer);
31132001f49Smrg      glReadBuffer(w->drawBuffer);
31232001f49Smrg   }
31332001f49Smrg
31432001f49Smrg   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
31532001f49Smrg
31632001f49Smrg   if (w->drawBuffer == GL_NONE) {
31732001f49Smrg      glDrawBuffer(GL_NONE);
31832001f49Smrg   }
31932001f49Smrg
32032001f49Smrg   eyex = dist  *  cos(w->yrot * DEG2RAD)  *  cos(w->xrot * DEG2RAD);
32132001f49Smrg   eyez = dist  *  sin(w->yrot * DEG2RAD)  *  cos(w->xrot * DEG2RAD);
32232001f49Smrg   eyey = dist  *  sin(w->xrot * DEG2RAD);
32332001f49Smrg
32432001f49Smrg   /* view from top */
32532001f49Smrg   glPushMatrix();
32632001f49Smrg   gluLookAt( eyex, eyey, eyez, 0.0, 0.0, 0.0,  0.0, 1.0, 0.0 );
32732001f49Smrg
32832001f49Smrg   glLightfv( GL_LIGHT0, GL_POSITION, light_pos );
32932001f49Smrg
33032001f49Smrg   /* draw table into stencil planes */
33132001f49Smrg   glDisable( GL_DEPTH_TEST );
33232001f49Smrg   glEnable( GL_STENCIL_TEST );
33332001f49Smrg   glStencilFunc( GL_ALWAYS, 1, 0xffffffff );
33432001f49Smrg   glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
33532001f49Smrg   glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
33632001f49Smrg   DrawTable(w);
33732001f49Smrg   glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
33832001f49Smrg
33932001f49Smrg   glEnable( GL_DEPTH_TEST );
34032001f49Smrg
34132001f49Smrg   /* render view from below (reflected viewport) */
34232001f49Smrg   /* only draw where stencil==1 */
34332001f49Smrg   if (eyey>0.0) {
34432001f49Smrg      glPushMatrix();
34532001f49Smrg
34632001f49Smrg      glStencilFunc( GL_EQUAL, 1, 0xffffffff );  /* draw if ==1 */
34732001f49Smrg      glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
34832001f49Smrg      glScalef( 1.0, -1.0, 1.0 );
34932001f49Smrg
35032001f49Smrg      /* Reposition light in reflected space. */
35132001f49Smrg      glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
35232001f49Smrg
35332001f49Smrg      DrawObjects(w, eyex, eyey, eyez);
35432001f49Smrg      glPopMatrix();
35532001f49Smrg
35632001f49Smrg      /* Restore light's original unreflected position. */
35732001f49Smrg      glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
35832001f49Smrg   }
35932001f49Smrg
36032001f49Smrg   glDisable( GL_STENCIL_TEST );
36132001f49Smrg
36232001f49Smrg   glEnable( GL_BLEND );
36332001f49Smrg   glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
36432001f49Smrg
36532001f49Smrg   glEnable( GL_TEXTURE_2D );
36632001f49Smrg   DrawTable(w);
36732001f49Smrg   glDisable( GL_TEXTURE_2D );
36832001f49Smrg   glDisable( GL_BLEND );
36932001f49Smrg
37032001f49Smrg   /* view from top */
37132001f49Smrg   glPushMatrix();
37232001f49Smrg
37332001f49Smrg   DrawObjects(w, eyex, eyey, eyez);
37432001f49Smrg
37532001f49Smrg   glPopMatrix();
37632001f49Smrg
37732001f49Smrg   glPopMatrix();
37832001f49Smrg
37932001f49Smrg   if (w->showBuffer == GL_DEPTH) {
38032001f49Smrg      ShowDepthBuffer(w->width, w->height, 1.0, 0.0);
38132001f49Smrg   }
38232001f49Smrg   else if (w->showBuffer == GL_STENCIL) {
38332001f49Smrg      ShowStencilBuffer(w->width, w->height, 255.0, 0.0);
38432001f49Smrg   }
38532001f49Smrg   else if (w->showBuffer == GL_ALPHA) {
38632001f49Smrg      ShowAlphaBuffer(w->width, w->height);
38732001f49Smrg   }
38832001f49Smrg
38932001f49Smrg   if (w->drawBuffer == GL_FRONT)
39032001f49Smrg      glFinish();
39132001f49Smrg   else
39232001f49Smrg      glutSwapBuffers();
39332001f49Smrg
39432001f49Smrg   /* calc/show frame rate */
39532001f49Smrg   {
39632001f49Smrg      static GLint t0 = 0;
39732001f49Smrg      static GLint frames = 0;
39832001f49Smrg      GLint t = glutGet(GLUT_ELAPSED_TIME);
39932001f49Smrg      frames++;
40032001f49Smrg      if (t - t0 >= 5000) {
40132001f49Smrg         GLfloat seconds = (t - t0) / 1000.0;
40232001f49Smrg         GLfloat fps = frames / seconds;
40332001f49Smrg         printf("%d frames in %g seconds = %g FPS\n", frames, seconds, fps);
40432001f49Smrg         fflush(stdout);
40532001f49Smrg         t0 = t;
40632001f49Smrg         frames = 0;
40732001f49Smrg      }
40832001f49Smrg   }
40932001f49Smrg}
41032001f49Smrg
41132001f49Smrg
41232001f49Smrgstatic void
41332001f49SmrgIdle(void)
41432001f49Smrg{
41532001f49Smrg   double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
41632001f49Smrg   struct window *w;
41732001f49Smrg   for (w = FirstWindow; w; w = w->next) {
41832001f49Smrg      if (w->anim) {
41932001f49Smrg         double dt;
42032001f49Smrg         if (w->t0 < 0.0)
42132001f49Smrg            w->t0 = t;
42232001f49Smrg         dt = t - w->t0;
42332001f49Smrg         w->t0 = t;
42432001f49Smrg         w->spin += 60.0 * dt;
42532001f49Smrg         w->yrot += 90.0 * dt;
42632001f49Smrg         assert(w->id);
42732001f49Smrg         glutSetWindow(w->id);
42832001f49Smrg         glutPostRedisplay();
42932001f49Smrg      }
43032001f49Smrg   }
43132001f49Smrg}
43232001f49Smrg
43332001f49Smrg
43432001f49Smrgstatic void
43532001f49SmrgUpdateIdleFunc(void)
43632001f49Smrg{
43732001f49Smrg   if (AnyAnimating())
43832001f49Smrg      glutIdleFunc(Idle);
43932001f49Smrg   else
44032001f49Smrg      glutIdleFunc(NULL);
44132001f49Smrg}
44232001f49Smrg
44332001f49Smrgstatic void
44432001f49SmrgKey(unsigned char key, int x, int y)
44532001f49Smrg{
44632001f49Smrg   struct window *w = CurrentWindow();
44732001f49Smrg   (void) x;
44832001f49Smrg   (void) y;
44932001f49Smrg
45032001f49Smrg   switch (key) {
45132001f49Smrg   case 'd':
45232001f49Smrg      w->showBuffer = GL_DEPTH;
45332001f49Smrg      glutPostRedisplay();
45432001f49Smrg      break;
45532001f49Smrg   case 's':
45632001f49Smrg      w->showBuffer = GL_STENCIL;
45732001f49Smrg      glutPostRedisplay();
45832001f49Smrg      break;
45932001f49Smrg   case 'a':
46032001f49Smrg      w->showBuffer = GL_ALPHA;
46132001f49Smrg      glutPostRedisplay();
46232001f49Smrg      break;
46332001f49Smrg   case 'c':
46432001f49Smrg      w->showBuffer = GL_NONE;
46532001f49Smrg      glutPostRedisplay();
46632001f49Smrg      break;
46732001f49Smrg   case 'f':
46832001f49Smrg      if (w->drawBuffer == GL_FRONT)
46932001f49Smrg         w->drawBuffer = GL_BACK;
47032001f49Smrg      else
47132001f49Smrg         w->drawBuffer = GL_FRONT;
47232001f49Smrg      glutPostRedisplay();
47332001f49Smrg      break;
47432001f49Smrg   case '0':
47532001f49Smrg      w->drawBuffer = GL_NONE;
47632001f49Smrg      glutPostRedisplay();
47732001f49Smrg      break;
47832001f49Smrg   case ' ':
47932001f49Smrg      w->anim = !w->anim;
48032001f49Smrg      w->t0 = -1;
48132001f49Smrg      UpdateIdleFunc();
48232001f49Smrg      glutPostRedisplay();
48332001f49Smrg      break;
48432001f49Smrg   case 'n':
48532001f49Smrg      CreateWindow();
48632001f49Smrg      UpdateIdleFunc();
48732001f49Smrg      break;
48832001f49Smrg   case 'k':
48932001f49Smrg      KillWindow(w);
49032001f49Smrg      if (FirstWindow == NULL)
49132001f49Smrg         exit(0);
49232001f49Smrg      break;
49332001f49Smrg   case 27:
49432001f49Smrg      KillAllWindows();
49532001f49Smrg      exit(0);
49632001f49Smrg      break;
49732001f49Smrg   default:
49832001f49Smrg      ;
49932001f49Smrg   }
50032001f49Smrg}
50132001f49Smrg
50232001f49Smrg
50332001f49Smrgstatic void
50432001f49SmrgSpecialKey(int key, int x, int y)
50532001f49Smrg{
50632001f49Smrg   struct window *w = CurrentWindow();
50732001f49Smrg   (void) x;
50832001f49Smrg   (void) y;
50932001f49Smrg   switch (key) {
51032001f49Smrg      case GLUT_KEY_UP:
51132001f49Smrg         w->xrot += 3.0;
51232001f49Smrg         if (w->xrot > 85)
51332001f49Smrg            w->xrot = 85;
51432001f49Smrg         break;
51532001f49Smrg      case GLUT_KEY_DOWN:
51632001f49Smrg         w->xrot -= 3.0;
51732001f49Smrg         if (w->xrot < 5)
51832001f49Smrg            w->xrot = 5;
51932001f49Smrg         break;
52032001f49Smrg      case GLUT_KEY_LEFT:
52132001f49Smrg         w->yrot += 3.0;
52232001f49Smrg         break;
52332001f49Smrg      case GLUT_KEY_RIGHT:
52432001f49Smrg         w->yrot -= 3.0;
52532001f49Smrg         break;
52632001f49Smrg   }
52732001f49Smrg   glutPostRedisplay();
52832001f49Smrg}
52932001f49Smrg
53032001f49Smrg
53132001f49Smrgstatic void
53232001f49SmrgCreateWindow(void)
53332001f49Smrg{
53432001f49Smrg   char title[1000];
53532001f49Smrg   struct window *w = (struct window *) calloc(1, sizeof(struct window));
53632001f49Smrg
53732001f49Smrg   glutInitWindowSize(INIT_WIDTH, INIT_HEIGHT);
53832001f49Smrg   w->id = glutCreateWindow("foo");
53932001f49Smrg   sprintf(title, "reflect window %d", w->id);
54032001f49Smrg   glutSetWindowTitle(title);
54132001f49Smrg   assert(w->id);
54232001f49Smrg   w->width = INIT_WIDTH;
54332001f49Smrg   w->height = INIT_HEIGHT;
54432001f49Smrg   w->anim = GL_TRUE;
54532001f49Smrg   w->xrot = 30.0;
54632001f49Smrg   w->yrot = 50.0;
54732001f49Smrg   w->spin = 0.0;
54832001f49Smrg   w->showBuffer = GL_NONE;
54932001f49Smrg   w->drawBuffer = GL_BACK;
55032001f49Smrg
55132001f49Smrg   InitWindow(w);
55232001f49Smrg
55332001f49Smrg   glutReshapeFunc(Reshape);
55432001f49Smrg   glutDisplayFunc(DrawWindow);
55532001f49Smrg   glutKeyboardFunc(Key);
55632001f49Smrg   glutSpecialFunc(SpecialKey);
55732001f49Smrg
55832001f49Smrg   /* insert at head of list */
55932001f49Smrg   w->next = FirstWindow;
56032001f49Smrg   FirstWindow = w;
56132001f49Smrg}
56232001f49Smrg
56332001f49Smrg
56432001f49Smrgstatic void
56532001f49SmrgUsage(void)
56632001f49Smrg{
56732001f49Smrg   printf("Keys:\n");
56832001f49Smrg   printf("  a      - show alpha buffer\n");
56932001f49Smrg   printf("  d      - show depth buffer\n");
57032001f49Smrg   printf("  s      - show stencil buffer\n");
57132001f49Smrg   printf("  c      - show color buffer\n");
57232001f49Smrg   printf("  f      - toggle rendering to front/back color buffer\n");
57332001f49Smrg   printf("  n      - create new window\n");
57432001f49Smrg   printf("  k      - kill window\n");
57532001f49Smrg   printf("  SPACE  - toggle animation\n");
57632001f49Smrg   printf("  ARROWS - rotate scene\n");
57732001f49Smrg}
57832001f49Smrg
57932001f49Smrg
58032001f49Smrgint
58132001f49Smrgmain(int argc, char *argv[])
58232001f49Smrg{
58332001f49Smrg   glutInit(&argc, argv);
58432001f49Smrg   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH |
58532001f49Smrg                       GLUT_STENCIL | GLUT_ALPHA);
58632001f49Smrg   CreateWindow();
58732001f49Smrg   glutIdleFunc(Idle);
58832001f49Smrg   Usage();
58932001f49Smrg   glutMainLoop();
59032001f49Smrg   return 0;
59132001f49Smrg}
592