?? terrain.cpp
字號:
//========================================================
/**
* @file Terrain.cpp
*
* 項目描述: 3DS文件載入
* 文件描述: 地形類
* 適用平臺: Windows98/2000/NT/XP
*
* 作者: WWBOSS
* 電子郵件: wwboss123@gmail.com
* 創(chuàng)建日期: 2006-12-06
* 修改日期: 2006-12-10
*
*/
//========================================================
#include "Terrain.h"
#include "CBMPLoader.h"
/** 當前CTerrain指針 */
CTerrain* CTerrain::m_pTerrain = NULL;
/** 多重紋理函數(shù)指針 */
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2fARB = NULL;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB = NULL;
/** 構(gòu)造函數(shù) */
CTerrain::CTerrain():m_bDetail(true),m_DetailScale(128)
{
/** 設(shè)置地形大小 */
setSize(MAP_WIDTH,CELL_WIDTH);
/** 為地形高程分配內(nèi)存,并初始化 */
m_pHeightMap = new BYTE[m_nWidth * m_nWidth];
for(int i=0; i<m_nWidth * m_nWidth; i++)
m_pHeightMap[i] = 0;
m_pTerrain = this;
}
/** 析構(gòu)函數(shù) */
CTerrain::~CTerrain()
{
/** 刪除內(nèi)存和指針 */
if(m_pHeightMap)
{
delete[] m_pHeightMap;
m_pHeightMap = 0;
}
/** 刪除紋理對象及其占用內(nèi)存 */
for(int i=0; i<2; i++)
{
m_texture[i].FreeImage();
glDeleteTextures(1,&m_texture[i].ID);
}
}
/** 初始化霧效 */
void CTerrain::initFog()
{
float fogColor[4] = { 0.8f,0.8f,0.8f,1.0f };
glEnable(GL_FOG);
glFogi(GL_FOG_MODE,GL_EXP); /** 設(shè)置霧效的模式 */
glFogfv(GL_FOG_COLOR,fogColor); /** 指定霧的顏色 */
glFogf(GL_FOG_DENSITY,0.001f); /** 設(shè)置霧的濃度 */
glFogf(GL_FOG_START,1.0); /** 設(shè)置線性霧的開始位置 */
glFogf(GL_FOG_END,1000.0); /** 設(shè)置線性霧的結(jié)束位置 */
glHint(GL_FOG_HINT,GL_DONT_CARE); /** 規(guī)定霧化效果的質(zhì)量 */
}
/** 初始化地形 */
bool CTerrain::init()
{
glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress("glActiveTextureARB");
glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress("glMultiTexCoord2fARB");
if(!glActiveTextureARB || !glMultiTexCoord2fARB)
{
//輸出錯誤信息
MessageBox(NULL, "不支持多重紋理!", "錯誤", MB_OK);
exit(0);
//setDetail(false);
}
/** 載入高度文件 */
loadRawFile("data/terrain.raw");
/** 載入紋理 */
loadTexture();
/** 初始化霧效 */
initFog();
return true;
}
/** 設(shè)置地形大小 */
void CTerrain::setSize(unsigned int width, unsigned int cell)
{
m_nWidth = width;
m_nCellWidth = cell;
}
/** 獲得高度圖中高度值 */
int CTerrain::getHeight(int x,int y)
{
if(!m_pHeightMap)
return 0;
int xx = x % m_nWidth;
int yy = y % m_nWidth;
/** 返回當前高度 */
return m_pHeightMap[(xx + yy * m_nWidth)];
}
/** 獲得地面高度 */
float CTerrain::getAveHeight(float x,float z)
{
float CameraX, CameraZ;
CameraX = x / m_nCellWidth;
CameraZ = z / m_nCellWidth;
/** 計算高程坐標(Col0, Row0),(Col1, Row1) */
int col0 = int(CameraX);
int row0 = int(CameraZ);
unsigned int col1 = col0 + 1;
unsigned int row1 = row0 + 1;
/** 確保單元坐標不超過高程以外 */
if (col1 > 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, "無法獲取高度數(shù)據(jù)!", "錯誤", MB_OK);
exit(0);
}
/** 關(guān)閉文件,成功返回 */
fclose(pFile);
return true;
}
/** 設(shè)置紋理坐標 */
void CTerrain::setTexCoord(float x,float z)
{
float u = (float)x / (float)m_nWidth;
float v = -(float)z / (float)m_nWidth;
///設(shè)置地面紋理的紋理坐標
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
///設(shè)置細節(jié)紋理的紋理坐標
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); /**< 創(chuàng)建紋理對象 */
/** 控制濾波 */
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);
/** 創(chuàng)建紋理 */
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);
/** 渲染細節(jié)紋理 */
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)開始循環(huán) */
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;
/** 指定紋理坐標,并發(fā)送頂點 */
//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;
/** 指定紋理坐標,并發(fā)送頂點 */
//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;
/** 指定紋理坐標,并發(fā)送頂點 */
//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;
/** 指定紋理坐標,并發(fā)送頂點 */
//setFogCoord(m_FogDepth, (float)y);
setTexCoord( (float)x, (float)z );
glVertex3f(x, y, z);
}
}
/** 變換開關(guān) */
bSwitchSides = !bSwitchSides;
}
/** 繪制結(jié)束 */
glEnd();
///關(guān)閉紋理單元1
glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);
//關(guān)閉紋理單元0
glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -