diff --git a/Image.cpp b/Image.cpp index 5f1936d..0c78f85 100644 --- a/Image.cpp +++ b/Image.cpp @@ -127,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)); +} diff --git a/README.rst b/README.rst index 993e29c..7d4c6fc 100644 --- a/README.rst +++ b/README.rst @@ -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 __, where and + are the tile numbers and 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`` diff --git a/TileGenerator.cpp b/TileGenerator.cpp index 90e311b..e2ab7e4 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -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) { @@ -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; @@ -251,19 +260,66 @@ void TileGenerator::generate(const std::string &input, const std::string &output } createImage(); - renderMap(); + + + if (m_tileW < INT_MAX || m_tileH < INT_MAX) + { + tilePositions(); + + int trueXMin = m_xMin; + int trueZMin = m_zMin; + + 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 << x << '_' << y << '_' << output; + writeImage(fn.str()); + } + } + } + } + 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); + } closeDatabase(); - if (m_drawScale) { - renderScale(); - } - if (m_drawOrigin) { - renderOrigin(); - } - if (m_drawPlayers) { - renderPlayers(input_path); - } - writeImage(output); printUnknown(); + + delete m_image; + m_image = NULL; } void TileGenerator::parseColorsStream(std::istream &in) @@ -380,8 +436,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_mapWidth > m_tileW) + m_mapWidth = m_tileW; + + if (m_mapHeight > m_tileH) + 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; @@ -401,15 +466,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 zlist = getZValueList(); + std::list zlist = getZValueList(positions); for (std::list::iterator zPosition = zlist.begin(); zPosition != zlist.end(); ++zPosition) { int zPos = *zPosition; std::map blocks; m_db->getBlocksOnZ(blocks, zPos); - for (std::list >::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; @@ -637,9 +702,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), @@ -651,10 +719,10 @@ void TileGenerator::renderPlayers(const std::string &inputPath) } } -inline std::list TileGenerator::getZValueList() const +inline std::list TileGenerator::getZValueList(PositionsList &positions) const { std::list zlist; - for (std::list >::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(); @@ -665,8 +733,7 @@ inline std::list 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() @@ -696,3 +763,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::tilePositions() +{ + 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(key, l)); + t = m_tiles.find(key); + } + + t->second.push_back(std::pair(p->first, p->second)); + } +} + diff --git a/include/Image.h b/include/Image.h index 1b5a6ba..216a0c2 100644 --- a/include/Image.h +++ b/include/Image.h @@ -26,6 +26,7 @@ public: 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&); diff --git a/include/TileGenerator.h b/include/TileGenerator.h index 6c97a7a..d8739e6 100644 --- a/include/TileGenerator.h +++ b/include/TileGenerator.h @@ -56,6 +56,8 @@ struct BitmapThing { // 16x16 bitmap uint16_t val[16]; }; +typedef std::list > PositionsList; + class TileGenerator { @@ -63,9 +65,11 @@ private: #if __cplusplus >= 201103L typedef std::unordered_map ColorMap; typedef std::unordered_set NameSet; + typedef std::unordered_map TileMap; #else typedef std::map ColorMap; typedef std::set NameSet; + typedef std::map TileMap; #endif public: @@ -81,6 +85,7 @@ public: void setDrawAlpha(bool drawAlpha); void setShading(bool shading); void setGeometry(int x, int y, int w, int h); + void setTileSize(int w, int h); void setMinY(int y); void setMaxY(int y); void parseColorsFile(const std::string &fileName); @@ -90,6 +95,7 @@ public: void setZoom(int zoom); void setScales(uint flags); void setDontWriteEmpty(bool f); + void tilePositions(); private: void parseColorsStream(std::istream &in); @@ -97,8 +103,8 @@ private: void closeDatabase(); void loadBlocks(); void createImage(); - void renderMap(); - std::list getZValueList() const; + void renderMap(PositionsList &positions); + std::list getZValueList(PositionsList &positions) const; void renderMapBlock(const BlockDecoder &blk, const BlockPos &pos); void renderMapBlockBottom(const BlockPos &pos); void renderShading(int zPos); @@ -138,9 +144,11 @@ private: int m_geomY; int m_geomX2; int m_geomY2; + int m_tileW; + int m_tileH; int m_mapWidth; int m_mapHeight; - std::list > m_positions; + ColorMap m_colorMap; BitmapThing m_readPixels; BitmapThing m_readInfo; @@ -148,6 +156,11 @@ private: Color m_color[16][16]; uint8_t m_thickness[16][16]; + PositionsList m_positions; + + TileMap m_tiles; + int m_numTilesX, m_numTilesY; + int m_zoom; uint m_scales; }; // class TileGenerator diff --git a/mapper.cpp b/mapper.cpp index 7acb7a0..cecd966 100644 --- a/mapper.cpp +++ b/mapper.cpp @@ -29,6 +29,7 @@ void usage() " --max-y \n" " --backend \n" " --geometry x:y+w+h\n" + " --tilesize wxh\n" " --extent\n" " --zoom \n" " --colors \n" @@ -82,6 +83,7 @@ int main(int argc, char *argv[]) {"noshading", no_argument, 0, 'H'}, {"backend", required_argument, 0, 'd'}, {"geometry", required_argument, 0, 'g'}, + {"tilesize", required_argument, 0, 't'}, {"extent", no_argument, 0, 'E'}, {"min-y", required_argument, 0, 'a'}, {"max-y", required_argument, 0, 'c'}, @@ -174,6 +176,18 @@ int main(int argc, char *argv[]) generator.setGeometry(x, y, w, h); } break; + case 't': { + std::istringstream geometry(optarg); + int w, h; + char c; + geometry >> w >> c >> h; + if (geometry.fail() || c != 'x' || w < 1 || h < 1) { + usage(); + exit(1); + } + generator.setTileSize(w, h); + } + break; case 'f': { uint flags = 0; if(strchr(optarg, 't') != NULL) diff --git a/minetestmapper.6 b/minetestmapper.6 index 9cba990..8049c4b 100644 --- a/minetestmapper.6 +++ b/minetestmapper.6 @@ -76,6 +76,12 @@ Use specific map backend; supported: *sqlite3*, *leveldb*, *redis*, *postgresql* .BR \-\-geometry " " \fIgeometry\fR Limit area to specific geometry (*x:y+w+h* where x and y specify the lower left corner), e.g. "--geometry -800:-800+1600+1600" +.TP +.BR \-\-tilesize " " \fItilesize\fR +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 __, where and +are the tile numbers and is the name specified with -o. Skip empty tiles by also specifying --noemptyimage. + .TP .BR \-\-extent " " \fIextent\fR Dont render the image, just print the extent of the map that would be generated, in the same format as the geometry above.