Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tiled #67

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
41 changes: 26 additions & 15 deletions Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@
#include "Image.h"

#ifndef NDEBUG
#define SIZECHECK(x, y) check_bounds((x), (y), m_width, m_height)
// allow x,y to be 256 pixels outside of the image.
// this allows stuff like the playername labels to be drawn somewhat outside of the
// image (relying on gd's built in clipping) while still catching probable
// buggy draw operations
#define SIZECHECK_FUZZY(x, y) check_bounds((x), (y), m_width, m_height, 256)
#else
#define SIZECHECK(x, y) do {} while(0)
#define SIZECHECK_FUZZY(x, y) do {} while(0)
#endif


// ARGB but with inverted alpha

static inline int color2int(Color c)
Expand All @@ -35,18 +40,18 @@ static inline Color int2color(int c)
return c2;
}

static inline void check_bounds(int x, int y, int width, int height)
static inline void check_bounds(int x, int y, int width, int height, int border)
{
if(x < 0 || x >= width) {
if(x < -border || x >= width + border) {
std::ostringstream oss;
oss << "Access outside image bounds (x), 0 < "
<< x << " < " << width << " is false.";
throw std::out_of_range(oss.str());
}
if(y < 0 || y >= height) {
if(y < -border || y >= height + border) {
std::ostringstream oss;
oss << "Access outside image bounds (y), 0 < "
<< y << " < " << height << " is false.";
oss << "Access outside image bounds (y)," << -border << " 0 < "
<< y << " < " << height+border << " is false.";
throw std::out_of_range(oss.str());
}
}
Expand All @@ -65,39 +70,39 @@ Image::~Image()

void Image::setPixel(int x, int y, const Color &c)
{
SIZECHECK(x, y);
SIZECHECK_FUZZY(x, y);
m_image->tpixels[y][x] = color2int(c);
}

Color Image::getPixel(int x, int y)
{
SIZECHECK(x, y);
SIZECHECK_FUZZY(x, y);
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);
SIZECHECK_FUZZY(x1, y1);
SIZECHECK_FUZZY(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);
SIZECHECK_FUZZY(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);
SIZECHECK_FUZZY(x, y);
SIZECHECK_FUZZY(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);
SIZECHECK_FUZZY(x, y);
gdImageArc(m_image, x, y, diameter, diameter, 0, 360, color2int(c));
}

Expand All @@ -122,3 +127,9 @@ void Image::save(const std::string &filename)
fclose(f);
#endif
}


void Image::fill(Color &c)
{
gdImageFilledRectangle(m_image, 0, 0, m_width - 1 , m_height - 1, color2int(c));
}
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ backend:
geometry:
Limit area to specific geometry (*x:z+w+h* where x and z specify the lower left corner), e.g. ``--geometry -800:-800+1600+1600``

tilesize:
Don't output one big image, but output tiles of the specified size, e.g. "--tilesize 128x128". The sizes will be rounded to
a multiple of 16. The filenames will be created in the form <x>_<y>_<filename>, where <x> and <y>
are the tile numbers and <filename> is the name specified with -o. Skip empty tiles by also specifying --noemptyimage.

zoom:
Apply zoom to drawn nodes by enlarging them to n*n squares, e.g. ``--zoom 4``

Expand Down
165 changes: 144 additions & 21 deletions TileGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ TileGenerator::TileGenerator():
m_geomY(-2048),
m_geomX2(2048),
m_geomY2(2048),
m_tileW(INT_MAX),
m_tileH(INT_MAX),
m_zoom(1),
m_scales(SCALE_LEFT | SCALE_TOP)
{
Expand Down Expand Up @@ -190,6 +192,13 @@ void TileGenerator::setGeometry(int x, int y, int w, int h)
m_geomY2 = round_multiple_nosign(y + h, 16) / 16;
}

void TileGenerator::setTileSize(int w, int h)
{
m_tileW = round_multiple_nosign(w, 16) / 16;
m_tileH = round_multiple_nosign(h, 16) / 16;
}


void TileGenerator::setMinY(int y)
{
m_yMin = y;
Expand Down Expand Up @@ -251,19 +260,95 @@ void TileGenerator::generate(const std::string &input, const std::string &output
}

createImage();
renderMap();
closeDatabase();
if (m_drawScale) {
renderScale();
}
if (m_drawOrigin) {
renderOrigin();


if (m_tileW < INT_MAX || m_tileH < INT_MAX)
{
m_xMin = round_multiple_nosign(m_xMin, m_tileW);
m_zMin = round_multiple_nosign(m_zMin, m_tileH);
int minTileX = m_xMin / m_tileW;
int minTileY = m_zMin / m_tileH;

sortPositionsIntoTiles();

int trueXMin = m_xMin;
int trueZMin = m_zMin;

// write info about the number of tiles and the tile sizes to a text file
// which can be used by another utility to generate zoom pyramids and/or
// add map annotations for a specific viewer.
std::ostringstream mfn;
mfn << "metadata_" << output << ".txt";
std::ofstream mf;

mf.open(mfn.str().c_str());

if (mf.is_open())
{

mf << "BaseName: " << output << std::endl;
mf << "NumTiles: " << m_numTilesX << " " << m_numTilesY << std::endl;
mf << "MinTile: " << minTileX << " " << minTileY << std::endl;
mf << "TileSize: " << (m_tileW*16) << " " << (m_tileH*16) << std::endl;
mf << "Zoom: " << m_zoom << std::endl;
mf.close();
}
else
{
std::cerr << "Warning: could not write to '" << mfn.str() << "'!" << std::endl;
}

for (int x = 0; x < m_numTilesX; x++)
{
for (int y = 0; y < m_numTilesY; y++)
{
TileMap::iterator t = m_tiles.find(x + (y << 16));
m_xMin = trueXMin + x * m_tileW;
m_zMin = trueZMin + y * m_tileH;
m_xMax = m_xMin + m_tileW - 1;
m_zMax = m_zMin + m_tileH -1;

if (t != m_tiles.end() || !m_dontWriteEmpty)
{
m_image->fill(m_bgColor);
if (t != m_tiles.end())
renderMap(t->second);
if (m_drawScale) {
renderScale();
}
if (m_drawOrigin) {
renderOrigin();
}
if (m_drawPlayers) {
renderPlayers(input_path);
}
ostringstream fn;
fn << "tile_" << (x + minTileX) << '_' << (y + minTileY) << '_' << output;
writeImage(fn.str());
}
}
}
}
if (m_drawPlayers) {
renderPlayers(input_path);
else
{
m_image->fill(m_bgColor);
renderMap(m_positions);
if (m_drawScale) {
renderScale();
}
if (m_drawOrigin) {
renderOrigin();
}
if (m_drawPlayers) {
renderPlayers(input_path);
}
writeImage(output);
}
writeImage(output);
closeDatabase();
printUnknown();

delete m_image;
m_image = NULL;
}

void TileGenerator::parseColorsStream(std::istream &in)
Expand Down Expand Up @@ -380,8 +465,17 @@ void TileGenerator::createImage()
m_zMax = m_geomY2-1;
}

m_mapWidth = (m_xMax - m_xMin + 1) * 16;
m_mapHeight = (m_zMax - m_zMin + 1) * 16;
m_mapWidth = (m_xMax - m_xMin + 1);
m_mapHeight = (m_zMax - m_zMin + 1);

if (m_tileW < INT_MAX)
m_mapWidth = m_tileW;

if (m_tileH < INT_MAX)
m_mapHeight = m_tileH;

m_mapWidth *= 16;
m_mapHeight *= 16;

m_xBorder = (m_scales & SCALE_LEFT) ? scale_d : 0;
m_yBorder = (m_scales & SCALE_TOP) ? scale_d : 0;
Expand All @@ -401,15 +495,15 @@ void TileGenerator::createImage()
m_image->drawFilledRect(0, 0, image_width, image_height, m_bgColor); // Background
}

void TileGenerator::renderMap()
void TileGenerator::renderMap(PositionsList &positions)
{
BlockDecoder blk;
std::list<int> zlist = getZValueList();
std::list<int> zlist = getZValueList(positions);
for (std::list<int>::iterator zPosition = zlist.begin(); zPosition != zlist.end(); ++zPosition) {
int zPos = *zPosition;
std::map<int16_t, BlockList> blocks;
m_db->getBlocksOnZ(blocks, zPos);
for (std::list<std::pair<int, int> >::const_iterator position = m_positions.begin(); position != m_positions.end(); ++position) {
for (PositionsList::const_iterator position = positions.begin(); position != positions.end(); ++position) {
if (position->second != zPos)
continue;

Expand Down Expand Up @@ -637,9 +731,12 @@ void TileGenerator::renderPlayers(const std::string &inputPath)
{
PlayerAttributes players(inputPath);
for (PlayerAttributes::Players::iterator player = players.begin(); player != players.end(); ++player) {
if (player->x < m_xMin * 16 || player->x > m_xMax * 16 ||
player->z < m_zMin * 16 || player->z > m_zMax * 16)
if (player->x < m_xMin*16 || player->x > m_xMax * 16 ||
player->z < m_zMin*16 || player->z > m_zMax * 16 )
{
continue;

}
if (player->y < m_yMin || player->y > m_yMax)
continue;
int imageX = getImageX(player->x, true),
Expand All @@ -651,10 +748,10 @@ void TileGenerator::renderPlayers(const std::string &inputPath)
}
}

inline std::list<int> TileGenerator::getZValueList() const
inline std::list<int> TileGenerator::getZValueList(PositionsList &positions) const
{
std::list<int> zlist;
for (std::list<std::pair<int, int> >::const_iterator position = m_positions.begin(); position != m_positions.end(); ++position)
for (PositionsList::const_iterator position = positions.begin(); position != positions.end(); ++position)
zlist.push_back(position->second);
zlist.sort();
zlist.unique();
Expand All @@ -665,8 +762,7 @@ inline std::list<int> TileGenerator::getZValueList() const
void TileGenerator::writeImage(const std::string &output)
{
m_image->save(output);
delete m_image;
m_image = NULL;
cout << "wrote image:" << output << endl;
}

void TileGenerator::printUnknown()
Expand Down Expand Up @@ -696,3 +792,30 @@ inline void TileGenerator::setZoomed(int x, int y, Color color)
{
m_image->drawFilledRect(getImageX(x), getImageY(y), m_zoom, m_zoom, color);
}


void TileGenerator::sortPositionsIntoTiles()
{
m_numTilesX = round_multiple_nosign(m_xMax - m_xMin + 1, m_tileW) / m_tileW;
m_numTilesY = round_multiple_nosign(m_zMax - m_zMin + 1, m_tileH) / m_tileH;

for (PositionsList::iterator p = m_positions.begin(); p != m_positions.end(); p++)
{
int xtile = (p->first - m_xMin) / m_tileW;
int ytile = (p->second - m_zMin) / m_tileH;

int key = xtile + (ytile << 16);

TileMap::iterator t = m_tiles.find(key);

if (t == m_tiles.end())
{
PositionsList l;
m_tiles.insert(std::pair<int, PositionsList>(key, l));
t = m_tiles.find(key);
}

t->second.push_back(std::pair<int, int>(p->first, p->second));
}
}

1 change: 1 addition & 0 deletions include/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Image {
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);
void fill(Color &c);

private:
Image(const Image&);
Expand Down
Loading