diff --git a/PixelCacheEntry.h b/PixelCacheEntry.h new file mode 100644 index 0000000..de3e66e --- /dev/null +++ b/PixelCacheEntry.h @@ -0,0 +1,101 @@ + +#ifndef PIXELCACHEINFO_H +#define PIXELCACHEINFO_H + +#include +#include"Color.h" + +struct PixelCacheEntry { + PixelCacheEntry(); + PixelCacheEntry(unsigned int color, double height=NAN); + PixelCacheEntry(const Color &color, double height=NAN); + PixelCacheEntry(const ColorEntry &entry, double height=NAN); + Color to_color(void) const; + ColorEntry to_colorEntry(void) const; + void reset(void); + void mixUnder(const PixelCacheEntry &p); + uint8_t red(void) const { return int(r*255+0.5); } + uint8_t green(void) const { return int(g*255+0.5); } + uint8_t blue(void) const { return int(b*255+0.5); } + uint8_t alpha(void) const { return int(a*255+0.5); } + uint8_t thicken(void) const { return int(t*255+0.5); } + int height(void) const { return int(h+0.5); } + + double r; + double g; + double b; + double a; + double t; + double h; + int n; +}; + +inline PixelCacheEntry::PixelCacheEntry() : + r(0), g(0), b(0), a(0), t(0), h(NAN), n(0) +{ +} + +inline PixelCacheEntry::PixelCacheEntry(unsigned int color, double height) : + r(((color>>16)&0xff)/255.0), g(((color>>8)&0xff)/255.0), b((color&0xff)/255.0), + a(((color>>24)&0xff)/255.0), t(0), h(height), n(1) +{ +} + +inline PixelCacheEntry::PixelCacheEntry(const Color &color, double height) : + r(color.r/255.0), g(color.g/255.0), b(color.b/255.0), + a(color.a/255.0), t(0), h(height), n(1) +{ +} + +inline PixelCacheEntry::PixelCacheEntry(const ColorEntry &entry, double height) : + r(entry.r/255.0), g(entry.g/255.0), b(entry.b/255.0), + a(entry.a/255.0), t(entry.t/255.0), h(height), n(1) +{ +} + +inline Color PixelCacheEntry::to_color(void) +{ + return Color(int(r*255+0.5),int(g*255+0.5),int(b*255+0.5),int(a*255+0.5)); +} + +inline ColorEntry PixelCacheEntry::to_colorEntry(void) +{ + return ColorEntry(int(r*255+0.5),int(g*255+0.5),int(b*255+0.5),int(a*255+0.5),int(t*255+0.5)); +} + +inline void PixelCacheEntry::reset(void) +{ + r=0; g=0; b=0; a=0; t=0; h=NAN; n=0; +} + +inline void PixelCacheEntry::mixUnder(const PixelCacheEntry &p) +{ + int prev_alpha = alpha(); + if (!n || a==0) { + r = p.r; + g = p.g; + b = p.b; + a = p.a; + t = p.t; + h = p.h; + n = p.n; + } + else { + // Regular mix + r = (a * r + p.a * (1 - a) * p.r); + g = (a * g + p.a * (1 - a) * p.g); + b = (a * b + p.a * (1 - a) * p.b); + a = (a + (1 - a) * p.a); + t = (t + p.t) / 2; + h = p.h; + } + if (prev_alpha == 255 && p.alpha() < 255) { + // Darken + // Parameters make deep water look good :-) + r = r * (0.85 + 0.1 * (1 - p.a)); + g = g * (0.85 + 0.1 * (1 - p.a)); + b = b * (0.85 + 0.1 * (1 - p.a)); + } +} + +#endif // PIXELCACHEINFO_H diff --git a/TileGenerator.cpp b/TileGenerator.cpp index fcf5734..e0575cb 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -88,19 +88,6 @@ static inline int colorSafeBounds(int color) } } -static inline Color mixColors(Color a, Color b) -{ - Color result; - double a1 = a.a / 255.0; - double a2 = b.a / 255.0; - - result.r = (int) (a1 * a.r + a2 * (1 - a1) * b.r); - result.g = (int) (a1 * a.g + a2 * (1 - a1) * b.g); - result.b = (int) (a1 * a.b + a2 * (1 - a1) * b.b); - result.a = (int) (255 * (a1 + a2 * (1 - a1))); - return result; -} - TileGenerator::TileGenerator(): verboseCoordinates(false), verboseStatistics(false), @@ -142,6 +129,7 @@ TileGenerator::TileGenerator(): m_tileMapXOffset(0), m_tileMapYOffset(0) { + resetPixelBlockCache(); } TileGenerator::~TileGenerator() @@ -524,6 +512,29 @@ inline BlockPos TileGenerator::decodeBlockPos(int64_t blockId) const return pos; } +void TileGenerator::resetPixelBlockCache(void) { + for (int x=0; x<16; x++) { + for (int z=0; z<16; z++) { + m_pixelBlockCache[z][x].reset(); + } + } +} + +void TileGenerator::pushPixelBlockCache(int xPos, int zPos) { + int xBegin = (xPos - m_xMin) * 16; + int zBegin = (m_zMax - zPos) * 16; + for (int x=0; x<16; x++) { + for (int z=0; z<16; z++) { + PixelCacheEntry &pixel = m_pixelBlockCache[z][x]; + if (pixel.n && !std::isnan(pixel.h)) { + m_image->tpixels[getImageY(zBegin + (15 - z))][getImageX(xBegin + x)] = color2libgd(pixel.to_color()); + m_blockPixelAttributes.attribute(15 - z, xBegin + x).thicken = pixel.thicken(); + m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pixel.height(); + } + } + } +} + void TileGenerator::createImage() { m_mapWidth = (m_xMax - m_xMin + 1) * 16; @@ -676,8 +687,12 @@ void TileGenerator::renderMap() const BlockPos &pos = *position; if (currentPos.x != pos.x || currentPos.z != pos.z) { area_rendered++; - if (currentPos.z != pos.z && currentPos.z != INT_MIN && m_shading) - renderShading(currentPos.z); + if (currentPos.z != INT_MIN) { + pushPixelBlockCache(currentPos.x, currentPos.z); + resetPixelBlockCache(); + if (currentPos.z != pos.z && m_shading) + renderShading(currentPos.z); + } if (progressIndicator && currentPos.z != pos.z) cout << "Processing Z-coordinate: " << std::setw(5) << pos.z*16 << "\r" << std::flush; for (int i = 0; i < 16; ++i) { @@ -782,8 +797,12 @@ void TileGenerator::renderMap() } } } - if(currentPos.z != INT_MIN && m_shading) - renderShading(currentPos.z); + if (currentPos.z != INT_MIN) { + pushPixelBlockCache(currentPos.x, currentPos.z); + resetPixelBlockCache(); + if(m_shading) + renderShading(currentPos.z); + } if (verboseStatistics) cout << "Statistics" << ": blocks read: " << m_db->getBlocksReadCount() @@ -805,8 +824,6 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const const unsigned char *mapData = mapBlock.c_str(); int minY = (pos.y < m_reqYMin) ? 16 : (pos.y > m_reqYMin) ? 0 : m_reqYMinNode; int maxY = (pos.y > m_reqYMax) ? -1 : (pos.y < m_reqYMax) ? 15 : m_reqYMaxNode; - Color col; - uint8_t th; for (int z = 0; z < 16; ++z) { int imageY = getImageY(zBegin + 15 - z); for (int x = 0; x < 16; ++x) { @@ -814,10 +831,6 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const continue; } int imageX = getImageX(xBegin + x); - if(m_drawAlpha) { - col = Color(0,0,0,0); - th = 0; - } for (int y = maxY; y >= minY; --y) { int position = x + (y << 4) + (z << 8); int content = readBlockContent(mapData, version, position); @@ -832,26 +845,25 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const if (color != m_colors.end()) { const Color c = color->second.to_color(); if (m_drawAlpha) { - if (col.a == 0) - col = c; - else - col = mixColors(col, c); - if(col.a == 0xFF) { - m_image->tpixels[imageY][imageX] = color2libgd(col); - m_blockPixelAttributes.attribute(15 - z, xBegin + x).thicken = th; - } else { - th = (th + color->second.t) / 2.0; - continue; + PixelCacheEntry pixel = PixelCacheEntry(color->second, pos.y * 16 + y); + m_pixelBlockCache[z][x].mixUnder(pixel); + if(pixel.alpha() == 0xff) { + m_readedPixels[z] |= (1 << x); + break; } - } else + else if(0 && m_pixelBlockCache[z][x].alpha() == 0xff) { + m_readedPixels[z] |= (1 << x); + break; + } + } else { m_image->tpixels[imageY][imageX] = color2libgd(c); - m_readedPixels[z] |= (1 << x); - m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y; + m_readedPixels[z] |= (1 << x); + m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y; + break; + } } else { m_unknownNodes.insert(name); - continue; } - break; } } } diff --git a/TileGenerator.h b/TileGenerator.h index 4d7806f..d4562b4 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -20,6 +20,7 @@ #include #include "PixelAttributes.h" #include "Color.h" +#include "PixelCacheEntry.h" #include "db.h" #define MINETEST_MAPBLOCK_MIN (-2048) @@ -119,6 +120,8 @@ private: void renderMap(); std::list getZValueList() const; Block getBlockOnPos(BlockPos pos); + void resetPixelBlockCache(void); + void pushPixelBlockCache(int xPos, int zPos); void renderMapBlock(const unsigned_string &mapBlock, const BlockPos &pos, int version); void renderShading(int zPos); void renderScale(); @@ -153,6 +156,7 @@ private: DB *m_db; gdImagePtr m_image; PixelAttributes m_blockPixelAttributes; + PixelCacheEntry m_pixelBlockCache[16][16]; int m_xMin; int m_xMax; int m_zMin;