diff --git a/PixelAttributes.cpp b/PixelAttributes.cpp index 0f15b27..493ca1c 100644 --- a/PixelAttributes.cpp +++ b/PixelAttributes.cpp @@ -15,11 +15,8 @@ using namespace std; PixelAttributes::PixelAttributes(): - m_width(0) + m_pixelAttributes(0) { - for (size_t i = 0; i < LineCount; ++i) { - m_pixelAttributes[i] = 0; - } } PixelAttributes::~PixelAttributes() @@ -27,35 +24,66 @@ PixelAttributes::~PixelAttributes() freeAttributes(); } -void PixelAttributes::setWidth(int width) +void PixelAttributes::setParameters(int width, int lines) { freeAttributes(); m_width = width + 1; // 1px gradient calculation - for (size_t i = 0; i < LineCount; ++i) { + m_previousLine = 0; + m_firstLine = 1; + m_lastLine = m_firstLine + lines - 1; + m_emptyLine = m_lastLine + 1; + m_lineCount = m_emptyLine + 1; + m_firstY = 0; + m_lastY = -1; + m_firstUnshadedY = 0; + + m_pixelAttributes = new PixelAttribute *[m_lineCount]; + if (!m_pixelAttributes) + throw std::runtime_error("Failed to allocate memory for PixelAttributes"); + + for (int i = 0; i < m_lineCount; ++i) { m_pixelAttributes[i] = new PixelAttribute[m_width]; + if (!m_pixelAttributes[i]) + throw std::runtime_error("Failed to allocate memory for PixelAttributes"); } + for (int i=0; i 0) { + int i; + for (i = m_previousLine; i + scroll <= m_lastLine; i++) { + PixelAttribute *tmp; + tmp = m_pixelAttributes[i]; + m_pixelAttributes[i] = m_pixelAttributes[i + scroll]; + m_pixelAttributes[i + scroll] = tmp; + } - size_t lineLength = m_width * sizeof(PixelAttribute); - for (int i = PreviousLine; i <= LastLine; ++i) { - memcpy(m_pixelAttributes[i], m_pixelAttributes[EmptyLine], lineLength); + size_t lineLength = m_width * sizeof(PixelAttribute); + for (; i <= m_lastLine; ++i) { + memcpy(m_pixelAttributes[i], m_pixelAttributes[m_emptyLine], lineLength); + } + + m_firstY += scroll; + m_firstUnshadedY -= scroll; + if (m_firstUnshadedY < m_firstY) m_firstUnshadedY = m_firstY; } } void PixelAttributes::freeAttributes() { - for (size_t i = 0; i < LineCount; ++i) { - if (m_pixelAttributes[i] != 0) { - delete[] m_pixelAttributes[i]; - m_pixelAttributes[i] = 0; + if (m_pixelAttributes) { + for (int i = 0; i < m_lineCount; ++i) { + if (m_pixelAttributes[i] != 0) { + delete[] m_pixelAttributes[i]; + } } + delete[] m_pixelAttributes; + m_pixelAttributes = 0; } } @@ -76,32 +104,34 @@ static inline double colorSafeBounds(double color) void PixelAttributes::renderShading(bool drawAlpha) { - for (int z = FirstLine; z <= LastLine; z++) { + int y; + for (y = yCoord2Line(m_firstUnshadedY); y <= yCoord2Line(m_lastY); y++) { 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()) + if (!m_pixelAttributes[y][x].is_valid() || !m_pixelAttributes[y - 1][x].is_valid() || !m_pixelAttributes[y][x - 1].is_valid()) 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); + double h = m_pixelAttributes[y][x].h; + double h1 = m_pixelAttributes[y][x - 1].h; + double h2 = m_pixelAttributes[y - 1][x].h; + double d = (h - h1) + (h - h2); 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]; + d = d * (1 - m_pixelAttributes[y][x].t); + PixelAttribute &pixel = m_pixelAttributes[y][x]; pixel.r = colorSafeBounds(pixel.r + d); pixel.g = colorSafeBounds(pixel.g + d); pixel.b = colorSafeBounds(pixel.b + d); } } + m_firstUnshadedY = y - yCoord2Line(0); } void PixelAttribute::mixUnder(const PixelAttribute &p) { int prev_alpha = alpha(); - if (!valid_height() || a==0) { + if (!is_valid() || a==0) { r = p.r; g = p.g; b = p.b; diff --git a/PixelAttributes.h b/PixelAttributes.h index faad345..882b806 100644 --- a/PixelAttributes.h +++ b/PixelAttributes.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "config.h" #include "Color.h" @@ -34,7 +35,7 @@ struct PixelAttribute { 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); } + inline bool is_valid() const { return !isnan(h); } PixelAttribute &operator=(const PixelAttribute &p); void mixUnder(const PixelAttribute &p); }; @@ -44,24 +45,27 @@ class PixelAttributes public: PixelAttributes(); virtual ~PixelAttributes(); - void setWidth(int width); - void scroll(); - inline PixelAttribute &attribute(int z, int x) { return m_pixelAttributes[z + 1][x + 1]; }; + void setParameters(int width, int lines); + void scroll(int keepY); + inline PixelAttribute &attribute(int y, int x) { return m_pixelAttributes[yCoord2Line(y)][x + 1]; }; void renderShading(bool drawAlpha); + void setLastY(int y) { m_lastY = y; } private: + int yCoord2Line(int y) { return y - m_firstY + m_firstLine; } void freeAttributes(); private: - enum Line { - PreviousLine = 0, - FirstLine = 1, - LastLine = BLOCK_SIZE, - EmptyLine = BLOCK_SIZE + 1, - LineCount = BLOCK_SIZE + 2 - }; - PixelAttribute *m_pixelAttributes[BLOCK_SIZE + 2]; // 1px gradient + empty + int m_previousLine; + int m_firstLine; + int m_lastLine; + int m_emptyLine; + int m_lineCount; + PixelAttribute **m_pixelAttributes; int m_width; + int m_firstY; + int m_lastY; + int m_firstUnshadedY; }; diff --git a/TileGenerator.cpp b/TileGenerator.cpp index d0db865..aaf590d 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -499,23 +499,31 @@ inline BlockPos TileGenerator::decodeBlockPos(int64_t blockId) const return pos; } -void TileGenerator::pushPixelRows(int zPos) { - int zBegin = (m_zMax - zPos) * 16; - for (int x=0; xtpixels[getImageY(zBegin + z)][getImageX(x)] = pixel.color().to_libgd(); +void TileGenerator::pushPixelRows(int zPos, int zLimit) { + if (m_shading) + m_blockPixelAttributes.renderShading(m_drawAlpha); + int zBegin = getZBegin(zPos); + int z; + for (z = zBegin; z < zBegin + 16; z++) { + for (int x=0; x < m_mapWidth; x++) { + PixelAttribute &pixel = m_blockPixelAttributes.attribute(z, x); + if (pixel.is_valid()) + m_image->tpixels[getImageY(z)][getImageX(x)] = pixel.color().to_libgd(); } } - m_blockPixelAttributes.scroll(); + m_blockPixelAttributes.scroll(z); + zPos--; + if (zPos > zLimit) { + zBegin = (m_zMax - zPos) * 16; + m_blockPixelAttributes.scroll(zBegin + 16); + } } void TileGenerator::createImage() { m_mapWidth = (m_xMax - m_xMin + 1) * 16; m_mapHeight = (m_zMax - m_zMin + 1) * 16; - m_blockPixelAttributes.setWidth(m_mapWidth); + m_blockPixelAttributes.setParameters(m_mapWidth, 16); // Set special values for origin (which depend on other paramters) if (m_tileWidth) { @@ -610,6 +618,8 @@ void TileGenerator::createImage() int borderColor = m_tileBorderColor.to_libgd(); for (int i = 0; i < tileBorderXLimit - tileBorderXStart; i++) { int xPos = m_tileMapXOffset + i * (m_tileWidth + m_tileBorderSize); + //int xPos2 = getImageX(m_tileMapXOffset + i * m_tileWidth) - m_border - 1; + //assert(xPos == xPos2); gdImageFilledRectangle(m_image, xPos + m_border, m_border, xPos + (m_tileBorderSize-1) + m_border, pictHeight + m_border - 1, borderColor); } } @@ -617,6 +627,8 @@ void TileGenerator::createImage() int borderColor = m_tileBorderColor.to_libgd(); for (int i = 0; i < tileBorderZLimit - tileBorderZStart; i++) { int yPos = m_tileMapYOffset + i * (m_tileHeight + m_tileBorderSize); + //int yPos2 = getImageY(m_tileMapYOffset + i * m_tileHeight) - m_border - 1; + //assert(yPos == yPos2); gdImageFilledRectangle(m_image, m_border, yPos + m_border, pictWidth + m_border - 1, yPos + (m_tileBorderSize-1) + m_border, borderColor); } } @@ -663,13 +675,13 @@ void TileGenerator::renderMap() const BlockPos &pos = *position; if (currentPos.x != pos.x || currentPos.z != pos.z) { area_rendered++; - if (currentPos.z != INT_MIN && currentPos.z != pos.z) { - if (m_shading) - m_blockPixelAttributes.renderShading(m_drawAlpha); - pushPixelRows(currentPos.z); + if (currentPos.z != pos.z) { + if (currentPos.z != INT_MIN) + pushPixelRows(currentPos.z, pos.z); + m_blockPixelAttributes.setLastY((m_zMax - pos.z) * 16 + 15); + if (progressIndicator) + cout << "Processing Z-coordinate: " << std::setw(5) << pos.z*16 << "\r" << std::flush; } - 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) { m_readedPixels[i] = 0; } @@ -772,11 +784,8 @@ void TileGenerator::renderMap() } } } - if (currentPos.z != INT_MIN) { - if (m_shading) - m_blockPixelAttributes.renderShading(m_drawAlpha); - pushPixelRows(currentPos.z); - } + if (currentPos.z != INT_MIN) + pushPixelRows(currentPos.z, currentPos.z - 1); if (verboseStatistics) cout << "Statistics" << ": blocks read: " << m_db->getBlocksReadCount() @@ -793,7 +802,8 @@ void TileGenerator::renderMap() inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const BlockPos &pos, int version) { - int xBegin = (pos.x - m_xMin) * 16; + int xBegin = getXBegin(pos.x); + int zBegin = getZBegin(pos.z); 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; @@ -816,13 +826,13 @@ inline void TileGenerator::renderMapBlock(const unsigned_string &mapBlock, const if (color != m_colors.end()) { PixelAttribute pixel = PixelAttribute(color->second, pos.y * 16 + y); if (m_drawAlpha) { - m_blockPixelAttributes.attribute(15 - z,xBegin + x).mixUnder(pixel); + m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin + x).mixUnder(pixel); if(pixel.alpha() == 0xff) { m_readedPixels[z] |= (1 << x); break; } } else { - m_blockPixelAttributes.attribute(15 - z, xBegin + x) = pixel; + m_blockPixelAttributes.attribute(zBegin + 15 - z, xBegin + x) = pixel; m_readedPixels[z] |= (1 << x); break; } diff --git a/TileGenerator.h b/TileGenerator.h index 6abfc11..6f5e9e5 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -119,7 +119,7 @@ private: void renderMap(); std::list getZValueList() const; Block getBlockOnPos(BlockPos pos); - void pushPixelRows(int zPos); + void pushPixelRows(int zPos, int zLimit); void renderMapBlock(const unsigned_string &mapBlock, const BlockPos &pos, int version); void renderScale(); void renderOrigin(); @@ -128,6 +128,8 @@ private: void printUnknown(); int getImageX(int val) const; int getImageY(int val) const; + int getXBegin(int xPos) const { return (xPos - m_xMin) * 16; } + int getZBegin(int zPos) const { return (m_zMax - zPos) * 16; } public: bool verboseCoordinates; @@ -165,8 +167,8 @@ private: int m_reqYMax; int m_reqZMin; int m_reqZMax; - int m_reqYMinNode; // Node offset within a map block - int m_reqYMaxNode; // Node offset within a map block + int m_reqYMinNode; // Node offset within a map block + int m_reqYMaxNode; // Node offset within a map block int m_mapWidth; int m_mapHeight; int m_tileXOrigin;