2013-07-29 07:13:03 -04:00
// HeightMap.cpp
// Implements the cHeightMap class representing a cCallback descendant that draws a B&W map of heights for the world
# include "Globals.h"
# include "HeightMap.h"
static const unsigned char g_BMPHeader [ ] =
{
0x42 , 0x4D , 0x36 , 0x00 , 0x10 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x36 , 0x00 , 0x00 , 0x00 , 0x28 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x02 , 0x00 , 0x00 , 0x00 , 0xfe , 0xff , 0xff , 0x01 , 0x00 , 0x20 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 , 0x13 , 0x0B , 0x00 , 0x00 , 0x13 , 0x0B , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
} ;
cHeightMap : : cHeightMap ( void ) :
m_CurrentRegionX ( 0 ) ,
m_CurrentRegionZ ( 0 ) ,
m_IsCurrentRegionValid ( false )
{
}
void cHeightMap : : Finish ( void )
{
if ( m_IsCurrentRegionValid )
{
StartNewRegion ( 0 , 0 ) ;
}
}
bool cHeightMap : : OnNewChunk ( int a_ChunkX , int a_ChunkZ )
{
int RegionX = ( a_ChunkX < 0 ) ? ( a_ChunkX - 31 ) / 32 : a_ChunkX / 32 ;
int RegionZ = ( a_ChunkZ < 0 ) ? ( a_ChunkZ - 31 ) / 32 : a_ChunkZ / 32 ;
if ( ( RegionX ! = m_CurrentRegionX ) | | ( RegionZ ! = m_CurrentRegionZ ) )
{
if ( m_IsCurrentRegionValid )
{
StartNewRegion ( RegionX , RegionZ ) ;
}
m_CurrentRegionX = RegionX ;
m_CurrentRegionZ = RegionZ ;
}
m_IsCurrentRegionValid = true ;
m_CurrentChunkX = a_ChunkX ;
m_CurrentChunkZ = a_ChunkZ ;
m_CurrentChunkOffX = m_CurrentChunkX - m_CurrentRegionX * 32 ;
m_CurrentChunkOffZ = m_CurrentChunkZ - m_CurrentRegionZ * 32 ;
memset ( m_BlockTypes , 0 , sizeof ( m_BlockTypes ) ) ;
return false ;
}
bool cHeightMap : : OnHeightMap ( const int * a_HeightMapBE )
{
ASSERT ( m_CurrentChunkOffX > = 0 ) ;
ASSERT ( m_CurrentChunkOffX < 32 ) ;
ASSERT ( m_CurrentChunkOffZ > = 0 ) ;
ASSERT ( m_CurrentChunkOffZ < 32 ) ;
int * BaseHeight = m_Height + m_CurrentChunkOffZ * 16 * 512 + m_CurrentChunkOffX * 16 ;
for ( int z = 0 ; z < 16 ; z + + )
{
int * Row = BaseHeight + z * 512 ;
for ( int x = 0 ; x < 16 ; x + + )
{
Row [ x ] = ntohl ( a_HeightMapBE [ z * 16 + x ] ) ;
}
} // for z
return false ; // Still want blockdata to remove trees from the heightmap
}
bool cHeightMap : : OnSection (
unsigned char a_Y ,
const BLOCKTYPE * a_BlockTypes ,
const NIBBLETYPE * a_BlockAdditional ,
const NIBBLETYPE * a_BlockMeta ,
const NIBBLETYPE * a_BlockLight ,
const NIBBLETYPE * a_BlockSkyLight
)
{
// Copy the section data into the appropriate place in the internal buffer
memcpy ( m_BlockTypes + a_Y * 16 * 16 * 16 , a_BlockTypes , 16 * 16 * 16 ) ;
return false ;
}
bool cHeightMap : : OnSectionsFinished ( void )
{
// Remove trees from the heightmap:
for ( int z = 0 ; z < 16 ; z + + )
{
for ( int x = 0 ; x < 16 ; x + + )
{
for ( int y = m_Height [ 512 * ( 16 * m_CurrentChunkOffZ + z ) + 16 * m_CurrentChunkOffX + x ] ; y > = 0 ; y - - )
{
if ( IsGround ( m_BlockTypes [ 256 * y + 16 * z + x ] ) )
{
m_Height [ 512 * ( 16 * m_CurrentChunkOffZ + z ) + 16 * m_CurrentChunkOffX + x ] = y ;
break ; // for y
}
} // for y
} // for x
} // for z
return true ;
}
void cHeightMap : : StartNewRegion ( int a_RegionX , int a_RegionZ )
{
AString FileName ;
Printf ( FileName , " Height.%d.%d.bmp " , m_CurrentRegionX , m_CurrentRegionZ ) ;
cFile f ;
if ( ! f . Open ( FileName , cFile : : fmWrite ) )
{
LOG ( " Cannot open file \" %s \" for writing the height map. Data for this region lost. " , FileName . c_str ( ) ) ;
}
else
{
f . Write ( g_BMPHeader , sizeof ( g_BMPHeader ) ) ;
for ( int z = 0 ; z < 512 ; z + + )
{
int RowData [ 512 ] ;
int * HeightRow = m_Height + z * 512 ;
for ( int x = 0 ; x < 512 ; x + + )
{
RowData [ x ] = std : : max ( std : : min ( HeightRow [ x ] , 255 ) , 0 ) * 0x010101 ;
}
f . Write ( RowData , sizeof ( RowData ) ) ;
} // for z
}
memset ( m_Height , 0 , sizeof ( m_Height ) ) ;
m_CurrentRegionX = a_RegionX ;
m_CurrentRegionZ = a_RegionZ ;
}
bool cHeightMap : : IsGround ( BLOCKTYPE a_BlockType )
{
// Name all blocks that are NOT ground, return false for them:
switch ( a_BlockType )
{
case E_BLOCK_AIR :
case E_BLOCK_BED :
2017-02-14 05:13:55 -05:00
case E_BLOCK_BEETROOTS :
2013-07-29 07:13:03 -04:00
case E_BLOCK_BREWING_STAND :
case E_BLOCK_BROWN_MUSHROOM :
case E_BLOCK_CACTUS :
case E_BLOCK_CAKE :
case E_BLOCK_CARROTS :
case E_BLOCK_CAULDRON :
case E_BLOCK_CHEST :
2017-02-14 05:13:55 -05:00
case E_BLOCK_CHORUS_FLOWER :
case E_BLOCK_CHORUS_PLANT :
2013-07-29 07:13:03 -04:00
case E_BLOCK_COBBLESTONE_WALL :
case E_BLOCK_COBWEB :
case E_BLOCK_COCOA_POD :
case E_BLOCK_CROPS :
case E_BLOCK_DEAD_BUSH :
case E_BLOCK_DETECTOR_RAIL :
case E_BLOCK_DIRT :
case E_BLOCK_DRAGON_EGG :
2017-02-14 05:13:55 -05:00
case E_BLOCK_END_GATEWAY :
2013-07-29 07:13:03 -04:00
case E_BLOCK_END_PORTAL :
2017-02-14 05:13:55 -05:00
case E_BLOCK_END_ROD :
2013-07-29 07:13:03 -04:00
case E_BLOCK_ENDER_CHEST :
case E_BLOCK_FENCE :
case E_BLOCK_FENCE_GATE :
case E_BLOCK_FIRE :
case E_BLOCK_FLOWER_POT :
case E_BLOCK_HEAD :
case E_BLOCK_IRON_BARS :
case E_BLOCK_LADDER :
case E_BLOCK_LAVA :
case E_BLOCK_LEAVES :
case E_BLOCK_LEVER :
case E_BLOCK_LILY_PAD :
case E_BLOCK_LOG : // NOTE: This block is actually solid, but we don't want it because it's the thing that trees are made of, and we're getting rid of trees
case E_BLOCK_MELON :
case E_BLOCK_MELON_STEM :
case E_BLOCK_NETHER_BRICK_FENCE :
case E_BLOCK_NETHER_PORTAL :
case E_BLOCK_POWERED_RAIL :
case E_BLOCK_PUMPKIN :
case E_BLOCK_PUMPKIN_STEM :
case E_BLOCK_RAIL :
case E_BLOCK_RED_ROSE :
case E_BLOCK_RED_MUSHROOM :
case E_BLOCK_REDSTONE_REPEATER_OFF :
case E_BLOCK_REDSTONE_REPEATER_ON :
case E_BLOCK_REDSTONE_TORCH_OFF :
case E_BLOCK_REDSTONE_TORCH_ON :
case E_BLOCK_REDSTONE_WIRE :
case E_BLOCK_REEDS :
case E_BLOCK_SAPLING :
case E_BLOCK_SIGN_POST :
case E_BLOCK_SNOW :
case E_BLOCK_STATIONARY_LAVA :
case E_BLOCK_STATIONARY_WATER :
case E_BLOCK_STONE_BUTTON :
case E_BLOCK_STONE_PRESSURE_PLATE :
2017-02-14 05:13:55 -05:00
case E_BLOCK_STRUCTURE_VOID :
2013-07-29 07:13:03 -04:00
case E_BLOCK_TALL_GRASS :
case E_BLOCK_TORCH :
case E_BLOCK_TRIPWIRE :
case E_BLOCK_TRIPWIRE_HOOK :
case E_BLOCK_VINES :
case E_BLOCK_WALLSIGN :
case E_BLOCK_WATER :
case E_BLOCK_WOODEN_BUTTON :
case E_BLOCK_WOODEN_PRESSURE_PLATE :
case E_BLOCK_YELLOW_FLOWER :
{
return false ;
}
}
return true ;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHeightMapFactory:
cHeightMapFactory : : ~ cHeightMapFactory ( )
{
// Force all threads to save their last regions:
for ( cCallbacks : : iterator itr = m_Callbacks . begin ( ) , end = m_Callbacks . end ( ) ; itr ! = end ; + + itr )
{
( ( cHeightMap * ) ( * itr ) ) - > Finish ( ) ;
}
// TODO: Join all the files into one giant image file
}