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

📄 landscape.cpp.svn-base

📁 自己做的小游戏
💻 SVN-BASE
字号:
#include "LandScape.h"
#include <windows.h>
#include <GL/gl.h>
#include "gamedata.h"
unsigned char *LandScape::m_HeightMap;
int LandScape::m_MapSize;
LandScape::LandScape(void)
{
}

LandScape::~LandScape(void)
{
//	if(m_HeightMap) delete m_HeightMap;
//	if(m_TriPool)	delete m_TriPool;
//	if(m_Patches)	delete m_Patches;
}

// ---------------------------------------------------------------------
// 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];
}

void LandScape::ComputeNormal(int x,int y, Vertex *out)
{
	if(x<=0 || x>=m_MapSize || y<=0 ||y >=m_MapSize) return;
	float z[5];
	z[0] = m_HeightMap[x+y*m_MapSize];
	z[1] = m_HeightMap[x-1+y*m_MapSize];
	z[2] = m_HeightMap[x+(y+1)*m_MapSize];
	z[3] = m_HeightMap[x+1+y*m_MapSize];
	z[4] = m_HeightMap[x+(y-1)*m_MapSize];

	float v[4][3][3] = {
		{{x,y,z[0]},{x-1,y,z[1]},{x,y+1,z[2]}},
		{{x,y,z[0]},{x,y+1,z[2]},{x+1,y,z[3]}},
		{{x,y,z[0]},{x+1,y,z[3]},{x,y-1,z[4]}},
		{{x,y,z[0]},{x,y-1,z[4]},{x-1,y,z[1]}}};

	float vector[4][3];
	for(int i=0;i<4;++i)
		calcNormal(v[i], vector[i]);

	out->x = vector[0][0]+vector[1][0]+vector[2][0]+vector[3][0];
	out->y = vector[0][1]+vector[1][1]+vector[2][1]+vector[3][1];
	out->z = vector[0][2]+vector[1][2]+vector[2][2]+vector[3][2];
}

//***********************
//Initialize all Patches
//
void LandScape::Init(unsigned char *hMap,int mapSize )
{
	Patch *patch;
	int X,Y;
	
	// Initialize all terrain data
	m_TriPool				= new TriPool(SIZE_TRIPOOL);
	m_HeightMap				= hMap;
	m_MapSize				= mapSize;
	m_Vectors				= (Vertex*)malloc(sizeof(Vertex)*m_MapSize*m_MapSize);
	
	m_Patches = new Patch[NUM_PATCHES_PER_SIDE*NUM_PATCHES_PER_SIDE];

	// Initialize all terrain patches
	for(X=0;X<NUM_PATCHES_PER_SIDE;++X)
		for(Y=0;Y<NUM_PATCHES_PER_SIDE;++Y)
		{
			patch = &m_Patches[NUM_PATCHES_PER_SIDE*X+Y];
			patch->Init(Y*PATCH_SIZE,X*PATCH_SIZE,Y*PATCH_SIZE,X*PATCH_SIZE,m_HeightMap,mapSize,m_Vectors,m_TriPool);
			patch->ComputeVariance();
		}

//	for(X=0;X<m_MapSize;++X)
//		for(Y=0;Y<m_MapSize;++Y)
//			ComputeNormal(X,Y, &m_Vectors[X+m_MapSize*Y]);
}

//************************
// reset all Patches ,recompute Variance
//
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
	m_TriPool->SetNextTriNode(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*NUM_PATCHES_PER_SIDE+X]);
			
			// Reset the patch
			patch->Reset();
			patch->SetVisibility(  );
			
			// 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*NUM_PATCHES_PER_SIDE+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*NUM_PATCHES_PER_SIDE+X+1].GetBaseLeft();
				else
					patch->GetBaseRight()->LeftNeighbor = NULL;		// Link to bordering Landscape here..

				if ( Y > 0 )
					patch->GetBaseLeft()->RightNeighbor = m_Patches[(Y-1)*NUM_PATCHES_PER_SIDE+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)*NUM_PATCHES_PER_SIDE+X].GetBaseLeft();
				else
					patch->GetBaseRight()->RightNeighbor = NULL;	// Link to bordering Landscape here..
			}
		}
}

