2000-09-15 17:43:57 +01:00
|
|
|
/* $Id: reflect.c,v 1.4 2000/09/15 16:43:57 brianp Exp $ */
|
1999-08-19 01:55:39 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2000-04-12 02:08:30 +01:00
|
|
|
* Authors:
|
|
|
|
* Brian Paul
|
|
|
|
* Dirk Reiners (reiners@igd.fhg.de) made some modifications to this code.
|
|
|
|
* Mark Kilgard (April 1997)
|
|
|
|
* Brian Paul (April 2000 - added keyboard d/s options)
|
1999-08-19 01:55:39 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "GL/glut.h"
|
2000-04-12 02:08:30 +01:00
|
|
|
#include "../util/showbuffer.c"
|
|
|
|
#include "../util/readtex.c"
|
1999-08-19 01:55:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
#define DEG2RAD (3.14159/180.0)
|
|
|
|
|
|
|
|
#define TABLE_TEXTURE "../images/tile.rgb"
|
|
|
|
|
2000-04-12 02:08:30 +01:00
|
|
|
static GLint ImgWidth, ImgHeight;
|
1999-08-19 01:55:39 +01:00
|
|
|
static GLenum ImgFormat;
|
|
|
|
static GLubyte *Image = NULL;
|
|
|
|
|
|
|
|
#define MAX_OBJECTS 2
|
|
|
|
static GLint table_list;
|
|
|
|
static GLint objects_list[MAX_OBJECTS];
|
|
|
|
|
|
|
|
static GLfloat xrot, yrot;
|
|
|
|
static GLfloat spin;
|
|
|
|
|
2000-04-12 02:08:30 +01:00
|
|
|
static GLint Width = 400, Height = 300;
|
|
|
|
static GLenum ShowBuffer = GL_NONE;
|
|
|
|
|
2000-09-15 17:43:57 +01:00
|
|
|
/* performance info */
|
|
|
|
static GLint T0 = 0;
|
|
|
|
static GLint Frames = 0;
|
1999-08-19 01:55:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
static void make_table( void )
|
|
|
|
{
|
|
|
|
static GLfloat table_mat[] = { 1.0, 1.0, 1.0, 0.6 };
|
|
|
|
static GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 };
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void make_objects( void )
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void init( void )
|
|
|
|
{
|
|
|
|
make_table();
|
|
|
|
make_objects();
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
|
|
|
xrot = 30.0;
|
|
|
|
yrot = 50.0;
|
|
|
|
spin = 0.0;
|
|
|
|
|
|
|
|
glShadeModel( GL_FLAT );
|
|
|
|
|
|
|
|
glEnable( GL_LIGHT0 );
|
|
|
|
glEnable( GL_LIGHTING );
|
|
|
|
|
|
|
|
glClearColor( 0.5, 0.5, 0.9, 1.0 );
|
|
|
|
|
|
|
|
glEnable( GL_NORMALIZE );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void reshape(int w, int h)
|
|
|
|
{
|
2000-04-12 02:08:30 +01:00
|
|
|
GLfloat yAspect = 2.5;
|
|
|
|
GLfloat xAspect = yAspect * (float) w / (float) h;
|
|
|
|
Width = w;
|
|
|
|
Height = h;
|
1999-08-19 01:55:39 +01:00
|
|
|
glViewport(0, 0, w, h);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
2000-04-12 02:08:30 +01:00
|
|
|
glFrustum( -xAspect, xAspect, -yAspect, yAspect, 10.0, 30.0 );
|
1999-08-19 01:55:39 +01:00
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void draw_objects( GLfloat eyex, GLfloat eyey, GLfloat eyez )
|
|
|
|
{
|
|
|
|
(void) eyex;
|
|
|
|
(void) eyey;
|
|
|
|
(void) eyez;
|
|
|
|
#ifndef USE_ZBUFFER
|
2000-04-12 02:08:30 +01:00
|
|
|
if (eyex<0.5) {
|
1999-08-19 01:55:39 +01:00
|
|
|
#endif
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef( 1.0, 1.5, 0.0 );
|
|
|
|
glRotatef( spin, 1.0, 0.5, 0.0 );
|
|
|
|
glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
|
|
|
|
glCallList( objects_list[0] );
|
|
|
|
glPopMatrix();
|
|
|
|
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*spin) ), 0.0 );
|
|
|
|
glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
|
|
|
|
glRotatef( spin, 1.0, 0.5, 0.0 );
|
|
|
|
glScalef( 0.5, 0.5, 0.5 );
|
|
|
|
glCallList( objects_list[1] );
|
|
|
|
glPopMatrix();
|
|
|
|
#ifndef USE_ZBUFFER
|
2000-04-12 02:08:30 +01:00
|
|
|
}
|
|
|
|
else {
|
1999-08-19 01:55:39 +01:00
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*spin) ), 0.0 );
|
|
|
|
glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
|
|
|
|
glRotatef( spin, 1.0, 0.5, 0.0 );
|
|
|
|
glScalef( 0.5, 0.5, 0.5 );
|
|
|
|
glCallList( objects_list[1] );
|
|
|
|
glPopMatrix();
|
|
|
|
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef( 1.0, 1.5, 0.0 );
|
|
|
|
glRotatef( spin, 1.0, 0.5, 0.0 );
|
|
|
|
glRotatef( 0.5*spin, 0.0, 0.5, 1.0 );
|
|
|
|
glCallList( objects_list[0] );
|
|
|
|
glPopMatrix();
|
2000-04-12 02:08:30 +01:00
|
|
|
}
|
1999-08-19 01:55:39 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void draw_table( void )
|
|
|
|
{
|
|
|
|
glCallList( table_list );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void draw_scene( void )
|
|
|
|
{
|
2000-04-12 02:08:30 +01:00
|
|
|
static GLfloat light_pos[] = { 0.0, 20.0, 0.0, 1.0 };
|
1999-08-19 01:55:39 +01:00
|
|
|
GLfloat dist = 20.0;
|
|
|
|
GLfloat eyex, eyey, eyez;
|
|
|
|
|
|
|
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
|
|
|
|
|
|
|
|
|
|
|
eyex = dist * cos(yrot*DEG2RAD) * cos(xrot*DEG2RAD);
|
|
|
|
eyez = dist * sin(yrot*DEG2RAD) * cos(xrot*DEG2RAD);
|
|
|
|
eyey = dist * sin(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 );
|
2000-04-12 02:08:30 +01:00
|
|
|
glEnable( GL_STENCIL_TEST );
|
1999-08-19 01:55:39 +01:00
|
|
|
glStencilFunc( GL_ALWAYS, 1, 0xffffffff );
|
|
|
|
glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
|
|
|
|
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
|
|
draw_table();
|
|
|
|
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);
|
|
|
|
|
|
|
|
draw_objects(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 );
|
|
|
|
draw_table();
|
|
|
|
glDisable( GL_TEXTURE_2D );
|
|
|
|
glDisable( GL_BLEND );
|
|
|
|
|
|
|
|
/* view from top */
|
|
|
|
glPushMatrix();
|
|
|
|
|
|
|
|
draw_objects(eyex, eyey, eyez);
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
|
2000-04-12 02:08:30 +01:00
|
|
|
if (ShowBuffer == GL_DEPTH) {
|
|
|
|
ShowDepthBuffer(Width, Height, 1.0, 0.0);
|
|
|
|
}
|
|
|
|
else if (ShowBuffer == GL_STENCIL) {
|
|
|
|
ShowStencilBuffer(Width, Height, 255.0, 0.0);
|
|
|
|
}
|
1999-08-19 01:55:39 +01:00
|
|
|
|
|
|
|
glutSwapBuffers();
|
2000-09-15 17:43:57 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
1999-08-19 01:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void Key( unsigned char key, int x, int y )
|
|
|
|
{
|
|
|
|
(void) x;
|
|
|
|
(void) y;
|
2000-04-12 02:08:30 +01:00
|
|
|
if (key == 'd') {
|
|
|
|
ShowBuffer = GL_DEPTH;
|
|
|
|
}
|
|
|
|
else if (key == 's') {
|
|
|
|
ShowBuffer = GL_STENCIL;
|
|
|
|
}
|
|
|
|
else if (key==27) {
|
1999-08-19 01:55:39 +01:00
|
|
|
exit(0);
|
2000-04-12 02:08:30 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ShowBuffer = GL_NONE;
|
|
|
|
}
|
|
|
|
glutPostRedisplay();
|
1999-08-19 01:55:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void SpecialKey( int key, int x, int y )
|
|
|
|
{
|
|
|
|
(void) x;
|
|
|
|
(void) y;
|
|
|
|
switch (key) {
|
|
|
|
case GLUT_KEY_UP:
|
|
|
|
xrot += 3.0;
|
2000-04-12 02:08:30 +01:00
|
|
|
if ( xrot > 85 )
|
|
|
|
xrot = 85;
|
1999-08-19 01:55:39 +01:00
|
|
|
break;
|
|
|
|
case GLUT_KEY_DOWN:
|
|
|
|
xrot -= 3.0;
|
2000-04-12 02:08:30 +01:00
|
|
|
if ( xrot < 5 )
|
|
|
|
xrot = 5;
|
1999-08-19 01:55:39 +01:00
|
|
|
break;
|
|
|
|
case GLUT_KEY_LEFT:
|
|
|
|
yrot += 3.0;
|
|
|
|
break;
|
|
|
|
case GLUT_KEY_RIGHT:
|
|
|
|
yrot -= 3.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
glutPostRedisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void idle( void )
|
|
|
|
{
|
|
|
|
spin += 2.0;
|
|
|
|
yrot += 3.0;
|
|
|
|
glutPostRedisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main( int argc, char *argv[] )
|
|
|
|
{
|
2000-06-15 15:25:48 +01:00
|
|
|
glutInit(&argc, argv);
|
2000-04-12 02:08:30 +01:00
|
|
|
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL);
|
1999-08-19 01:55:39 +01:00
|
|
|
glutInitWindowPosition( 0, 0 );
|
2000-04-12 02:08:30 +01:00
|
|
|
glutInitWindowSize( Width, Height );
|
1999-08-19 01:55:39 +01:00
|
|
|
glutCreateWindow(argv[0]);
|
|
|
|
glutReshapeFunc(reshape);
|
|
|
|
glutDisplayFunc(draw_scene);
|
|
|
|
glutKeyboardFunc(Key);
|
|
|
|
glutSpecialFunc(SpecialKey);
|
|
|
|
glutIdleFunc(idle);
|
|
|
|
init();
|
|
|
|
glutMainLoop();
|
|
|
|
return 0;
|
|
|
|
}
|