📄 terrain.cpp
字号:
// the generated texture map does not look incredibly blocky
// Arguments: -x, z: coordinates to get the height at
// -fHeightToTexRatio: Height map size to texture
// map size ratio
// Return Value: An unsigned char value: the interpolated height
//--------------------------------------------------------------
unsigned char CTERRAIN::InterpolateHeight( int x, int z, float fHeightToTexRatio )
{
unsigned char ucLow, ucHighX, ucHighZ;
float ucX, ucZ;
float fScaledX= x*fHeightToTexRatio;
float fScaledZ= z*fHeightToTexRatio;
float fInterpolation;
//set the middle boundary
ucLow= GetTrueHeightAtPoint( ( int )fScaledX, ( int )fScaledZ );
//start off by interpolating along the X axis
//set the high boundary
if( ( fScaledX+1 )>m_iSize )
return ucLow;
else
ucHighX= GetTrueHeightAtPoint( ( int )fScaledX+1, ( int )fScaledZ );
//calculate the interpolation (for the X axis)
fInterpolation= ( fScaledX-( int )fScaledX );
ucX= ( ( ucHighX-ucLow )*fInterpolation )+ucLow;
//interpolate along the Z axis now
//set the high boundary
if( ( fScaledZ+1 )>m_iSize )
return ucLow;
else
ucHighZ= GetTrueHeightAtPoint( ( int )fScaledX, ( int )fScaledZ+1 );
//calculate the interpolation (for the Z axis)
fInterpolation= ( fScaledZ-( int )fScaledZ );
ucZ= ( ( ucHighZ-ucLow )*fInterpolation )+ucLow;
//calculate the overall interpolation (average of the two values)
return ( ( unsigned char )( ( ucX+ucZ )/2 ) );
}
//--------------------------------------------------------------
// Name: CTERRAIN::GenerateTextureMap - public
// Description: Generate a texture map from the four tiles (that must
// be loaded before this function is called)
// Arguments: -uiSize: the size of the texture map to be generated
// Return Value: None
//--------------------------------------------------------------
void CTERRAIN::GenerateTextureMap( unsigned int uiSize )
{
unsigned char ucRed, ucGreen, ucBlue;
unsigned int iTempID;
unsigned int x, z;
unsigned int uiTexX, uiTexZ;
float fTotalRed, fTotalGreen, fTotalBlue;
float fBlend[4];
float fMapRatio;
int iLastHeight;
int i;
//find out the number of tiles that we have
m_tiles.iNumTiles= 0;
for( i=0; i<TRN_NUM_TILES; i++ )
{
//if the current tile is loaded, then we add one to the total tile count
if( m_tiles.textureTiles[i].IsLoaded( ) )
m_tiles.iNumTiles++;
}
//now, re-loop through, and calculate the texture regions
iLastHeight= -1;
for( i=0; i<TRN_NUM_TILES; i++ )
{
//we only want to perform these calculations if we actually have a tile loaded
if( m_tiles.textureTiles[i].IsLoaded( ) )
{
//calculate the three height boundaries
m_tiles.m_regions[i].m_iLowHeight= iLastHeight+1;
iLastHeight+= 255/m_tiles.iNumTiles;
m_tiles.m_regions[i].m_iOptimalHeight= iLastHeight;
m_tiles.m_regions[i].m_iHighHeight= ( iLastHeight-m_tiles.m_regions[i].m_iLowHeight )+iLastHeight;
}
}
//create room for a new texture
m_texture.Create( uiSize, uiSize, 24 );
//get the height map to texture map ratio (since, most of the time,
//the texture map will be a higher resolution than the height map, so
//we need the ratio of height map pixels to texture map pixels)
fMapRatio= ( float )m_iSize/uiSize;
//time to create the texture data
for( z=0; z<uiSize; z++ )
{
for( x=0; x<uiSize; x++ )
{
//set our total color counters to 0.0f
fTotalRed = 0.0f;
fTotalGreen= 0.0f;
fTotalBlue = 0.0f;
//loop through the tiles (for the third time in this function!)
for( i=0; i<TRN_NUM_TILES; i++ )
{
//if the tile is loaded, we can do the calculations
if( m_tiles.textureTiles[i].IsLoaded( ) )
{
uiTexX= x;
uiTexZ= z;
//get texture coordinates
GetTexCoords( m_tiles.textureTiles[i], &uiTexX, &uiTexZ );
//get the current color in the texture at the coordinates that we got
//in GetTexCoords
m_tiles.textureTiles[i].GetColor( uiTexX, uiTexZ, &ucRed, &ucGreen, &ucBlue );
//get the current coordinate's blending percentage for this tile
fBlend[i]= RegionPercent( i, Limit( InterpolateHeight( x, z, fMapRatio ) ) );
//calculate the RGB values that will be used
fTotalRed += ucRed*fBlend[i];
fTotalGreen+= ucGreen*fBlend[i];
fTotalBlue += ucBlue*fBlend[i];
}
}
//set our terrain's texture color to the one that we previously calculated
m_texture.SetColor( x, z, Limit( ( unsigned char )fTotalRed ),
Limit( ( unsigned char )fTotalGreen ),
Limit( ( unsigned char )fTotalBlue ) );
}
}
//build the OpenGL texture
glGenTextures( 1, &iTempID );
glBindTexture( GL_TEXTURE_2D, iTempID );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
//make the texture
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, uiSize, uiSize, 0, GL_RGB, GL_UNSIGNED_BYTE, m_texture.GetData( ) );
//set the texture's ID
m_texture.SetID( iTempID );
}
//--------------------------------------------------------------
// Name: CTERRAIN::LoadLightMap - public
// Description: Load a grayscale RAW light map
// Arguments: -szFilename: the file name of the light map
// -im_iSize: the m_iSize (power of 2) of the map
// Return Value: A boolean value: -true: successful load
// -false: unsuccessful load
//--------------------------------------------------------------
bool CTERRAIN::LoadLightMap( char* szFilename, int iSize )
{
FILE* pFile;
//check to see if the data has been set
if( m_lightmap.m_ucpData )
UnloadLightMap( );
//open the RAW lightmap
pFile= fopen( szFilename, "rb" );
if( pFile==NULL )
{
//bad filename
g_log.Write( LOG_FAILURE, "Could not load %s\n", szFilename );
return false;
}
//allocate the memory for our lightmap
m_lightmap.m_ucpData= new unsigned char [iSize*iSize];
//check to see if memory was successfully allocated
if( m_lightmap.m_ucpData==NULL )
{
//the memory could not be allocated something is seriously wrong here
g_log.Write( LOG_FAILURE, "Could not allocate memory for%s\n", szFilename );
return false;
}
//read the lightmap into context
fread( m_lightmap.m_ucpData, 1, iSize*iSize, pFile );
//Close the file
fclose( pFile );
//set the m_iSize data
m_lightmap.m_iSize= iSize;
//WOOHOO! The lightmap has been successfully loaded
g_log.Write( LOG_SUCCESS, "Loaded %s\n", szFilename );
return true;
}
//--------------------------------------------------------------
// Name: CTERRAIN::SaveLightMap - public
// Description: Save a grayscale RAW light map to a file
// Arguments: -szFilename: the filename of the light map
// Return Value: A boolean value: -true: successful save
// -false: unsuccessful save
//--------------------------------------------------------------
bool CTERRAIN::SaveLightMap( char* szFilename )
{
FILE* pFile;
//open a file for the RAW lightmap to be saved to
pFile= fopen( szFilename, "wb" );
if( pFile==NULL )
{
//could not open the file for writing
g_log.Write( LOG_FAILURE, "Could not create %s\n", szFilename );
return false;
}
//check to see if we have data to actually write to a file
if( m_lightmap.m_ucpData==NULL )
{
//something is seriously wrong here
g_log.Write( LOG_FAILURE, "The height data buffer for %s is empty\n", szFilename );
return false;
}
//write the lightmap to the file
fwrite( m_lightmap.m_ucpData, 1, m_lightmap.m_iSize*m_lightmap.m_iSize, pFile );
//close the file
fclose( pFile );
//yahoo! The lightmap has been successfully written
g_log.Write( LOG_SUCCESS, "Saved %s\n", szFilename );
return true;
}
//--------------------------------------------------------------
// Name: CTERRAIN::UnloadLightMap - public
// Description: Unload the class's light map (if there is one)
// Arguments: None
// Return Value: None
//--------------------------------------------------------------
void CTERRAIN::UnloadLightMap( void )
{
//check to see if the data has been set
if( m_lightmap.m_ucpData )
{
//delete the data
delete[] m_lightmap.m_ucpData;
//reset the map dimensions also
m_iSize= 0;
}
//the height map has been unloaded
g_log.Write( LOG_SUCCESS, "Successfully unloaded the light map\n" );
}
//--------------------------------------------------------------
// Name: CTERRAIN::CalculateLighting - public
// Description: Calculates lighting for the pre-set technique, and
// stores all computations in a lightmap
// Arguments: None
// Return Value: None
//--------------------------------------------------------------
void CTERRAIN::CalculateLighting( void )
{
float fShade;
int x, z;
//a lightmap has already been provided, no need to create one :)
if( m_lightingType==LIGHTMAP )
return;
//allocate memory if it is needed
if( m_lightmap.m_iSize!=m_iSize || m_lightmap.m_ucpData==NULL )
{
//delete the memory for the old data
delete[] m_lightmap.m_ucpData;
//allocate memory for the new lightmap data buffer
m_lightmap.m_ucpData= new unsigned char [m_iSize*m_iSize];
m_lightmap.m_iSize= m_iSize;
}
//loop through all vertices
for( z=0; z<m_iSize; z++ )
{
for( x=0; x<m_iSize; x++ )
{
//using height-based lighting, trivial
if( m_lightingType==HEIGHT_BASED )
SetBrightnessAtPoint( x, z, GetTrueHeightAtPoint( x, z ) );
//using the slope-lighting technique
else if( m_lightingType==SLOPE_LIGHT )
{
//ensure that we won't be stepping over array boundaries by doing this
if( z>=m_iDirectionZ && x>=m_iDirectionX )
{
//calculate the shading value using the "slope lighting" algorithm
fShade= 1.0f-( GetTrueHeightAtPoint( x-m_iDirectionX, z-m_iDirectionZ ) -
GetTrueHeightAtPoint( x, z ) )/m_fLightSoftness;
}
//if we are, then just return a very bright color value (white)
else
fShade= 1.0f;
//clamp the shading value to the min/max brightness boundaries
if( fShade<m_fMinBrightness )
fShade= m_fMinBrightness;
if( fShade>m_fMaxBrightness )
fShade= m_fMaxBrightness;
//set the new brightness for our lightmap
SetBrightnessAtPoint( x, z, ( unsigned char )( fShade*255 ) );
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -