minetest-mapper-cpp/Minetestmapper/TileGenerator.cpp

2019 lines
65 KiB
C++
Raw Permalink Normal View History

2012-08-23 03:46:22 -07:00
/*
* =====================================================================
* Version: 1.0
* Created: 23.08.2012 12:35:53
* Author: Miroslav Bendík
* Company: LinuxOS.sk
* =====================================================================
*/
#include <cerrno>
#include <climits>
2012-08-23 05:21:34 -07:00
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
2012-08-24 00:46:14 -07:00
#include <sstream>
2014-03-09 04:32:13 -07:00
#include <stdexcept>
#include <utility>
2012-09-01 04:01:31 -07:00
#include "config.h"
#include "DataFileParser.h"
#include "PaintEngine_libgd.h"
#include "PlayerAttributes.h"
#include "Settings.h"
2012-08-23 03:46:22 -07:00
#include "TileGenerator.h"
2012-09-18 01:43:34 -07:00
#include "ZlibDecompressor.h"
#ifdef USE_SQLITE3
2014-03-05 12:41:27 -08:00
#include "db-sqlite3.h"
#endif
2018-03-26 00:25:19 -07:00
#ifdef USE_POSTGRESQL
#include "db-postgresql.h"
#endif
2018-03-26 00:25:19 -07:00
#ifdef USE_LEVELDB
2014-03-05 12:41:27 -08:00
#include "db-leveldb.h"
#endif
2018-03-26 00:25:19 -07:00
#ifdef USE_REDIS
#include "db-redis.h"
#endif
2012-08-23 03:46:22 -07:00
#define MESSAGE_WIDTH 25
#define MAX_NOPREFETCH_VOLUME (1LL<<24)
#define MIN_NOPREFETCH_VOLUME (1LL<<16)
#define MAX_NOPREFETCH_VOLUME_EXAMPLE "16384x256x16384"
using namespace std;
static const ColorEntry nodeColorNotDrawnObject;
const ColorEntry *TileGenerator::NodeColorNotDrawn = &nodeColorNotDrawnObject;
const BlockPos TileGenerator::BlockPosLimitMin(MAPBLOCK_MIN, MAPBLOCK_MIN, MAPBLOCK_MIN);
const BlockPos TileGenerator::BlockPosLimitMax(MAPBLOCK_MAX, MAPBLOCK_MAX, MAPBLOCK_MAX);
TileGenerator::TileGenerator()
2012-08-23 03:46:22 -07:00
{
// Load default grey colors.
m_heightMapColors.push_back(HeightMapColor(INT_MIN, Color(0,0,0), -129, Color(0,0,0)));
m_heightMapColors.push_back(HeightMapColor(-128, Color(0,0,0), 127, Color(255,255,255)));
m_heightMapColors.push_back(HeightMapColor(128, Color(255,255,255), INT_MAX, Color(255,255,255)));
2012-08-23 03:46:22 -07:00
}
TileGenerator::~TileGenerator()
{
closeDb();
2012-08-23 03:46:22 -07:00
}
void TileGenerator::setSilenceSuggestion(unsigned flags)
{
m_silenceSuggestions |= flags;
}
void TileGenerator::setGenerateNoPrefetch(BlockListPrefetch enable)
{
m_generatePrefetch = enable;
}
void TileGenerator::setDBFormat(BlockPos::StrFormat format, bool query)
{
m_databaseFormat = format;
m_databaseFormatSet = true;
m_reportDatabaseFormat = query;
}
void TileGenerator::setHeightMap(bool enable)
{
m_heightMap = enable;
}
void TileGenerator::setHeightMapYScale(float scale)
{
m_heightMapYScale = scale;
}
void TileGenerator::setSeaLevel(int level)
{
m_seaLevel = level;
}
void TileGenerator::setBgColor(const Color &bgColor)
2012-08-23 03:46:22 -07:00
{
m_bgColor = bgColor;
2012-08-23 03:46:22 -07:00
}
void TileGenerator::setBlockDefaultColor(const Color &color)
{
m_blockDefaultColor = color;
// Any value will do, except for 0
m_blockDefaultColor.a = 1;
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
void TileGenerator::setShrinkGeometry(bool shrink)
{
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
m_shrinkGeometry = shrink;
}
void TileGenerator::setBlockGeometry(bool block)
{
m_blockGeometry = block;
}
void TileGenerator::setScaleColor(const Color &scaleColor)
2012-08-23 03:46:22 -07:00
{
m_scaleColor = scaleColor;
2012-08-23 03:46:22 -07:00
}
void TileGenerator::setOriginColor(const Color &originColor)
2012-08-23 03:46:22 -07:00
{
m_originColor = originColor;
2012-08-23 03:46:22 -07:00
}
void TileGenerator::setPlayerColor(const Color &playerColor)
2012-08-23 03:46:22 -07:00
{
m_playerColor = playerColor;
2012-08-23 05:43:11 -07:00
}
void TileGenerator::setHeightMapColor(const Color &color0, const Color &color1)
{
m_heightMapColors.clear();
m_heightMapColors.push_back(HeightMapColor(INT_MIN, color0, -129, color0));
m_heightMapColors.push_back(HeightMapColor(-128, color0, 127, color1));
m_heightMapColors.push_back(HeightMapColor(128, color1, INT_MAX, color1));
}
void TileGenerator::setTileBorderColor(const Color &tileBorderColor)
{
m_tileBorderColor = tileBorderColor;
}
void TileGenerator::setTileBorderSize(int size)
{
m_tileBorderSize = size;
}
void TileGenerator::setTileSize(int width, int heigth)
{
m_tileWidth = width;
m_tileHeight = heigth;
}
void TileGenerator::setTileOrigin(int x, int y)
{
m_tileXOrigin = x;
m_tileZOrigin = y;
m_tileXCentered = false;
m_tileYCentered = false;
}
void TileGenerator::setTileCenter(int x, int y)
{
m_tileXOrigin = x;
m_tileZOrigin = y;
m_tileXCentered = true;
m_tileYCentered = true;
}
void TileGenerator::setScaleFactor(int f)
{
m_scaleFactor = f;
}
2012-08-23 03:46:22 -07:00
void TileGenerator::setDrawOrigin(bool drawOrigin)
{
m_drawOrigin = drawOrigin;
}
void TileGenerator::setDrawPlayers(bool drawPlayers)
{
m_drawPlayers = drawPlayers;
}
void TileGenerator::setDrawScale(int scale)
2012-08-23 03:46:22 -07:00
{
m_drawScale = (scale & DRAWSCALE_MASK) | (m_drawScale & DRAWHEIGHTSCALE_MASK & ((~scale & DRAWSCALE_MASK) << 4));
}
void TileGenerator::setDrawHeightScale(int scale)
{
unsigned s = scale;
int bits = 0;
for (; s; s >>= 1)
if ((s & 0x1)) bits++;
if (bits > 1)
throw std::runtime_error(std::string("Multiple height scale positions requested"));
m_drawScale = (scale & DRAWHEIGHTSCALE_MASK) | (m_drawScale & DRAWSCALE_MASK & ((~scale & DRAWHEIGHTSCALE_MASK) >> 4));
2012-08-23 03:46:22 -07:00
}
void TileGenerator::setSideScaleInterval(int major, int minor)
{
m_sideScaleMajor = major;
m_sideScaleMinor = minor;
}
void TileGenerator::setHeightScaleInterval(int major, int minor)
{
m_heightScaleMajor = major;
m_heightScaleMinor = minor;
}
void TileGenerator::setDrawAlpha(bool drawAlpha)
{
m_drawAlpha = drawAlpha;
}
void TileGenerator::setDrawAir(bool drawAir)
{
m_drawAir = drawAir;
}
void TileGenerator::setDrawIgnore(bool drawIgnore)
{
m_drawIgnore = drawIgnore;
}
void TileGenerator::setShading(bool shading)
{
m_shading = shading;
}
void TileGenerator::enableProgressIndicator()
{
progressIndicator = true;
}
void TileGenerator::setGeometry(const NodeCoord &corner1, const NodeCoord &corner2)
2012-11-24 10:25:13 -08:00
{
2015-02-26 01:02:49 -08:00
if (corner1.x() > 0) {
m_reqXMin = corner1.x() / 16;
2012-11-24 10:25:13 -08:00
}
else {
2015-02-26 01:02:49 -08:00
m_reqXMin = (corner1.x() - 15) / 16;
2012-11-24 10:25:13 -08:00
}
2015-02-26 01:02:49 -08:00
if (corner1.y() > 0) {
m_reqZMin = corner1.y() / 16;
2012-11-24 10:25:13 -08:00
}
else {
2015-02-26 01:02:49 -08:00
m_reqZMin = (corner1.y() - 15) / 16;
2012-11-24 10:25:13 -08:00
}
2015-02-26 01:02:49 -08:00
m_mapXStartNodeOffsetOrig = m_mapXStartNodeOffset = corner1.x() - m_reqXMin * 16;
m_mapYEndNodeOffsetOrig = m_mapYEndNodeOffset = m_reqZMin * 16 - corner1.y();
2012-11-24 10:25:13 -08:00
2015-02-26 01:02:49 -08:00
if (corner2.x() > 0) {
m_reqXMax = corner2.x() / 16;
2012-11-24 10:25:13 -08:00
}
else {
2015-02-26 01:02:49 -08:00
m_reqXMax = (corner2.x() - 15) / 16;
2012-11-24 10:25:13 -08:00
}
2015-02-26 01:02:49 -08:00
if (corner2.y() > 0) {
m_reqZMax = corner2.y() / 16;
2012-11-24 10:25:13 -08:00
}
else {
2015-02-26 01:02:49 -08:00
m_reqZMax = (corner2.y() - 15) / 16;
2012-11-24 10:25:13 -08:00
}
2015-02-26 01:02:49 -08:00
m_mapXEndNodeOffsetOrig = m_mapXEndNodeOffset = corner2.x() - (m_reqXMax * 16 + 15);
m_mapYStartNodeOffsetOrig = m_mapYStartNodeOffset = (m_reqZMax * 16 + 15) - corner2.y();
2012-11-24 10:25:13 -08:00
}
2014-03-05 09:06:05 -08:00
void TileGenerator::setMinY(int y)
{
if (y > 0) {
m_reqYMin = y / 16;
}
else {
m_reqYMin = (y - 15) / 16;
}
m_reqYMinNode = y - 16 * m_reqYMin;
2014-03-05 09:06:05 -08:00
}
void TileGenerator::setMaxY(int y)
{
if (y > 0) {
m_reqYMax = y / 16;
}
else {
m_reqYMax = (y - 15) / 16;
}
m_reqYMaxNode = y - 16 * m_reqYMax;
2014-03-05 09:06:05 -08:00
}
void TileGenerator::parseNodeColorsFile(const std::string &fileName)
{
ColorsFileParser d(verboseReadColors, m_drawAlpha);
d.parseDataFile(fileName, "map colors");
m_nodeColors = d.getNodeColors();
}
void TileGenerator::parseHeightMapNodesFile(const std::string &fileName)
{
HeightMapNodesFileParser p(verboseReadColors, m_drawAlpha);
p.parseDataFile(fileName, "heightmap nodes");
m_nodeColors = p.getNodeColors();
}
void TileGenerator::parseHeightMapColorsFile(const std::string &fileName)
{
HeightMapColorsFileParser p(verboseReadColors, m_drawAlpha);
p.parseDataFile(fileName, "heightmap colors");
m_heightMapColors = p.getHeightMapColors();
}
void TileGenerator::setBackend(const std::string &backend)
2014-03-05 12:41:27 -08:00
{
m_requestedBackend = backend;
2014-03-05 12:41:27 -08:00
}
void TileGenerator::setScanEntireWorld(bool enable)
{
m_scanEntireWorld = enable;
}
void TileGenerator::setChunkSize(int size)
{
m_chunkSize = size;
}
void TileGenerator::sanitizeParameters()
{
if (m_scaleFactor > 1) {
int dx0 = m_mapXStartNodeOffset % m_scaleFactor;
int dx1 = -m_mapXEndNodeOffset % m_scaleFactor;
int dy0 = m_mapYStartNodeOffset % m_scaleFactor;
int dy1 = -m_mapYEndNodeOffset % m_scaleFactor;
if (dx0 || dx1 || dy0 || dy1) {
m_mapXStartNodeOffsetOrig = m_mapXStartNodeOffset;
m_mapXEndNodeOffsetOrig = m_mapXEndNodeOffset;
m_mapYStartNodeOffsetOrig = m_mapYStartNodeOffset;
m_mapYEndNodeOffsetOrig = m_mapYEndNodeOffset;
m_mapXStartNodeOffset -= dx0;
m_mapXEndNodeOffset += dx1;
m_mapYStartNodeOffset -= dy0;
m_mapYEndNodeOffset += dy1;
std::cerr << "NOTE: rounding requested map boundaries to a multiple of the scale factor"
<< "(changes -" << dx0 << ",+" << dx1 << " x -" << dy1 << ",+" << dy0 << ")" << std::endl;
}
dx0 = dy0 = 0;
if (m_tileWidth != TILESIZE_CHUNK)
dx0 = m_tileWidth % m_scaleFactor;
if (dx0) dx0 = m_scaleFactor - dx0;
if (m_tileHeight != TILESIZE_CHUNK)
dy0 = m_tileHeight % m_scaleFactor;
if (dy0) dy0 = m_scaleFactor - dy0;
if (dx0 || dy0) {
m_tileWidth += dx0;
m_tileHeight += dy0;
std::cerr << "NOTE: rounding requested tile size up to nearest multiple of the scale factor: "
<< m_tileWidth << " x " << m_tileHeight << std::endl;
}
}
}
2012-08-23 05:21:34 -07:00
void TileGenerator::generate(const std::string &input, const std::string &output)
2012-08-23 04:32:22 -07:00
{
2012-09-01 04:41:00 -07:00
string input_path = input;
if (input_path[input.length() - 1] != PATH_SEPARATOR) {
input_path += PATH_SEPARATOR;
}
openDb(input_path);
sanitizeParameters();
2012-08-23 04:32:22 -07:00
loadBlocks();
if (m_xMin > m_xMax || m_yMin > m_yMax || m_zMin > m_zMax) {
std::cout << "World is empty: no map generated" << std::endl;
return;
}
computeMapParameters(input);
2012-08-23 05:21:34 -07:00
createImage();
2012-08-23 06:35:00 -07:00
renderMap();
if ((m_drawScale & DRAWSCALE_MASK)) {
2012-08-25 05:11:55 -07:00
renderScale();
}
if (m_heightMap && (m_drawScale & DRAWHEIGHTSCALE_MASK)) {
renderHeightScale();
}
2012-08-25 06:21:51 -07:00
if (m_drawOrigin) {
renderOrigin();
}
2012-08-25 07:29:41 -07:00
if (m_drawPlayers) {
2012-09-01 04:41:00 -07:00
renderPlayers(input_path);
2012-08-25 07:29:41 -07:00
}
if (!m_drawObjects.empty()) {
renderDrawObjects();
}
closeDb();
2014-06-23 22:47:15 -07:00
if (progressIndicator)
cout << "Writing image...\r" << std::flush;
2012-08-23 05:21:34 -07:00
writeImage(output);
2014-06-23 22:47:15 -07:00
if (progressIndicator)
cout << std::setw(20) << " " << "\r" << std::flush;
2012-08-25 07:41:53 -07:00
printUnknown();
2012-08-23 04:32:22 -07:00
}
std::string TileGenerator::getWorldDatabaseBackend(const std::string &input)
2012-08-23 04:32:22 -07:00
{
Settings world_mt(input + PATH_SEPARATOR + "world.mt");
return world_mt.get("backend", "sqlite3");
}
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)
{
m_backend = m_requestedBackend;
bool unsupported = false;
if (m_backend == "auto")
m_backend = getWorldDatabaseBackend(input);
if(m_backend == "sqlite3") {
#ifdef USE_SQLITE3
DBSQLite3 *db;
m_db = db = new DBSQLite3(input);
m_scanEntireWorld = true;
#else
unsupported = true;
#endif
}
else if (m_backend == "postgresql") {
2018-04-24 08:47:05 -07:00
#ifdef USE_POSTGRESQL
DBPostgreSQL *db;
m_db = db = new DBPostgreSQL(input);
#else
unsupported = true;
#endif
}
else if (m_backend == "leveldb") {
2018-03-26 00:25:19 -07:00
#ifdef USE_LEVELDB
2014-03-05 12:41:27 -08:00
m_db = new DBLevelDB(input);
m_scanEntireWorld = true;
#else
unsupported = true;
#endif
}
else if (m_backend == "redis") {
2018-04-24 08:47:05 -07:00
#ifdef USE_REDIS
m_db = new DBRedis(input);
m_scanEntireWorld = true;
#else
unsupported = true;
2014-03-05 12:41:27 -08:00
#endif
}
else if (m_requestedBackend == "auto")
throw std::runtime_error(((std::string) "World uses unrecognised database backend: ") + m_backend);
2014-03-05 12:41:27 -08:00
else
throw std::runtime_error(((std::string) "Internal error: unknown database backend: ") + m_requestedBackend);
if (unsupported)
throw std::runtime_error(((std::string) "World uses backend '") + m_backend + ", which was not enabled at compile-time.");
2012-08-23 04:32:22 -07:00
}
void TileGenerator::closeDb()
{
delete m_db;
m_db = nullptr;
}
2012-08-23 04:32:22 -07:00
void TileGenerator::loadBlocks()
{
int mapXMin, mapXMax;
int mapYMin, mapYMax;
int mapZMin, mapZMax;
int geomYMin, geomYMax;
long long map_blocks;
if (verboseCoordinates >= 2) {
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
bool partialBlocks = (m_mapXStartNodeOffset || m_mapXEndNodeOffset || m_mapYStartNodeOffset || m_mapYEndNodeOffset);
bool adjustedGeom = (m_mapXStartNodeOffsetOrig != m_mapXStartNodeOffset || m_mapYEndNodeOffsetOrig != m_mapYEndNodeOffset
|| m_mapXEndNodeOffsetOrig != m_mapXEndNodeOffset || m_mapYStartNodeOffsetOrig != m_mapYStartNodeOffset);
if (partialBlocks || !m_blockGeometry || adjustedGeom) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< (m_blockGeometry ? "Command-line Geometry:" : "Requested Geometry:")
<< std::right
<< std::setw(7) << m_reqXMin*16+m_mapXStartNodeOffsetOrig << ","
<< std::setw(7) << m_reqYMin*16+m_reqYMinNode << ","
<< std::setw(7) << m_reqZMin*16-m_mapYEndNodeOffsetOrig
<< " .. "
<< std::setw(7) << m_reqXMax*16+15+m_mapXEndNodeOffsetOrig << ","
<< std::setw(7) << m_reqYMax*16+m_reqYMaxNode << ","
<< std::setw(7) << m_reqZMax*16+15-m_mapYStartNodeOffsetOrig
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
<< " ("
<< std::setw(6) << m_reqXMin << ","
<< std::setw(6) << m_reqYMin << ","
<< std::setw(6) << m_reqZMin
<< " .. "
<< std::setw(6) << m_reqXMax << ","
<< std::setw(6) << m_reqYMax << ","
<< std::setw(6) << m_reqZMax
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
<< ")\n";
}
if (partialBlocks || m_blockGeometry) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< (m_blockGeometry ? "Requested Geometry:" : "Block-aligned Geometry:")
<< std::right
<< std::setw(7) << m_reqXMin*16 << ","
<< std::setw(7) << m_reqYMin*16+m_reqYMinNode << ","
<< std::setw(7) << m_reqZMin*16 <<
" .. "
<< std::setw(7) << m_reqXMax*16+15 << ","
<< std::setw(7) << m_reqYMax*16+m_reqYMaxNode << ","
<< std::setw(7) << m_reqZMax*16+15
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
<< " ("
<< std::setw(6) << m_reqXMin << ","
<< std::setw(6) << m_reqYMin << ","
<< std::setw(6) << m_reqZMin
<< " .. "
<< std::setw(6) << m_reqXMax << ","
<< std::setw(6) << m_reqYMax << ","
<< std::setw(6) << m_reqZMax
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
<< ")\n";
}
if (!m_blockGeometry && adjustedGeom) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Adjusted Geometry:"
<< std::right
<< std::setw(7) << m_reqXMin*16+m_mapXStartNodeOffset << ","
<< std::setw(7) << m_reqYMin*16+m_reqYMinNode << ","
<< std::setw(7) << m_reqZMin*16-m_mapYEndNodeOffset
<< " .. "
<< std::setw(7) << m_reqXMax*16+15+m_mapXEndNodeOffset << ","
<< std::setw(7) << m_reqYMax*16+m_reqYMaxNode << ","
<< std::setw(7) << m_reqZMax*16+15-m_mapYStartNodeOffset
<< " ("
<< std::setw(6) << m_reqXMin << ","
<< std::setw(6) << m_reqYMin << ","
<< std::setw(6) << m_reqZMin
<< " .. "
<< std::setw(6) << m_reqXMax << ","
<< std::setw(6) << m_reqYMax << ","
<< std::setw(6) << m_reqZMax
<< ")\n";
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
}
if (m_blockGeometry) {
m_mapXStartNodeOffset = 0;
m_mapXEndNodeOffset = 0;
m_mapYStartNodeOffset = 0;
m_mapYEndNodeOffset = 0;
}
mapXMin = MAPBLOCK_MAX;
mapXMax = MAPBLOCK_MIN;
mapYMin = MAPBLOCK_MAX;
mapYMax = MAPBLOCK_MIN;
mapZMin = MAPBLOCK_MAX;
mapZMax = MAPBLOCK_MIN;
geomYMin = MAPBLOCK_MAX;
geomYMax = MAPBLOCK_MIN;
m_worldBlocks = 0;
map_blocks = 0;
if (m_reportDatabaseFormat && m_backend != "leveldb") {
std::cerr << "WARNING: querying database format is only sensible when using the leveldb backend - querying disabled" << std::endl;
m_reportDatabaseFormat = false;
}
if (m_reportDatabaseFormat && m_generatePrefetch != BlockListPrefetch::Prefetch) {
std::cerr << "WARNING: querying database format: ignoring '--disable-blocklist-prefetch' and/or '--prescan-world=disabled'." << std::endl;
m_generatePrefetch = BlockListPrefetch::Prefetch;
}
if (m_generatePrefetch != BlockListPrefetch::Prefetch && !m_databaseFormatSet && m_backend == "leveldb") {
throw(std::runtime_error("When using --disable-blocklist-prefetch with a leveldb backend, database format must be set (--database-format)"));
}
if (m_generatePrefetch != BlockListPrefetch::Prefetch) {
if (m_generatePrefetch == BlockListPrefetch::NoPrefetch) {
long long volume = (long long)(m_reqXMax - m_reqXMin + 1) * (m_reqYMax - m_reqYMin + 1) * (m_reqZMax - m_reqZMin + 1);
if (volume > MAX_NOPREFETCH_VOLUME) {
std::ostringstream oss;
// Note: the 'force' variants of the options are intentionally undocumented.
oss << "Requested map volume is excessive for --disable-blocklist-prefetch or --prescan-world=disabled: " << std::endl
<< " Volume is: " << volume
<< " (" << (m_reqXMax - m_reqXMin + 1)
<< " x " << (m_reqYMax - m_reqYMin + 1)
<< " x " << (m_reqZMax - m_reqZMin + 1)
<< " blocks of 16x16x16 nodes);"
<< std::endl
<< " Mapping will be slow. Use '--disable-blocklist-prefetch=force' or '--prescan-world=disabled-force'" << std::endl
<< " to force this for more than " << MAX_NOPREFETCH_VOLUME << " blocks (i.e. " << MAX_NOPREFETCH_VOLUME_EXAMPLE << " nodes)";
throw(std::runtime_error(oss.str()));
}
}
if (m_shrinkGeometry) {
std::cerr << "WARNING: geometrymode 'shrink' not supported with '--disable-blocklist-prefetch'" << std::endl;
m_shrinkGeometry = false;
}
m_xMin = m_reqXMin;
m_xMax = m_reqXMax;
m_yMin = m_reqYMin;
m_yMax = m_reqYMax;
m_zMin = m_reqZMin;
m_zMax = m_reqZMax;
}
else {
if (progressIndicator)
cout << "Scanning world (reading block list)...\r" << std::flush;
DB::BlockPosList blocks;
BlockPos posMin(m_reqXMin, m_reqYMin, m_reqZMin);
BlockPos posMax(m_reqXMax, m_reqYMax, m_reqZMax);
if (!m_scanEntireWorld && (posMin != BlockPosLimitMin || posMax != BlockPosLimitMax))
blocks = m_db->getBlockPosList(BlockPos(m_reqXMin, m_reqYMin, m_reqZMin), BlockPos(m_reqXMax, m_reqYMax, m_reqZMax));
else {
m_scanEntireWorld = true;
blocks = m_db->getBlockPosList();
}
for(const BlockPos &pos : blocks) {
m_worldBlocks++;
m_databaseFormatFound[pos.databaseFormat()]++;
if (pos.x() < mapXMin) {
mapXMin = pos.x();
}
if (pos.x() > mapXMax) {
mapXMax = pos.x();
}
if (pos.y() < mapYMin) {
mapYMin = pos.y();
}
if (pos.y() > mapYMax) {
mapYMax = pos.y();
}
if (pos.z() < mapZMin) {
mapZMin = pos.z();
}
if (pos.z() > mapZMax) {
mapZMax = pos.z();
}
if (pos.x() < m_reqXMin || pos.x() > m_reqXMax || pos.z() < m_reqZMin || pos.z() > m_reqZMax) {
continue;
}
if (pos.y() < geomYMin) {
geomYMin = pos.y();
}
if (pos.y() > geomYMax) {
geomYMax = pos.y();
}
if (pos.y() < m_reqYMin || pos.y() > m_reqYMax) {
continue;
}
map_blocks++;
if (pos.y() < m_yMin) {
m_yMin = pos.y();
}
if (pos.y() > m_yMax) {
m_yMax = pos.y();
}
if (pos.x() < m_xMin) {
m_xMin = pos.x();
}
if (pos.x() > m_xMax) {
m_xMax = pos.x();
}
if (pos.z() < m_zMin) {
m_zMin = pos.z();
}
if (pos.z() > m_zMax) {
m_zMax = pos.z();
}
m_positions.push_back(pos);
2014-03-05 12:41:27 -08:00
}
if (verboseCoordinates >= 1 && m_scanEntireWorld) {
if (mapXMin <= mapXMax || mapYMin <= mapYMax || mapZMin <= mapZMax) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "World Geometry:" << std::right
<< std::setw(7) << mapXMin*16 << ","
<< std::setw(7) << mapYMin*16 << ","
<< std::setw(7) << mapZMin*16
<< " .. "
<< std::setw(7) << mapXMax*16+15 << ","
<< std::setw(7) << mapYMax*16+15 << ","
<< std::setw(7) << mapZMax*16+15
<< " ("
<< std::setw(6) << mapXMin << ","
<< std::setw(6) << mapYMin << ","
<< std::setw(6) << mapZMin
<< " .. "
<< std::setw(6) << mapXMax << ","
<< std::setw(6) << mapYMax << ","
<< std::setw(6) << mapZMax
<< ") blocks: "
<< std::setw(10) << m_worldBlocks << "\n";
}
else {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "World Geometry:" << std::right
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-"
<< " .. "
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-"
<< " ("
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-"
<< " .. "
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-"
<< ") blocks: "
<< std::setw(10) << m_worldBlocks << "\n";
}
2014-03-05 12:41:27 -08:00
}
if (m_shrinkGeometry) {
if (m_xMin != m_reqXMin) m_mapXStartNodeOffset = 0;
if (m_xMax != m_reqXMax) m_mapXEndNodeOffset = 0;
if (m_zMin != m_reqZMin) m_mapYEndNodeOffset = 0;
if (m_zMax != m_reqZMax) m_mapYStartNodeOffset = 0;
2014-03-05 12:41:27 -08:00
}
else {
if (verboseCoordinates >= 2) {
if (m_xMin <= m_xMax || m_yMin <= m_yMax || m_zMin <= m_zMax) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Minimal Map Geometry:" << std::right
<< std::setw(7) << m_xMin*16 << ","
<< std::setw(7) << m_yMin*16+m_reqYMinNode << ","
<< std::setw(7) << m_zMin*16
<< " .. "
<< std::setw(7) << m_xMax*16+15 << ","
<< std::setw(7) << m_yMax*16+m_reqYMaxNode << ","
<< std::setw(7) << m_zMax*16+15
<< " ("
<< std::setw(6) << m_xMin << ","
<< std::setw(6) << m_yMin << ","
<< std::setw(6) << m_zMin
<< " .. "
<< std::setw(6) << m_xMax << ","
<< std::setw(6) << m_yMax << ","
<< std::setw(6) << m_zMax
<< ")\n";
}
else {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Minimal Map Geometry:" << std::right
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-"
<< " .. "
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-"
<< " ("
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-"
<< " .. "
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-"
<< ")\n";
}
}
m_xMin = m_reqXMin;
m_xMax = m_reqXMax;
m_zMin = m_reqZMin;
m_zMax = m_reqZMax;
}
if (verboseCoordinates >= 2) {
if (geomYMin <= geomYMax) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Map Vertical Limits:" << std::right
<< std::setw(7) << "x" << ","
<< std::setw(7) << geomYMin*16 << ","
<< std::setw(7) << "z"
<< " .. "
<< std::setw(7) << "x" << ","
<< std::setw(7) << geomYMax*16+15 << ","
<< std::setw(7) << "z"
<< " ("
<< std::setw(6) << "x" << ","
<< std::setw(6) << geomYMin << ","
<< std::setw(6) << "z"
<< " .. "
<< std::setw(6) << "x" << ","
<< std::setw(6) << geomYMax << ","
<< std::setw(6) << "z"
<< ")\n";
}
else {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Map Vertical Limits:" << std::right
<< std::setw(7) << "x" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "z"
<< " .. "
<< std::setw(7) << "x" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "z"
<< " ("
<< std::setw(6) << "x" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "z"
<< " .. "
<< std::setw(6) << "x" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "z"
<< ")\n";
}
2014-03-05 12:41:27 -08:00
}
m_positions.sort();
}
if ((m_xMin <= m_xMax || m_zMin <= m_zMax) && m_yMin > m_yMax) {
m_yMin = MAPBLOCK_MIN;
m_yMax = MAPBLOCK_MAX;
}
if (verboseCoordinates >= 1) {
if (m_xMin <= m_xMax || m_zMin <= m_zMax) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Map Output Geometry:" << std::right
<< std::setw(7) << m_xMin*16+m_mapXStartNodeOffset << ","
<< std::setw(7) << m_yMin*16+m_reqYMinNode << ","
<< std::setw(7) << m_zMin*16-m_mapYEndNodeOffset
<< " .. "
<< std::setw(7) << m_xMax*16+15+m_mapXEndNodeOffset << ","
<< std::setw(7) << m_yMax*16+m_reqYMaxNode << ","
<< std::setw(7) << m_zMax*16+15-m_mapYStartNodeOffset
<< " ("
<< std::setw(6) << m_xMin << ","
<< std::setw(6) << m_yMin << ","
<< std::setw(6) << m_zMin
<< " .. "
<< std::setw(6) << m_xMax << ","
<< std::setw(6) << m_yMax << ","
<< std::setw(6) << m_zMax
<< ") blocks: "
<< std::setw(10) << map_blocks << "\n";
}
else {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Map Output Geometry:" << std::right
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-"
<< " .. "
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "-"
<< " ("
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-"
<< " .. "
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "-"
<< ") blocks: "
<< std::setw(10) << map_blocks << "\n";
}
}
if (m_backend == "leveldb" && m_generatePrefetch == BlockListPrefetch::Prefetch) {
if (m_databaseFormatFound[BlockPos::AXYZ] && m_databaseFormatFound[BlockPos::I64])
m_recommendedDatabaseFormat = "mixed";
else if (m_databaseFormatFound[BlockPos::AXYZ])
m_recommendedDatabaseFormat = "freeminer-axyz";
else if (m_databaseFormatFound[BlockPos::I64])
m_recommendedDatabaseFormat = "minetest-i64";
else
m_recommendedDatabaseFormat = "";
if (m_reportDatabaseFormat || verboseStatistics >= 3) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Database block format(s):" << std::endl
<< " " << std::setw(MESSAGE_WIDTH-4) << std::left << "Total blocks:"
<< std::setw(15) << std::right << m_worldBlocks
<< std::endl;
if (m_databaseFormatFound[BlockPos::Unknown]) {
cout
<< " " << std::setw(MESSAGE_WIDTH-4) << std::left << "Unknown:"
<< std::setw(15) << std::right << m_databaseFormatFound[BlockPos::Unknown]
<< std::endl;
}
cout
<< " " << std::setw(MESSAGE_WIDTH-4) << std::left << "Minetest-I64:"
<< std::setw(15) << std::right << m_databaseFormatFound[BlockPos::I64]
<< std::endl
<< " " << std::setw(MESSAGE_WIDTH-4) << std::left << "Freeminer-AXYZ:"
<< std::setw(15) << std::right << m_databaseFormatFound[BlockPos::AXYZ]
<< std::endl;
long long other_blocks = m_worldBlocks
- m_databaseFormatFound[BlockPos::Unknown]
- m_databaseFormatFound[BlockPos::I64]
- m_databaseFormatFound[BlockPos::AXYZ];
if (other_blocks) {
cout
<< " " << std::setw(MESSAGE_WIDTH-8) << std::left << "Miscounted:"
<< std::setw(15) << std::right << other_blocks
<< std::endl;
}
}
}
2012-08-23 04:32:22 -07:00
}
void TileGenerator::scalePixelRows(PixelAttributes &pixelAttributes, PixelAttributes &pixelAttributesScaled, int zPosLimit) {
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
int y;
for (y = pixelAttributes.getNextY(); y <= pixelAttributes.getLastY() && y < worldBlockZ2StoredY(m_zMin - 1) + m_mapYEndNodeOffset; y++) {
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
for (int x = m_mapXStartNodeOffset; x < worldBlockX2StoredX(m_xMax + 1) + m_mapXEndNodeOffset; x++) {
#define pixel pixelAttributes.attribute(y, x)
//PixelAttribute &pixel = pixelAttributes.attribute(y, x);
if (pixel.nextEmpty) {
pixelAttributesScaled.attribute(y / m_scaleFactor, x/m_scaleFactor).nextEmpty = true;
x += 15;
continue;
}
#ifdef DEBUG
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
int mapX = x - m_mapXStartNodeOffset;
int mapY = y - m_mapYStartNodeOffset;
{ int ix = mapX2ImageX(mapX / m_scaleFactor); assert(ix - borderLeft() >= 0 && ix - borderLeft() - borderRight() < m_pictWidth); }
{ int iy = mapY2ImageY(mapY / m_scaleFactor); assert(iy - borderTop() >= 0 && iy - borderTop() - borderBottom() < m_pictHeight); }
#endif
if (pixel.is_valid() || pixel.color().to_uint())
pixelAttributesScaled.attribute(y / m_scaleFactor, x / m_scaleFactor).add(pixel);
#undef pixel
}
}
for (y = pixelAttributesScaled.getNextY(); y <= pixelAttributesScaled.getLastY(); y++) {
for (int x = m_mapXStartNodeOffset / m_scaleFactor; x < (worldBlockX2StoredX(m_xMax + 1) + m_mapXEndNodeOffset) / m_scaleFactor; x++) {
#define pixel pixelAttributesScaled.attribute(y, x)
if (pixel.nextEmpty) {
x += 16 / m_scaleFactor - 1;
continue;
}
if (pixel.is_valid() || pixel.color().to_uint())
pixel.normalize();
#undef pixel
}
}
int yLimit = worldBlockZ2StoredY(zPosLimit);
if (y <= yLimit) {
pixelAttributes.scroll(yLimit);
}
}
void TileGenerator::pushPixelRows(PixelAttributes &pixelAttributes, int zPosLimit) {
if (m_shading)
// Make shading less pronounced when map is scaled down
// (the formula for the emphasis parameter was determined (tuned) experimentally...)
pixelAttributes.renderShading(m_scaleFactor < 3 ? 1 : 1 / sqrt(m_scaleFactor), m_drawAlpha);
int y;
for (y = pixelAttributes.getNextY(); y <= pixelAttributes.getLastY() && y < (worldBlockZ2StoredY(m_zMin - 1) + m_mapYEndNodeOffset) / m_scaleFactor; y++) {
for (int x = m_mapXStartNodeOffset / m_scaleFactor; x < (worldBlockX2StoredX(m_xMax + 1) + m_mapXEndNodeOffset) / m_scaleFactor; x++) {
int mapX = x - m_mapXStartNodeOffset / m_scaleFactor;
int mapY = y - m_mapYStartNodeOffset / m_scaleFactor;
#define pixel pixelAttributes.attribute(y, x)
//PixelAttribute &pixel = pixelAttributes.attribute(y, x);
if (pixel.nextEmpty) {
x += 16 / m_scaleFactor - 1;
continue;
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
#ifdef DEBUG
{ int ix = mapX2ImageX(mapX); assert(ix - borderLeft() >= 0 && ix - borderLeft() - borderRight() < m_pictWidth); }
{ int iy = mapY2ImageY(mapY); assert(iy - borderTop() >= 0 && iy - borderTop() - borderBottom() < m_pictHeight); }
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
#endif
if (pixel.is_valid() || pixel.color().to_uint())
2017-10-16 01:58:32 -07:00
paintEngine->drawPixel(mapX2ImageX(mapX), mapY2ImageY(mapY), pixel.color());
#undef pixel
}
}
int yLimit = worldBlockZ2StoredY(zPosLimit) / m_scaleFactor;
if (y <= yLimit) {
pixelAttributes.scroll(yLimit);
}
}
void TileGenerator::computeTileParameters(
// Input parameters
int minPos,
int maxPos,
int mapStartNodeOffset,
int mapEndNodeOffset,
int tileOrigin,
int tileSize,
// Output parameters
int &tileBorderCount,
int &tileMapStartOffset,
int &tileMapEndOffset,
// Behavior selection
bool ascending)
{
int start = minPos * 16 + mapStartNodeOffset - tileOrigin;
int limit = (maxPos+1) * 16 + mapEndNodeOffset - tileOrigin;
int shift;
// shift values, so that start = 0..tileSize-1
// (effect of tileOrigin is identical to (tileOrigin + tileSize)
// so any multiple of tileSize can be safely added)
if (start<0)
shift = - (start + 1) / tileSize + 1;
else
shift = - start / tileSize;
start += shift * tileSize;
limit += shift * tileSize;
int tileBorderStart = 0; // First border to draw
int tileBorderLimit = 0; // Last + 1 border to draw
if (ascending) {
// Prefer tile borders towards negative infinity
// 0 -> 0
// 1..tileSize -> 1
// (tileSize+1)..(2*tileSize) -> 2
// etc.
tileBorderStart = (start + tileSize - 1) / tileSize;
tileBorderLimit = (limit + tileSize - 1) / tileSize;
} else {
// Prefer tile borders towards positive infinity
// 0..(tileSize-1) -> 1
// tileSize..(2*tileSize-1) -> 2
// etc.
tileBorderStart = start / tileSize + 1;
tileBorderLimit = limit / tileSize + 1;
}
tileMapStartOffset = (tileSize - start) % tileSize;
tileMapEndOffset = limit - ((tileBorderLimit-tileBorderStart) * tileSize);
tileBorderCount = tileBorderLimit - tileBorderStart;
}
void TileGenerator::computeMapParameters(const std::string &input)
2012-08-23 05:21:34 -07:00
{
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;
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
m_storedWidth = (m_xMax - m_xMin + 1) * 16;
m_storedHeight = (m_zMax - m_zMin + 1) * 16;
int mapWidth = m_storedWidth - m_mapXStartNodeOffset + m_mapXEndNodeOffset;
int mapHeight = m_storedHeight - m_mapYStartNodeOffset + m_mapYEndNodeOffset;
#ifdef DEBUG
assert(mapWidth % m_scaleFactor == 0);
assert(mapHeight % m_scaleFactor == 0);
#else
mapWidth += mapWidth % m_scaleFactor;
mapHeight += mapHeight % m_scaleFactor;
#endif
m_blockPixelAttributes.setParameters(m_storedWidth, 16, m_mapYStartNodeOffset, 1, true);
m_blockPixelAttributesScaled.setParameters(m_storedWidth / m_scaleFactor, 16 / m_scaleFactor, m_mapYStartNodeOffset / m_scaleFactor, m_scaleFactor, false);
// Set special values for origin (which depend on other paramters)
if (m_tileWidth) {
switch (m_tileXOrigin) {
2015-01-03 10:10:19 -08:00
case TILECENTER_AT_WORLDCENTER:
m_tileXOrigin = -m_tileWidth / 2;
break;
2015-01-03 10:10:19 -08:00
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;
2015-01-03 10:10:19 -08:00
case TILECENTER_AT_MAPCENTER:
m_tileXOrigin = m_xMin * 16 + m_mapXStartNodeOffset + mapWidth / 2 - m_tileWidth / 2;
break;
2015-01-03 10:10:19 -08:00
case TILECORNER_AT_MAPCENTER:
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
m_tileXOrigin = m_xMin * 16 + m_mapXStartNodeOffset + mapWidth / 2;
break;
default:
if (m_tileXCentered)
m_tileXOrigin -= m_tileWidth/2;
break;
}
if (m_tileXOrigin >= 0)
m_tileXOrigin -= m_tileXOrigin % m_scaleFactor;
else
m_tileXOrigin -= -m_tileXOrigin % m_scaleFactor;
}
if (m_tileHeight) {
switch (m_tileZOrigin) {
2015-01-03 10:10:19 -08:00
case TILECENTER_AT_WORLDCENTER:
m_tileZOrigin = -m_tileHeight / 2;
break;
2015-01-03 10:10:19 -08:00
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;
2015-01-03 10:10:19 -08:00
case TILECENTER_AT_MAPCENTER:
m_tileZOrigin = (m_zMax + 1) * 16 - 1 - m_mapYStartNodeOffset - mapHeight / 2 - m_tileHeight / 2;
break;
2015-01-03 10:10:19 -08:00
case TILECORNER_AT_MAPCENTER:
m_tileZOrigin = (m_zMax + 1) * 16 - 1 - m_mapYStartNodeOffset - mapHeight / 2;
break;
default:
if (m_tileYCentered)
m_tileZOrigin -= m_tileHeight / 2;
break;
}
if (m_tileXOrigin >= 0)
m_tileZOrigin -= m_tileZOrigin % m_scaleFactor;
else
m_tileZOrigin -= -m_tileZOrigin % m_scaleFactor;
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
// Compute adjustments for tiles.
m_pictWidth = mapWidth;
m_pictHeight = mapHeight;
if (m_tileWidth && m_tileBorderSize) {
int tileMapXEndOffset; // Dummy
TileGenerator::computeTileParameters(
// Input parameters
m_xMin,
m_xMax,
m_mapXStartNodeOffset,
m_mapXEndNodeOffset,
m_tileXOrigin,
m_tileWidth,
// Output parameters
m_tileBorderXCount,
m_tileMapXOffset,
tileMapXEndOffset,
// Behavior selection
true);
}
if (m_tileHeight && m_tileBorderSize) {
int tileMapYEndOffset; // Dummy
TileGenerator::computeTileParameters(
// Input parameters
m_zMin,
m_zMax,
-m_mapYEndNodeOffset,
-m_mapYStartNodeOffset,
m_tileZOrigin,
m_tileHeight,
// Output parameters
m_tileBorderYCount,
tileMapYEndOffset,
m_tileMapYOffset,
// Behavior selection
false);
}
m_pictWidth /= m_scaleFactor;
m_pictWidth += m_tileBorderXCount * m_tileBorderSize;
m_pictHeight /= m_scaleFactor;
m_pictHeight += m_tileBorderYCount * m_tileBorderSize;
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
void TileGenerator::createImage()
{
int totalPictHeight = m_pictHeight + borderTop() + borderBottom();
int totalPictWidth = m_pictWidth + borderLeft() + borderRight();
2017-10-16 01:58:32 -07:00
paintEngine = new PaintEngine_libgd();
2018-06-08 21:12:10 -07:00
paintEngine->checkImageSize(totalPictWidth, totalPictHeight, std::cerr);
2017-10-16 01:58:32 -07:00
if (!paintEngine->create(totalPictWidth, totalPictHeight)) {
ostringstream oss;
oss << "Failed to allocate " << totalPictWidth << "x" << totalPictHeight << " image";
throw std::runtime_error(oss.str());
}
2012-08-23 05:21:34 -07:00
// Background
2017-10-16 01:58:32 -07:00
paintEngine->fill(m_bgColor);
// Draw tile borders
if (m_tileWidth && m_tileBorderSize) {
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
for (int i = 0; i < m_tileBorderXCount; i++) {
int xPos = m_tileMapXOffset / m_scaleFactor + i * (m_tileWidth / m_scaleFactor + m_tileBorderSize);
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
#ifdef DEBUG
int xPos2 = mapX2ImageX(m_tileMapXOffset / m_scaleFactor + i * m_tileWidth / m_scaleFactor) - borderLeft() - m_tileBorderSize;
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
assert(xPos == xPos2);
#endif
2017-10-16 01:58:32 -07:00
paintEngine->drawFilledRect(xPos + borderLeft(), borderTop(), xPos + (m_tileBorderSize - 1) + borderLeft(), m_pictHeight + borderTop() - 1, m_tileBorderColor);
}
}
if (m_tileHeight && m_tileBorderSize) {
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
for (int i = 0; i < m_tileBorderYCount; i++) {
int yPos = m_tileMapYOffset / m_scaleFactor + i * (m_tileHeight / m_scaleFactor + m_tileBorderSize);
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
#ifdef DEBUG
int yPos2 = mapY2ImageY(m_tileMapYOffset / m_scaleFactor + i * m_tileHeight / m_scaleFactor) - borderTop() - m_tileBorderSize;
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
assert(yPos == yPos2);
#endif
2017-10-16 01:58:32 -07:00
paintEngine->drawFilledRect(borderLeft(), yPos + borderTop(), m_pictWidth + borderLeft() - 1, yPos + (m_tileBorderSize - 1) + borderTop(), m_tileBorderColor);
}
}
2012-08-23 05:21:34 -07:00
}
2018-04-22 06:07:55 -07:00
void TileGenerator::processMapBlock(const DB::Block &mapBlock)
{
2018-04-22 06:07:55 -07:00
if ((!m_drawAir && mapBlock.onlyAir())
|| (!m_drawIgnore && mapBlock.onlyIgnore())) {
// Nothing to draw :-)
return;
}
2018-04-22 06:07:55 -07:00
for (const auto &entry : mapBlock.getMappings()) {
const string &name = entry.second;
const int nodeId = entry.first;
// In case of a height map, it stores just dummy colors...
NodeColorMap::const_iterator color = m_nodeColors.find(name);
if (name == "air" && !(m_drawAir && color != m_nodeColors.end())) {
m_nodeIDColor[nodeId] = NodeColorNotDrawn;
}
else if (name == "ignore" && !(m_drawIgnore && color != m_nodeColors.end())) {
m_nodeIDColor[nodeId] = NodeColorNotDrawn;
}
else {
if (color != m_nodeColors.end()) {
// If the color is marked 'ignore', then treat it accordingly.
// Colors marked 'ignore' take precedence over 'air'
if ((color->second.f & ColorEntry::FlagIgnore)) {
if (m_drawIgnore)
m_nodeIDColor[nodeId] = &color->second;
2018-04-22 06:07:55 -07:00
else
m_nodeIDColor[nodeId] = NodeColorNotDrawn;
}
2018-04-22 06:07:55 -07:00
// If the color is marked 'air', then treat it accordingly.
else if ((color->second.f & ColorEntry::FlagAir)) {
if (m_drawAir)
m_nodeIDColor[nodeId] = &color->second;
else
m_nodeIDColor[nodeId] = NodeColorNotDrawn;
}
// Regular node.
else {
2018-04-22 06:07:55 -07:00
m_nodeIDColor[nodeId] = &color->second;
}
}
2018-04-22 06:07:55 -07:00
else {
m_nameMap[nodeId] = name;
m_nodeIDColor[nodeId] = nullptr;
}
}
}
2018-04-22 06:07:55 -07:00
renderMapBlock(mapBlock);
}
class MapBlockIterator
{
public:
virtual ~MapBlockIterator(void) {}
virtual MapBlockIterator &operator++(void) = 0;
virtual BlockPos &operator*(void) = 0;
virtual MapBlockIterator &operator=(const MapBlockIterator &i) = 0;
virtual bool operator==(const MapBlockIterator &i) const = 0;
bool operator!=(const MapBlockIterator &i) const { return !operator==(i); }
virtual void breakDim(int i) { (void) i; }
};
class MapBlockIteratorBlockList : public MapBlockIterator
{
public:
MapBlockIteratorBlockList(void) {}
MapBlockIteratorBlockList(const std::list<BlockPos>::iterator &i) : m_iter(i) {}
MapBlockIterator &operator++(void) override { m_iter++; return *this; }
BlockPos &operator*(void) override { return *m_iter; }
MapBlockIterator &operator=(const MapBlockIterator &i) override
{ const MapBlockIteratorBlockList &i2 = dynamic_cast<const MapBlockIteratorBlockList &>(i); m_iter = i2.m_iter; return *this; }
bool operator==(const MapBlockIterator &i) const override
{ const MapBlockIteratorBlockList &i2 = dynamic_cast<const MapBlockIteratorBlockList &>(i); return m_iter == i2.m_iter; }
// breakDim() might be implemented, but is not strictly necessary
private:
std::list<BlockPos>::iterator m_iter;
};
class MapBlockIteratorBlockPos : public MapBlockIterator
{
public:
MapBlockIteratorBlockPos(void) {}
MapBlockIteratorBlockPos(const BlockPosIterator &i) : m_iter(i) {}
MapBlockIterator &operator++(void) override { m_iter++; return *this; }
BlockPos &operator*(void) override { return *m_iter; }
MapBlockIterator &operator=(const MapBlockIterator &i) override
{ const MapBlockIteratorBlockPos &i2 = dynamic_cast<const MapBlockIteratorBlockPos &>(i); m_iter = i2.m_iter; return *this; }
bool operator==(const MapBlockIterator &i) const override
{ const MapBlockIteratorBlockPos &i2 = dynamic_cast<const MapBlockIteratorBlockPos &>(i); return m_iter == i2.m_iter; }
void breakDim(int i) override { m_iter.breakDim(i); }
private:
BlockPosIterator m_iter;
};
2014-03-05 12:41:27 -08:00
void TileGenerator::renderMap()
{
int unpackErrors = 0;
long long blocks_rendered = 0;
int area_rendered = 0;
BlockPos currentPos;
2015-02-26 01:02:49 -08:00
currentPos.x() = INT_MIN;
currentPos.y() = INT_MAX;
2015-02-26 01:02:49 -08:00
currentPos.z() = INT_MIN;
bool allReaded = false;
MapBlockIterator *position;
MapBlockIterator *begin;
MapBlockIterator *end;
if (m_generatePrefetch != BlockListPrefetch::Prefetch) {
position = new MapBlockIteratorBlockPos();
begin = new MapBlockIteratorBlockPos(BlockPosIterator(
BlockPos(m_xMin, m_yMax, m_zMax, m_databaseFormat),
BlockPos(m_xMax, m_yMin, m_zMin, m_databaseFormat)));
end = new MapBlockIteratorBlockPos(BlockPosIterator(
BlockPos(m_xMin, m_yMax, m_zMax, m_databaseFormat),
BlockPos(m_xMax, m_yMin, m_zMin, m_databaseFormat),
BlockPosIterator::End));
}
else {
position = new MapBlockIteratorBlockList(std::list<BlockPos>::iterator());
begin = new MapBlockIteratorBlockList(m_positions.begin());
end = new MapBlockIteratorBlockList(m_positions.end());
}
std::cout << std::flush;
std::cerr << std::flush;
for (*position = *begin; *position != *end; ++*position) {
const BlockPos &pos = **position;
2015-02-26 01:02:49 -08:00
if (currentPos.x() != pos.x() || currentPos.z() != pos.z()) {
area_rendered++;
if (currentPos.y() == m_yMin)
m_emptyMapArea++;
2015-02-26 01:02:49 -08:00
if (currentPos.z() != pos.z()) {
if (m_scaleFactor > 1) {
2015-02-26 01:02:49 -08:00
scalePixelRows(m_blockPixelAttributes, m_blockPixelAttributesScaled, pos.z());
pushPixelRows(m_blockPixelAttributesScaled, pos.z());
m_blockPixelAttributesScaled.setLastY(((m_zMax - pos.z()) * 16 + 15) / m_scaleFactor);
}
else {
2015-02-26 01:02:49 -08:00
pushPixelRows(m_blockPixelAttributes, pos.z());
}
2015-02-26 01:02:49 -08:00
m_blockPixelAttributes.setLastY((m_zMax - pos.z()) * 16 + 15);
if (progressIndicator)
2015-02-26 01:02:49 -08:00
cout << "Processing Z-coordinate: " << std::setw(6) << pos.z()*16
<< " (" << std::fixed << std::setprecision(0) << 100.0 * (m_zMax - pos.z()) / (m_zMax - m_zMin)
2014-06-23 22:47:15 -07:00
<< "%) \r" << std::flush;
}
m_readedPixels.fill(0);
allReaded = false;
currentPos = pos;
}
else if (allReaded) {
position->breakDim(1);
continue;
}
currentPos.y() = pos.y();
2018-04-22 06:07:55 -07:00
const DB::Block block = m_db->getBlockOnPos(pos);
if (!block.isEmpty()) {
try {
processMapBlock(block);
blocks_rendered++;
2012-08-24 13:51:17 -07:00
allReaded = true;
for (int i = 0; i < 16; ++i) {
if (m_readedPixels[i] != 0xffff) {
allReaded = false;
2012-08-24 03:10:26 -07:00
}
}
}
catch (UnpackError &e) {
2015-02-26 01:02:49 -08:00
std::cerr << "Failed to unpack map block " << pos.x() << "," << pos.y() << "," << pos.z()
<< " (id: " << pos.databasePosStr(BlockPos::I64) << "). Block corrupt ?"
<< std::endl
2015-02-26 01:02:49 -08:00
<< "\tCoordinates: " << pos.x()*16 << "," << pos.y()*16 << "," << pos.z()*16 << "+16+16+16"
<< "; Data: " << e.type << " at: " << e.offset << "(+" << e.length << ")/" << e.dataLength
<< std::endl;
unpackErrors++;
}
catch (ZlibDecompressor::DecompressError &e) {
2015-02-26 01:02:49 -08:00
std::cerr << "Failed to decompress data in map block " << pos.x() << "," << pos.y() << "," << pos.z()
<< " (id: " << pos.databasePosStr(BlockPos::I64) << "). Block corrupt ?"
<< std::endl
2015-02-26 01:02:49 -08:00
<< "\tCoordinates: " << pos.x()*16 << "," << pos.y()*16 << "," << pos.z()*16 << "+16+16+16"
<< "; Cause: " << e.message
<< std::endl;
unpackErrors++;
2012-08-24 13:51:17 -07:00
}
}
if (unpackErrors >= 100) {
throw(std::runtime_error("Too many block unpacking errors - bailing out"));
}
2012-08-24 13:51:17 -07:00
}
delete position;
delete begin;
delete end;
2015-02-26 01:02:49 -08:00
if (currentPos.z() != INT_MIN) {
if (currentPos.y() == m_yMin)
m_emptyMapArea++;
if (m_scaleFactor > 1) {
2015-02-26 01:02:49 -08:00
scalePixelRows(m_blockPixelAttributes, m_blockPixelAttributesScaled, currentPos.z() - 1);
pushPixelRows(m_blockPixelAttributesScaled, currentPos.z() - 1);
}
else {
2015-02-26 01:02:49 -08:00
pushPixelRows(m_blockPixelAttributes, currentPos.z() - 1);
}
}
bool eraseProgress = true;
if (verboseCoordinates >= 1) {
eraseProgress = false;
if (m_YMinMapped <= m_YMaxMapped) {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Mapped Vertical Range:" << std::right
<< std::setw(7) << "x" << ","
<< std::setw(7) << m_YMinMapped*16 << ","
<< std::setw(7) << "z"
<< " .. "
<< std::setw(7) << "x" << ","
<< std::setw(7) << m_YMaxMapped*16+15 << ","
<< std::setw(7) << "z"
<< " ("
<< std::setw(6) << "x" << ","
<< std::setw(6) << m_YMinMapped << ","
<< std::setw(6) << "z"
<< " .. "
<< std::setw(6) << "x" << ","
<< std::setw(6) << m_YMaxMapped << ","
<< std::setw(6) << "z"
<< ")\n";
}
else {
cout
<< std::setw(MESSAGE_WIDTH) << std::left
<< "Mapped Vertical Range:" << std::right
<< std::setw(7) << "x" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "z"
<< " .. "
<< std::setw(7) << "x" << ","
<< std::setw(7) << "-" << ","
<< std::setw(7) << "z"
<< " ("
<< std::setw(6) << "x" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "z"
<< " .. "
<< std::setw(6) << "x" << ","
<< std::setw(6) << "-" << ","
<< std::setw(6) << "z"
<< ")\n";
}
}
if (m_generatePrefetch == BlockListPrefetch::Prefetch && m_backend == "leveldb" && (m_reportDatabaseFormat || verboseStatistics >= 1)) {
cout
<< "Database format setting when using --disable-blocklist-prefetch: ";
if (!m_recommendedDatabaseFormat.empty())
cout << m_recommendedDatabaseFormat;
else
cout << "unknown - use 'mixed' to be safe";
cout << std::endl;
}
if (verboseStatistics >= 1) {
eraseProgress = false;
cout << "Statistics"
<< ": blocks read/queried: " << m_db->getBlocksReadCount()
<< " / " << m_db->getBlocksQueriedCount()
<< "; blocks rendered: " << blocks_rendered
<< "; area rendered: " << area_rendered
<< "/" << (m_xMax-m_xMin+1) * (m_zMax-m_zMin+1)
<< " (" << (long long)area_rendered*16*16 << " nodes)";
if (unpackErrors)
cout << " (" << unpackErrors << " errors)";
cout << std::endl;
}
if (progressIndicator && eraseProgress)
2014-06-23 22:47:15 -07:00
cout << std::setw(50) << "" << "\r";
if (m_generatePrefetch != BlockListPrefetch::Prefetch) {
double queryFactor = 1.0 * m_db->getBlocksQueriedCount() / m_db->getBlocksReadCount();
if (verboseStatistics >= 4) {
std::cout << std::fixed << std::setprecision(2);
std::cout << "disable-blocklist-prefetch statistics:" << std::endl
<< " Query factor: " << queryFactor << std::endl;
}
if (!(m_silenceSuggestions & SUGGESTION_PREFETCH) && queryFactor >= 10) {
std::cout << std::fixed << std::setprecision(2);
std::cout << "NOTE: amount of database blocks queried exceeds amount read by a factor " << queryFactor << "." << std::endl
<< " This makes --disable-blocklist-prefetch rather inefficient. Consider disabling it, or" << std::endl
<< " adjusting the vertical limits (e.g. --min-y=" << m_YMinMapped * 16 << " --max-y=" << m_YMaxMapped*16+15 << ")" << std::endl;
}
}
else {
double blocksFractionMapped = 1.0 * m_db->getBlocksReadCount() / m_worldBlocks;
long long worldVolumeMapped = (m_xMax-m_xMin+1) * (m_zMax-m_zMin+1) * (m_YMaxMapped-m_YMinMapped+1);
if (verboseStatistics >= 4) {
std::cout << std::fixed << std::setprecision(2);
std::cout << "disable-blocklist-prefetch statistics:" << std::endl
<< " World size (1M Blocks): " << m_worldBlocks / 1000.0 / 1000
<< " (" << MIN_NOPREFETCH_VOLUME / 1000.0 / 1000 << " .. "
<< MAX_NOPREFETCH_VOLUME / 1000.0 / 1000 << ")" << std::endl
<< " Fraction of world blocks mapped: "
<< 100 * blocksFractionMapped << "% (limit: 10%)" << std::endl
<< " Volume mapped: "
<< worldVolumeMapped / 10000.0 << "% (" << worldVolumeMapped << ")" << std::endl;
}
if (!(m_silenceSuggestions & SUGGESTION_PREFETCH)
&& m_worldBlocks >= MIN_NOPREFETCH_VOLUME
&& blocksFractionMapped < 0.1
&& worldVolumeMapped < MAX_NOPREFETCH_VOLUME) {
std::cout << "NOTE: Mapping speed may improve using the option --disable-blocklist-prefetch,"
<< " combined with vertical limits (" << m_YMinMapped * 16 << " .. " << m_YMaxMapped*16+15 << ")" << std::endl;
if (m_backend == "leveldb") {
std::cout << " The option --database-format=" << (!m_recommendedDatabaseFormat.empty() ? m_recommendedDatabaseFormat : "mixed")
<< " is also required for the (current) leveldb backend." << std::endl
<< " Use --verbose=2 or --database-format=query for details" << std::endl;
}
}
}
2012-08-24 13:51:17 -07:00
}
Color TileGenerator::computeMapHeightColor(int height)
{
int adjustedHeight = int((height - m_seaLevel) * m_heightMapYScale + 0.5);
float r = 0;
float g = 0;
float b = 0;
int n = 0;
for (const HeightMapColor &colorSpec : m_heightMapColors) {
if (adjustedHeight >= colorSpec.height[0] && adjustedHeight <= colorSpec.height[1]) {
float weight = (float)(colorSpec.height[1] - adjustedHeight + 1) / (colorSpec.height[1] - colorSpec.height[0] + 1);
for (const Color &j : colorSpec.color) {
r += j.r * weight;
g += j.g * weight;
b += j.b * weight;
weight = 1 - weight;
}
n++;
}
}
return Color(int(r / n + 0.5), int(g / n + 0.5), int(b / n + 0.5));
}
2018-04-22 06:07:55 -07:00
inline void TileGenerator::renderMapBlock(const MapBlock &mapBlock)
2012-08-24 13:51:17 -07:00
{
2018-04-22 06:07:55 -07:00
const BlockPos &pos = mapBlock.getPos();
2015-02-26 01:02:49 -08:00
int xBegin = worldBlockX2StoredX(pos.x());
int zBegin = worldBlockZ2StoredY(pos.z());
2018-04-22 06:07:55 -07:00
//const unsigned char *mapData = mapBlock.data();
2015-02-26 01:02:49 -08:00
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;
bool renderedAnything = false;
2012-08-24 13:51:17 -07:00
for (int z = 0; z < 16; ++z) {
bool rowIsEmpty = true;
2012-08-24 13:51:17 -07:00
for (int x = 0; x < 16; ++x) {
if (m_readedPixels[z] & (1 << x)) {
continue;
}
// The #define of pixel performs *significantly* *better* than the definition of PixelAttribute &pixel ...
#define pixel m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin + x)
//PixelAttribute &pixel = m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin + x);
if (m_blockDefaultColor.to_uint() && !pixel.color().to_uint()) {
rowIsEmpty = false;
pixel = PixelAttribute(m_blockDefaultColor, NAN);
}
2014-03-05 09:06:05 -08:00
for (int y = maxY; y >= minY; --y) {
2012-08-24 13:51:17 -07:00
int position = x + (y << 4) + (z << 8);
2018-04-22 06:07:55 -07:00
int content = mapBlock.readBlockContent(position);//readBlockContent(mapData, version, position);
#define nodeColor (*m_nodeIDColor[content])
//const ColorEntry &nodeColor = *m_nodeIDColor[content];
if (m_nodeIDColor[content] == NodeColorNotDrawn) {
2012-08-24 13:51:17 -07:00
continue;
}
2015-02-26 01:02:49 -08:00
int height = pos.y() * 16 + y;
if (m_heightMap) {
if (m_nodeIDColor[content] && nodeColor.a != 0) {
if (!(m_readedPixels[z] & (1 << x))) {
if (height > m_surfaceHeight) m_surfaceHeight = height;
if (height < m_surfaceDepth) m_surfaceDepth = height;
}
rowIsEmpty = false;
renderedAnything = true;
pixel = PixelAttribute(computeMapHeightColor(height), height);
m_readedPixels[z] |= (1 << x);
break;
}
}
else if (m_nodeIDColor[content]) {
rowIsEmpty = false;
renderedAnything = true;
pixel.mixUnder(PixelAttribute(nodeColor, height));
if ((m_drawAlpha && nodeColor.a == 0xff) || (!m_drawAlpha && nodeColor.a != 0)) {
m_readedPixels[z] |= (1 << x);
break;
}
} else {
NodeID2NameMap::iterator blockName = m_nameMap.find(content);
if (blockName != m_nameMap.end())
m_unknownNodes.insert(blockName->second);
2012-08-24 13:51:17 -07:00
}
#undef nodeColor
2012-08-24 02:01:48 -07:00
}
#undef pixel
2012-08-24 02:01:48 -07:00
}
if (!rowIsEmpty)
m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin).nextEmpty = false;
2012-08-24 00:46:14 -07:00
}
if (renderedAnything) {
if (pos.y() < m_YMinMapped)
m_YMinMapped = pos.y();
if (pos.y() > m_YMaxMapped)
m_YMaxMapped = pos.y();
}
2012-08-24 00:46:14 -07:00
}
2012-08-23 06:35:00 -07:00
2012-08-25 05:11:55 -07:00
void TileGenerator::renderScale()
{
if ((m_drawScale & DRAWSCALE_LEFT) && (m_drawScale & DRAWSCALE_TOP)) {
2017-10-16 01:58:32 -07:00
paintEngine->drawChar(borderLeft() - 26, 0, PaintEngine::Font::MediumBold, 'X', m_scaleColor);
paintEngine->drawChar(2, borderTop() - 26, PaintEngine::Font::MediumBold, 'Z', m_scaleColor);
}
int major = m_sideScaleMajor ? m_sideScaleMajor : 4 * 16 * m_scaleFactor;
int minor = m_sideScaleMinor;
2012-08-25 06:06:11 -07:00
string scaleText;
if ((m_drawScale & DRAWSCALE_TOP)) {
int start;
int extra_left = borderLeft() ? 0 : major;
int extra_right = borderRight() ? 0 : major;
if (m_xMin >= 0)
start = (m_xMin * 16 + m_mapXStartNodeOffset - 1 + major - 1 - extra_left) / major * major;
else
start = (m_xMin * 16 + m_mapXStartNodeOffset - 1 - extra_left) / major * major;
for (int i = start; i <= (m_xMax + 1) * 16 + m_mapXEndNodeOffset + extra_right; i += major) {
stringstream buf;
buf << i;
int xPos = worldX2ImageX(i);
scaleText = buf.str();
2017-10-16 01:58:32 -07:00
paintEngine->drawText(xPos + 2, 0, PaintEngine::Font::MediumBold, scaleText, m_scaleColor);
if ((major % 16) == 0) {
buf.str("");
buf << "(" << i / 16 << ")";
scaleText = buf.str();
2017-10-16 01:58:32 -07:00
paintEngine->drawText(xPos + 2, 16, PaintEngine::Font::Tiny, scaleText, m_scaleColor);
}
2017-10-16 01:58:32 -07:00
paintEngine->drawLine(xPos, 0, xPos, borderTop() - 1, m_scaleColor);
}
if (minor) {
if (m_xMin >= 0)
start = (m_xMin * 16 + m_mapXStartNodeOffset + minor - 2) / minor * minor;
else
start = (m_xMin * 16 + m_mapXStartNodeOffset - 1) / minor * minor;
for (int i = start; i <= (m_xMax + 1) * 16 + m_mapXEndNodeOffset; i += minor) {
int xPos = worldX2ImageX(i);
2017-10-16 01:58:32 -07:00
paintEngine->drawLine(xPos, borderTop() - 5, xPos, borderTop() - 1, m_scaleColor);
}
}
2012-08-25 06:06:11 -07:00
}
if ((m_drawScale & DRAWSCALE_LEFT)) {
int start;
int extra_top = borderTop() ? 0 : major;
int extra_bottom = borderBottom() ? 0 : major;
if (m_zMax >= 0)
start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset + extra_top) / major * major;
else
start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset - major + 1 + extra_top) / major * major;
for (int i = start; i >= m_zMin * 16 - m_mapYEndNodeOffset - 1 - extra_bottom; i -= major) {
stringstream buf;
buf << i;
int yPos = worldZ2ImageY(i);
scaleText = buf.str();
2017-10-16 01:58:32 -07:00
paintEngine->drawText(2, yPos, PaintEngine::Font::MediumBold, scaleText, m_scaleColor);
if ((major % 16) == 0) {
buf.str("");
buf << "(" << i / 16 << ")";
scaleText = buf.str();
2017-10-16 01:58:32 -07:00
paintEngine->drawText(2, yPos - 10, PaintEngine::Font::Tiny, scaleText, m_scaleColor);
}
paintEngine->drawLine(0, yPos, borderLeft() - 1, yPos, m_scaleColor);
}
if (minor) {
if (m_zMax >= 0)
start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset) / minor * minor;
else
start = ((m_zMax + 1) * 16 - m_mapYStartNodeOffset - minor + 1) / minor * minor;
for (int i = start; i >= m_zMin * 16 - m_mapYEndNodeOffset - 1; i -= minor) {
int yPos = worldZ2ImageY(i);
2017-10-16 01:58:32 -07:00
paintEngine->drawLine(borderLeft() - 5, yPos, borderLeft() - 1, yPos, m_scaleColor);
}
}
2012-08-25 06:06:11 -07:00
}
// DRAWSCALE_RIGHT and DRAWSCALE_BOTTOM not implemented - getting the text positioned right seems not trivial (??)
2012-08-25 05:11:55 -07:00
}
void TileGenerator::renderHeightScale()
{
int height_min = m_surfaceDepth - 16;
int height_limit = m_surfaceHeight + 16;
int xBorderOffset = borderLeft();
int yBorderOffset = borderTop() + m_pictHeight;
double height_step = (double)(height_limit - height_min) / m_pictWidth;
if (height_step < 1.0 / 16) {
height_step = 1.0 / 16;
}
double major;
int minor = m_heightScaleMinor;
if (m_heightScaleMajor) {
major = m_heightScaleMajor;
}
else {
major = 64;
while (major / height_step / 64 < 0.75)
major *= 2;
while (major / height_step / 64 > 1.5)
major /= 2;
}
double height = height_min;
for (int x = 0; height < height_limit; x++, height += height_step) {
Color color = computeMapHeightColor(int(height + 0.5));
2017-10-16 01:58:32 -07:00
paintEngine->drawLine(xBorderOffset + x, yBorderOffset + 8, xBorderOffset + x, yBorderOffset + borderBottom() - 20, color);
int iheight = static_cast<int>(height + (height > 0 ? 0.5 : -0.5));
int iheightMaj = static_cast<int>(trunc(iheight / major + (height > 0 ? 0.5 : -0.5)) * major);
if (fabs(height - iheightMaj) <= height_step / 2 && (height - iheightMaj) > -height_step / 2) {
if (iheightMaj / int(major) % 2 == 1 && fabs(height) > 9999 && major / height_step < 56) {
// Maybe not enough room for the number. Draw a tick mark instead
2017-10-16 01:58:32 -07:00
paintEngine->drawLine(xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 16, m_scaleColor);
}
else {
stringstream buf;
buf << iheightMaj;
string scaleText = buf.str();
2017-10-16 01:58:32 -07:00
paintEngine->drawText(xBorderOffset + x + 2, yBorderOffset + borderBottom() - 16, PaintEngine::Font::MediumBold,
scaleText, m_scaleColor);
paintEngine->drawLine(xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 1, m_scaleColor);
}
}
if (minor) {
int iheightMin = int(iheight / minor + (height > 0 ? 0.5 : -0.5)) * minor;
if (fabs(height - iheightMin) <= height_step / 2 && (height - iheightMin) > -height_step / 2) {
2017-10-16 01:58:32 -07:00
paintEngine->drawLine(xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 16, m_scaleColor);
}
}
}
}
2012-08-25 06:21:51 -07:00
void TileGenerator::renderOrigin()
{
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
int imageX = worldX2ImageX(0);
int imageY = worldZ2ImageY(0);
2017-10-16 01:58:32 -07:00
paintEngine->drawCircle(imageX, imageY, 12, m_originColor);
2012-08-25 06:21:51 -07:00
}
2012-08-25 07:29:41 -07:00
void TileGenerator::renderPlayers(const std::string &inputPath)
{
PlayerAttributes players(inputPath);
for (const Player &player : players) {
int imageX = worldX2ImageX(static_cast<int>(player.x / 10));
int imageY = worldZ2ImageY(static_cast<int>(player.z / 10));
2012-09-01 04:01:31 -07:00
2017-10-16 01:58:32 -07:00
paintEngine->drawCircle(imageX, imageY, 5, m_playerColor);
paintEngine->drawText(imageX + 2, imageY + 2, PaintEngine::Font::MediumBold, player.name, m_playerColor);
2012-09-01 04:01:31 -07:00
}
2012-08-25 07:29:41 -07:00
}
void TileGenerator::renderDrawObjects()
{
for (DrawObject &drawObject : m_drawObjects) {
// Hack to adjust the center of an ellipse with even dimensions to align it correctly
bool ellipseAdjustCenter[2] = { false, true };
#ifdef DEBUG
assert(o->type != DrawObject::Unknown);
assert(o->haveDimensions || !o->haveCenter);
// Look for problems...
if (o->haveCenter)
o->corner1 = NodeCoord(NodeCoord::Invalid, NodeCoord::Invalid, NodeCoord::Invalid);
else
o->center = NodeCoord(NodeCoord::Invalid, NodeCoord::Invalid, NodeCoord::Invalid);
if (o->haveDimensions)
o->corner2 = NodeCoord(NodeCoord::Invalid, NodeCoord::Invalid, NodeCoord::Invalid);
else
o->dimensions = NodeCoord(NodeCoord::Invalid, NodeCoord::Invalid, NodeCoord::Invalid);
#else
// Avoid problems - the resulting image may still be incorrect though...
if (drawObject.type == DrawObject::Unknown)
continue;
if (drawObject.haveCenter)
drawObject.corner1 = drawObject.center;
else
drawObject.center = drawObject.corner1;
if (drawObject.haveDimensions)
drawObject.corner2 = drawObject.dimensions;
else
drawObject.dimensions = drawObject.corner2;
if (!drawObject.haveDimensions && drawObject.haveCenter)
drawObject.haveDimensions = true;
#endif
for (int i = 0; i < 2; i++) {
if (drawObject.world) {
int (TileGenerator::*world2Image)(int val) const;
if (i==0)
world2Image = &TileGenerator::worldX2ImageX;
else
world2Image = &TileGenerator::worldZ2ImageY;
if (drawObject.haveCenter)
drawObject.center.dimension[i] = (this->*world2Image)(drawObject.center.dimension[i]);
else
drawObject.corner1.dimension[i] = (this->*world2Image)(drawObject.corner1.dimension[i]);
if (!drawObject.haveDimensions) {
drawObject.corner2.dimension[i] = (this->*world2Image)(drawObject.corner2.dimension[i]);
if (i == 1)
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
}
else if (i==1) {
drawObject.dimensions.dimension[i] = -drawObject.dimensions.dimension[i];
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
}
}
else {
if (drawObject.haveCenter)
drawObject.center.dimension[i] += i ? borderTop() : borderLeft();
else
drawObject.corner1.dimension[i] += i ? borderTop() : borderLeft();
if (!drawObject.haveDimensions)
drawObject.corner2.dimension[i] += i ? borderTop() : borderLeft();
}
}
for (int i = 0; i < 2; i++) {
// Make sure all individual coordinates are ordered and dimensions are positive
// EXCEPT for lines: lines do not have reflection symmetry.
if (drawObject.type != DrawObject::Line) {
if (!drawObject.haveDimensions) {
if (drawObject.corner1.dimension[i] > drawObject.corner2.dimension[i]) {
int temp = drawObject.corner1.dimension[i];
drawObject.corner1.dimension[i] = drawObject.corner2.dimension[i];
drawObject.corner2.dimension[i] = temp;
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
}
}
else if (drawObject.dimensions.dimension[i] < 0) {
if (!drawObject.haveCenter)
drawObject.corner1.dimension[i] += drawObject.dimensions.dimension[i] + 1;
else
// Even dimensions cause asymetry
drawObject.center.dimension[i] += ((1 - drawObject.dimensions.dimension[i]) % 2);
drawObject.dimensions.dimension[i] = -drawObject.dimensions.dimension[i];
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
}
}
// Convert to the apropriate type of coordinates.
if (drawObject.type == DrawObject::Ellipse) {
if (!drawObject.haveDimensions) {
drawObject.dimensions.dimension[i] = drawObject.corner2.dimension[i] - drawObject.corner1.dimension[i] + 1;
drawObject.center.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] / 2;
}
else if (!drawObject.haveCenter) {
drawObject.center.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] / 2;
}
if (drawObject.world && ellipseAdjustCenter[i] && drawObject.dimensions.dimension[i] % 2 == 0)
drawObject.center.dimension[i] -= 1;
}
else if (drawObject.type == DrawObject::Line || drawObject.type == DrawObject::Rectangle) {
if (drawObject.haveCenter) {
drawObject.corner1.dimension[i] = drawObject.center.dimension[i] - drawObject.dimensions.dimension[i] / 2;
if (drawObject.dimensions.dimension[i] < 0)
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] + 1;
else
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] - 1;
}
else if (drawObject.haveDimensions) {
if (drawObject.dimensions.dimension[i] < 0)
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] + 1;
else
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] - 1;
}
}
#ifdef DEBUG
else
assert(o->type == DrawObject::Point || o->type == DrawObject::Text);
#endif
}
switch(drawObject.type) {
case DrawObject::Point:
paintEngine->drawPixel(drawObject.center.x(), drawObject.center.y(), drawObject.color);
break;
case DrawObject::Line:
paintEngine->drawLine(drawObject.corner1.x(), drawObject.corner1.y(), drawObject.corner2.x(), drawObject.corner2.y(), drawObject.color);
break;
case DrawObject::Ellipse:
paintEngine->drawArc(drawObject.center.x(), drawObject.center.y(), drawObject.dimensions.x(), drawObject.dimensions.y(), 0, 360, drawObject.color);
break;
case DrawObject::Rectangle:
paintEngine->drawRect(drawObject.corner1.x(), drawObject.corner1.y(), drawObject.corner2.x(), drawObject.corner2.y(), drawObject.color);
break;
2017-10-16 01:58:32 -07:00
case DrawObject::Text:
paintEngine->drawText(drawObject.center.x(), drawObject.center.y(), PaintEngine::Font::MediumBold, drawObject.text, drawObject.color);
break;
default:
#ifdef DEBUG
assert(o->type != o->type);
#endif
break;
}
}
}
2012-08-24 00:46:14 -07:00
inline std::list<int> TileGenerator::getZValueList() const
{
std::list<int> zlist;
for (const BlockPos &position : m_positions) {
zlist.push_back(position.z());
2012-08-24 00:46:14 -07:00
}
zlist.sort();
zlist.unique();
2012-09-01 04:34:27 -07:00
zlist.reverse();
2012-08-24 00:46:14 -07:00
return zlist;
}
2012-08-23 05:21:34 -07:00
void TileGenerator::writeImage(const std::string &output)
{
2017-10-16 01:58:32 -07:00
paintEngine->save(output, std::string(), -1);
2012-08-23 05:21:34 -07:00
}
2012-08-25 07:41:53 -07:00
void TileGenerator::printUnknown()
{
if (!m_unknownNodes.empty()) {
2012-08-25 07:41:53 -07:00
std::cerr << "Unknown nodes:" << std::endl;
for (const string &unknownNode : m_unknownNodes) {
std::cerr << unknownNode << std::endl;
2012-08-25 07:41:53 -07:00
}
}
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
// Adjust map coordinate for tiles and border
inline int TileGenerator::mapX2ImageX(int val) const
2012-08-25 05:11:55 -07:00
{
if (m_tileWidth && m_tileBorderSize)
val += ((val - m_tileMapXOffset / m_scaleFactor + m_tileWidth / m_scaleFactor) / (m_tileWidth / m_scaleFactor)) * m_tileBorderSize;
return val + borderLeft();
2012-08-25 05:11:55 -07:00
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
// Adjust map coordinate for tiles and border
inline int TileGenerator::mapY2ImageY(int val) const
2012-08-25 05:11:55 -07:00
{
if (m_tileHeight / m_scaleFactor && m_tileBorderSize)
val += ((val - m_tileMapYOffset / m_scaleFactor + m_tileHeight / m_scaleFactor) / (m_tileHeight / m_scaleFactor)) * m_tileBorderSize;
return val + borderTop();
2012-08-25 05:11:55 -07:00
}
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
// Convert world coordinate to image coordinate
inline int TileGenerator::worldX2ImageX(int val) const
{
val = (val - m_xMin * 16) - m_mapXStartNodeOffset;
return mapX2ImageX(val / m_scaleFactor);
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
}
// Convert world coordinate to image coordinate
inline int TileGenerator::worldZ2ImageY(int val) const
{
val = (m_zMax * 16 + 15 - val) - m_mapYStartNodeOffset;
return mapY2ImageY(val / m_scaleFactor);
Make the geometry pixel-accurate instead of map-block accurate When requesting, for instance, a 75x85 map, the mapper will now create a 75x85 map, instead of an 80x96 (or even 96x108) map as it did before. This new behavior is the default when using one of the options --centergeometry or --cornergeometry. In addition, both of these options will no longer shrink the map, to remove rows or columns of empty blocks at the edges. Previously, this behavior was enabled with --forcegeometry. An option --geometrymode has been added as well, to tune the interpretation of the geometry. It supports 4 flags: - pixel: the requested geometry is interpreted with pixel granularity. The map is not enlarged to include entire map blocks. - block: the requested geometry is interpreted with block granularity. The map is enlarged with at most 15 nodes at each of the four edges, so that it includes entire map blocks only. - fixed: a map of the requested geometry is created (after adjustmens for 'block' mode). Empty rows or columns at the edges are not removed. - shrink: Empty rows and columns at the map edges are removed to generate the smallest picture possible. Lastly, a new geometry syntax has been added, which is more compatible with known syntax (i.e. X-Windows), and which allows the offset to be optional. If the offset is omitted, the picture defaults to be centered around 0,0. `<width>x<height>[+|-<xoffset>+|-<yoffset>]` For compatibility, the behavior of the option --geometry was not changed. If (and only if) used before --geometrymode, it enables block granularity and shrink. The old option --forcegeometry is no longer documented, but still recognised for compatibility.
2014-04-15 01:46:21 -07:00
}