diff --git a/README.rst b/README.rst index bacc418..d6b93e4 100644 --- a/README.rst +++ b/README.rst @@ -348,13 +348,20 @@ sqlite-cacheworldrow: This may improve performance when a large percentage of the world is mapped. -tiles [+] +chunksize: + Manually specify the chunk size (for use with --tiles chunk) + +tiles [+]|block|chunk Divide the map in square tiles of the requested size. A border of the requested width (or width 1, of not specfied) is drawn between the tiles. In order to preserve all map pixels (and to prevent overwriting them with borders), extra pixel rows and columns for the borders are inserted into the map. + The special values 'block' and 'chunk' draw tiles that correspond to map + blocks (16x16 nodes) or to chunks (the unit of map generation; 5x5 blocks + for a world with default settings). + In order to allow partial world maps to be combined into larger maps, edge borders of the map are always drawn on the same side (left or top). Other edges are always border-less. @@ -365,6 +372,8 @@ tiles [+] `--tiles 1000+2` + `--tiles block` + NOTE: As a consequence of preserving all map pixels: * tiled maps (in particular slanted straight lines) may look slightly diff --git a/TileGenerator.cpp b/TileGenerator.cpp index 24ddb91..514a41e 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -143,6 +143,7 @@ TileGenerator::TileGenerator(): m_shrinkGeometry(true), m_blockGeometry(false), m_sqliteCacheWorldRow(false), + m_chunkSize(0), m_image(0), m_xMin(INT_MAX/16-1), m_xMax(INT_MIN/16+1), @@ -367,6 +368,11 @@ void TileGenerator::setBackend(std::string backend) m_backend = backend; } +void TileGenerator::setChunkSize(int size) +{ + m_chunkSize = size; +} + void TileGenerator::generate(const std::string &input, const std::string &output) { string input_path = input; @@ -376,7 +382,7 @@ void TileGenerator::generate(const std::string &input, const std::string &output openDb(input_path); loadBlocks(); - computeMapParameters(); + computeMapParameters(input); createImage(); renderMap(); if (m_drawScale) { @@ -524,6 +530,49 @@ std::string TileGenerator::getWorldDatabaseBackend(const std::string &input) return backend; } +int TileGenerator::getMapChunkSize(const std::string &input) +{ + int chunkSize = -1; + + std::string worldFile = input + PATH_SEPARATOR + "map_meta.txt"; + ifstream in; + in.open(worldFile.c_str(), ifstream::in); + if (!in.is_open()) { + cerr << "Could not obtain world chunk size: failed to open map_meta.txt - using default size (" + << CHUNK_SIZE_DEFAULT << ")" << std::endl; + return CHUNK_SIZE_DEFAULT; + } + + std::string line; + int linenr = 0; + for (std::getline(in,line); in.good(); std::getline(in,line)) { + linenr++; + istringstream iline; + iline.str(line); + iline >> std::skipws; + string variable; + char eq; + iline >> variable; + if (variable != "chunksize") + continue; + iline >> std::ws >> eq; + iline >> chunkSize; + if (in.fail() || eq != '=') { + cerr << "Could not obtain world chunk size: error parsing configuration line - using default size (" + << CHUNK_SIZE_DEFAULT << ")" << std::endl; + return CHUNK_SIZE_DEFAULT; + } + if (chunkSize <= 0) { + cerr << "Invalid chunk size found in map_meta.txt (" << chunkSize << ") - using default size (" + << CHUNK_SIZE_DEFAULT << ")" << std::endl; + return CHUNK_SIZE_DEFAULT; + } + } + in.close(); + if (chunkSize < 0) return CHUNK_SIZE_DEFAULT; + else return chunkSize; +} + void TileGenerator::openDb(const std::string &input) { string backend = m_backend; @@ -876,8 +925,15 @@ void TileGenerator::computeTileParameters( tileBorderCount = tileBorderLimit - tileBorderStart; } -void TileGenerator::computeMapParameters() +void TileGenerator::computeMapParameters(const std::string &input) { + if (!m_chunkSize && (m_tileWidth == TILESIZE_CHUNK || m_tileHeight == TILESIZE_CHUNK)) + m_chunkSize = getMapChunkSize(input); + if (m_tileWidth == TILESIZE_CHUNK) + m_tileWidth = m_chunkSize * BLOCK_SIZE; + if (m_tileHeight == TILESIZE_CHUNK) + m_tileHeight = m_chunkSize * BLOCK_SIZE; + m_storedWidth = (m_xMax - m_xMin + 1) * 16; m_storedHeight = (m_zMax - m_zMin + 1) * 16; int mapWidth = m_storedWidth - m_mapXStartNodeOffset + m_mapXEndNodeOffset; @@ -893,6 +949,9 @@ void TileGenerator::computeMapParameters() case TILECORNER_AT_WORLDCENTER: m_tileXOrigin = 0; break; + case TILECENTER_AT_CHUNKCENTER: + m_tileXOrigin = ((m_chunkSize%2) ? BLOCK_SIZE / 2 : 0) - m_tileWidth / 2; + break; case TILECENTER_AT_MAPCENTER: m_tileXOrigin = m_xMin * 16 + m_mapXStartNodeOffset + mapWidth / 2 - m_tileWidth / 2; break; @@ -913,6 +972,9 @@ void TileGenerator::computeMapParameters() case TILECORNER_AT_WORLDCENTER: m_tileZOrigin = 0; break; + case TILECENTER_AT_CHUNKCENTER: + m_tileZOrigin = ((m_chunkSize%2) ? BLOCK_SIZE / 2 : 0) - m_tileHeight / 2; + break; case TILECENTER_AT_MAPCENTER: m_tileZOrigin = (m_zMax + 1) * 16 - 1 - m_mapYStartNodeOffset - mapHeight / 2 - m_tileHeight / 2; break; diff --git a/TileGenerator.h b/TileGenerator.h index ba73a7f..bfbb538 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -29,8 +29,10 @@ #include "Color.h" #include "db.h" +#define TILESIZE_CHUNK (INT_MIN) #define TILECENTER_AT_WORLDCENTER (INT_MAX) #define TILECORNER_AT_WORLDCENTER (INT_MAX - 1) +#define TILECENTER_AT_CHUNKCENTER (INT_MAX - 2) #define TILECENTER_AT_MAPCENTER (INT_MIN) #define TILECORNER_AT_MAPCENTER (INT_MIN + 1) @@ -109,15 +111,17 @@ public: void enableProgressIndicator(void); void parseColorsFile(const std::string &fileName, int depth = 0); void setBackend(std::string backend); + void setChunkSize(int size); void generate(const std::string &input, const std::string &output); private: void parseColorsStream(std::istream &in, const std::string &filename, int depth); std::string getWorldDatabaseBackend(const std::string &input); + int getMapChunkSize(const std::string &input); void openDb(const std::string &input); void loadBlocks(); void createImage(); - void computeMapParameters(); + void computeMapParameters(const std::string &input); void computeTileParameters( // Input parameters int minPos, @@ -176,6 +180,7 @@ private: bool m_shrinkGeometry; bool m_blockGeometry; bool m_sqliteCacheWorldRow; + int m_chunkSize; DB *m_db; gdImagePtr m_image; diff --git a/config.h b/config.h index 2a28afc..b8f256a 100644 --- a/config.h +++ b/config.h @@ -13,9 +13,10 @@ #define PATH_SEPARATOR '/' #endif -#define BLOCK_SIZE 16 -#define MAPBLOCK_MIN (-2048) -#define MAPBLOCK_MAX 2047 +#define BLOCK_SIZE 16 +#define MAPBLOCK_MIN (-2048) +#define MAPBLOCK_MAX 2047 +#define CHUNK_SIZE_DEFAULT 5 // Max number of node name -> color mappings stored in a mapblock #define MAPBLOCK_MAXCOLORS 65536 diff --git a/mapper.cpp b/mapper.cpp index 477bb8c..7dddd57 100644 --- a/mapper.cpp +++ b/mapper.cpp @@ -29,6 +29,7 @@ using namespace std; #define OPT_BLOCKCOLOR 0x84 #define OPT_DRAWAIR 0x85 #define OPT_VERBOSE_SEARCH_COLORS 0x86 +#define OPT_CHUNKSIZE 0x87 // Will be replaced with the actual name and location of the executable (if found) string executableName = "minetestmapper"; @@ -96,9 +97,10 @@ void usage() #if USE_SQLITE3 " --sqlite-cacheworldrow\n" #endif - " --tiles [+]\n" + " --tiles [+]|block|chunk\n" " --tileorigin ,|world|map\n" " --tilecenter ,|world|map\n" + " --chunksize \n" " --verbose[=n]\n" " --verbose-search-colors[=n]\n" " --progress\n" @@ -556,6 +558,7 @@ int main(int argc, char *argv[]) {"tileorigin", required_argument, 0, 'T'}, {"tilecenter", required_argument, 0, 'T'}, {"tilebordercolor", required_argument, 0, 'B'}, + {"chunksize", required_argument, 0, OPT_CHUNKSIZE}, {"verbose", optional_argument, 0, 'v'}, {"verbose-search-colors", optional_argument, 0, OPT_VERBOSE_SEARCH_COLORS}, {"progress", no_argument, 0, OPT_PROGRESS_INDICATOR}, @@ -696,26 +699,49 @@ int main(int argc, char *argv[]) generator.setMaxY(maxy); } break; - case 't': { - istringstream tilesize; - tilesize.str(optarg); - int size, border; - char c; - tilesize >> size; - if (tilesize.fail() || size<0) { - std::cerr << "Invalid tile size specification (" << optarg << ")" << std::endl; + case OPT_CHUNKSIZE : { + istringstream iss; + iss.str(optarg); + int size; + iss >> size; + if (iss.fail() || size < 0) { + std::cerr << "Invalid chunk size (" << optarg << ")" << std::endl; usage(); exit(1); } - generator.setTileSize(size, size); - tilesize >> c >> border; - if (!tilesize.fail()) { - if (c != '+' || border < 1) { - std::cerr << "Invalid tile border size specification (" << optarg << ")" << std::endl; + generator.setChunkSize(size); + } + break; + case 't': { + istringstream tilesize; + tilesize.str(optarg); + if (tilesize.str() == "block") { + generator.setTileSize(BLOCK_SIZE, BLOCK_SIZE); + generator.setTileOrigin(TILECORNER_AT_WORLDCENTER, TILECORNER_AT_WORLDCENTER); + } + else if (tilesize.str() == "chunk") { + generator.setTileSize(TILESIZE_CHUNK, TILESIZE_CHUNK); + generator.setTileOrigin(TILECENTER_AT_CHUNKCENTER, TILECENTER_AT_CHUNKCENTER); + } + else { + int size, border; + char c; + tilesize >> size; + if (tilesize.fail() || size<0) { + std::cerr << "Invalid tile size specification (" << optarg << ")" << std::endl; usage(); exit(1); } - generator.setTileBorderSize(border); + generator.setTileSize(size, size); + tilesize >> c >> border; + if (!tilesize.fail()) { + if (c != '+' || border < 1) { + std::cerr << "Invalid tile border size specification (" << optarg << ")" << std::endl; + usage(); + exit(1); + } + generator.setTileBorderSize(border); + } } } break;