📄 terrain.cpp
字号:
//normalize the terrain for our purposes
NormalizeTerrain( fTempBuffer );
//transfer the terrain into our class's unsigned char height buffer
for( z=0; z<m_iSize; z++ )
{
for( x=0; x<m_iSize; x++ )
SetHeightAtPoint( ( unsigned char )fTempBuffer[( z*m_iSize )+x], x, z );
}
//delete temporary buffer
if( fTempBuffer )
{
//delete the data
delete[] fTempBuffer;
}
return true;
}
//--------------------------------------------------------------
// Name: CTERRAIN::MakeTerrainPlasma - public
// Description: Create a height data set using the "Midpoint
// Displacement" algorithm. Thanks a lot to
// Jason Shankel for this code!
// Arguments: -iSize: Desired size of the height map
// -fRoughness: Desired roughness of the created map
// Return Value: A boolean value: -true: successful creation
// -false: unsuccessful creation
//--------------------------------------------------------------
bool CTERRAIN::MakeTerrainPlasma( int iSize, float fRoughness )
{
float* fTempBuffer;
float fHeight, fHeightReducer;
int iRectSize= iSize;
int ni, nj;
int mi, mj;
int pmi, pmj;
int i, j;
int x, z;
if( m_heightData.m_ucpData )
UnloadHeightMap( );
if( fRoughness<0 )
fRoughness*= -1;
fHeight = ( float )iRectSize/2.0f;
fHeightReducer= ( float )pow( 2, -1*fRoughness );
m_iSize= iSize;
//allocate the memory for our height data
m_heightData.m_ucpData= new unsigned char [m_iSize*m_iSize];
fTempBuffer= new float [m_iSize*m_iSize];
//check to see if memory was successfully allocated
if( m_heightData.m_ucpData==NULL )
{
//something is seriously wrong here
g_log.Write( LOG_FAILURE, "Could not allocate memory for height map" );
return false;
}
//check to see if memory was successfully allocated
if( fTempBuffer==NULL )
{
//something is seriously wrong here
g_log.Write( LOG_FAILURE, "Could not allocate memory for height map" );
return false;
}
//set the first value in the height field
fTempBuffer[0]= 0.0f;
//being the displacement process
while( iRectSize>0 )
{
/*Diamond step -
Find the values at the center of the retangles by averaging the values at
the corners and adding a random offset:
a.....b
. .
. e .
. .
c.....d
e = (a+b+c+d)/4 + random
In the code below:
a = (i,j)
b = (ni,j)
c = (i,nj)
d = (ni,nj)
e = (mi,mj) */
for( i=0; i<m_iSize; i+=iRectSize )
{
for( j=0; j<m_iSize; j+=iRectSize )
{
ni= ( i+iRectSize )%m_iSize;
nj= ( j+iRectSize )%m_iSize;
mi= ( i+iRectSize/2 );
mj= ( j+iRectSize/2 );
fTempBuffer[mi+mj*m_iSize]= ( float )( ( fTempBuffer[i+j*m_iSize] + fTempBuffer[ni+j*m_iSize] + fTempBuffer[i+nj*m_iSize] + fTempBuffer[ni+nj*m_iSize] )/4 + RangedRandom( -fHeight/2, fHeight/2 ) );
}
}
/*Square step -
Find the values on the left and top sides of each rectangle
The right and bottom sides are the left and top sides of the neighboring rectangles,
so we don't need to calculate them
The height m_heightData.m_ucpData wraps, so we're never left hanging. The right side of the last
rectangle in a row is the left side of the first rectangle in the row. The bottom
side of the last rectangle in a column is the top side of the first rectangle in
the column
.......
. .
. .
. d .
. .
. .
......a..g..b
. . .
. . .
. e h f .
. . .
. . .
......c......
g = (d+f+a+b)/4 + random
h = (a+c+e+f)/4 + random
In the code below:
a= (i,j)
b= (ni,j)
c= (i,nj)
d= (mi,pmj)
e= (pmi,mj)
f= (mi,mj)
g= (mi,j)
h= (i,mj)*/
for( i=0; i<m_iSize; i+=iRectSize )
{
for( j=0; j<m_iSize; j+=iRectSize )
{
ni= ( i+iRectSize )%m_iSize;
nj= ( j+iRectSize )%m_iSize;
mi= ( i+iRectSize/2 );
mj= ( j+iRectSize/2 );
pmi= ( i-iRectSize/2+m_iSize )%m_iSize;
pmj= ( j-iRectSize/2+m_iSize )%m_iSize;
//Calculate the square value for the top side of the rectangle
fTempBuffer[mi+j*m_iSize]= ( float )( ( fTempBuffer[i+j*m_iSize] +
fTempBuffer[ni+j*m_iSize] +
fTempBuffer[mi+pmj*m_iSize] +
fTempBuffer[mi+mj*m_iSize] )/4+
RangedRandom( -fHeight/2, fHeight/2 ) );
//Calculate the square value for the left side of the rectangle
fTempBuffer[i+mj*m_iSize]= ( float )( ( fTempBuffer[i+j*m_iSize] +
fTempBuffer[i+nj*m_iSize] +
fTempBuffer[pmi+mj*m_iSize] +
fTempBuffer[mi+mj*m_iSize] )/4+
RangedRandom( -fHeight/2, fHeight/2 ) );
}
}
//reduce the rectangle size by two to prepare for the next
//displacement stage
iRectSize/= 2;
//reduce the height by the height reducer
fHeight*= fHeightReducer;
}
//normalize the terrain for our purposes
NormalizeTerrain( fTempBuffer );
//transfer the terrain into our class's unsigned char height buffer
for( z=0; z<m_iSize; z++ )
{
for( x=0; x<m_iSize; x++ )
SetHeightAtPoint( ( unsigned char )fTempBuffer[( z*m_iSize )+x], x, z );
}
//delete temporary buffer
if( fTempBuffer )
{
//delete the data
delete[] fTempBuffer;
}
return true;
}
//--------------------------------------------------------------
// Name: CTERRAIN::RegionPercent - public
// Description: Get the percentage of which a texture tile should be
// visible at a given height
// Arguments: -tileType: type of tile to check
// -ucHeight: the current height to test for
// Return Value: A floating point value: the percentage of which the
// current texture occupies at the given height
//--------------------------------------------------------------
float CTERRAIN::RegionPercent( int tileType, unsigned char ucHeight )
{
float fTemp1, fTemp2;
//if the height is lower than the lowest tile's height, then we want full brightness,
//if we don't do this, the area will get darkened, and no texture will get shown
if( m_tiles.textureTiles[LOWEST_TILE].IsLoaded( ) )
{
if( tileType==LOWEST_TILE && ucHeight<m_tiles.m_regions[LOWEST_TILE].m_iOptimalHeight )
return 1.0f;
}
else if( m_tiles.textureTiles[LOW_TILE].IsLoaded( ) )
{
if( tileType==LOW_TILE && ucHeight<m_tiles.m_regions[LOW_TILE].m_iOptimalHeight )
return 1.0f;
}
else if( m_tiles.textureTiles[HIGH_TILE].IsLoaded( ) )
{
if( tileType==HIGH_TILE && ucHeight<m_tiles.m_regions[HIGH_TILE].m_iOptimalHeight )
return 1.0f;
}
else if( m_tiles.textureTiles[HIGHEST_TILE].IsLoaded( ) )
{
if( tileType==HIGHEST_TILE && ucHeight<m_tiles.m_regions[HIGHEST_TILE].m_iOptimalHeight )
return 1.0f;
}
//height is lower than the region's boundary
if( ucHeight<m_tiles.m_regions[tileType].m_iLowHeight )
return 0.0f;
//height is higher than the region's boundary
else if( ucHeight>m_tiles.m_regions[tileType].m_iHighHeight )
return 0.0f;
//height is below the optimum height
if( ucHeight<m_tiles.m_regions[tileType].m_iOptimalHeight )
{
//calculate the texture percentage for the given tile's region
fTemp1= ( float )ucHeight-m_tiles.m_regions[tileType].m_iLowHeight;
fTemp2= ( float )m_tiles.m_regions[tileType].m_iOptimalHeight-m_tiles.m_regions[tileType].m_iLowHeight;
return ( fTemp1/fTemp2 );
}
//height is exactly the same as the optimal height
else if( ucHeight==m_tiles.m_regions[tileType].m_iOptimalHeight )
return 1.0f;
//height is above the optimal height
else if( ucHeight>m_tiles.m_regions[tileType].m_iOptimalHeight )
{
//calculate the texture percentage for the given tile's region
fTemp1= ( float )m_tiles.m_regions[tileType].m_iHighHeight-m_tiles.m_regions[tileType].m_iOptimalHeight;
return ( ( fTemp1-( ucHeight-m_tiles.m_regions[tileType].m_iOptimalHeight ) )/fTemp1 );
}
//something is seriously wrong if the height doesn't fit the previous cases
return 0.0f;
}
//--------------------------------------------------------------
// Name: CTERRAIN::GetTexCoords - public
// Description: Get texture coordinates :)
// present in the final texture
// Arguments: -texture: the texture to get coordinates for
// -*x, *y: the unaltered texture coordinates, and the
// storage place for the altered coordinates
// Return Value: None
//--------------------------------------------------------------
void CTERRAIN::GetTexCoords( CIMAGE texture, unsigned int* x, unsigned int* y )
{
unsigned int uiWidth = texture.GetWidth( );
unsigned int uiHeight= texture.GetHeight( );
int iRepeatX= -1;
int iRepeatY= -1;
int i= 0;
//loop until we figure out how many times the tile has repeated (on the X axis)
while( iRepeatX==-1 )
{
i++;
//if x is less than the total width, then we found a winner!
if( *x<( uiWidth*i ) )
iRepeatX= i-1;
}
//prepare to figure out the repetition on the Y axis
i= 0;
//loop until we figure out how many times the tile has repeated (on the Y axis)
while( iRepeatY==-1 )
{
i++;
//if y is less than the total height, then we have a bingo!
if( *y<( uiHeight*i ) )
iRepeatY= i-1;
}
//update the given texture coordinates
*x= *x-( uiWidth*iRepeatX );
*y= *y-( uiHeight*iRepeatY );
}
//--------------------------------------------------------------
// Name: CTERRAIN::InterpolateHeight - public
// Description: Interpolate the heights in the height map so that
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -