📄 treecollection.cpp
字号:
// TreeCollection.cpp: Implementierung der Klasse CTreeCollection.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TreeCollection.h"
// Conversion factor for converting between degrees and radians
#define PI_OVER_180 0.0174532925f
//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////
CTreeCollection::CTreeCollection()
{
// Init member variables to default values
m_TextureCount = -1;
m_TreeCount = -1;
m_Landscape = 0;
m_MaxTerrainRoughness = 0.1f;
m_Trees = 0;
}
CTreeCollection::~CTreeCollection()
{
if (m_Trees)
{
delete [] m_Trees;
m_Trees = 0;
}
}
bool CTreeCollection::RegisterTexture(char sFileName[])
{
// Registers a new landscape texture
// Has the maximum of loadable textures been reached ?
if (m_TextureCount >= MAX_TEXTURE_COUNT)
return FALSE;
// Load & add the new texture
if (m_TextureCount == -1)
{
// First texture
m_TextureCount = 0;
m_TextureList[m_TextureCount].LoadTransparentBMP(sFileName);
}
else
{
// Already one or more Texture(s) present
m_TextureCount++;
m_TextureList[m_TextureCount].LoadTransparentBMP(sFileName);
}
// Texture succesful added
return TRUE;
}
bool CTreeCollection::DrawAllTrees(float fYRotation, float fXViewer, float fYViewer, float fZViewer, float fTreeBrightness)
{
// Draw all generated trees
int iCurTree;
// Return if no trees or textures are present
if (m_TreeCount == -1 || m_TextureCount == -1)
return FALSE;
// Calculate distance form viewer for all trees
for (iCurTree=0; iCurTree<m_TreeCount; iCurTree++)
{
m_Trees[iCurTree].CalculateDistance(fXViewer, fYViewer, fZViewer);
}
// Sort the CTree array for drawing it with transparency
qsort((void*) m_Trees, (size_t) m_TreeCount, sizeof(CTree), Compare);
// Save blending state
glPushAttrib(GL_COLOR_BUFFER_BIT);
// Enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(fTreeBrightness, fTreeBrightness, fTreeBrightness, fTreeBrightness);
// Normal for all trees
glNormal3f(0.0f, 0.0f, 1.0f);
// Setup clipping plane for sorting out invisible trees
CTriangle cClippingPlane;
cClippingPlane.m_Vertices[0][0] = fXViewer + sinf((fYRotation + 90.0f) * PI_OVER_180);
cClippingPlane.m_Vertices[0][1] = fYViewer;
cClippingPlane.m_Vertices[0][2] = fZViewer + cosf((fYRotation + 90.0f) * PI_OVER_180);
cClippingPlane.m_Vertices[1][0] = fXViewer + sinf((fYRotation - 90.0f) * PI_OVER_180);
cClippingPlane.m_Vertices[1][1] = fYViewer;
cClippingPlane.m_Vertices[1][2] = fZViewer + cosf((fYRotation - 90.0f) * PI_OVER_180);
cClippingPlane.m_Vertices[2][0] = fXViewer;
cClippingPlane.m_Vertices[2][1] = fYViewer + 1.0f;
cClippingPlane.m_Vertices[2][2] = fZViewer;
cClippingPlane.CalcNormal();
// Loop trough all trees
for (iCurTree=0; iCurTree<m_TreeCount; iCurTree++)
{
// Draw the tree only if could be in view
float fTreePos[3] = { m_Trees[iCurTree].m_PosX, m_Trees[iCurTree].m_PosY, m_Trees[iCurTree].m_PosZ };
if (cClippingPlane.GetInfinitePlaneDistance(fTreePos) > 0.0f)
{
// Use current tree texture
m_TextureList[m_Trees[iCurTree].m_TextureIndex].Use();
// Save matrix state
glPushMatrix();
// Perform billboard rotation
glTranslatef(m_Trees[iCurTree].m_PosX,
m_Trees[iCurTree].m_PosY, m_Trees[iCurTree].m_PosZ);
glRotatef(fYRotation, 0.0f, 1.0f, 0.0f);
// Draw current tree
m_Trees[iCurTree].DrawTree(fYRotation);
glPopMatrix();
}
}
glPopAttrib();
// Succesfull
return TRUE;
}
static int Compare(const void *arg1, const void *arg2)
{
// Callback function for comparing two CTree classes with qsort()
// Cast void pointers to CTree classes
CTree *cTree1 = (CTree*) arg1;
CTree *cTree2 = (CTree*) arg2;
// Is the distance from cTree1 greater ?
if (cTree1->m_DistanceToViewer > cTree2->m_DistanceToViewer)
return -1;
// Is the distance from cTree2 greater ?
if (cTree1->m_DistanceToViewer < cTree2->m_DistanceToViewer)
return 1;
// Equal far away
return 0;
}
bool CTreeCollection::GenerateTrees(int iTreeCount, float fTreeSize)
{
// Generate iTreeCount trees
// Return if no landscape or no textures are present
// or no trees should be generated.
if (!m_Landscape || m_TextureCount == -1)
return FALSE;
if (iTreeCount < 1)
return TRUE;
// Delete old trees (if neccessary) and allocate space for the new
if (m_Trees)
{
delete [] m_Trees;
m_Trees = 0;
}
m_Trees = new CTree[iTreeCount];
// Get landscape dimensions
RECT rcDimensions;
m_Landscape->GetLandscapeDimensions(&rcDimensions);
unsigned int iTries;
// Generate the trees
for (int iCurTree=0; iCurTree<iTreeCount; iCurTree++)
{
// Set random texture index
m_Trees[iCurTree].m_TextureIndex = Rnd(m_TextureCount + 1);
// Set tree size
m_Trees[iCurTree].m_TreeSize = fTreeSize;
// Set random position
iTries = 0;
// Loop till a valid position (free & even) has been found
do
{
// Generate new random position (make sure that no positions are chosen that
// lie on a vertex, cause GetSurfaceHeight() has problems with those points)
m_Trees[iCurTree].m_PosZ = Rnd(rcDimensions.right) * m_Landscape->GetStepSize() +
(m_Landscape->GetStepSize() / 2.0f);
m_Trees[iCurTree].m_PosX = Rnd(rcDimensions.bottom) * m_Landscape->GetStepSize() +
(m_Landscape->GetStepSize() / 2.0f);
m_Trees[iCurTree].m_PosY = m_Landscape->GetSurfaceHeight(
m_Trees[iCurTree].m_PosZ,
m_Trees[iCurTree].m_PosX);
iTries++;
if (iTries > 1000)
return FALSE;
} while (IsPlaceOccupied(iCurTree) == TRUE || IsPlaceEvenEnough(iCurTree) == FALSE);
}
// Set new tree count
m_TreeCount = iTreeCount;
// Succesfull
return TRUE;
}
bool CTreeCollection::IsPlaceOccupied(unsigned int iTreeIndex)
{
// Returns TRUE when another tree is close to the passed tree
float fTreeSize = m_Trees[0].m_TreeSize;
for (int iCurTree=0; iCurTree<(int) iTreeIndex; iCurTree++)
{
if (sqrt(powf((float) fabs(m_Trees[iCurTree].m_PosX - m_Trees[iTreeIndex].m_PosX), 2.0f) +
powf((float) fabs(m_Trees[iCurTree].m_PosZ - m_Trees[iTreeIndex].m_PosZ), 2.0f)) < fTreeSize * 2.0f)
// Position occupied
return TRUE;
}
// No other tree is present at the location of iTreeIndex
return FALSE;
}
bool CTreeCollection::IsPlaceEvenEnough(unsigned int iTreeIndex)
{
// Returns true when the terrain at the position of the passed tree is even enough
// Verify pointer first
if (!m_Landscape)
return FALSE;
// Get relevant height values
float fHeight1 = m_Landscape->GetSurfaceHeight(m_Trees[iTreeIndex].m_PosZ - m_Trees[iTreeIndex].m_TreeSize,
m_Trees[iTreeIndex].m_PosX - m_Trees[iTreeIndex].m_TreeSize);
float fHeight2 = m_Landscape->GetSurfaceHeight(m_Trees[iTreeIndex].m_PosZ + m_Trees[iTreeIndex].m_TreeSize,
m_Trees[iTreeIndex].m_PosX - m_Trees[iTreeIndex].m_TreeSize);
float fHeight3 = m_Landscape->GetSurfaceHeight(m_Trees[iTreeIndex].m_PosZ - m_Trees[iTreeIndex].m_TreeSize,
m_Trees[iTreeIndex].m_PosX + m_Trees[iTreeIndex].m_TreeSize);
float fHeight4 = m_Landscape->GetSurfaceHeight(m_Trees[iTreeIndex].m_PosZ + m_Trees[iTreeIndex].m_TreeSize,
m_Trees[iTreeIndex].m_PosX + m_Trees[iTreeIndex].m_TreeSize);
// Check for height differences
if (fHeight1 - m_Trees[iTreeIndex].m_PosY > m_MaxTerrainRoughness ||
fHeight2 - m_Trees[iTreeIndex].m_PosY > m_MaxTerrainRoughness ||
fHeight3 - m_Trees[iTreeIndex].m_PosY > m_MaxTerrainRoughness ||
fHeight4 - m_Trees[iTreeIndex].m_PosY > m_MaxTerrainRoughness)
return FALSE;
return TRUE;
}
int CTreeCollection::Rnd(int iMax)
{
// Return an integer with a value between 0 and iMax
return ((rand() * iMax) / RAND_MAX);
}
void CTreeCollection::SetLandscape(CLandscape *pLandscape)
{
m_Landscape = pLandscape;
}
void CTreeCollection::SetMaxTerrainRoughness(float fMaxRoughness)
{
// Set maximum terrain roughness for a valid tree position
if (fMaxRoughness > 0.0f)
m_MaxTerrainRoughness = fMaxRoughness;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -