diff --git a/Color.h b/Color.h index e777bbc..6f4c4c2 100644 --- a/Color.h +++ b/Color.h @@ -6,6 +6,10 @@ struct Color { Color(): r(0xFF), g(0xFF), b(0xFF), a(0) {}; Color(uint8_t r, uint8_t g, uint8_t b): r(r), g(g), b(b), a(0xFF) {}; Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a): r(r), g(g), b(b), a(a) {}; + Color &operator=(const Color &c); + unsigned to_uint() const { return (unsigned(a) << 24) + (unsigned(r) << 16) + (unsigned(g) << 8) + unsigned(b); } + //libgd treats 255 as transparent, and 0 as opaque ... + int to_libgd() const { return ((0xff - int(a)) << 24) + (int(r) << 16) + (int(g) << 8) + int(b); } uint8_t r; uint8_t g; uint8_t b; @@ -23,25 +27,13 @@ struct ColorEntry { uint8_t t; }; -inline int rgb2int(uint8_t r, uint8_t g, uint8_t b, uint8_t a=0xFF) +inline Color &Color::operator=(const Color &c) { - return (a << 24) + (r << 16) + (g << 8) + b; -} - -//libgd treats 255 as transparent, and 0 as opaque ... -inline int rgb2libgd(uint8_t r, uint8_t g, uint8_t b, uint8_t a=0xFF) -{ - return rgb2int(r, g, b, 0xff-a); -} - -inline int color2int(Color c) -{ - return rgb2int(c.r, c.g, c.b, c.a); -} - -inline int color2libgd(Color c) -{ - return rgb2libgd(c.r, c.g, c.b, c.a); + r = c.r; + g = c.g; + b = c.b; + a = c.a; + return *this; } #endif // COLOR_H diff --git a/PixelAttributes.cpp b/PixelAttributes.cpp index 6eda50e..3f281ed 100644 --- a/PixelAttributes.cpp +++ b/PixelAttributes.cpp @@ -9,6 +9,7 @@ #include #include +#include #include "PixelAttributes.h" using namespace std; @@ -38,7 +39,7 @@ void PixelAttributes::setWidth(int width) void PixelAttributes::scroll() { size_t lineLength = m_width * sizeof(PixelAttribute); - memcpy(m_pixelAttributes[FirstLine], m_pixelAttributes[LastLine], lineLength); + memcpy(m_pixelAttributes[PreviousLine], m_pixelAttributes[LastLine], lineLength); for (size_t i = 1; i < LineCount - 1; ++i) { memcpy(m_pixelAttributes[i], m_pixelAttributes[EmptyLine], lineLength); } @@ -54,3 +55,71 @@ void PixelAttributes::freeAttributes() } } + +static inline double colorSafeBounds(double color) +{ + if (color > 1) { + return 1; + } + else if (color < 0) { + return 0; + } + else { + return color; + } +} + + +void PixelAttributes::renderShading(bool drawAlpha) +{ + for (int z = FirstLine; z <= LastLine; z++) { + for (int x = 1; x < m_width; x++) { + if (!m_pixelAttributes[z][x].valid_height() || !m_pixelAttributes[z - 1][x].valid_height() || !m_pixelAttributes[z][x - 1].valid_height()) + continue; + double y = m_pixelAttributes[z][x].h; + double y1 = m_pixelAttributes[z][x - 1].h; + double y2 = m_pixelAttributes[z - 1][x].h; + double d = (y - y1) + (y - y2); + if (d > 3) { + d = 3; + } + d = d * 12 / 255; + if (drawAlpha) + d = d * (1 - m_pixelAttributes[z][x].t); + PixelAttribute &pixel = m_pixelAttributes[z][x]; + pixel.r = colorSafeBounds(pixel.r + d); + pixel.g = colorSafeBounds(pixel.g + d); + pixel.b = colorSafeBounds(pixel.b + d); + } + } +} + +void PixelAttribute::mixUnder(const PixelAttribute &p) +{ + int prev_alpha = alpha(); + if (!valid_height() || a==0) { + r = p.r; + g = p.g; + b = p.b; + a = p.a; + t = p.t; + h = p.h; + } + else { + 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)); + } + +} + diff --git a/PixelAttributes.h b/PixelAttributes.h index 64068f7..faad345 100644 --- a/PixelAttributes.h +++ b/PixelAttributes.h @@ -11,16 +11,32 @@ #define PIXELATTRIBUTES_H_ADZ35GYF #include +#include #include #include "config.h" +#include "Color.h" struct PixelAttribute { - PixelAttribute(): height(std::numeric_limits::min()), thicken(0) {}; - int height; - uint8_t thicken; - inline bool valid_height() { - return height != std::numeric_limits::min(); - } + PixelAttribute(): h(NAN), t(0), a(0), r(0), g(0), b(0) {}; + PixelAttribute(const Color &color, double height); + PixelAttribute(const ColorEntry &entry, double height); + double h; + double t; + double a; + double r; + double g; + double b; + 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); } + unsigned height(void) const { return unsigned(h+0.5); } + Color color(void) const { return Color(red(), green(), blue(), alpha()); } + + inline bool valid_height() const { return !isnan(h); } + PixelAttribute &operator=(const PixelAttribute &p); + void mixUnder(const PixelAttribute &p); }; class PixelAttributes @@ -31,13 +47,15 @@ public: void setWidth(int width); void scroll(); inline PixelAttribute &attribute(int z, int x) { return m_pixelAttributes[z + 1][x + 1]; }; + void renderShading(bool drawAlpha); private: void freeAttributes(); private: enum Line { - FirstLine = 0, + PreviousLine = 0, + FirstLine = 1, LastLine = BLOCK_SIZE, EmptyLine = BLOCK_SIZE + 1, LineCount = BLOCK_SIZE + 2 @@ -46,5 +64,29 @@ private: int m_width; }; + +inline PixelAttribute::PixelAttribute(const Color &color, double height) : + h(height), t(0), a(color.a/255.0), + r(color.r/255.0), g(color.g/255.0), b(color.b/255.0) +{ +} + +inline PixelAttribute::PixelAttribute(const ColorEntry &entry, double height) : + h(height), t(entry.t/255.0), a(entry.a/255.0), + r(entry.r/255.0), g(entry.g/255.0), b(entry.b/255.0) +{ +} + +inline PixelAttribute &PixelAttribute::operator=(const PixelAttribute &p) +{ + h = p.h; + t = p.t; + a = p.a; + r = p.r; + g = p.g; + b = p.b; + return *this; +} + #endif /* end of include guard: PIXELATTRIBUTES_H_ADZ35GYF */ diff --git a/PixelCacheEntry.h b/PixelCacheEntry.h deleted file mode 100644 index f8dbaaf..0000000 --- a/PixelCacheEntry.h +++ /dev/null @@ -1,101 +0,0 @@ - -#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) const -{ - 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) const -{ - 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 e0575cb..2cb698a 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -75,19 +75,6 @@ static inline int readBlockContent(const unsigned char *mapData, int version, in } } -static inline int colorSafeBounds(int color) -{ - if (color > 255) { - return 255; - } - else if (color < 0) { - return 0; - } - else { - return color; - } -} - TileGenerator::TileGenerator(): verboseCoordinates(false), verboseStatistics(false), @@ -129,7 +116,6 @@ TileGenerator::TileGenerator(): m_tileMapXOffset(0), m_tileMapYOffset(0) { - resetPixelBlockCache(); } TileGenerator::~TileGenerator() @@ -512,27 +498,16 @@ 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; +void TileGenerator::pushPixelRows(int zPos) { int zBegin = (m_zMax - zPos) * 16; - for (int x=0; x<16; x++) { + for (int x=0; xtpixels[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(); - } + PixelAttribute &pixel = m_blockPixelAttributes.attribute(z,x); + if (pixel.valid_height()) + m_image->tpixels[getImageY(zBegin + z)][getImageX(x)] = pixel.color().to_libgd(); } } + m_blockPixelAttributes.scroll(); } void TileGenerator::createImage() @@ -627,18 +602,18 @@ void TileGenerator::createImage() throw std::runtime_error(oss.str()); } // Background - gdImageFilledRectangle(m_image, 0, 0, pictWidth + m_border - 1, pictHeight + m_border -1, color2libgd(m_bgColor)); + gdImageFilledRectangle(m_image, 0, 0, pictWidth + m_border - 1, pictHeight + m_border -1, m_bgColor.to_libgd()); // Draw tile borders if (m_tileWidth && m_tileBorderSize) { - int borderColor = color2libgd(m_tileBorderColor); + int borderColor = m_tileBorderColor.to_libgd(); for (int i = 0; i < tileBorderXLimit - tileBorderXStart; i++) { int xPos = m_tileMapXOffset + i * (m_tileWidth + m_tileBorderSize); gdImageFilledRectangle(m_image, xPos + m_border, m_border, xPos + (m_tileBorderSize-1) + m_border, pictHeight + m_border - 1, borderColor); } } if (m_tileHeight && m_tileBorderSize) { - int borderColor = color2libgd(m_tileBorderColor); + int borderColor = m_tileBorderColor.to_libgd(); for (int i = 0; i < tileBorderZLimit - tileBorderZStart; i++) { int yPos = m_tileMapYOffset + i * (m_tileHeight + m_tileBorderSize); gdImageFilledRectangle(m_image, m_border, yPos + m_border, pictWidth + m_border - 1, yPos + (m_tileBorderSize-1) + m_border, borderColor); @@ -687,11 +662,10 @@ void TileGenerator::renderMap() const BlockPos &pos = *position; if (currentPos.x != pos.x || currentPos.z != pos.z) { area_rendered++; - if (currentPos.z != INT_MIN) { - pushPixelBlockCache(currentPos.x, currentPos.z); - resetPixelBlockCache(); - if (currentPos.z != pos.z && m_shading) - renderShading(currentPos.z); + if (currentPos.z != INT_MIN && currentPos.z != pos.z) { + if (m_shading) + m_blockPixelAttributes.renderShading(m_drawAlpha); + pushPixelRows(currentPos.z); } if (progressIndicator && currentPos.z != pos.z) cout << "Processing Z-coordinate: " << std::setw(5) << pos.z*16 << "\r" << std::flush; @@ -798,10 +772,9 @@ void TileGenerator::renderMap() } } if (currentPos.z != INT_MIN) { - pushPixelBlockCache(currentPos.x, currentPos.z); - resetPixelBlockCache(); - if(m_shading) - renderShading(currentPos.z); + if (m_shading) + m_blockPixelAttributes.renderShading(m_drawAlpha); + pushPixelRows(currentPos.z); } if (verboseStatistics) cout << "Statistics" @@ -820,17 +793,14 @@ void TileGenerator::renderMap() inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const BlockPos &pos, int version) { int xBegin = (pos.x - m_xMin) * 16; - int zBegin = (m_zMax - pos.z) * 16; 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; for (int z = 0; z < 16; ++z) { - int imageY = getImageY(zBegin + 15 - z); for (int x = 0; x < 16; ++x) { if (m_readedPixels[z] & (1 << x)) { continue; } - int imageX = getImageX(xBegin + x); for (int y = maxY; y >= minY; --y) { int position = x + (y << 4) + (z << 8); int content = readBlockContent(mapData, version, position); @@ -843,22 +813,16 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const const string &name = blockName->second; ColorMap::const_iterator color = m_colors.find(name); if (color != m_colors.end()) { - const Color c = color->second.to_color(); + PixelAttribute pixel = PixelAttribute(color->second, pos.y * 16 + y); if (m_drawAlpha) { - PixelCacheEntry pixel = PixelCacheEntry(color->second, pos.y * 16 + y); - m_pixelBlockCache[z][x].mixUnder(pixel); + m_blockPixelAttributes.attribute(15 - z,xBegin + x).mixUnder(pixel); if(pixel.alpha() == 0xff) { m_readedPixels[z] |= (1 << x); break; } - else if(0 && m_pixelBlockCache[z][x].alpha() == 0xff) { - m_readedPixels[z] |= (1 << x); - break; - } } else { - m_image->tpixels[imageY][imageX] = color2libgd(c); + m_blockPixelAttributes.attribute(15 - z, xBegin + x) = pixel; m_readedPixels[z] |= (1 << x); - m_blockPixelAttributes.attribute(15 - z, xBegin + x).height = pos.y * 16 + y; break; } } else { @@ -869,45 +833,9 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const } } -inline void TileGenerator::renderShading(int zPos) -{ - int zBegin = (m_zMax - zPos) * 16; - for (int z = 0; z < 16; ++z) { - int imageY = zBegin + z; - if (imageY >= m_mapHeight) { - continue; - } - imageY = getImageY(imageY); - for (int x = 0; x < m_mapWidth; ++x) { - if (!m_blockPixelAttributes.attribute(z, x).valid_height() || !m_blockPixelAttributes.attribute(z, x - 1).valid_height() || !m_blockPixelAttributes.attribute(z - 1, x).valid_height()) { - continue; - } - int y = m_blockPixelAttributes.attribute(z, x).height; - int y1 = m_blockPixelAttributes.attribute(z, x - 1).height; - int y2 = m_blockPixelAttributes.attribute(z - 1, x).height; - int d = ((y - y1) + (y - y2)) * 12; - if (d > 36) { - d = 36; - } - if (m_drawAlpha) - d = d * ((0xFF - m_blockPixelAttributes.attribute(z, x).thicken) / 255.0); - int sourceColor = m_image->tpixels[imageY][getImageX(x)] & 0xffffff; - uint8_t r = (sourceColor & 0xff0000) >> 16; - uint8_t g = (sourceColor & 0x00ff00) >> 8; - uint8_t b = (sourceColor & 0x0000ff); - r = colorSafeBounds(r + d); - g = colorSafeBounds(g + d); - b = colorSafeBounds(b + d); - - m_image->tpixels[imageY][getImageX(x)] = rgb2libgd(r, g, b); - } - } - m_blockPixelAttributes.scroll(); -} - void TileGenerator::renderScale() { - int color = color2libgd(m_scaleColor); + int color = m_scaleColor.to_libgd(); gdImageString(m_image, gdFontGetMediumBold(), 24, 0, reinterpret_cast(const_cast("X")), color); gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast(const_cast("Z")), color); @@ -938,12 +866,12 @@ void TileGenerator::renderOrigin() { int imageX = getImageX(-m_xMin * 16); int imageY = getImageY(m_mapHeight - 1 - m_zMin * -16); - gdImageArc(m_image, imageX, imageY, 12, 12, 0, 360, color2libgd(m_originColor)); + gdImageArc(m_image, imageX, imageY, 12, 12, 0, 360, m_originColor.to_libgd()); } void TileGenerator::renderPlayers(const std::string &inputPath) { - int color = color2libgd(m_playerColor); + int color = m_playerColor.to_libgd(); PlayerAttributes players(inputPath); for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) { diff --git a/TileGenerator.h b/TileGenerator.h index d4562b4..6abfc11 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -20,7 +20,6 @@ #include #include "PixelAttributes.h" #include "Color.h" -#include "PixelCacheEntry.h" #include "db.h" #define MINETEST_MAPBLOCK_MIN (-2048) @@ -120,10 +119,8 @@ private: void renderMap(); std::list getZValueList() const; Block getBlockOnPos(BlockPos pos); - void resetPixelBlockCache(void); - void pushPixelBlockCache(int xPos, int zPos); + void pushPixelRows(int zPos); void renderMapBlock(const unsigned_string &mapBlock, const BlockPos &pos, int version); - void renderShading(int zPos); void renderScale(); void renderOrigin(); void renderPlayers(const std::string &inputPath); @@ -156,7 +153,6 @@ private: DB *m_db; gdImagePtr m_image; PixelAttributes m_blockPixelAttributes; - PixelCacheEntry m_pixelBlockCache[16][16]; int m_xMin; int m_xMax; int m_zMin;