www.pudn.com > 3DSLoader.rar > Terrain.cpp


//======================================================== 
/** 
*  @file      Terrain.cpp 
* 
*  项目描述: 3DS文件载入 
*  文件描述:  地形类  
*  适用平台: Windows98/2000/NT/XP 
*   
*  作者:     WWBOSS 
*  电子邮件:  wwboss123@gmail.com 
*  创建日期: 2006-12-06	 
*  修改日期: 2006-12-10 
* 
*/      
//======================================================== 
 
#include "Terrain.h" 
#include "CBMPLoader.h" 
 
/** 当前CTerrain指针 */ 
CTerrain* CTerrain::m_pTerrain = NULL; 
 
 
/** 多重纹理函数指针 */ 
PFNGLMULTITEXCOORD2FARBPROC		glMultiTexCoord2fARB = NULL; 
PFNGLACTIVETEXTUREARBPROC		glActiveTextureARB = NULL; 
 
/** 构造函数 */ 
CTerrain::CTerrain():m_bDetail(true),m_DetailScale(128) 
{ 
	/** 设置地形大小 */ 
	setSize(MAP_WIDTH,CELL_WIDTH); 
	 
	/** 为地形高程分配内存,并初始化 */ 
	m_pHeightMap = new BYTE[m_nWidth * m_nWidth]; 
	for(int i=0; i m_nWidth) col1 = 0; 
	if (row1 > m_nWidth) row1 = 0; 
 
	/** 获取单元的四个角的高度 */ 
	float h00 = (float)(m_pHeightMap[col0*m_nCellWidth + row0*m_nCellWidth*m_nWidth]); 
	float h01 = (float)(m_pHeightMap[col1*m_nCellWidth + row0*m_nCellWidth*m_nWidth]); 
	float h11 = (float)(m_pHeightMap[col1*m_nCellWidth + row1*m_nCellWidth*m_nWidth]); 
	float h10 = (float)(m_pHeightMap[col0*m_nCellWidth + row1*m_nCellWidth*m_nWidth]); 
 
	/** 计算机摄像机相对于单元格的位置 */ 
	float tx = CameraX - int(CameraX); 
	float ty = CameraZ - int(CameraZ); 
 
	/** 进行双线性插值得到地面高度 */ 
	float txty = tx * ty; 
 
	float final_height	= h00 * (1.0f - ty - tx + txty) 
						+ h01 * (tx - txty) 
						+ h11 * txty 
						+ h10 * (ty - txty); 
	return final_height; 
} 
 
/** 载入高度图 */ 
bool CTerrain::loadRawFile(const char* fileName) 
{ 
	FILE *pFile = NULL; 
 
	/** 打开文件 */ 
	pFile = fopen( fileName, "rb" ); 
 
	/** 错误检查 */ 
	if ( pFile == NULL )	 
	{ 
		/** 输出错误信息,并返回false */ 
		MessageBox(NULL, "打开高度图文件失败!", "错误", MB_OK); 
		exit(0); 
	} 
 
	/** 读取高度图文件 */ 
	fread( m_pHeightMap, 1, m_nWidth*m_nWidth, pFile ); 
 
	/** 获取错误代码 */ 
	int result = ferror( pFile ); 
 
	/** 检查错误代码 */ 
	if (result) 
	{ 
		MessageBox(NULL, "无法获取高度数据!", "错误", MB_OK); 
		exit(0); 
	} 
     
	/** 关闭文件,成功返回 */ 
	fclose(pFile); 
	return true; 
} 
 
/** 设置纹理坐标 */ 
void CTerrain::setTexCoord(float x,float z) 
{ 
	 
	float u =  (float)x / (float)m_nWidth; 
	float v = -(float)z / (float)m_nWidth; 
	 
	///设置地面纹理的纹理坐标 
	glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v); 
 
	///设置细节纹理的纹理坐标 
	glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v); 
} 
 
 
/** 载入地面纹理 */ 
bool CTerrain::loadTexture() 
{ 
	char* fileName[] = {"data/terrain.bmp","data/detail.bmp"};	 
	for(int i=0; i < 2; i++) 
	{ 
		if(!m_texture[i].LoadBitmap(fileName[i]) )                    /**< 载入位图文件 */ 
		{ 
			MessageBox(NULL,"装载位图文件失败!","错误",MB_OK);       /**< 如果载入失败则弹出对话框 */ 
			exit(0); 
		} 
		glGenTextures(1, &m_texture[i].ID);                            /**< 生成一个纹理对象名称 */ 
		 
			 
		glBindTexture(GL_TEXTURE_2D, m_texture[i].ID);                 /**< 创建纹理对象 */ 
		 
		/** 控制滤波 */ 
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); 
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); 
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); 
		 
		/** 创建纹理 */ 
		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, m_texture[i].imageWidth, 
						m_texture[i].imageHeight, GL_RGB, GL_UNSIGNED_BYTE, 
						m_texture[i].image); 
	} 
  	 
	return true; 
 
} 
 
