Make PixelAttributes more generic

In preparation for other changes
This commit is contained in:
Rogier 2014-04-14 20:46:12 +02:00
parent ec557c0231
commit 2119a6ae75
4 changed files with 111 additions and 65 deletions

View File

@ -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<m_lineCount; i++)
for (int j=0; j<m_width; j++)
m_pixelAttributes[i][j].a=0;
}
void PixelAttributes::scroll()
void PixelAttributes::scroll(int keepY)
{
PixelAttribute *tmp;
tmp = m_pixelAttributes[PreviousLine];
m_pixelAttributes[PreviousLine] = m_pixelAttributes[LastLine];
m_pixelAttributes[LastLine] = tmp;
int scroll = keepY - m_firstY;
if (scroll > 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;

View File

@ -13,6 +13,7 @@
#include <limits>
#include <cmath>
#include <stdint.h>
#include <stdexcept>
#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;
};

View File

@ -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; x<m_mapWidth; x++) {
for (int z=0; z<16; z++) {
PixelAttribute &pixel = m_blockPixelAttributes.attribute(z,x);
if (pixel.valid_height())
m_image->tpixels[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;
}

View File

@ -119,7 +119,7 @@ private:
void renderMap();
std::list<int> 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;