diff options
author | Thierry Reding <[email protected]> | 2006-10-14 03:46:41 +0000 |
---|---|---|
committer | Thierry Reding <[email protected]> | 2006-10-14 03:46:41 +0000 |
commit | 1ddf606332a188e46a47607cd41eb5d81bdf4c8a (patch) | |
tree | 8cb51078803106d87aedeae7bbd7a762a0d369d1 /progs/demos/reflect.c |
Import Mesa 6.5.1 (MesaLib, MesaDemos, MesaGLUT).
Diffstat (limited to 'progs/demos/reflect.c')
-rw-r--r-- | progs/demos/reflect.c | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/progs/demos/reflect.c b/progs/demos/reflect.c new file mode 100644 index 00000000000..0bec0663bc2 --- /dev/null +++ b/progs/demos/reflect.c @@ -0,0 +1,590 @@ +/* + * Demo of a reflective, texture-mapped surface with OpenGL. + * Brian Paul August 14, 1995 This file is in the public domain. + * + * Hardware texture mapping is highly recommended! + * + * The basic steps are: + * 1. Render the reflective object (a polygon) from the normal viewpoint, + * setting the stencil planes = 1. + * 2. Render the scene from a special viewpoint: the viewpoint which + * is on the opposite side of the reflective plane. Only draw where + * stencil = 1. This draws the objects in the reflective surface. + * 3. Render the scene from the original viewpoint. This draws the + * objects in the normal fashion. Use blending when drawing + * the reflective, textured surface. + * + * This is a very crude demo. It could be much better. + */ + +/* + * Authors: + * Brian Paul + * Dirk Reiners ([email protected]) made some modifications to this code. + * Mark Kilgard (April 1997) + * Brian Paul (April 2000 - added keyboard d/s options) + * Brian Paul (August 2005 - added multi window feature) + */ + + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "GL/glut.h" +#include "showbuffer.h" +#include "readtex.h" + + +#define DEG2RAD (3.14159/180.0) +#define TABLE_TEXTURE "../images/tile.rgb" +#define MAX_OBJECTS 2 +#define INIT_WIDTH 400 +#define INIT_HEIGHT 300 + +#ifdef _WIN32 +#undef CreateWindowA +#endif + +struct window { + int id; /* returned by glutCreateWindow() */ + int width, height; + GLboolean anim; + GLfloat xrot, yrot; + GLfloat spin; + GLenum showBuffer; + GLenum drawBuffer; + GLuint table_list; + GLuint objects_list[MAX_OBJECTS]; + double t0; + struct window *next; +}; + + +static struct window *FirstWindow = NULL; + + +static void +CreateWindow(void); + + +static struct window * +CurrentWindow(void) +{ + int id = glutGetWindow(); + struct window *w; + for (w = FirstWindow; w; w = w->next) { + if (w->id == id) + return w; + } + return NULL; +} + + +static GLboolean +AnyAnimating(void) +{ + struct window *w; + for (w = FirstWindow; w; w = w->next) { + if (w->anim) + return 1; + } + return 0; +} + + +static void +KillWindow(struct window *w) +{ + struct window *win, *prev = NULL; + for (win = FirstWindow; win; win = win->next) { + if (win == w) { + if (prev) { + prev->next = win->next; + } + else { + FirstWindow = win->next; + } + glutDestroyWindow(win->id); + win->next = NULL; + free(win); + return; + } + prev = win; + } +} + + +static void +KillAllWindows(void) +{ + while (FirstWindow) + KillWindow(FirstWindow); +} + + +static GLuint +MakeTable(void) +{ + static GLfloat table_mat[] = { 1.0, 1.0, 1.0, 0.6 }; + static GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 }; + GLuint table_list; + + table_list = glGenLists(1); + glNewList( table_list, GL_COMPILE ); + + /* load table's texture */ + glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_mat ); + /*glMaterialfv( GL_FRONT, GL_EMISSION, gray );*/ + glMaterialfv( GL_FRONT, GL_DIFFUSE, table_mat ); + glMaterialfv( GL_FRONT, GL_AMBIENT, gray ); + + /* draw textured square for the table */ + glPushMatrix(); + glScalef( 4.0, 4.0, 4.0 ); + glBegin( GL_POLYGON ); + glNormal3f( 0.0, 1.0, 0.0 ); + glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 0.0, 1.0 ); + glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, 0.0, 1.0 ); + glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 0.0, -1.0 ); + glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 0.0, -1.0 ); + glEnd(); + glPopMatrix(); + + glDisable( GL_TEXTURE_2D ); + + glEndList(); + return table_list; +} + + +static void +MakeObjects(GLuint *objects_list) +{ + GLUquadricObj *q; + + static GLfloat cyan[] = { 0.0, 1.0, 1.0, 1.0 }; + static GLfloat green[] = { 0.2, 1.0, 0.2, 1.0 }; + static GLfloat black[] = { 0.0, 0.0, 0.0, 0.0 }; + + q = gluNewQuadric(); + gluQuadricDrawStyle( q, GLU_FILL ); + gluQuadricNormals( q, GLU_SMOOTH ); + + objects_list[0] = glGenLists(1); + glNewList( objects_list[0], GL_COMPILE ); + glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cyan ); + glMaterialfv( GL_FRONT, GL_EMISSION, black ); + gluCylinder( q, 0.5, 0.5, 1.0, 15, 1 ); + glEndList(); + + objects_list[1] = glGenLists(1); + glNewList( objects_list[1], GL_COMPILE ); + glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green ); + glMaterialfv( GL_FRONT, GL_EMISSION, black ); + gluCylinder( q, 1.5, 0.0, 2.5, 15, 1 ); + glEndList(); + + gluDeleteQuadric(q); +} + + +static void +InitWindow(struct window *w) +{ + GLint imgWidth, imgHeight; + GLenum imgFormat; + GLubyte *image = NULL; + + w->table_list = MakeTable(); + MakeObjects(w->objects_list); + + image = LoadRGBImage( TABLE_TEXTURE, &imgWidth, &imgHeight, &imgFormat ); + if (!image) { + printf("Couldn't read %s\n", TABLE_TEXTURE); + exit(0); + } + + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight, + imgFormat, GL_UNSIGNED_BYTE, image); + free(image); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + glShadeModel( GL_FLAT ); + + glEnable( GL_LIGHT0 ); + glEnable( GL_LIGHTING ); + + glClearColor( 0.5, 0.5, 0.9, 0.0 ); + + glEnable( GL_NORMALIZE ); +} + + +static void +Reshape(int width, int height) +{ + struct window *w = CurrentWindow(); + GLfloat yAspect = 2.5; + GLfloat xAspect = yAspect * (float) width / (float) height; + w->width = width; + w->height = height; + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -xAspect, xAspect, -yAspect, yAspect, 10.0, 30.0 ); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + + +static void +DrawObjects(struct window *w, GLfloat eyex, GLfloat eyey, GLfloat eyez) +{ + (void) eyex; + (void) eyey; + (void) eyez; +#ifndef USE_ZBUFFER + if (eyex<0.5) { +#endif + glPushMatrix(); + glTranslatef( 1.0, 1.5, 0.0 ); + glRotatef( w->spin, 1.0, 0.5, 0.0 ); + glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 ); + glCallList( w->objects_list[0] ); + glPopMatrix(); + + glPushMatrix(); + glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w->spin) ), 0.0 ); + glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 ); + glRotatef( w->spin, 1.0, 0.5, 0.0 ); + glScalef( 0.5, 0.5, 0.5 ); + glCallList( w->objects_list[1] ); + glPopMatrix(); +#ifndef USE_ZBUFFER + } + else { + glPushMatrix(); + glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w->spin) ), 0.0 ); + glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 ); + glRotatef( w->spin, 1.0, 0.5, 0.0 ); + glScalef( 0.5, 0.5, 0.5 ); + glCallList( w->objects_list[1] ); + glPopMatrix(); + + glPushMatrix(); + glTranslatef( 1.0, 1.5, 0.0 ); + glRotatef( w->spin, 1.0, 0.5, 0.0 ); + glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 ); + glCallList( w->objects_list[0] ); + glPopMatrix(); + } +#endif +} + + +static void +DrawTable(struct window *w) +{ + glCallList(w->table_list); +} + + +static void +DrawWindow(void) +{ + struct window *w = CurrentWindow(); + static GLfloat light_pos[] = { 0.0, 20.0, 0.0, 1.0 }; + GLfloat dist = 20.0; + GLfloat eyex, eyey, eyez; + + if (w->drawBuffer == GL_NONE) { + glDrawBuffer(GL_BACK); + glReadBuffer(GL_BACK); + } + else { + glDrawBuffer(w->drawBuffer); + glReadBuffer(w->drawBuffer); + } + + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + if (w->drawBuffer == GL_NONE) { + glDrawBuffer(GL_NONE); + } + + eyex = dist * cos(w->yrot * DEG2RAD) * cos(w->xrot * DEG2RAD); + eyez = dist * sin(w->yrot * DEG2RAD) * cos(w->xrot * DEG2RAD); + eyey = dist * sin(w->xrot * DEG2RAD); + + /* view from top */ + glPushMatrix(); + gluLookAt( eyex, eyey, eyez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ); + + glLightfv( GL_LIGHT0, GL_POSITION, light_pos ); + + /* draw table into stencil planes */ + glDisable( GL_DEPTH_TEST ); + glEnable( GL_STENCIL_TEST ); + glStencilFunc( GL_ALWAYS, 1, 0xffffffff ); + glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ); + glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); + DrawTable(w); + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + + glEnable( GL_DEPTH_TEST ); + + /* render view from below (reflected viewport) */ + /* only draw where stencil==1 */ + if (eyey>0.0) { + glPushMatrix(); + + glStencilFunc( GL_EQUAL, 1, 0xffffffff ); /* draw if ==1 */ + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + glScalef( 1.0, -1.0, 1.0 ); + + /* Reposition light in reflected space. */ + glLightfv(GL_LIGHT0, GL_POSITION, light_pos); + + DrawObjects(w, eyex, eyey, eyez); + glPopMatrix(); + + /* Restore light's original unreflected position. */ + glLightfv(GL_LIGHT0, GL_POSITION, light_pos); + } + + glDisable( GL_STENCIL_TEST ); + + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + glEnable( GL_TEXTURE_2D ); + DrawTable(w); + glDisable( GL_TEXTURE_2D ); + glDisable( GL_BLEND ); + + /* view from top */ + glPushMatrix(); + + DrawObjects(w, eyex, eyey, eyez); + + glPopMatrix(); + + glPopMatrix(); + + if (w->showBuffer == GL_DEPTH) { + ShowDepthBuffer(w->width, w->height, 1.0, 0.0); + } + else if (w->showBuffer == GL_STENCIL) { + ShowStencilBuffer(w->width, w->height, 255.0, 0.0); + } + else if (w->showBuffer == GL_ALPHA) { + ShowAlphaBuffer(w->width, w->height); + } + + if (w->drawBuffer == GL_FRONT) + glFinish(); + else + glutSwapBuffers(); + + /* calc/show frame rate */ + { + static GLint t0 = 0; + static GLint frames = 0; + GLint t = glutGet(GLUT_ELAPSED_TIME); + frames++; + if (t - t0 >= 5000) { + GLfloat seconds = (t - t0) / 1000.0; + GLfloat fps = frames / seconds; + printf("%d frames in %g seconds = %g FPS\n", frames, seconds, fps); + t0 = t; + frames = 0; + } + } +} + + +static void +Idle(void) +{ + double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; + struct window *w; + for (w = FirstWindow; w; w = w->next) { + if (w->anim) { + double dt; + if (w->t0 < 0.0) + w->t0 = t; + dt = t - w->t0; + w->t0 = t; + w->spin += 60.0 * dt; + w->yrot += 90.0 * dt; + assert(w->id); + glutSetWindow(w->id); + glutPostRedisplay(); + } + } +} + + +static void +UpdateIdleFunc(void) +{ + if (AnyAnimating()) + glutIdleFunc(Idle); + else + glutIdleFunc(NULL); +} + +static void +Key(unsigned char key, int x, int y) +{ + struct window *w = CurrentWindow(); + (void) x; + (void) y; + + switch (key) { + case 'd': + w->showBuffer = GL_DEPTH; + glutPostRedisplay(); + break; + case 's': + w->showBuffer = GL_STENCIL; + glutPostRedisplay(); + break; + case 'a': + w->showBuffer = GL_ALPHA; + glutPostRedisplay(); + break; + case 'c': + w->showBuffer = GL_NONE; + glutPostRedisplay(); + break; + case 'f': + if (w->drawBuffer == GL_FRONT) + w->drawBuffer = GL_BACK; + else + w->drawBuffer = GL_FRONT; + glutPostRedisplay(); + break; + case '0': + w->drawBuffer = GL_NONE; + glutPostRedisplay(); + break; + case ' ': + w->anim = !w->anim; + w->t0 = -1; + UpdateIdleFunc(); + glutPostRedisplay(); + break; + case 'n': + CreateWindow(); + UpdateIdleFunc(); + break; + case 'k': + KillWindow(w); + if (FirstWindow == NULL) + exit(0); + break; + case 27: + KillAllWindows(); + exit(0); + break; + default: + ; + } +} + + +static void +SpecialKey(int key, int x, int y) +{ + struct window *w = CurrentWindow(); + (void) x; + (void) y; + switch (key) { + case GLUT_KEY_UP: + w->xrot += 3.0; + if (w->xrot > 85) + w->xrot = 85; + break; + case GLUT_KEY_DOWN: + w->xrot -= 3.0; + if (w->xrot < 5) + w->xrot = 5; + break; + case GLUT_KEY_LEFT: + w->yrot += 3.0; + break; + case GLUT_KEY_RIGHT: + w->yrot -= 3.0; + break; + } + glutPostRedisplay(); +} + + +static void +CreateWindow(void) +{ + char title[1000]; + struct window *w = (struct window *) calloc(1, sizeof(struct window)); + + glutInitWindowSize(INIT_WIDTH, INIT_HEIGHT); + w->id = glutCreateWindow("foo"); + sprintf(title, "reflect window %d", w->id); + glutSetWindowTitle(title); + assert(w->id); + w->width = INIT_WIDTH; + w->height = INIT_HEIGHT; + w->anim = GL_TRUE; + w->xrot = 30.0; + w->yrot = 50.0; + w->spin = 0.0; + w->showBuffer = GL_NONE; + w->drawBuffer = GL_BACK; + + InitWindow(w); + + glutReshapeFunc(Reshape); + glutDisplayFunc(DrawWindow); + glutKeyboardFunc(Key); + glutSpecialFunc(SpecialKey); + + /* insert at head of list */ + w->next = FirstWindow; + FirstWindow = w; +} + + +static void +Usage(void) +{ + printf("Keys:\n"); + printf(" a - show alpha buffer\n"); + printf(" d - show depth buffer\n"); + printf(" s - show stencil buffer\n"); + printf(" c - show color buffer\n"); + printf(" f - toggle rendering to front/back color buffer\n"); + printf(" n - create new window\n"); + printf(" k - kill window\n"); + printf(" SPACE - toggle animation\n"); + printf(" ARROWS - rotate scene\n"); +} + + +int +main(int argc, char *argv[]) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | + GLUT_STENCIL | GLUT_ALPHA); + CreateWindow(); + glutIdleFunc(Idle); + Usage(); + glutMainLoop(); + return 0; +} |