windows-nt/Source/XPSP1/NT/multimedia/opengl/test/misc/membrane/membrane.cxx
2020-09-26 16:20:57 +08:00

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;
}