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

1037 lines
24 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>
#define PI ((float)3.14159265358979323846)
#define WIDTH 512
#define HEIGHT 512
#define TESS_MIN 5
#define TESS_MAX 100
int tessLevel = TESS_MAX / 2; // corresponds to # of rings/sections in object
int tessInc = 5;
typedef struct
{
float fX, fY, fZ;
float fNx, fNy, fNz;
DWORD dwColor;
} VERTEX;
typedef struct
{
int iV1;
int iV2;
int iV3;
} TRIANGLE;
enum {
OBJECT_TYPE_SPHERE = 0,
OBJECT_TYPE_TORUS,
OBJECT_TYPE_CYLINDER
};
class OBJECT {
public:
OBJECT( int rings, int sections );
~OBJECT( );
int VertexCount() { return nVerts; }
int TriangleCount() { return nTris; }
VERTEX *VertexData() { return pVertData; }
TRIANGLE *TriangleData() { return pTriData; }
int NumRings() { return nRings; }
int NumSections() { return nSections; }
protected:
int iType; // object type
int nVerts, nTris;
int nRings, nSections;
VERTEX *pVertData;
TRIANGLE *pTriData;
};
class SPHERE : public OBJECT {
public:
SPHERE( int rings, int sections );
private:
void GenerateData( float fRadius );
int CalcNVertices();
int CalcNTriangles();
};
enum {
DRAW_METHOD_VERTEX_ARRAY = 0,
DRAW_METHOD_DREE,
DRAW_METHOD_TRIANGLES,
DRAW_METHOD_TRISTRIPS,
NUM_DRAW_METHODS
};
// Draw method names
char *pszListType[NUM_DRAW_METHODS] =
{
"Vertex Array", "DrawRangeElements", "Direct Triangles", "Direct Strips"
};
class DRAW_CONTROLLER {
public:
DRAW_CONTROLLER::DRAW_CONTROLLER();
DRAW_CONTROLLER::~DRAW_CONTROLLER();
void InitGL();
void CycleDrawMethod();
void ToggleDisplayListDraw() {bDisplayList = !bDisplayList; }
void ToggleLighting() {bLighting = !bLighting; SetLighting(); }
void Draw();
OBJECT *GetDrawObject() {return pObject;}
void SetDrawObject( OBJECT *pObj, int objectType );
char *GetDrawMethodName();
private:
int iDrawMethod;
BOOL bDisplayList;
BOOL bLighting;
BOOL bDREE; // if DrawRangeElements extension available or not
BOOL bDREE_Disabled; // DREE can be temporarily disabled if not
// practical to use (e.g. high tesselation)
int nDREE_MaxVertices;
int nDREE_MaxIndices;
PFNGLDRAWRANGEELEMENTSWINPROC pfnDrawRangeElementsWIN;
OBJECT *pObject; // Draw object
int iObjectType;
GLint dlList[NUM_DRAW_METHODS];
char **pszDrawMethodNames;
char szNameBuf[80];
void SetLighting();
void NewList();
void DeleteLists();
void DeleteList(int iList);
void DrawObject();
// Draw methods
void DrawVertexArray ();
void DrawRangeElements();
void DrawTriangles();
void DrawStrips();
void Vertex(int iVert);
void CheckDREE_Existence();
BOOL CheckDREE_Usable();
};
class SCENE {
public:
SCENE();
~SCENE();
void Draw();
void NewObject( int tessLevel );
DRAW_CONTROLLER drawController;
private:
GLfloat fXr, fYr, fZr;
GLfloat fDXr, fDYr, fDZr;
};
enum {
TIMER_METHOD_SINGLE = 0, // single-shot timer
TIMER_METHOD_AVERAGE, // average time for past n results
};
#define MAX_RESULTS 10
class TIMER {
public:
TIMER( int timerMethodArg );
void Start() { dwMillis = GetTickCount(); }
BOOL Stop( int numItems, float *fRate );
void Reset();
private:
int timerMethod;
int nItems;
int nTotalItems; // total # triangles accumulated
DWORD dwMillis;
DWORD dwTotalMillis;
DWORD updateInterval; // interval between timer updates
// These variables are for result averaging
float fResults[MAX_RESULTS];
int nResults; // current # of results
int nMaxResults; // max # of results for averaging
int iOldestResult; // index of oldest result
float fSummedResults; // current sum of results
};
// Global objects
SCENE *scene;
SPHERE *sphere;
TIMER timer( TIMER_METHOD_AVERAGE );
#define RGB_COLOR(red, green, blue) \
(((DWORD)(BYTE)(red) << 0) | \
((DWORD)(BYTE)(green) << 8) | \
((DWORD)(BYTE)(blue) << 16))
#define FRANDOM(x) (((float)rand() / RAND_MAX) * (x))
#define DROT 10.0f
BOOL fSingle = FALSE;
/****** OBJECT *******************************************************/
OBJECT::OBJECT( int rings, int sections )
: nRings( rings ), nSections( sections )
{
pTriData = NULL;
pVertData = NULL;
}
OBJECT::~OBJECT()
{
// These ptrs alloc'd in inheriting classes...
if( pVertData )
free( pVertData );
if( pTriData )
free( pTriData );
}
/****** SPHERE *******************************************************/
SPHERE::SPHERE(
int rings, int sections )
: OBJECT( rings, sections )
{
iType = OBJECT_TYPE_SPHERE;
nVerts = CalcNVertices();
nTris = CalcNTriangles();
// Allocate memory for the sphere data (freed by the base OBJECT class)
// Vertex data
pVertData = (VERTEX *) malloc( nVerts * sizeof(VERTEX) );
assert( pVertData != NULL );
// Triangle indices
pTriData = (TRIANGLE *) malloc( nTris * sizeof(TRIANGLE) );
assert( pTriData != NULL );
GenerateData(1.0f);
}
int
SPHERE::CalcNVertices()
{
return (((nRings)+1)*(nSections)+2);
}
int
SPHERE::CalcNTriangles()
{
return (((nRings)+1)*(nSections)*2);
}
void
SPHERE::GenerateData( float fRadius )
{
float fTheta, fPhi; /* Angles used to sweep around sphere */
float fDTheta, fDPhi; /* Angle between each section and ring */
float fX, fY, fZ, fV, fRSinTheta; /* Temporary variables */
int i, j, n, m; /* counters */
VERTEX *pvtx = pVertData;
TRIANGLE *ptri = pTriData;
/*
* Generate vertices at the top and bottom points.
*/
pvtx[0].fX = 0.0f;
pvtx[0].fY = fRadius;
pvtx[0].fZ = 0.0f;
pvtx[0].fNx = 0.0f;
pvtx[0].fNy = 1.0f;
pvtx[0].fNz = 0.0f;
pvtx[0].dwColor = RGB_COLOR(0, 0, 255);
pvtx[nVerts - 1].fX = 0.0f;
pvtx[nVerts - 1].fY = -fRadius;
pvtx[nVerts - 1].fZ = 0.0f;
pvtx[nVerts - 1].fNx = 0.0f;
pvtx[nVerts - 1].fNy = -1.0f;
pvtx[nVerts - 1].fNz = 0.0f;
pvtx[nVerts - 1].dwColor = RGB_COLOR(0, 255, 0);
/*
* Generate vertex points for rings
*/
fDTheta = PI / (float) (nRings + 2);
fDPhi = 2.0f * PI / (float) nSections;
n = 1; /* vertex being generated, begins at 1 to skip top point */
fTheta = fDTheta;
for (i = 0; i <= nRings; i++)
{
fY = (float)(fRadius * cos(fTheta)); /* y is the same for each ring */
fV = fTheta / PI; /* v is the same for each ring */
fRSinTheta = (float)(fRadius * sin(fTheta));
fPhi = 0.0f;
for (j = 0; j < nSections; j++)
{
fX = (float)(fRSinTheta * sin(fPhi));
fZ = (float)(fRSinTheta * cos(fPhi));
pvtx[n].fX = fX;
pvtx[n].fZ = fZ;
pvtx[n].fY = fY;
pvtx[n].fNx = fX / fRadius;
pvtx[n].fNy = fY / fRadius;
pvtx[n].fNz = fZ / fRadius;
if (n & 1)
{
pvtx[n].dwColor = RGB_COLOR(0, 0, 255);
}
else
{
pvtx[n].dwColor = RGB_COLOR(0, 255, 0);
}
fPhi += fDPhi;
n++;
}
fTheta += fDTheta;
}
/*
* Generate triangles for top and bottom caps.
*/
for (i = 0; i < nSections; i++)
{
ptri[i].iV1 = 0;
ptri[i].iV2 = i + 1;
ptri[i].iV3 = 1 + ((i + 1) % nSections);
ptri[nTris - nSections + i].iV1 = nVerts - 1;
ptri[nTris - nSections + i].iV2 = nVerts - 2 - i;
ptri[nTris - nSections + i].iV3 = nVerts - 2 - ((1 + i) % nSections);
}
/*
* Generate triangles for the rings
*/
m = 1; /* first vertex in current ring, begins at 1 to skip top point*/
n = nSections; /* triangle being generated, skip the top cap */
for (i = 0; i < nRings; i++)
{
for (j = 0; j < nSections; j++)
{
ptri[n].iV1 = m + j;
ptri[n].iV2 = m + nSections + j;
ptri[n].iV3 = m + nSections + ((j + 1) % nSections);
ptri[n + 1].iV1 = ptri[n].iV1;
ptri[n + 1].iV2 = ptri[n].iV3;
ptri[n + 1].iV3 = m + ((j + 1) % nSections);
n += 2;
}
m += nSections;
}
}
/****** DRAW_CONTROLLER *********************************************/
DRAW_CONTROLLER::DRAW_CONTROLLER( )
{
iDrawMethod = 0;
bDisplayList = FALSE;
bLighting = TRUE;
// check out if DREE exists
CheckDREE_Existence();
pszDrawMethodNames = pszListType;
// Set display list indices to 0 (so they will be filled later)
for( int i = 0; i < NUM_DRAW_METHODS; i++ )
dlList[i] = 0;
// Init GL state
InitGL();
}
DRAW_CONTROLLER::~DRAW_CONTROLLER( )
{
DeleteLists();
}
void
DRAW_CONTROLLER::DeleteLists()
{
for( int i = 0; i < NUM_DRAW_METHODS; i ++ )
DeleteList( i );
}
void
DRAW_CONTROLLER::DeleteList( int iList )
{
if( dlList[iList] ) {
glDeleteLists( dlList[iList], 1 );
dlList[iList] = 0;
}
}
void
DRAW_CONTROLLER::CheckDREE_Existence()
{
// Check for DrawRangeElements extension
pfnDrawRangeElementsWIN = (PFNGLDRAWRANGEELEMENTSWINPROC)
wglGetProcAddress("glDrawRangeElementsWIN");
if (pfnDrawRangeElementsWIN == NULL) {
bDREE = FALSE;
bDREE_Disabled = TRUE;
return;
}
// Extension exists - find out its limits
bDREE = TRUE;
glGetIntegerv( GL_MAX_ELEMENTS_VERTICES_WIN, &nDREE_MaxVertices );
glGetIntegerv( GL_MAX_ELEMENTS_INDICES_WIN, &nDREE_MaxIndices );
}
BOOL
DRAW_CONTROLLER::CheckDREE_Usable( )
{
// Cancel DrawRangeElements if vertex structure makes it impractical :
// - Vertex range too great to fit in call, or
// - Too many indices
// (I add 1 here to account for top or bottom vertices in a batch)
if( ( (2*pObject->NumSections() + 1) > nDREE_MaxVertices ) ||
( (2*pObject->NumSections()*3) > nDREE_MaxIndices )
)
bDREE_Disabled = TRUE;
else
bDREE_Disabled = FALSE;
return !bDREE_Disabled;
}
char *
DRAW_CONTROLLER::GetDrawMethodName()
{
// Returns name of current drawing method. If in dlist mode, then this is
// prepended to the name.
sprintf(szNameBuf, "%s%s",
bDisplayList ? "Display List " : "",
pszDrawMethodNames[iDrawMethod] );
return szNameBuf;
}
void
DRAW_CONTROLLER::CycleDrawMethod()
{
iDrawMethod++;
if( bDREE_Disabled && (iDrawMethod == DRAW_METHOD_DREE) )
iDrawMethod++;
if( iDrawMethod >= NUM_DRAW_METHODS )
iDrawMethod = 0;
}
void
DRAW_CONTROLLER::NewList( )
{
// Create new list for the current draw method
if( ! dlList[iDrawMethod] ) {
dlList[iDrawMethod] = glGenLists(1);
}
glNewList(dlList[iDrawMethod], GL_COMPILE);
DrawObject();
glEndList();
}
void
DRAW_CONTROLLER::SetDrawObject( OBJECT *pObj, int objectType )
{
iObjectType = objectType;
pObject = pObj;
// Delete all current lists
DeleteLists();
// Check if DREE can be used - and if not go on to next method if
// current method is DREE
if( !CheckDREE_Usable() && (iDrawMethod == DRAW_METHOD_DREE) )
CycleDrawMethod();
}
void
DRAW_CONTROLLER::Draw()
{
// Draws display list or immediate mode
// Display list draw
if( bDisplayList ) {
// Create dlist if necessary
if( !dlList[iDrawMethod] )
NewList();
glCallList( dlList[iDrawMethod] );
return;
}
// Immediate mode draw
DrawObject();
}
void
DRAW_CONTROLLER::DrawObject()
{
// Issues draw commands
switch( iDrawMethod ) {
case DRAW_METHOD_VERTEX_ARRAY :
DrawVertexArray();
break;
case DRAW_METHOD_DREE :
DrawRangeElements();
break;
case DRAW_METHOD_TRIANGLES :
DrawTriangles();
break;
case DRAW_METHOD_TRISTRIPS :
DrawStrips();
break;
}
}
void
DRAW_CONTROLLER::DrawVertexArray()
{
glDrawElements(GL_TRIANGLES,
pObject->TriangleCount()*3,
GL_UNSIGNED_INT,
pObject->TriangleData() );
}
void
DRAW_CONTROLLER::DrawRangeElements()
{
GLint *pTriIndices;
GLint nVerts, nTris;
GLenum type = GL_UNSIGNED_INT;
nVerts = pObject->VertexCount();
nTris = pObject->TriangleCount();
pTriIndices = (int *) pObject->TriangleData();
// Check for trivial case requiring no batching
if( (nVerts <= nDREE_MaxVertices) &&
(nTris*3 <= nDREE_MaxIndices) ) {
pfnDrawRangeElementsWIN(GL_TRIANGLES,
0,
nVerts-1,
nTris*3,
type,
pTriIndices );
return;
}
// Have to batch : Since the vertex ordering of the sphere is along rings,
// we will batch by groups of rings, according to the vertex index ranges
// allowed by the DrawRangeElements call.
//
// Need some more variables:
GLuint start, end;
GLsizei count;
GLuint nRingsPerBatch, nTrisPerBatch, nElemsPerBatch,
nVerticesPerBatch, elemsLeft;
int sections = pObject->NumSections();
int rings = pObject->NumRings();
nRingsPerBatch = nDREE_MaxVertices / (sections);
nTrisPerBatch = (nRingsPerBatch-1)*sections*2;
nElemsPerBatch = nTrisPerBatch*3;
nVerticesPerBatch = nRingsPerBatch*sections;
elemsLeft = nTris*3;
// Special case first batch with top vertex
start = 0;
end = nVerticesPerBatch - sections;
count = nElemsPerBatch - (sections*3); // top row only has half the tris of
// a 'normal' row
pfnDrawRangeElementsWIN(GL_TRIANGLES,
start,
end,
count,
type,
pTriIndices);
// Batch groups of rings around sphere
pTriIndices += count;
start = (end - sections + 1);
elemsLeft -= count;
while( elemsLeft >= nElemsPerBatch )
{
pfnDrawRangeElementsWIN(GL_TRIANGLES,
start,
start + nVerticesPerBatch - 1,
nElemsPerBatch,
type,
pTriIndices);
start += (nVerticesPerBatch - sections);
pTriIndices += nElemsPerBatch;
elemsLeft -= nElemsPerBatch;
}
// Do last batch, including bottom vertex
if( elemsLeft ) {
pfnDrawRangeElementsWIN(GL_TRIANGLES,
start,
nVerts-1,
elemsLeft,
type,
pTriIndices);
}
}
void
DRAW_CONTROLLER::Vertex(int iVert)
{
VERTEX *pvtx;
pvtx = pObject->VertexData() + iVert;
glColor3ubv((GLubyte *)&pvtx->dwColor);
glNormal3fv(&pvtx->fNx);
glVertex3fv(&pvtx->fX);
}
void
DRAW_CONTROLLER::DrawTriangles()
{
int iVert, *pidx;
glBegin(GL_TRIANGLES);
pidx = (int *) pObject->TriangleData();
for (iVert = 0; iVert < pObject->TriangleCount()*3; iVert++)
{
Vertex(*pidx++);
}
glEnd();
}
void
DRAW_CONTROLLER::DrawStrips()
{
int iIdxBase;
int iRing, iSection;
int sections = pObject->NumSections();
int rings = pObject->NumRings();
// Triangle fans for top and bottom caps
glBegin(GL_TRIANGLE_FAN);
Vertex(0);
iIdxBase = 1;
for (iSection = 0; iSection <= sections; iSection++)
{
Vertex(iIdxBase+(iSection % sections));
}
glEnd();
glBegin(GL_TRIANGLE_FAN);
Vertex(pObject->VertexCount() - 1);
iIdxBase = pObject->VertexCount() - sections - 1;
for (iSection = sections; iSection >= 0 ; iSection--)
{
Vertex(iIdxBase+(iSection % sections));
}
glEnd();
// Triangle strips for each ring
iIdxBase = 1;
for (iRing = 0; iRing < rings; iRing++)
{
glBegin(GL_TRIANGLE_STRIP);
for (iSection = 0; iSection <= sections; iSection++)
{
Vertex(iIdxBase+(iSection % sections));
Vertex(iIdxBase+(iSection % sections)+sections);
}
glEnd();
iIdxBase += sections;
}
}
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, 10, 0, 0, 0, 0, 1, 0);
glMatrixMode(GL_MODELVIEW);
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
sphere = new SPHERE( tessLevel, tessLevel );
assert( sphere != NULL );
// Inform DRAW_CONTROLLER about new object
drawController.SetDrawObject( sphere, OBJECT_TYPE_SPHERE );
// Initialize array pointer data
VERTEX *pVertData = sphere->VertexData();
glVertexPointer(3, GL_FLOAT, sizeof(VERTEX), &pVertData->fX);
glNormalPointer(GL_FLOAT, sizeof(VERTEX), &pVertData->fNx);
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VERTEX), &pVertData->dwColor);
// 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;
}
void
SCENE::Draw()
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glRotatef(fXr, 1.0f, 0.0f, 0.0f);
glRotatef(fYr, 0.0f, 1.0f, 0.0f);
glRotatef(fZr, 0.0f, 0.0f, 1.0f);
drawController.Draw();
// next rotation...
fXr += fDXr;
fYr += fDYr;
fZr += fDZr;
}
/****** TIMER *******************************************************/
TIMER::TIMER( int timerMethodArg )
: timerMethod( timerMethodArg )
{
updateInterval = 2000; // in milliseconds
Reset();
}
void
TIMER::Reset()
{
dwTotalMillis = 0;
nTotalItems = 0;
// Parameters for result averaging
nResults = 0;
nMaxResults = MAX_RESULTS; // number of most recent results to average
fSummedResults = 0.0f;
iOldestResult = 0; // index of oldest result
}
BOOL
TIMER::Stop( int numItems, float *fRate )
{
dwMillis = GetTickCount()-dwMillis;
dwTotalMillis += dwMillis;
nTotalItems += numItems;
// If total elapsed time is greater than the update interval, send back
// timing information
if (dwTotalMillis > updateInterval )
{
float fItemsPerSecond;
int iNewResult;
fItemsPerSecond = (float) nTotalItems*1000.0f/dwTotalMillis;
switch( timerMethod ) {
case TIMER_METHOD_AVERAGE :
// Average last n results (they are kept in a circular buffer)
if( nResults < nMaxResults ) {
// Haven't filled the buffer yet
iNewResult = nResults;
nResults++;
} else {
// Full buffer : replace oldest entry with new value
fSummedResults -= fResults[iOldestResult];
iNewResult = iOldestResult;
iOldestResult = (iOldestResult == (nMaxResults - 1)) ?
0 :
(iOldestResult + 1);
}
// Add new result, maintain sum to simplify calculations
fResults[iNewResult] = fItemsPerSecond;
fSummedResults += fItemsPerSecond;
// average the result
fItemsPerSecond = fSummedResults / (float) nResults;
break;
}
// Set running totals back to 0
dwTotalMillis = 0;
nTotalItems = 0;
*fRate = fItemsPerSecond;
return TRUE;
} else
return FALSE; // no new information yet
}
/********************************************************************/
void Reset()
{
// Called when display changes
// Remove any timing info from title bar, and reset the timer
SetWindowText(auxGetHWND(), scene->drawController.GetDrawMethodName() );
timer.Reset();
}
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 Redraw(void)
{
DRAW_CONTROLLER *pDrawControl = &scene->drawController;
float trianglesPerSecond;
timer.Start();
// Draw the scene
scene->Draw();
if (fSingle)
glFlush();
else
auxSwapBuffers();
// Print timing information if Stop returns TRUE
if( timer.Stop( pDrawControl->GetDrawObject()->TriangleCount(),
&trianglesPerSecond ) ) {
char szMsg[80];
sprintf(szMsg, "%s: %.0lf tri/sec",
pDrawControl->GetDrawMethodName(),
trianglesPerSecond );
// Print timing info in title bar
SetWindowText(auxGetHWND(), szMsg);
}
}
void Reshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
Reset();
}
void Keyd(void)
{
scene->drawController.ToggleDisplayListDraw();
Reset();
}
void Keyl(void)
{
scene->drawController.ToggleLighting();
Reset();
}
void KeySPACE(void)
{
scene->drawController.CycleDrawMethod();
Reset();
}
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"))
fSingle = TRUE;
}
auxInitPosition(10, 10, WIDTH, HEIGHT);
eMode = AUX_RGB;
if (!fSingle)
{
eMode |= AUX_DOUBLE;
}
auxInitDisplayMode(eMode);
auxInitWindow("Vertex Array/Direct Comparison");
auxReshapeFunc(Reshape);
auxIdleFunc(Redraw);
auxKeyFunc(AUX_l, Keyl);
auxKeyFunc(AUX_d, Keyd);
auxKeyFunc(AUX_SPACE, KeySPACE);
auxKeyFunc(AUX_UP, KeyUp);
auxKeyFunc(AUX_DOWN, KeyDown);
// Create scene, with object(s)
scene = new SCENE;
// Start drawing
auxMainLoop(Redraw);
// Party's over
delete scene;
}