@@ -1,8 +1,8 @@
#include " Globals.h"
#include " BiomeView.h"
#include " QtChunk.h"
#include < QPainter>
#include < QResizeEvent>
#include " Region.h"
@@ -14,6 +14,116 @@ static const int DELTA_STEP = 120; // The normal per-notch wheel delta
/* * Map for converting biome values to colors. Initialized from biomeColors[]. */
static uchar biomeToColor[256 * 4 ];
/* * Map for converting biome values to colors. Used to initialize biomeToColor[].*/
static struct
{
EMCSBiome m_Biome;
uchar m_Color[3 ];
} biomeColors[] =
{
{ biOcean, { 0x00 , 0x00 , 0x70 }, },
{ biPlains, { 0x8d , 0xb3 , 0x60 }, },
{ biDesert, { 0xfa , 0x94 , 0x18 }, },
{ biExtremeHills, { 0x60 , 0x60 , 0x60 }, },
{ biForest, { 0x05 , 0x66 , 0x21 }, },
{ biTaiga, { 0x0b , 0x66 , 0x59 }, },
{ biSwampland, { 0x2f , 0xff , 0xda }, },
{ biRiver, { 0x30 , 0x30 , 0xaf }, },
{ biHell, { 0x7f , 0x00 , 0x00 }, },
{ biSky, { 0x00 , 0x7f , 0xff }, },
{ biFrozenOcean, { 0xa0 , 0xa0 , 0xdf }, },
{ biFrozenRiver, { 0xa0 , 0xa0 , 0xff }, },
{ biIcePlains, { 0xff , 0xff , 0xff }, },
{ biIceMountains, { 0xa0 , 0xa0 , 0xa0 }, },
{ biMushroomIsland, { 0xff , 0x00 , 0xff }, },
{ biMushroomShore, { 0xa0 , 0x00 , 0xff }, },
{ biBeach, { 0xfa , 0xde , 0x55 }, },
{ biDesertHills, { 0xd2 , 0x5f , 0x12 }, },
{ biForestHills, { 0x22 , 0x55 , 0x1c }, },
{ biTaigaHills, { 0x16 , 0x39 , 0x33 }, },
{ biExtremeHillsEdge, { 0x7f , 0x8f , 0x7f }, },
{ biJungle, { 0x53 , 0x7b , 0x09 }, },
{ biJungleHills, { 0x2c , 0x42 , 0x05 }, },
{ biJungleEdge, { 0x62 , 0x8b , 0x17 }, },
{ biDeepOcean, { 0x00 , 0x00 , 0x30 }, },
{ biStoneBeach, { 0xa2 , 0xa2 , 0x84 }, },
{ biColdBeach, { 0xfa , 0xf0 , 0xc0 }, },
{ biBirchForest, { 0x30 , 0x74 , 0x44 }, },
{ biBirchForestHills, { 0x1f , 0x5f , 0x32 }, },
{ biRoofedForest, { 0x40 , 0x51 , 0x1a }, },
{ biColdTaiga, { 0x31 , 0x55 , 0x4a }, },
{ biColdTaigaHills, { 0x59 , 0x7d , 0x72 }, },
{ biMegaTaiga, { 0x59 , 0x66 , 0x51 }, },
{ biMegaTaigaHills, { 0x59 , 0x66 , 0x59 }, },
{ biExtremeHillsPlus, { 0x50 , 0x70 , 0x50 }, },
{ biSavanna, { 0xbd , 0xb2 , 0x5f }, },
{ biSavannaPlateau, { 0xa7 , 0x9d , 0x64 }, },
{ biMesa, { 0xd9 , 0x45 , 0x15 }, },
{ biMesaPlateauF, { 0xb0 , 0x97 , 0x65 }, },
{ biMesaPlateau, { 0xca , 0x8c , 0x65 }, },
// M variants:
{ biSunflowerPlains, { 0xb5 , 0xdb , 0x88 }, },
{ biDesertM, { 0xff , 0xbc , 0x40 }, },
{ biExtremeHillsM, { 0x88 , 0x88 , 0x88 }, },
{ biFlowerForest, { 0x2d , 0x8e , 0x49 }, },
{ biTaigaM, { 0x33 , 0x8e , 0x81 }, },
{ biSwamplandM, { 0x07 , 0xf9 , 0xb2 }, },
{ biIcePlainsSpikes, { 0xb4 , 0xdc , 0xdc }, },
{ biJungleM, { 0x7b , 0xa3 , 0x31 }, },
{ biJungleEdgeM, { 0x62 , 0x8b , 0x17 }, },
{ biBirchForestM, { 0x58 , 0x9c , 0x6c }, },
{ biBirchForestHillsM, { 0x47 , 0x87 , 0x5a }, },
{ biRoofedForestM, { 0x68 , 0x79 , 0x42 }, },
{ biColdTaigaM, { 0x24 , 0x3f , 0x36 }, },
{ biMegaSpruceTaiga, { 0x45 , 0x4f , 0x3e }, },
{ biMegaSpruceTaigaHills, { 0x45 , 0x4f , 0x4e }, },
{ biExtremeHillsPlusM, { 0x78 , 0x98 , 0x78 }, },
{ biSavannaM, { 0xe5 , 0xda , 0x87 }, },
{ biSavannaPlateauM, { 0xa7 , 0x9d , 0x74 }, },
{ biMesaBryce, { 0xff , 0x6d , 0x3d }, },
{ biMesaPlateauFM, { 0xd8 , 0xbf , 0x8d }, },
{ biMesaPlateauM, { 0xf2 , 0xb4 , 0x8d }, },
} ;
static class BiomeColorsInitializer
{
public:
BiomeColorsInitializer (void )
{
// Reset all colors to gray:
for (size_t i = 0 ; i < ARRAYCOUNT (biomeToColor); i++)
{
biomeToColor[i] = 0x7f ;
}
// Set known biomes to their colors:
for (size_t i = 0 ; i < ARRAYCOUNT (biomeColors); i++)
{
uchar * color = &biomeToColor[4 * biomeColors[i].m_Biome ];
color[0 ] = biomeColors[i].m_Color [2 ];
color[1 ] = biomeColors[i].m_Color [1 ];
color[2 ] = biomeColors[i].m_Color [0 ];
color[3 ] = 0xff ;
}
}
} biomeColorInitializer;
// //////////////////////////////////////////////////////////////////////////////
// BiomeView:
BiomeView::BiomeView (QWidget * parent) :
super(parent),
m_X(0 ),
@@ -40,7 +150,7 @@ BiomeView::BiomeView(QWidget * parent) :
redraw ();
// Add a chunk-update callback mechanism:
connect (&m_Cache, SIGNAL (chunkAvailable (int , int )), this , SLOT (chunkAvailable (int , int )));
connect (&m_Cache, SIGNAL (regionAvailable (int , int )), this , SLOT (regionAvailable (int , int )));
// Allow mouse and keyboard interaction:
setFocusPolicy (Qt::StrongFocus);
@@ -143,9 +253,15 @@ void BiomeView::redraw()
void BiomeView::chunkAvailable (int a_ChunkX , int a_ChunkZ )
void BiomeView::regionAvailable (int a_RegionX , int a_RegionZ )
{
drawChunk (a_ChunkX, a_ChunkZ);
for (int z = 0 ; z < 32 ; z++)
{
for (int x = 0 ; x < 32 ; x++)
{
drawChunk (a_RegionX * 32 + x, a_RegionZ * 32 + z);
}
}
update ();
}
@@ -175,8 +291,11 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
return ;
}
// fetch the chunk:
ChunkPtr chunk = m_Cache.fetch (a_ChunkX, a_ChunkZ);
// Fetch the region:
int regionX;
int regionZ;
Region::chunkToRegion (a_ChunkX, a_ChunkZ, regionX, regionZ);
RegionPtr region = m_Cache.fetch (regionX, regionZ);
// Figure out where on the screen this chunk should be drawn:
// first find the center chunk
@@ -194,11 +313,10 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
centerx += (a_ChunkX - centerchunkx) * chunksize;
centery += (a_ChunkZ - centerchunkz) * chunksize;
int srcoffset = 0 ;
uchar * bits = m_Image.bits ();
int imgstride = m_Image.bytesPerLine ();
int skipx = 0 ,skipy = 0 ;
int skipx = 0 , skipy = 0 ;
int blockwidth = chunksize, blockheight = chunksize;
// now if we're off the screen we need to crop
if (centerx < 0 )
@@ -227,29 +345,52 @@ void BiomeView::drawChunk(int a_ChunkX, int a_ChunkZ)
int imgoffset = centerx * 4 + centery * imgstride;
// If the chunk is valid, use its data; otherwise use the empty placeholder:
const uchar * src = m_EmptyChunkImage ;
if (chunk .get () != nullptr )
const short * src = m_EmptyChunkBiomes ;
if (region .get () != nullptr )
{
src = chunk->getImage ();
int relChunkX = a_ChunkX - regionX * 32 ;
int relChunkZ = a_ChunkZ - regionZ * 32 ;
Chunk & chunk = region->getRelChunk (relChunkX, relChunkZ);
if (chunk.isValid ())
{
src = chunk.getBiomes ();
}
}
// Blit or scale -blit the image:
// Scale -blit the image:
for (int z = skipy; z < blockheight; z++, imgoffset += imgstride)
{
srcoffset = floor ((double )z / m_Zoom) * 16 * 4 ;
if (m_Zoom == 1.0 )
{
memcpy (bits + imgoffset, src + srcoffset + skipx * 4 , (blockwidth - skipx) * 4 );
}
else
size_t srcoffset = static_cast <size_t >(std::floor ((double )z / m_Zoom)) * 16 ;
int imgxoffset = imgoffset;
for (int x = skipx; x < blockwidth; x++)
{
int xofs = 0 ;
for (int x = skipx; x < blockwidth; x++, xofs +=4 )
short biome = src[srcoffset + static_cast <size_t >(std::floor ((double )x / m_Zoom))];
const uchar * color;
if (biome < 0 )
{
memcpy (bits + imgoffset + xofs, src + srcoffset + (int )floor ((double )x / m_Zoom) * 4 , 4 );
static const uchar emptyBiome1[] = { 0x44 , 0x44 , 0x44 , 0xff };
static const uchar emptyBiome2[] = { 0x88 , 0x88 , 0x88 , 0xff };
color = ((x & 8 ) ^ (z & 8 )) ? emptyBiome1 : emptyBiome2;
}
}
}
else
{
if (biome * 4 >= ARRAYCOUNT (biomeToColor))
{
static const uchar errorImage[] = { 0xff , 0x00 , 0x00 , 0xff };
color = errorImage;
}
else
{
color = biomeToColor + biome * 4 ;
}
}
bits[imgxoffset] = color[0 ];
bits[imgxoffset + 1 ] = color[1 ];
bits[imgxoffset + 2 ] = color[2 ];
bits[imgxoffset + 3 ] = color[3 ];
imgxoffset += 4 ;
} // for x
} // for z
}
@@ -317,11 +458,12 @@ void BiomeView::mouseMoveEvent(QMouseEvent * a_Event)
// Update the status bar info text:
int blockX = floor ((a_Event->x () - width () / 2 ) / m_Zoom + m_X);
int blockZ = floor ((a_Event->y () - height () / 2 ) / m_Zoom + m_Z);
int chunkX, chunkZ;
int relX = blockX, relY, relZ = blockZ;
cChunkDef::AbsoluteToRelative (relX, relY, relZ, chunkX, chunkZ);
auto chunk = m_Cache.fetch (chunkX, chunkZ);
int biome = (chunk.get () != nullptr ) ? chunk->getBiome (relX, relZ) : biInvalidBiome;
int regionX, regionZ;
Region::blockToRegion (blockX, blockZ, regionX, regionZ);
int relX = blockX - regionX * 512 ;
int relZ = blockZ - regionZ * 512 ;
auto region = m_Cache.fetch (regionX, regionZ);
int biome = (region.get () != nullptr ) ? region->getRelBiome (relX, relZ) : biInvalidBiome;
emit hoverChanged (blockX, blockZ, biome);
}