?? utility.cpp
字號:
//
// Utility.cpp
// Bryan Turner
//
// Parts of the code in this file were borrowed from numerous public sources &
// literature. I reserve NO rights to this code and give a hearty thank-you to all the
// excellent sources used in this project. These include, but are not limited to:
//
// Longbow Digital Arts Programming Forum (www.LongbowDigitalArts.com)
// Gamasutra Features (www.Gamasutra.com)
// GameDev References (www.GameDev.net)
// C. Cookson's ROAM implementation (C.J.Cookson@dcs.warwick.ac.uk OR cjcookson@hotmail.com)
// OpenGL Super Bible (Waite Group Press)
// And many more...
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gl/gl.h> // OpenGL
#include <gl/glu.h> // GLU library
#include "utility.h"
#include "landscape.h"
// Observer and Follower modes
#define FOLLOW_MODE (0)
#define OBSERVE_MODE (1)
#define DRIVE_MODE (2)
#define FLY_MODE (3)
// Perspective & Window defines
#define FOV_ANGLE (90.0f)
#define NEAR_CLIP (1.0f)
#define FAR_CLIP (2500.0f)
// --------------------------------------
// GLOBALS
// --------------------------------------
Landscape gLand;
// Texture
GLuint gTextureID=1;
// Camera Stuff
GLfloat gViewPosition[] = { 0.f, 5.f, 0.f };
GLfloat gCameraPosition[] = { 0.f, 0.f, -555.f };
GLfloat gCameraRotation[] = { 42.f, -181.f, 0.f };
GLfloat gAnimateAngle = 0.f;
GLfloat gClipAngle;
// Misc. Globals
int gAnimating = 0;
int gRotating = 0;
int gDrawFrustum = 1;
int gCameraMode = OBSERVE_MODE;
int gDrawMode = DRAW_USE_TEXTURE;
int gStartX=-1, gStartY;
int gNumTrisRendered;
long gStartTime, gEndTime;
unsigned char *gHeightMap;
unsigned char *gHeightMaster;
int gNumFrames;
float gFovX = 90.0f;
// Beginning frame varience (should be high, it will adjust automatically)
float gFrameVariance = 50;
// Desired number of Binary Triangle tessellations per frame.
// This is not the desired number of triangles rendered!
// There are usually twice as many Binary Triangle structures as there are rendered triangles.
int gDesiredTris = 10000;
// ---------------------------------------------------------------------
// Reduces a normal vector specified as a set of three coordinates,
// to a unit normal vector of length one.
//
void ReduceToUnit(float vector[3])
{
float length;
// Calculate the length of the vector
length = sqrtf((vector[0]*vector[0]) +
(vector[1]*vector[1]) +
(vector[2]*vector[2]));
// Keep the program from blowing up by providing an exceptable
// value for vectors that may calculated too close to zero.
if(length == 0.0f)
length = 1.0f;
// Dividing each element by the length will result in a
// unit normal vector.
vector[0] /= length;
vector[1] /= length;
vector[2] /= length;
}
// ---------------------------------------------------------------------
// Points p1, p2, & p3 specified in counter clock-wise order
//
void calcNormal(float v[3][3], float out[3])
{
float v1[3],v2[3];
static const int x = 0;
static const int y = 1;
static const int z = 2;
// Calculate two vectors from the three points
v1[x] = v[0][x] - v[1][x];
v1[y] = v[0][y] - v[1][y];
v1[z] = v[0][z] - v[1][z];
v2[x] = v[1][x] - v[2][x];
v2[y] = v[1][y] - v[2][y];
v2[z] = v[1][z] - v[2][z];
// Take the cross product of the two vectors to get
// the normal vector which will be stored in out
out[x] = v1[y]*v2[z] - v1[z]*v2[y];
out[y] = v1[z]*v2[x] - v1[x]*v2[z];
out[z] = v1[x]*v2[y] - v1[y]*v2[x];
// Normalize the vector (shorten length to one)
ReduceToUnit(out);
}
// ---------------------------------------------------------------------
// Load the Height Field from a data file
//
void loadTerrain(int size, unsigned char **dest)
{
FILE *fp;
char fileName[30];
// Optimization: Add an extra row above and below the height map.
// - The extra top row contains a copy of the last row in the height map.
// - The extra bottom row contains a copy of the first row in the height map.
// This simplifies the wrapping of height values to a trivial case.
gHeightMaster = (unsigned char *)malloc( size * size * sizeof(unsigned char) + size * 2 );
// Give the rest of the application a pointer to the actual start of the height map.
*dest = gHeightMaster + size;
sprintf( fileName, "Height%d.raw", size );
fp = fopen(fileName, "rb");
// TESTING: READ A TREAD MARKS MAP...
if ( fp == NULL )
{
sprintf( fileName, "Map.ved", size );
fp = fopen(fileName, "rb");
if ( fp != NULL )
fseek( fp, 40, SEEK_SET ); // Skip to the goods...
}
if (fp == NULL)
{
// Oops! Couldn't find the file.
// Clear the board.
memset( gHeightMaster, 0, size * size + size * 2 );
return;
}
fread(gHeightMaster + size, 1, (size * size), fp);
fclose(fp);
// Copy the last row of the height map into the extra first row.
memcpy( gHeightMaster, gHeightMaster + size * size, size );
// Copy the first row of the height map into the extra last row.
memcpy( gHeightMaster + size * size + size, gHeightMaster + size, size );
}
// ---------------------------------------------------------------------
// Free the Height Field array
//
void freeTerrain()
{
if ( gHeightMaster )
free( gHeightMaster );
}
// ---------------------------------------------------------------------
// Switch GL Contexts when moving between draw modes to improve performance.
//
void SetDrawModeContext()
{
switch (gDrawMode)
{
case DRAW_USE_TEXTURE:
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glPolygonMode(GL_FRONT, GL_FILL);
break;
case DRAW_USE_LIGHTING:
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glPolygonMode(GL_FRONT, GL_FILL);
break;
case DRAW_USE_FILL_ONLY:
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glPolygonMode(GL_FRONT, GL_FILL);
break;
default:
case DRAW_USE_WIREFRAME:
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glPolygonMode(GL_FRONT, GL_LINE);
break;
}
}
// ---------------------------------------------------------------------
// Initialize the ROAM implementation
//
int roamInit(unsigned char *map)
{
// Perform some bounds checking on the #define statements
if ( gDesiredTris > POOL_SIZE )
return -1;
if ( POOL_SIZE < 100 )
return -1;
// ----------- TEXTURE INITIALIZATION -----------
glBindTexture(GL_TEXTURE_2D, gTextureID);
unsigned char *pTexture = (unsigned char *)malloc(TEXTURE_SIZE*TEXTURE_SIZE*3);
unsigned char *pTexWalk = pTexture;
if ( !pTexture )
exit(0);
// Create a random stipple pattern for the texture. Only use the Green channel.
// This could easily be modified to load in a bitmap or other texture source.
for ( int x = 0; x < TEXTURE_SIZE; x++ )
for ( int y = 0; y < TEXTURE_SIZE; y++ )
{
int color = (int)(128.0+(40.0 * rand())/RAND_MAX);
if ( color > 255 ) color = 255;
if ( color < 0 ) color = 0;
*(pTexWalk++) = 0;
*(pTexWalk++) = color; // Only use the Green chanel.
*(pTexWalk++) = 0;
}
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TEXTURE_SIZE, TEXTURE_SIZE, GL_RGB, GL_UNSIGNED_BYTE, pTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
free(pTexture);
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// ----------- LANDSCAPE INITIALIZATION -----------
gLand.Init(map);
return 0;
}
// ---------------------------------------------------------------------
// Call all functions needed to draw a frame of the landscape
//
void roamDrawFrame()
{
// Perform all the functions needed to render one frame.
gLand.Reset();
gLand.Tessellate();
gLand.Render();
}
// ---------------------------------------------------------------------
// Draw a simplistic frustum for debug purposes.
//
void drawFrustum()
{
//
// Draw the camera eye & frustum
//
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glPointSize(5.f);
glLineWidth(3.f);
glBegin(GL_LINES);
// Draw the View Vector starting at the eye (red)
glColor3f(1, 0, 0);
glVertex3f( gViewPosition[0],
gViewPosition[1],
gViewPosition[2] );
glVertex3f( gViewPosition[0] + 50.0f * sinf( gClipAngle * M_PI / 180.0f ),
gViewPosition[1],
gViewPosition[2] - 50.0f * cosf( gClipAngle * M_PI / 180.0f ));
// Draw the view frustum (blue)
glColor3f(0, 0, 1);
glVertex3f( gViewPosition[0],
gViewPosition[1],
gViewPosition[2] );
glVertex3f( gViewPosition[0] + 1000.0f * sinf( (gClipAngle-45.0f) * M_PI / 180.0f ),
gViewPosition[1],
gViewPosition[2] - 1000.0f * cosf( (gClipAngle-45.0f) * M_PI / 180.0f ));
glVertex3f( gViewPosition[0],
gViewPosition[1],
gViewPosition[2] );
glVertex3f( gViewPosition[0] + 1000.0f * sinf( (gClipAngle+45.0f) * M_PI / 180.0f ),
gViewPosition[1],
gViewPosition[2] - 1000.0f * cosf( (gClipAngle+45.0f) * M_PI / 180.0f ));
// Draw the clipping planes behind the eye (yellow)
const float PI_DIV_180 = M_PI / 180.0f;
const float FOV_DIV_2 = gFovX/2;
int ptEyeX = (int)(gViewPosition[0] - PATCH_SIZE * sinf( gClipAngle * PI_DIV_180 ));
int ptEyeY = (int)(gViewPosition[2] + PATCH_SIZE * cosf( gClipAngle * PI_DIV_180 ));
int ptLeftX = (int)(ptEyeX + 100.0f * sinf( (gClipAngle-FOV_DIV_2) * PI_DIV_180 ));
int ptLeftY = (int)(ptEyeY - 100.0f * cosf( (gClipAngle-FOV_DIV_2) * PI_DIV_180 ));
int ptRightX = (int)(ptEyeX + 100.0f * sinf( (gClipAngle+FOV_DIV_2) * PI_DIV_180 ));
int ptRightY = (int)(ptEyeY - 100.0f * cosf( (gClipAngle+FOV_DIV_2) * PI_DIV_180 ));
glColor3f(1, 1, 0);
glVertex3f( (float)ptEyeX,
gViewPosition[1],
(float)ptEyeY );
glVertex3f( (float)ptLeftX,
gViewPosition[1],
(float)ptLeftY);
glVertex3f( (float)ptEyeX,
gViewPosition[1],
(float)ptEyeY );
glVertex3f( (float)ptRightX,
gViewPosition[1],
(float)ptRightY);
glEnd();
glLineWidth(1.f);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -