📄 roamsimple.cpp
字号:
// Reset the patch.
//
void Patch::Reset()
{
// Assume patch is not visible.
m_isVisible = 0;
// Reset the important relationships
m_BaseLeft.LeftChild = m_BaseLeft.RightChild = m_BaseRight.LeftChild = m_BaseLeft.LeftChild = NULL;
// Attach the two m_Base triangles together
m_BaseLeft.BaseNeighbor = &m_BaseRight;
m_BaseRight.BaseNeighbor = &m_BaseLeft;
// Clear the other relationships.
m_BaseLeft.RightNeighbor = m_BaseLeft.LeftNeighbor = m_BaseRight.RightNeighbor = m_BaseRight.LeftNeighbor = NULL;
}
// ---------------------------------------------------------------------
// Compute the variance tree for each of the Binary Triangles in this patch.
//
void Patch::ComputeVariance()
{
// Compute variance on each of the base triangles...
m_CurrentVariance = m_VarianceLeft;
RecursComputeVariance( 0, PATCH_SIZE, m_HeightMap[PATCH_SIZE * MAP_SIZE],
PATCH_SIZE, 0, m_HeightMap[PATCH_SIZE],
0, 0, m_HeightMap[0],
1);
m_CurrentVariance = m_VarianceRight;
RecursComputeVariance( PATCH_SIZE, 0, m_HeightMap[ PATCH_SIZE],
0, PATCH_SIZE, m_HeightMap[ PATCH_SIZE * MAP_SIZE],
PATCH_SIZE, PATCH_SIZE, m_HeightMap[(PATCH_SIZE * MAP_SIZE) + PATCH_SIZE],
1);
// Clear the dirty flag for this patch
m_VarianceDirty = 0;
}
// ---------------------------------------------------------------------
// Discover the orientation of a triangle's points:
//
// Taken from "Programming Principles in Computer Graphics", L. Ammeraal (Wiley)
//
inline int orientation( int pX, int pY, int qX, int qY, int rX, int rY )
{
int aX, aY, bX, bY;
float d;
aX = qX - pX;
aY = qY - pY;
bX = rX - pX;
bY = rY - pY;
d = (float)aX * (float)bY - (float)aY * (float)bX;
return (d < 0) ? (-1) : (d > 0);
}
// ---------------------------------------------------------------------
// Set patch's visibility flag.
//
void Patch::SetVisibility( int eyeX, int eyeY, int leftX, int leftY, int rightX, int rightY )
{
// Get patch's center point
int patchCenterX = m_WorldX + PATCH_SIZE / 2;
int patchCenterY = m_WorldY + PATCH_SIZE / 2;
// Set visibility flag (orientation of both triangles must be counter clockwise)
m_isVisible = (orientation( eyeX, eyeY, rightX, rightY, patchCenterX, patchCenterY ) < 0) &&
(orientation( leftX, leftY, eyeX, eyeY, patchCenterX, patchCenterY ) < 0);
}
// ---------------------------------------------------------------------
// Create an approximate mesh.
//
void Patch::Tessellate()
{
// Split each of the base triangles
m_CurrentVariance = m_VarianceLeft;
RecursTessellate ( &m_BaseLeft,
m_WorldX, m_WorldY+PATCH_SIZE,
m_WorldX+PATCH_SIZE, m_WorldY,
m_WorldX, m_WorldY,
1 );
m_CurrentVariance = m_VarianceRight;
RecursTessellate( &m_BaseRight,
m_WorldX+PATCH_SIZE, m_WorldY,
m_WorldX, m_WorldY+PATCH_SIZE,
m_WorldX+PATCH_SIZE, m_WorldY+PATCH_SIZE,
1 );
}
// ---------------------------------------------------------------------
// Render the mesh.
//
void Patch::Render()
{
// Store old matrix
glPushMatrix();
// Translate the patch to the proper world coordinates
glTranslatef( (GLfloat)m_WorldX, 0, (GLfloat)m_WorldY );
glBegin(GL_TRIANGLES);
RecursRender ( &m_BaseLeft,
0, PATCH_SIZE,
PATCH_SIZE, 0,
0, 0);
RecursRender( &m_BaseRight,
PATCH_SIZE, 0,
0, PATCH_SIZE,
PATCH_SIZE, PATCH_SIZE);
glEnd();
// Restore the matrix
glPopMatrix();
}
// -------------------------------------------------------------------------------------------------
// LANDSCAPE CLASS
// -------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------
// Definition of the static member variables
//
int Landscape::m_NextTriNode;
TriTreeNode Landscape::m_TriPool[POOL_SIZE];
// ---------------------------------------------------------------------
// Allocate a TriTreeNode from the pool.
//
TriTreeNode *Landscape::AllocateTri()
{
TriTreeNode *pTri;
// IF we've run out of TriTreeNodes, just return NULL (this is handled gracefully)
if ( m_NextTriNode >= POOL_SIZE )
return NULL;
pTri = &(m_TriPool[m_NextTriNode++]);
pTri->LeftChild = pTri->RightChild = NULL;
return pTri;
}
// ---------------------------------------------------------------------
// Initialize all patches
//
void Landscape::Init(unsigned char *hMap)
{
Patch *patch;
int X, Y;
// Store the Height Field array
m_HeightMap = hMap;
// Initialize all terrain patches
for ( Y=0; Y < NUM_PATCHES_PER_SIDE; Y++)
for ( X=0; X < NUM_PATCHES_PER_SIDE; X++ )
{
patch = &(m_Patches[Y][X]);
patch->Init( X*PATCH_SIZE, Y*PATCH_SIZE, X*PATCH_SIZE, Y*PATCH_SIZE, hMap );
patch->ComputeVariance();
}
}
// ---------------------------------------------------------------------
// Reset all patches, recompute variance if needed
//
void Landscape::Reset()
{
//
// Perform simple visibility culling on entire patches.
// - Define a triangle set back from the camera by one patch size, following
// the angle of the frustum.
// - A patch is visible if it's center point is included in the angle: Left,Eye,Right
// - This visibility test is only accurate if the camera cannot look up or down significantly.
//
const float PI_DIV_180 = M_PI / 180.0f;
const float FOV_DIV_2 = gFovX/2;
int eyeX = (int)(gViewPosition[0] - PATCH_SIZE * sinf( gClipAngle * PI_DIV_180 ));
int eyeY = (int)(gViewPosition[2] + PATCH_SIZE * cosf( gClipAngle * PI_DIV_180 ));
int leftX = (int)(eyeX + 100.0f * sinf( (gClipAngle-FOV_DIV_2) * PI_DIV_180 ));
int leftY = (int)(eyeY - 100.0f * cosf( (gClipAngle-FOV_DIV_2) * PI_DIV_180 ));
int rightX = (int)(eyeX + 100.0f * sinf( (gClipAngle+FOV_DIV_2) * PI_DIV_180 ));
int rightY = (int)(eyeY - 100.0f * cosf( (gClipAngle+FOV_DIV_2) * PI_DIV_180 ));
int X, Y;
Patch *patch;
// Set the next free triangle pointer back to the beginning
SetNextTriNode(0);
// Reset rendered triangle count.
gNumTrisRendered = 0;
// Go through the patches performing resets, compute variances, and linking.
for ( Y=0; Y < NUM_PATCHES_PER_SIDE; Y++ )
for ( X=0; X < NUM_PATCHES_PER_SIDE; X++)
{
patch = &(m_Patches[Y][X]);
// Reset the patch
patch->Reset();
patch->SetVisibility( eyeX, eyeY, leftX, leftY, rightX, rightY );
// Check to see if this patch has been deformed since last frame.
// If so, recompute the varience tree for it.
if ( patch->isDirty() )
patch->ComputeVariance();
if ( patch->isVisibile() )
{
// Link all the patches together.
if ( X > 0 )
patch->GetBaseLeft()->LeftNeighbor = m_Patches[Y][X-1].GetBaseRight();
else
patch->GetBaseLeft()->LeftNeighbor = NULL; // Link to bordering Landscape here..
if ( X < (NUM_PATCHES_PER_SIDE-1) )
patch->GetBaseRight()->LeftNeighbor = m_Patches[Y][X+1].GetBaseLeft();
else
patch->GetBaseRight()->LeftNeighbor = NULL; // Link to bordering Landscape here..
if ( Y > 0 )
patch->GetBaseLeft()->RightNeighbor = m_Patches[Y-1][X].GetBaseRight();
else
patch->GetBaseLeft()->RightNeighbor = NULL; // Link to bordering Landscape here..
if ( Y < (NUM_PATCHES_PER_SIDE-1) )
patch->GetBaseRight()->RightNeighbor = m_Patches[Y+1][X].GetBaseLeft();
else
patch->GetBaseRight()->RightNeighbor = NULL; // Link to bordering Landscape here..
}
}
}
// ---------------------------------------------------------------------
// Create an approximate mesh of the landscape.
//
void Landscape::Tessellate()
{
// Perform Tessellation
int nCount;
Patch *patch = &(m_Patches[0][0]);
for (nCount=0; nCount < NUM_PATCHES_PER_SIDE*NUM_PATCHES_PER_SIDE; nCount++, patch++ )
{
if (patch->isVisibile())
patch->Tessellate( );
}
}
// ---------------------------------------------------------------------
// Render each patch of the landscape & adjust the frame variance.
//
void Landscape::Render()
{
int nCount;
Patch *patch = &(m_Patches[0][0]);
// Scale the terrain by the terrain scale specified at compile time.
glScalef( 1.0f, MULT_SCALE, 1.0f );
for (nCount=0; nCount < NUM_PATCHES_PER_SIDE*NUM_PATCHES_PER_SIDE; nCount++, patch++ )
{
if (patch->isVisibile())
patch->Render();
}
// Check to see if we got close to the desired number of triangles.
// Adjust the frame variance to a better value.
if ( GetNextTriNode() != gDesiredTris )
gFrameVariance += ((float)GetNextTriNode() - (float)gDesiredTris) / (float)gDesiredTris;
// Bounds checking.
if ( gFrameVariance < 0 )
gFrameVariance = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -