Move everything that deals with images directly to an Image class

This commit is contained in:
sfan5 2016-11-18 23:34:31 +01:00
parent 77fdcd15fb
commit a41d231c34
6 changed files with 176 additions and 75 deletions

@ -142,6 +142,7 @@ set(mapper_SRCS
PlayerAttributes.cpp PlayerAttributes.cpp
TileGenerator.cpp TileGenerator.cpp
ZlibDecompressor.cpp ZlibDecompressor.cpp
Image.cpp
mapper.cpp mapper.cpp
util.cpp util.cpp
db-sqlite3.cpp db-sqlite3.cpp

106
Image.cpp Normal file

@ -0,0 +1,106 @@
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <gd.h>
#include <gdfontmb.h>
#include "Image.h"
#ifndef NDEBUG
#define SIZECHECK(x, y) do { \
if((x) < 0 || (x) >= m_width) \
throw std::out_of_range("sizecheck x"); \
if((y) < 0 || (y) >= m_height) \
throw std::out_of_range("sizecheck y"); \
} while(0)
#else
#define SIZECHECK(x, y) do {} while(0)
#endif
// BGRA but with inverted alpha
static inline int color2int(Color c)
{
u8 a = 255 - c.a;
return (a << 24) | (c.r << 16) | (c.g << 8) | c.b;
}
static inline Color int2color(int c)
{
Color c2;
u8 a;
c2.b = c & 0xff;
c2.g = (c >> 8) & 0xff;
c2.r = (c >> 16) & 0xff;
a = (c >> 24) & 0xff;
c2.a = 255 - a;
return c2;
}
Image::Image(int width, int height) :
m_width(width), m_height(height), m_image(NULL)
{
m_image = gdImageCreateTrueColor(m_width, m_height);
}
Image::~Image()
{
gdImageDestroy(m_image);
}
void Image::setPixel(int x, int y, const Color &c)
{
SIZECHECK(x, y);
m_image->tpixels[y][x] = color2int(c);
}
Color Image::getPixel(int x, int y)
{
#ifndef NDEBUG
if(x < 0 || x > m_width || y < 0 || y > m_height)
throw std::out_of_range("sizecheck");
#endif
return int2color(m_image->tpixels[y][x]);
}
void Image::drawLine(int x1, int y1, int x2, int y2, const Color &c)
{
SIZECHECK(x1, y1);
SIZECHECK(x2, y2);
gdImageLine(m_image, x1, y1, x2, y2, color2int(c));
}
void Image::drawText(int x, int y, const std::string &s, const Color &c)
{
SIZECHECK(x, y);
gdImageString(m_image, gdFontGetMediumBold(), x, y, (unsigned char*) s.c_str(), color2int(c));
}
void Image::drawFilledRect(int x, int y, int w, int h, const Color &c)
{
SIZECHECK(x, y);
SIZECHECK(x + w - 1, y + h - 1);
gdImageFilledRectangle(m_image, x, y, x + w - 1, y + h - 1, color2int(c));
}
void Image::drawCircle(int x, int y, int diameter, const Color &c)
{
SIZECHECK(x, y);
gdImageArc(m_image, x, y, diameter, diameter, 0, 360, color2int(c));
}
void Image::save(const std::string &filename)
{
FILE *f = fopen(filename.c_str(), "wb");
if(!f) {
std::ostringstream oss;
oss << "Error writing image file: " << std::strerror(errno);
throw std::runtime_error(oss.str());
}
gdImagePng(m_image, f); // other formats?
fclose(f);
}

35
Image.h Normal file

@ -0,0 +1,35 @@
#ifndef IMAGE_HEADER
#define IMAGE_HEADER
#include "types.h"
#include <string>
#include <gd.h>
struct Color {
Color() : r(0), g(0), b(0), a(0) {};
Color(u8 r, u8 g, u8 b) : r(r), g(g), b(b), a(255) {};
Color(u8 r, u8 g, u8 b, u8 a) : r(r), g(g), b(b), a(a) {};
u8 r, g, b, a;
};
class Image {
public:
Image(int width, int height);
~Image();
void setPixel(int x, int y, const Color &c);
Color getPixel(int x, int y);
void drawLine(int x1, int y1, int x2, int y2, const Color &c);
void drawText(int x, int y, const std::string &s, const Color &c);
void drawFilledRect(int x, int y, int w, int h, const Color &c);
void drawCircle(int x, int y, int diameter, const Color &c);
void save(const std::string &filename);
private:
Image(const Image&);
int m_width, m_height;
gdImagePtr m_image;
};
#endif // IMAGE_HEADER

@ -2,11 +2,9 @@
#include <cstdlib> #include <cstdlib>
#include <climits> #include <climits>
#include <fstream> #include <fstream>
#include <gdfontmb.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <cerrno>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include "config.h" #include "config.h"
@ -29,16 +27,6 @@ static inline uint16_t readU16(const unsigned char *data)
return data[0] << 8 | data[1]; return data[0] << 8 | data[1];
} }
static inline int rgb2int(uint8_t r, uint8_t g, uint8_t b, uint8_t a=0xFF)
{
return (a << 24) + (r << 16) + (g << 8) + b;
}
static inline int color2int(Color c)
{
return rgb2int(c.r, c.g, c.b, c.a);
}
// rounds n (away from 0) to a multiple of f while preserving the sign of n // rounds n (away from 0) to a multiple of f while preserving the sign of n
static inline int round_multiple_nosign(int n, int f) static inline int round_multiple_nosign(int n, int f)
{ {
@ -377,10 +365,9 @@ void TileGenerator::createImage()
std::cerr << "Warning: The width or height of the image to be created exceeds 4096 pixels!" std::cerr << "Warning: The width or height of the image to be created exceeds 4096 pixels!"
<< " (Dimensions: " << image_width << "x" << image_height << ")" << " (Dimensions: " << image_width << "x" << image_height << ")"
<< std::endl; << std::endl;
m_image = gdImageCreateTrueColor(image_width, image_height); m_image = new Image(image_width, image_height);
m_blockPixelAttributes.setWidth(m_mapWidth); m_blockPixelAttributes.setWidth(m_mapWidth);
// Background m_image->drawFilledRect(0, 0, image_width, image_height, m_bgColor); // Background
gdImageFilledRectangle(m_image, 0, 0, image_width - 1, image_height - 1, color2int(m_bgColor));
} }
void TileGenerator::renderMap() void TileGenerator::renderMap()
@ -560,7 +547,7 @@ inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPo
else else
m_color[z][x] = mixColors(m_color[z][x], c); m_color[z][x] = mixColors(m_color[z][x], c);
if(m_color[z][x].a == 0xFF) { if(m_color[z][x].a == 0xFF) {
setZoomed(m_image,imageY,imageX,color2int(m_color[z][x])); setZoomed(imageX, imageY, m_color[z][x]);
m_readPixels[z] |= (1 << x); m_readPixels[z] |= (1 << x);
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x]; m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
} else { } else {
@ -568,7 +555,7 @@ inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPo
continue; continue;
} }
} else { } else {
setZoomed(m_image,imageY,imageX,color2int(c)); setZoomed(imageX, imageY, c);
m_readPixels[z] |= (1 << x); m_readPixels[z] |= (1 << x);
} }
if(!(m_readInfo[z] & (1 << x))) { if(!(m_readInfo[z] & (1 << x))) {
@ -598,7 +585,7 @@ inline void TileGenerator::renderMapBlockBottom(const BlockPos &pos)
int imageX = xBegin + x; int imageX = xBegin + x;
if (m_drawAlpha) { if (m_drawAlpha) {
setZoomed(m_image,imageY,imageX, color2int(m_color[z][x])); setZoomed(imageX, imageY, m_color[z][x]);
m_readPixels[z] |= (1 << x); m_readPixels[z] |= (1 << x);
m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x]; m_blockPixelAttributes.attribute(15 - z, xBegin + x).thickness = m_thickness[z][x];
} }
@ -628,14 +615,11 @@ inline void TileGenerator::renderShading(int zPos)
// more thickness -> less visible shadows: t=0 -> 100% visible, t=255 -> 0% visible // more thickness -> less visible shadows: t=0 -> 100% visible, t=255 -> 0% visible
if (m_drawAlpha) if (m_drawAlpha)
d = d * ((0xFF - m_blockPixelAttributes.attribute(z, x).thickness) / 255.0); d = d * ((0xFF - m_blockPixelAttributes.attribute(z, x).thickness) / 255.0);
int sourceColor = m_image->tpixels[getImageY(imageY)][getImageX(x)] & 0xffffff; Color c = m_image->getPixel(getImageX(x), getImageY(imageY));
uint8_t r = (sourceColor & 0xff0000) >> 16; c.r = colorSafeBounds(c.r + d);
uint8_t g = (sourceColor & 0x00ff00) >> 8; c.g = colorSafeBounds(c.g + d);
uint8_t b = (sourceColor & 0x0000ff); c.b = colorSafeBounds(c.b + d);
r = colorSafeBounds(r + d); setZoomed(x, imageY, c);
g = colorSafeBounds(g + d);
b = colorSafeBounds(b + d);
setZoomed(m_image,imageY,x, rgb2int(r, g, b));
} }
} }
m_blockPixelAttributes.scroll(); m_blockPixelAttributes.scroll();
@ -643,33 +627,31 @@ inline void TileGenerator::renderShading(int zPos)
void TileGenerator::renderScale() void TileGenerator::renderScale()
{ {
int color = color2int(m_scaleColor);
string scaleText; string scaleText;
if (m_scales & SCALE_TOP) { if (m_scales & SCALE_TOP) {
gdImageString(m_image, gdFontGetMediumBold(), 24, 0, reinterpret_cast<unsigned char *>(const_cast<char *>("X")), color); m_image->drawText(24, 0, "X", m_scaleColor);
for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4) { for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4) {
stringstream buf; stringstream buf;
buf << i * 16; buf << i * 16;
scaleText = buf.str(); scaleText = buf.str();
int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder; int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder;
gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, 0, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color); m_image->drawText(xPos + 2, 0, scaleText, m_scaleColor);
gdImageLine(m_image, xPos, 0, xPos, m_yBorder - 1, color); m_image->drawLine(xPos, 0, xPos, m_yBorder - 1, m_scaleColor);
} }
} }
if (m_scales & SCALE_LEFT) { if (m_scales & SCALE_LEFT) {
gdImageString(m_image, gdFontGetMediumBold(), 2, 24, reinterpret_cast<unsigned char *>(const_cast<char *>("Z")), color); m_image->drawText(2, 24, "Z", m_scaleColor);
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) { for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) {
stringstream buf; stringstream buf;
buf << i * 16; buf << i * 16;
scaleText = buf.str(); scaleText = buf.str();
int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder; int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder;
gdImageString(m_image, gdFontGetMediumBold(), 2, yPos, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color); m_image->drawText(2, yPos, scaleText, m_scaleColor);
gdImageLine(m_image, 0, yPos, m_xBorder - 1, yPos, color); m_image->drawLine(0, yPos, m_xBorder - 1, yPos, m_scaleColor);
} }
} }
@ -680,9 +662,9 @@ void TileGenerator::renderScale()
scaleText = buf.str(); scaleText = buf.str();
int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder; int xPos = (m_xMin * -16 + i * 16)*m_zoom + m_xBorder;
int yPos = m_yBorder + m_mapHeight; int yPos = m_yBorder + m_mapHeight*m_zoom;
gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, yPos, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color); m_image->drawText(xPos + 2, yPos, scaleText, m_scaleColor);
gdImageLine(m_image, xPos, yPos, xPos, yPos + 39, color); m_image->drawLine(xPos, yPos, xPos, yPos + 39, m_scaleColor);
} }
} }
@ -692,10 +674,10 @@ void TileGenerator::renderScale()
buf << i * 16; buf << i * 16;
scaleText = buf.str(); scaleText = buf.str();
int xPos = m_xBorder + m_mapWidth; int xPos = m_xBorder + m_mapWidth*m_zoom;
int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder; int yPos = (m_mapHeight - 1 - (i * 16 - m_zMin * 16))*m_zoom + m_yBorder;
gdImageString(m_image, gdFontGetMediumBold(), xPos + 2, yPos, reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), color); m_image->drawText(xPos + 2, yPos, scaleText, m_scaleColor);
gdImageLine(m_image, xPos, yPos, xPos + 39, yPos, color); m_image->drawLine(xPos, yPos, xPos + 39, yPos, m_scaleColor);
} }
} }
} }
@ -704,20 +686,18 @@ void TileGenerator::renderOrigin()
{ {
int imageX = (-m_xMin * 16)*m_zoom + m_xBorder; int imageX = (-m_xMin * 16)*m_zoom + m_xBorder;
int imageY = (m_mapHeight - m_zMin * -16)*m_zoom + m_yBorder; int imageY = (m_mapHeight - m_zMin * -16)*m_zoom + m_yBorder;
gdImageArc(m_image, imageX, imageY, 12, 12, 0, 360, color2int(m_originColor)); m_image->drawCircle(imageX, imageY, 12, m_originColor);
} }
void TileGenerator::renderPlayers(const std::string &inputPath) void TileGenerator::renderPlayers(const std::string &inputPath)
{ {
int color = color2int(m_playerColor);
PlayerAttributes players(inputPath); PlayerAttributes players(inputPath);
for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) { for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) {
int imageX = (player->x / 10 - m_xMin * 16)*m_zoom + m_xBorder; int imageX = (player->x / 10 - m_xMin * 16)*m_zoom + m_xBorder;
int imageY = (m_mapHeight - (player->z / 10 - m_zMin * 16))*m_zoom + m_yBorder; int imageY = (m_mapHeight - (player->z / 10 - m_zMin * 16))*m_zoom + m_yBorder;
gdImageArc(m_image, imageX, imageY, 5, 5, 0, 360, color); m_image->drawCircle(imageX, imageY, 5, m_playerColor);
gdImageString(m_image, gdFontGetMediumBold(), imageX + 2, imageY + 2, reinterpret_cast<unsigned char *>(const_cast<char *>(player->name.c_str())), color); m_image->drawText(imageX + 2, imageY + 2, player->name, m_playerColor);
} }
} }
@ -735,16 +715,9 @@ inline std::list<int> TileGenerator::getZValueList() const
void TileGenerator::writeImage(const std::string &output) void TileGenerator::writeImage(const std::string &output)
{ {
FILE *out; m_image->save(output);
out = fopen(output.c_str(), "wb"); delete m_image;
if (!out) { m_image = NULL;
std::ostringstream oss;
oss << "Error opening '" << output.c_str() << "': " << std::strerror(errno);
throw std::runtime_error(oss.str());
}
gdImagePng(m_image, out);
fclose(out);
gdImageDestroy(m_image);
} }
void TileGenerator::printUnknown() void TileGenerator::printUnknown()
@ -767,11 +740,6 @@ inline int TileGenerator::getImageY(int val) const
return (m_zoom*val) + m_yBorder; return (m_zoom*val) + m_yBorder;
} }
inline void TileGenerator::setZoomed(gdImagePtr image, int y, int x, int color) { inline void TileGenerator::setZoomed(int x, int y, Color color) {
int xx,yy; m_image->drawFilledRect(getImageX(x), getImageY(y), m_zoom, m_zoom, color);
for (xx = 0; xx < m_zoom; xx++) {
for (yy = 0; yy < m_zoom; yy++) {
image->tpixels[m_yBorder + (y*m_zoom) + xx][m_xBorder + (x*m_zoom) + yy] = color;
}
}
} }

@ -15,6 +15,7 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include "PixelAttributes.h" #include "PixelAttributes.h"
#include "Image.h"
#include "db.h" #include "db.h"
#include "types.h" #include "types.h"
@ -25,16 +26,6 @@ enum {
SCALE_RIGHT = (1 << 3), SCALE_RIGHT = (1 << 3),
}; };
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(0) {};
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a): r(r), g(g), b(b), a(a) {};
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
struct ColorEntry { struct ColorEntry {
ColorEntry(): r(0), g(0), b(0), a(0), t(0) {}; ColorEntry(): r(0), g(0), b(0), a(0), t(0) {};
ColorEntry(uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t t): r(r), g(g), b(b), a(a), t(t) {}; ColorEntry(uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint8_t t): r(r), g(g), b(b), a(a), t(t) {};
@ -99,7 +90,7 @@ private:
void printUnknown(); void printUnknown();
int getImageX(int val) const; int getImageX(int val) const;
int getImageY(int val) const; int getImageY(int val) const;
void setZoomed(gdImagePtr image, int x, int y, int color); void setZoomed(int x, int y, Color color);
private: private:
Color m_bgColor; Color m_bgColor;
@ -115,7 +106,7 @@ private:
int m_xBorder, m_yBorder; int m_xBorder, m_yBorder;
DB *m_db; DB *m_db;
gdImagePtr m_image; Image *m_image;
PixelAttributes m_blockPixelAttributes; PixelAttributes m_blockPixelAttributes;
int m_xMin; int m_xMin;
int m_xMax; int m_xMax;

@ -1,5 +1,5 @@
#include <string> #include <string>
typedef std::basic_string<unsigned char> ustring; typedef std::basic_string<unsigned char> ustring;
typedef unsigned int uint; typedef unsigned int uint;
typedef uint8_t u8;