⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 treecollection.cpp

📁 c++程序
💻 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 + -