/** 渲染地形 */ 
void CTerrain::render() 
{ 
		 
	int X = 0, Y = 0;						 
	float x, y, z;							 
	bool bSwitchSides = false; 
 
	/** 检查高度图是否有效 */ 
	if(!m_pHeightMap)  
		return;					 
 
	/** 绑定纹理 */ 
	 
	glActiveTextureARB(GL_TEXTURE0_ARB); 
	glEnable(GL_TEXTURE_2D); 
	glBindTexture(GL_TEXTURE_2D, m_texture[0].ID); 
	 
	/** 渲染细节纹理 */ 
	if(m_bDetail) 
	{ 
		glActiveTextureARB(GL_TEXTURE1_ARB); 
		glEnable(GL_TEXTURE_2D); 
 
		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); 
		glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2); 
 
		glBindTexture(GL_TEXTURE_2D, m_texture[1].ID); 
		 
		/** 变换纹理矩阵 */ 
		glMatrixMode(GL_TEXTURE); 
		    glLoadIdentity(); 
			glScalef((float)m_DetailScale, (float)m_DetailScale, 1); 
		glMatrixMode(GL_MODELVIEW); 
	} 
 
	/** 绘制三角形带 */ 
	glBegin( GL_TRIANGLE_STRIP );			 
 
	/** 从行(X)开始循环 */ 
	for ( X = 0; X <= m_nWidth; X += m_nCellWidth ) 
	{ 
		/** 检查该列是否需要从相反顺序绘制 */ 
		if(bSwitchSides) 
		{	 
			/** 绘制地形的一列 */ 
			for ( Y = m_nWidth; Y >= 0; Y -= m_nCellWidth ) 
			{ 
				/** 顶点(X, Y, Z) */		 
				x = X;							 
				y = getHeight( X, Y );	 
				z = Y;							 
 
				/** 指定纹理坐标,并发送顶点 */ 
				//setFogCoord(m_FogDepth, (float)y); 
				setTexCoord( (float)x, (float)z ); 
				glVertex3f(x, y, z);		 
 
				/** 顶点(X + m_nCellWidth, Y, Z) */		 
				x = X + m_nCellWidth;  
				y = getHeight( X + m_nCellWidth, Y );  
				z = Y; 
 
				/** 指定纹理坐标,并发送顶点 */ 
				//setFogCoord(m_FogDepth, (float)y); 
				setTexCoord( (float)x, (float)z ); 
				glVertex3f(x, y, z);			 
			} 
		} 
		else 
		{	 
			/** 绘制地形的一列 */ 
			for ( Y = 0; Y <= m_nWidth; Y += m_nCellWidth ) 
			{ 
				/** 顶点(X + m_nCellWidth, Y, Z) */	 
				x = X + m_nCellWidth;  
				y = getHeight( X + m_nCellWidth, Y );  
				z = Y; 
 
				/** 指定纹理坐标,并发送顶点 */ 
				//setFogCoord(m_FogDepth, (float)y); 
				setTexCoord( (float)x, (float)z ); 
				glVertex3f(x, y, z); 
 
				/** 顶点 (X, Y, Z) */		 
				x = X;							 
				y = getHeight( X, Y );	 
				z = Y;							 
 
				/** 指定纹理坐标,并发送顶点 */ 
				//setFogCoord(m_FogDepth, (float)y); 
				setTexCoord( (float)x, (float)z ); 
				glVertex3f(x, y, z);		 
			} 
		} 
			 
		/** 变换开关 */ 
		bSwitchSides = !bSwitchSides; 
	} 
 
	/** 绘制结束 */ 
	glEnd(); 
 
	///关闭纹理单元1 
	glActiveTextureARB(GL_TEXTURE1_ARB); 
    glDisable(GL_TEXTURE_2D); 
 
	//关闭纹理单元0 
	glActiveTextureARB(GL_TEXTURE0_ARB);		 
    glDisable(GL_TEXTURE_2D); 
 
}