// ---------------------------------------------------------------------
// Create an approximate mesh of the landscape.
//
void LandScape::Tessellate()
{
	// Perform Tessellation
	Patch *patch = &(m_Patches[0]);
	for (int i=0; i < NUM_PATCHES_PER_SIDE*NUM_PATCHES_PER_SIDE; i++, patch++ )
	{
		if (patch->isVisibile())
			patch->Tessellate( );
	}
}

// ---------------------------------------------------------------------
// Render each patch of the landscape & adjust the frame variance.
//
int LandScape::Render()
{
	//Number of Triangles
	int NumTrisRendered = 0;
	int nCount;
	Patch *patch = &(m_Patches[0]);

	// Store old matrix
	glPushMatrix();

	// Scale the terrain by the terrain scale specified at compile time.
	glScalef( TERRAIN_MULTIPL, MULT_SCALE, TERRAIN_MULTIPL );

	glColor3f(1,1,1);

	for (nCount=0; nCount < NUM_PATCHES_PER_SIDE*NUM_PATCHES_PER_SIDE; nCount++, patch++ )
	{
		if (patch->isVisibile())
			NumTrisRendered += patch->Render();
	}

	// Restore the matrix
	glPopMatrix();

	return NumTrisRendered;
}

// 计算任意点的高度y:
//
// 假设三角形三个顶点为:A(x1,y1,z1),B(x2,y2,z2),C(x3,y3,z3)
// 则有2变量 u,v 使得三角形上任意点的坐标(x,y,z)满足:
//
// x = ( 1 - u - v )*x1 +u*x2 +v*x3; (1)
//
// 对于y,z亦如此
//
// 应此可以根据三角形上点D的x,z坐标计算出u,v变量的值,
// 然后用y,y1,y2,y3代入公式(1)计算出D点的y值
//
float LandScape::GetY(float xp,float zp)
{
	float x = xp/TERRAIN_MULTIPL;
	float z = zp/TERRAIN_MULTIPL;

	//如果超出地图范围,返回0
	if(x<0 || x>m_MapSize*TERRAIN_MULTIPL || z<0 || z>m_MapSize*TERRAIN_MULTIPL)
		return 0;

	//(x,z)点所在三角形的3个顶点坐标
	float x1,x2,x3,y1,y2,y3,z1,z2,z3;
	//(x,z)点所在方格的左下顶点x,z坐标
	int intx,intz;
	//u,v变量
	float u,v;
	//(x,z)点对应高度y
	float y;

	intx = (int)x;
	intz = (int)z;
	
	//计算点所在三角形3顶点坐标
	x1 = intx+1;
	z1 = intz;
	y1 = m_HeightMap[(int)(x1+z1*m_MapSize)];
	x2 = intx;
	z2 = intz+1;
	y2 = m_HeightMap[int(x2+z2*m_MapSize)];
	if( x-intx + z-intz >1 )
	{
		x3 = intx+1;
		z3 = intz+1;
	}
	else
	{
		x3 = intx;
		z3 = intz;
	}
	y3 = m_HeightMap[(int)(x3+z3*m_MapSize)];

	//根据三角形三顶点坐标和点的x,z坐标计算u,v变量的值
	v = (z1*(x-x2)+z2*(x1-x)+z*(x2-x1))/(x1*z2-x1*z3-x2*z1+x2*z3+x3*z1-x3*z2);
	u = (x-x1+v*(x1-x3))/(x2-x1);
	
	//计算点的y值
	y = (1-u-v)*y1+u*y2+v*y3;

	return y;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -