579 lines
12 KiB
C++
579 lines
12 KiB
C++
|
#include <stdlib.h>
|
||
|
#include <stdio.h>
|
||
|
#include <math.h>
|
||
|
#include <string.h>
|
||
|
#include <time.h>
|
||
|
#include <assert.h>
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <gl\gl.h>
|
||
|
#include <gl\glu.h>
|
||
|
#include <gl\glaux.h>
|
||
|
|
||
|
#include "mtk.hxx"
|
||
|
#include "objects.hxx"
|
||
|
#include "wave.hxx"
|
||
|
|
||
|
#define WIDTH 256
|
||
|
#define HEIGHT 256
|
||
|
|
||
|
float fViewDist = 10.0f;
|
||
|
float fTrans = 0.0f;
|
||
|
//#define FTRANSINC 0.05f
|
||
|
#define FTRANSINC 0.02f
|
||
|
float fTransInc = -FTRANSINC;
|
||
|
|
||
|
BOOL bDestAlpha;
|
||
|
|
||
|
|
||
|
#define TESS_MIN 5
|
||
|
#define TESS_MAX 100
|
||
|
//int tessLevel = TESS_MAX / 2; // corresponds to # of rings/sections in object
|
||
|
int tessLevel = 30; // corresponds to # of rings/sections in object
|
||
|
int tessInc = 5;
|
||
|
|
||
|
class DRAW_CONTROLLER {
|
||
|
public:
|
||
|
DRAW_CONTROLLER::DRAW_CONTROLLER();
|
||
|
DRAW_CONTROLLER::~DRAW_CONTROLLER() {};
|
||
|
void InitGL();
|
||
|
void ToggleLighting() {bLighting = !bLighting; SetLighting(); }
|
||
|
void SetLighting();
|
||
|
void SetDrawObject( OBJECT *pObj, int objectType );
|
||
|
void DrawObject();
|
||
|
void NextRotation();
|
||
|
|
||
|
//mf : this may move
|
||
|
// Object rotation
|
||
|
GLfloat fXr, fYr, fZr;
|
||
|
GLfloat fDXr, fDYr, fDZr;
|
||
|
|
||
|
private:
|
||
|
void DrawVertexArray();
|
||
|
|
||
|
BOOL bLighting;
|
||
|
OBJECT *pObject; // Draw object
|
||
|
int iObjectType;
|
||
|
};
|
||
|
|
||
|
class SCENE {
|
||
|
public:
|
||
|
SCENE();
|
||
|
~SCENE();
|
||
|
void Draw();
|
||
|
void DrawMembrane();
|
||
|
void NewObject( int tessLevel );
|
||
|
DRAW_CONTROLLER drawController;
|
||
|
private:
|
||
|
void DrawUsingAlphaBuffer();
|
||
|
void DrawNormally();
|
||
|
// Scene rotation
|
||
|
GLfloat fXr, fYr, fZr;
|
||
|
GLfloat fDXr, fDYr, fDZr;
|
||
|
};
|
||
|
|
||
|
// Global objects
|
||
|
SCENE *scene;
|
||
|
SPHERE *sphere;
|
||
|
AVG_UPDATE_TIMER timer( 2.0f, 4 );
|
||
|
|
||
|
#define RGB_COLOR(red, green, blue) \
|
||
|
(((DWORD)(BYTE)(red) << 0) | \
|
||
|
((DWORD)(BYTE)(green) << 8) | \
|
||
|
((DWORD)(BYTE)(blue) << 16))
|
||
|
|
||
|
#define RGBA_COLOR(red, green, blue, alpha) \
|
||
|
(((DWORD)(BYTE)(red) << 0) | \
|
||
|
((DWORD)(BYTE)(green) << 8) | \
|
||
|
((DWORD)(BYTE)(blue) << 16) | \
|
||
|
((DWORD)(BYTE)(alpha) << 24))
|
||
|
|
||
|
#define FRANDOM(x) (((float)rand() / RAND_MAX) * (x))
|
||
|
|
||
|
#define DROT 10.0f
|
||
|
|
||
|
BOOL fSingleBuf = FALSE;
|
||
|
|
||
|
// forwards
|
||
|
static void SetGLState(); // volatile state
|
||
|
|
||
|
|
||
|
/****** DRAW_CONTROLLER *********************************************/
|
||
|
|
||
|
DRAW_CONTROLLER::DRAW_CONTROLLER( )
|
||
|
{
|
||
|
bLighting = TRUE;
|
||
|
|
||
|
// Init GL state
|
||
|
InitGL();
|
||
|
|
||
|
// Init object rotation and motion
|
||
|
fXr = 0.0f;
|
||
|
fYr = 0.0f;
|
||
|
fZr = 0.0f;
|
||
|
fDXr = DROT - FRANDOM(2 * DROT);
|
||
|
fDYr = DROT - FRANDOM(2 * DROT);
|
||
|
fDZr = DROT - FRANDOM(2 * DROT);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DRAW_CONTROLLER::SetDrawObject( OBJECT *pObj, int objectType )
|
||
|
{
|
||
|
iObjectType = objectType;
|
||
|
pObject = pObj;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
DRAW_CONTROLLER::DrawObject()
|
||
|
{
|
||
|
// Set object position, rotation, and draw it
|
||
|
|
||
|
glPushMatrix();
|
||
|
|
||
|
#if 0
|
||
|
glTranslatef( 0.0f, 0.0f, -0.8f );
|
||
|
#else
|
||
|
glTranslatef( 0.0f, 0.0f, fTrans );
|
||
|
#endif
|
||
|
|
||
|
glRotatef(fXr, 1.0f, 0.0f, 0.0f);
|
||
|
glRotatef(fYr, 0.0f, 1.0f, 0.0f);
|
||
|
glRotatef(fZr, 0.0f, 0.0f, 1.0f);
|
||
|
|
||
|
DrawVertexArray();
|
||
|
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DRAW_CONTROLLER::DrawVertexArray()
|
||
|
{
|
||
|
glDrawElements(GL_TRIANGLES,
|
||
|
pObject->TriangleCount()*3,
|
||
|
GL_UNSIGNED_INT,
|
||
|
pObject->TriangleData() );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DRAW_CONTROLLER::NextRotation()
|
||
|
{
|
||
|
// increment object rotation
|
||
|
fXr += fDXr;
|
||
|
fYr += fDYr;
|
||
|
fZr += fDZr;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DRAW_CONTROLLER::InitGL(void)
|
||
|
{
|
||
|
float fv4[4];
|
||
|
int iv1[1];
|
||
|
int i;
|
||
|
|
||
|
fv4[0] = 0.05f;
|
||
|
fv4[1] = 0.05f;
|
||
|
fv4[2] = 0.05f;
|
||
|
fv4[3] = 1.0f;
|
||
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fv4);
|
||
|
|
||
|
fv4[0] = 0.0f;
|
||
|
fv4[1] = 1.0f;
|
||
|
fv4[2] = 1.0f;
|
||
|
fv4[3] = 0.0f;
|
||
|
glLightfv(GL_LIGHT0, GL_POSITION, fv4);
|
||
|
fv4[0] = 0.9f;
|
||
|
fv4[1] = 0.9f;
|
||
|
fv4[2] = 0.9f;
|
||
|
fv4[3] = 1.0f;
|
||
|
glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4);
|
||
|
glEnable(GL_LIGHT0);
|
||
|
glEnable(GL_LIGHTING);
|
||
|
|
||
|
fv4[0] = 0.6f;
|
||
|
fv4[1] = 0.6f;
|
||
|
fv4[2] = 0.6f;
|
||
|
fv4[3] = 1.0f;
|
||
|
glMaterialfv(GL_FRONT, GL_SPECULAR, fv4);
|
||
|
iv1[0] = 40;
|
||
|
glMaterialiv(GL_FRONT, GL_SHININESS, iv1);
|
||
|
|
||
|
glEnable(GL_CULL_FACE);
|
||
|
|
||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||
|
glEnableClientState(GL_NORMAL_ARRAY);
|
||
|
glEnableClientState(GL_COLOR_ARRAY);
|
||
|
|
||
|
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
||
|
glEnable(GL_COLOR_MATERIAL);
|
||
|
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
gluPerspective(45, 1, .01, 15);
|
||
|
gluLookAt(0, 0, fViewDist, 0, 0, 0, 0, 1, 0);
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
|
||
|
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
||
|
|
||
|
SetLighting();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
DRAW_CONTROLLER::SetLighting(void)
|
||
|
{
|
||
|
if( bLighting ) {
|
||
|
glEnable( GL_LIGHTING );
|
||
|
} else {
|
||
|
glDisable( GL_LIGHTING );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/****** SCENE *******************************************************/
|
||
|
|
||
|
|
||
|
SCENE::SCENE()
|
||
|
{
|
||
|
srand(time(NULL));
|
||
|
|
||
|
// Create sphere draw object for the scene
|
||
|
NewObject( tessLevel );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
SCENE::NewObject( int tessLevel )
|
||
|
{
|
||
|
// Only one object allowed for now - delete any previous object
|
||
|
if( sphere )
|
||
|
delete sphere;
|
||
|
|
||
|
// Create new sphere for the scene
|
||
|
float fAlpha = 0.5f;
|
||
|
sphere = new SPHERE( tessLevel, tessLevel, fAlpha );
|
||
|
assert( sphere != NULL );
|
||
|
|
||
|
// Inform DRAW_CONTROLLER about new object
|
||
|
drawController.SetDrawObject( sphere, OBJECT_TYPE_SPHERE );
|
||
|
|
||
|
// Initialize array pointer data
|
||
|
SetGLState();
|
||
|
|
||
|
VERTEX *pVertData = sphere->VertexData();
|
||
|
glVertexPointer(3, GL_FLOAT, sizeof(VERTEX), &pVertData->fX);
|
||
|
glNormalPointer(GL_FLOAT, sizeof(VERTEX), &pVertData->fNx);
|
||
|
// Color pointer data is dependent on state...
|
||
|
SetGLState();
|
||
|
|
||
|
// Init scene rotation and motion
|
||
|
fXr = 0.0f;
|
||
|
fYr = 0.0f;
|
||
|
fZr = 0.0f;
|
||
|
fDXr = DROT - FRANDOM(2 * DROT);
|
||
|
fDYr = DROT - FRANDOM(2 * DROT);
|
||
|
fDZr = DROT - FRANDOM(2 * DROT);
|
||
|
}
|
||
|
|
||
|
SCENE::~SCENE()
|
||
|
{
|
||
|
// Delete any scene objects
|
||
|
if( sphere )
|
||
|
delete sphere;
|
||
|
}
|
||
|
|
||
|
/******************************Public*Routine******************************\
|
||
|
* Draw
|
||
|
*
|
||
|
* Draw the scene using src or dst alpha blending.
|
||
|
*
|
||
|
\**************************************************************************/
|
||
|
|
||
|
void
|
||
|
SCENE::Draw()
|
||
|
{
|
||
|
if( bDestAlpha )
|
||
|
DrawUsingAlphaBuffer();
|
||
|
else
|
||
|
DrawNormally();
|
||
|
|
||
|
// Inrement object rotation
|
||
|
drawController.NextRotation();
|
||
|
|
||
|
if( fTrans < -1.2f ) {
|
||
|
fTransInc = FTRANSINC;
|
||
|
} else if( fTrans > 0.5f ) {
|
||
|
fTransInc = -FTRANSINC;
|
||
|
}
|
||
|
|
||
|
fTrans += fTransInc;
|
||
|
}
|
||
|
|
||
|
/**************************************************************************\
|
||
|
* DrawUsingAlphaBuffer
|
||
|
*
|
||
|
* The destination alpha buffer is used to optimize drawing. The optimization
|
||
|
* is based on the fact that the objects cover a small area compared to the
|
||
|
* entire window. Blending, which is slow, only occurs over the area occupied
|
||
|
* by the object. Without the alpha buffer, blending must occur over the entire
|
||
|
* window.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
void
|
||
|
SCENE::DrawUsingAlphaBuffer()
|
||
|
{
|
||
|
glClear( GL_DEPTH_BUFFER_BIT );
|
||
|
|
||
|
glLoadIdentity();
|
||
|
|
||
|
glEnable( GL_DEPTH_TEST );
|
||
|
glDepthFunc( GL_ALWAYS );
|
||
|
|
||
|
DrawMembrane();
|
||
|
|
||
|
// Draw object's alpha values only on first pass
|
||
|
|
||
|
glDepthFunc( GL_LEQUAL );
|
||
|
|
||
|
//#define TURN_OFF_LIGHTING 1
|
||
|
#if TURN_OFF_LIGHTING
|
||
|
//mf: this makes it slower.. not sure why
|
||
|
glDisable( GL_LIGHTING );
|
||
|
#endif
|
||
|
|
||
|
glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE );
|
||
|
|
||
|
drawController.DrawObject();
|
||
|
|
||
|
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
|
||
|
|
||
|
#if TURN_OFF_LIGHTING
|
||
|
glEnable( GL_LIGHTING );
|
||
|
#endif
|
||
|
|
||
|
// set up dst alpha blending for next pass
|
||
|
glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA );
|
||
|
glEnable( GL_BLEND );
|
||
|
glDisable( GL_DEPTH_TEST );
|
||
|
|
||
|
// Draw object normally on second pass
|
||
|
|
||
|
drawController.DrawObject();
|
||
|
|
||
|
glDisable( GL_BLEND );
|
||
|
}
|
||
|
|
||
|
/**************************************************************************\
|
||
|
* DrawNormally
|
||
|
*
|
||
|
* The scene is drawn without using destination alpha buffer. The objects are
|
||
|
* drawn first, then the membrane is blended in afterwards.
|
||
|
\**************************************************************************/
|
||
|
|
||
|
void
|
||
|
SCENE::DrawNormally()
|
||
|
{
|
||
|
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
|
||
|
|
||
|
glLoadIdentity();
|
||
|
|
||
|
drawController.DrawObject();
|
||
|
|
||
|
// Blend the membrane with the objects already drawn
|
||
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||
|
glEnable( GL_BLEND );
|
||
|
DrawMembrane();
|
||
|
glDisable( GL_BLEND );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
SCENE::DrawMembrane()
|
||
|
{
|
||
|
float fSize = fViewDist;
|
||
|
|
||
|
glDisable( GL_LIGHTING );
|
||
|
|
||
|
glColor4f( 0.0f, 0.5f, 0.9f, 0.5f );
|
||
|
|
||
|
glBegin( GL_QUADS );
|
||
|
glVertex3f( fSize, fSize, 0.0f );
|
||
|
glVertex3f( -fSize, fSize, 0.0f );
|
||
|
glVertex3f( -fSize, -fSize, 0.0f );
|
||
|
glVertex3f( fSize, -fSize, 0.0f );
|
||
|
glEnd();
|
||
|
|
||
|
// Reinstate the current lighting model
|
||
|
drawController.SetLighting();
|
||
|
}
|
||
|
|
||
|
/********************************************************************/
|
||
|
|
||
|
void Reset()
|
||
|
{
|
||
|
// Called when display changes
|
||
|
|
||
|
// Remove any timing info from title bar, and reset the timer
|
||
|
SetWindowText(auxGetHWND(), "" );
|
||
|
timer.Reset();
|
||
|
timer.Start();
|
||
|
}
|
||
|
|
||
|
void NewTessLevel( int tessLevel )
|
||
|
{
|
||
|
static int oldTessLevel = 0; // to avoid unnecessary work
|
||
|
|
||
|
// retesselate scene's object
|
||
|
if( tessLevel == oldTessLevel )
|
||
|
return;
|
||
|
scene->NewObject( tessLevel );
|
||
|
|
||
|
Reset();
|
||
|
|
||
|
oldTessLevel = tessLevel;
|
||
|
}
|
||
|
|
||
|
void Draw(void)
|
||
|
{
|
||
|
DRAW_CONTROLLER *pDrawControl = &scene->drawController;
|
||
|
float updatesPerSecond;
|
||
|
|
||
|
// Draw the scene
|
||
|
|
||
|
scene->Draw();
|
||
|
|
||
|
if (fSingleBuf)
|
||
|
glFlush();
|
||
|
else
|
||
|
auxSwapBuffers();
|
||
|
|
||
|
// Print timing information if Stop returns TRUE
|
||
|
|
||
|
if( timer.Update( 1, &updatesPerSecond ) ) {
|
||
|
char szMsg[80];
|
||
|
sprintf(szMsg, "%s: %.2lf frames/sec",
|
||
|
"",
|
||
|
updatesPerSecond );
|
||
|
|
||
|
// Print timing info in title bar
|
||
|
SetWindowText(auxGetHWND(), szMsg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
SetGLState()
|
||
|
{
|
||
|
VERTEX *pVertData = sphere->VertexData();
|
||
|
|
||
|
// Set vertex array pointers
|
||
|
|
||
|
glVertexPointer(3, GL_FLOAT, sizeof(VERTEX), &pVertData->fX);
|
||
|
glNormalPointer(GL_FLOAT, sizeof(VERTEX), &pVertData->fNx);
|
||
|
// If using destination alpha blending, the object is drawn with alpha=1.0,
|
||
|
// so specify 3-valued rgb colors (a defaults to 1.0). Otherwise,
|
||
|
// the object is drawn using 4-valued rgba colors
|
||
|
int colorDataSize = bDestAlpha ? 3 : 4;
|
||
|
glColorPointer( colorDataSize, GL_UNSIGNED_BYTE, sizeof(VERTEX),
|
||
|
&pVertData->dwColor);
|
||
|
|
||
|
// Set other GL state
|
||
|
|
||
|
if( bDestAlpha ) {
|
||
|
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
|
||
|
} else {
|
||
|
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
|
||
|
glClearColor( 0.0f, 0.5f, 0.9f, 0.0f );
|
||
|
glEnable( GL_DEPTH_TEST );
|
||
|
glDepthFunc( GL_LEQUAL );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Reshape(GLsizei w, GLsizei h)
|
||
|
{
|
||
|
glViewport(0, 0, w, h);
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
void Keya(void)
|
||
|
{
|
||
|
bDestAlpha = !bDestAlpha;
|
||
|
SetGLState();
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
void Keyd(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void Keyl(void)
|
||
|
{
|
||
|
scene->drawController.ToggleLighting();
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
void KeySPACE(void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void KeyUp(void)
|
||
|
{
|
||
|
// increase tesselation
|
||
|
tessLevel += tessInc;
|
||
|
if( tessLevel > TESS_MAX )
|
||
|
tessLevel = TESS_MAX;
|
||
|
NewTessLevel( tessLevel );
|
||
|
}
|
||
|
|
||
|
void KeyDown(void)
|
||
|
{
|
||
|
// decrease tesselation
|
||
|
tessLevel -= tessInc;
|
||
|
if( tessLevel < TESS_MIN )
|
||
|
tessLevel = TESS_MIN;
|
||
|
NewTessLevel( tessLevel );
|
||
|
}
|
||
|
|
||
|
void __cdecl main(int argc, char **argv)
|
||
|
{
|
||
|
GLenum eMode;
|
||
|
|
||
|
while (--argc > 0)
|
||
|
{
|
||
|
argv++;
|
||
|
|
||
|
if (!strcmp(*argv, "-sb"))
|
||
|
fSingleBuf = TRUE;
|
||
|
}
|
||
|
|
||
|
auxInitPosition(10, 10, WIDTH, HEIGHT);
|
||
|
// eMode = AUX_RGB | AUX_DEPTH16 | AUX_ALPHA;
|
||
|
//mf: ??!! had to choose 32-bitz - don't know why, z-planes seem tight enough
|
||
|
eMode = AUX_RGB | AUX_DEPTH24 | AUX_ALPHA;
|
||
|
if (!fSingleBuf)
|
||
|
{
|
||
|
eMode |= AUX_DOUBLE;
|
||
|
}
|
||
|
|
||
|
auxInitDisplayMode(eMode);
|
||
|
auxInitWindow("Insane in the Membrane");
|
||
|
|
||
|
auxReshapeFunc(Reshape);
|
||
|
auxIdleFunc(Draw);
|
||
|
|
||
|
auxKeyFunc(AUX_a, Keya);
|
||
|
auxKeyFunc(AUX_l, Keyl);
|
||
|
auxKeyFunc(AUX_d, Keyd);
|
||
|
auxKeyFunc(AUX_SPACE, KeySPACE);
|
||
|
auxKeyFunc(AUX_UP, KeyUp);
|
||
|
auxKeyFunc(AUX_DOWN, KeyDown);
|
||
|
|
||
|
bDestAlpha = TRUE;
|
||
|
|
||
|
// Create scene, with object(s)
|
||
|
scene = new SCENE;
|
||
|
|
||
|
// Start drawing
|
||
|
timer.Start();
|
||
|
auxMainLoop(Draw);
|
||
|
|
||
|
// Party's over
|
||
|
delete scene;
|
||
|
}
|