Merge PixelCacheEntry into PixelAttributes

master
Rogier 2014-04-13 01:18:34 +02:00
parent b9993d68cf
commit ce94029c95
6 changed files with 152 additions and 226 deletions

28
Color.h
View File

@ -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

View File

@ -9,6 +9,7 @@
#include <cstdlib>
#include <cstring>
#include <iostream>
#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));
}
}

View File

@ -11,16 +11,32 @@
#define PIXELATTRIBUTES_H_ADZ35GYF
#include <limits>
#include <cmath>
#include <stdint.h>
#include "config.h"
#include "Color.h"
struct PixelAttribute {
PixelAttribute(): height(std::numeric_limits<int>::min()), thicken(0) {};
int height;
uint8_t thicken;
inline bool valid_height() {
return height != std::numeric_limits<int>::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 */

View File

@ -1,101 +0,0 @@
#ifndef PIXELCACHEINFO_H
#define PIXELCACHEINFO_H
#include<cmath>
#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

View File

@ -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; x<m_mapWidth; 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();
}
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<unsigned char *>(const_cast<char *>("X")), color);
gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast<unsigned char *>(const_cast<char *>("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) {

View File

@ -20,7 +20,6 @@
#include <string>
#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<int> 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;