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
|
|
|
|
* =====================================================================
|
|
|
|
*/
|
2018-04-15 05:45:43 -07:00
|
|
|
#include <cerrno>
|
|
|
|
#include <climits>
|
2012-08-23 05:21:34 -07:00
|
|
|
#include <cstdio>
|
2012-08-23 03:55:31 -07:00
|
|
|
#include <cstdlib>
|
2018-04-15 05:45:43 -07:00
|
|
|
#include <cstring>
|
2012-08-23 03:55:31 -07:00
|
|
|
#include <fstream>
|
2014-04-09 15:55:50 -07:00
|
|
|
#include <iomanip>
|
2018-04-15 05:45:43 -07:00
|
|
|
#include <iostream>
|
2012-08-24 00:46:14 -07:00
|
|
|
#include <sstream>
|
2014-03-09 04:32:13 -07:00
|
|
|
#include <stdexcept>
|
2018-04-15 05:45:43 -07:00
|
|
|
#include <utility>
|
2018-04-14 00:02:22 -07:00
|
|
|
|
|
|
|
|
2012-09-01 04:01:31 -07:00
|
|
|
#include "config.h"
|
2018-04-14 00:02:22 -07:00
|
|
|
#include "DataFileParser.h"
|
2018-04-15 05:45:43 -07:00
|
|
|
#include "PaintEngine_libgd.h"
|
2012-09-01 07:40:18 -07:00
|
|
|
#include "PlayerAttributes.h"
|
2018-04-15 05:45:43 -07:00
|
|
|
#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"
|
2018-03-23 04:34:52 -07:00
|
|
|
#ifdef USE_SQLITE3
|
2014-03-05 12:41:27 -08:00
|
|
|
#include "db-sqlite3.h"
|
2014-05-13 03:28:13 -07:00
|
|
|
#endif
|
2018-03-26 00:25:19 -07:00
|
|
|
#ifdef USE_POSTGRESQL
|
2015-12-16 06:15:47 -08:00
|
|
|
#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
|
2014-05-12 03:17:49 -07:00
|
|
|
#include "db-redis.h"
|
|
|
|
#endif
|
2012-08-23 03:46:22 -07:00
|
|
|
|
2015-03-03 15:09:56 -08:00
|
|
|
#define MESSAGE_WIDTH 25
|
2015-02-24 13:12:41 -08:00
|
|
|
#define MAX_NOPREFETCH_VOLUME (1LL<<24)
|
|
|
|
#define MIN_NOPREFETCH_VOLUME (1LL<<16)
|
|
|
|
#define MAX_NOPREFETCH_VOLUME_EXAMPLE "16384x256x16384"
|
|
|
|
|
2015-03-03 15:09:56 -08:00
|
|
|
|
2012-08-23 03:55:31 -07:00
|
|
|
using namespace std;
|
|
|
|
|
2014-05-22 09:57:08 -07:00
|
|
|
static const ColorEntry nodeColorNotDrawnObject;
|
|
|
|
const ColorEntry *TileGenerator::NodeColorNotDrawn = &nodeColorNotDrawnObject;
|
|
|
|
|
2015-12-17 02:54:03 -08:00
|
|
|
const BlockPos TileGenerator::BlockPosLimitMin(MAPBLOCK_MIN, MAPBLOCK_MIN, MAPBLOCK_MIN);
|
|
|
|
const BlockPos TileGenerator::BlockPosLimitMax(MAPBLOCK_MAX, MAPBLOCK_MAX, MAPBLOCK_MAX);
|
|
|
|
|
2015-01-24 10:40:42 -08:00
|
|
|
|
2018-04-15 05:45:43 -07:00
|
|
|
TileGenerator::TileGenerator()
|
2012-08-23 03:46:22 -07:00
|
|
|
{
|
2015-02-14 23:45:28 -08: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()
|
|
|
|
{
|
2016-05-23 03:46:25 -07:00
|
|
|
closeDb();
|
2012-08-23 03:46:22 -07:00
|
|
|
}
|
|
|
|
|
2015-03-10 05:23:44 -07:00
|
|
|
void TileGenerator::setSilenceSuggestion(unsigned flags)
|
|
|
|
{
|
|
|
|
m_silenceSuggestions |= flags;
|
|
|
|
}
|
|
|
|
|
2018-04-29 05:44:34 -07:00
|
|
|
void TileGenerator::setGenerateNoPrefetch(BlockListPrefetch enable)
|
2015-02-24 13:12:41 -08:00
|
|
|
{
|
2018-04-29 05:44:34 -07:00
|
|
|
m_generatePrefetch = enable;
|
2015-02-24 13:12:41 -08:00
|
|
|
}
|
|
|
|
|
2015-03-10 05:16:43 -07:00
|
|
|
void TileGenerator::setDBFormat(BlockPos::StrFormat format, bool query)
|
|
|
|
{
|
|
|
|
m_databaseFormat = format;
|
|
|
|
m_databaseFormatSet = true;
|
|
|
|
m_reportDatabaseFormat = query;
|
|
|
|
}
|
|
|
|
|
2015-02-14 23:45:28 -08:00
|
|
|
void TileGenerator::setHeightMap(bool enable)
|
2015-01-24 10:40:42 -08:00
|
|
|
{
|
|
|
|
m_heightMap = enable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TileGenerator::setHeightMapYScale(float scale)
|
|
|
|
{
|
|
|
|
m_heightMapYScale = scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TileGenerator::setSeaLevel(int level)
|
|
|
|
{
|
|
|
|
m_seaLevel = level;
|
|
|
|
}
|
|
|
|
|
2014-04-24 06:59:41 -07:00
|
|
|
void TileGenerator::setBgColor(const Color &bgColor)
|
2012-08-23 03:46:22 -07:00
|
|
|
{
|
2014-04-24 06:59:41 -07:00
|
|
|
m_bgColor = bgColor;
|
2012-08-23 03:46:22 -07:00
|
|
|
}
|
|
|
|
|
2014-05-23 04:16:07 -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)
|
2014-02-16 12:24:32 -08: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
|
|
|
m_shrinkGeometry = shrink;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TileGenerator::setBlockGeometry(bool block)
|
|
|
|
{
|
|
|
|
m_blockGeometry = block;
|
2014-02-16 12:24:32 -08:00
|
|
|
}
|
|
|
|
|
2014-04-24 06:59:41 -07:00
|
|
|
void TileGenerator::setScaleColor(const Color &scaleColor)
|
2012-08-23 03:46:22 -07:00
|
|
|
{
|
2014-04-24 06:59:41 -07:00
|
|
|
m_scaleColor = scaleColor;
|
2012-08-23 03:46:22 -07:00
|
|
|
}
|
|
|
|
|
2014-04-24 06:59:41 -07:00
|
|
|
void TileGenerator::setOriginColor(const Color &originColor)
|
2012-08-23 03:46:22 -07:00
|
|
|
{
|
2014-04-24 06:59:41 -07:00
|
|
|
m_originColor = originColor;
|
2012-08-23 03:46:22 -07:00
|
|
|
}
|
|
|
|
|
2014-04-24 06:59:41 -07:00
|
|
|
void TileGenerator::setPlayerColor(const Color &playerColor)
|
2012-08-23 03:46:22 -07:00
|
|
|
{
|
2014-04-24 06:59:41 -07:00
|
|
|
m_playerColor = playerColor;
|
2012-08-23 05:43:11 -07:00
|
|
|
}
|
|
|
|
|
2015-02-14 23:45:28 -08: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));
|
|
|
|
}
|
|
|
|
|
2014-04-24 06:59:41 -07:00
|
|
|
void TileGenerator::setTileBorderColor(const Color &tileBorderColor)
|
2014-04-07 19:40:09 -07:00
|
|
|
{
|
2014-04-24 06:59:41 -07:00
|
|
|
m_tileBorderColor = tileBorderColor;
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2014-05-21 09:26:39 -07:00
|
|
|
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;
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
|
2015-02-14 05:31:25 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-02-08 03:10:35 -08:00
|
|
|
void TileGenerator::setDrawScale(int scale)
|
2012-08-23 03:46:22 -07:00
|
|
|
{
|
2015-02-14 23:46:36 -08: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
|
|
|
}
|
|
|
|
|
2015-02-14 12:25:40 -08: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;
|
|
|
|
}
|
|
|
|
|
2014-06-19 02:37:16 -07:00
|
|
|
void TileGenerator::setDrawAlpha(bool drawAlpha)
|
2014-04-03 11:32:48 -07:00
|
|
|
{
|
|
|
|
m_drawAlpha = drawAlpha;
|
|
|
|
}
|
|
|
|
|
2014-05-22 08:46:16 -07:00
|
|
|
void TileGenerator::setDrawAir(bool drawAir)
|
|
|
|
{
|
|
|
|
m_drawAir = drawAir;
|
|
|
|
}
|
|
|
|
|
2016-01-05 03:16:39 -08:00
|
|
|
void TileGenerator::setDrawIgnore(bool drawIgnore)
|
|
|
|
{
|
|
|
|
m_drawIgnore = drawIgnore;
|
|
|
|
}
|
|
|
|
|
2014-03-05 08:19:37 -08:00
|
|
|
void TileGenerator::setShading(bool shading)
|
|
|
|
{
|
|
|
|
m_shading = shading;
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:24:31 -07:00
|
|
|
void TileGenerator::enableProgressIndicator()
|
2014-04-09 15:55:50 -07:00
|
|
|
{
|
|
|
|
progressIndicator = true;
|
|
|
|
}
|
|
|
|
|
2014-04-24 09:26:38 -07:00
|
|
|
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)
|
|
|
|
{
|
2014-03-23 11:47:49 -07:00
|
|
|
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)
|
|
|
|
{
|
2014-03-23 11:47:49 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-02-14 23:45:28 -08:00
|
|
|
void TileGenerator::parseNodeColorsFile(const std::string &fileName)
|
|
|
|
{
|
2018-04-14 00:02:22 -07:00
|
|
|
ColorsFileParser d(verboseReadColors, m_drawAlpha);
|
|
|
|
d.parseDataFile(fileName, "map colors");
|
|
|
|
m_nodeColors = d.getNodeColors();
|
2015-02-14 23:45:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void TileGenerator::parseHeightMapNodesFile(const std::string &fileName)
|
|
|
|
{
|
2018-04-14 00:02:22 -07:00
|
|
|
HeightMapNodesFileParser p(verboseReadColors, m_drawAlpha);
|
|
|
|
p.parseDataFile(fileName, "heightmap nodes");
|
|
|
|
m_nodeColors = p.getNodeColors();
|
2015-02-14 23:45:28 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void TileGenerator::parseHeightMapColorsFile(const std::string &fileName)
|
|
|
|
{
|
2018-04-14 00:02:22 -07:00
|
|
|
HeightMapColorsFileParser p(verboseReadColors, m_drawAlpha);
|
|
|
|
p.parseDataFile(fileName, "heightmap colors");
|
|
|
|
m_heightMapColors = p.getHeightMapColors();
|
2012-08-23 03:55:31 -07:00
|
|
|
}
|
|
|
|
|
2018-04-24 20:24:31 -07:00
|
|
|
void TileGenerator::setBackend(const std::string &backend)
|
2014-03-05 12:41:27 -08:00
|
|
|
{
|
2015-12-17 03:30:46 -08:00
|
|
|
m_requestedBackend = backend;
|
2014-03-05 12:41:27 -08:00
|
|
|
}
|
|
|
|
|
2015-12-17 02:54:03 -08:00
|
|
|
void TileGenerator::setScanEntireWorld(bool enable)
|
|
|
|
{
|
|
|
|
m_scanEntireWorld = enable;
|
|
|
|
}
|
|
|
|
|
2015-01-03 10:10:50 -08:00
|
|
|
void TileGenerator::setChunkSize(int size)
|
|
|
|
{
|
|
|
|
m_chunkSize = size;
|
|
|
|
}
|
|
|
|
|
2018-04-24 20:24:31 -07:00
|
|
|
void TileGenerator::sanitizeParameters()
|
2015-02-14 05:31:25 -08:00
|
|
|
{
|
|
|
|
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);
|
2015-02-14 05:31:25 -08:00
|
|
|
sanitizeParameters();
|
2012-08-23 04:32:22 -07:00
|
|
|
loadBlocks();
|
2015-03-10 07:37:30 -07:00
|
|
|
if (m_xMin > m_xMax || m_yMin > m_yMax || m_zMin > m_zMax) {
|
|
|
|
std::cout << "World is empty: no map generated" << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
2015-01-03 10:10:50 -08:00
|
|
|
computeMapParameters(input);
|
2012-08-23 05:21:34 -07:00
|
|
|
createImage();
|
2012-08-23 06:35:00 -07:00
|
|
|
renderMap();
|
2015-02-14 23:46:36 -08:00
|
|
|
if ((m_drawScale & DRAWSCALE_MASK)) {
|
2012-08-25 05:11:55 -07:00
|
|
|
renderScale();
|
|
|
|
}
|
2015-02-14 23:46:36 -08:00
|
|
|
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
|
|
|
}
|
2014-05-08 11:28:38 -07:00
|
|
|
if (!m_drawObjects.empty()) {
|
|
|
|
renderDrawObjects();
|
|
|
|
}
|
2016-05-23 03:46:25 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-05-13 10:52:37 -07:00
|
|
|
std::string TileGenerator::getWorldDatabaseBackend(const std::string &input)
|
2012-08-23 04:32:22 -07:00
|
|
|
{
|
2015-12-16 06:31:07 -08:00
|
|
|
Settings world_mt(input + PATH_SEPARATOR + "world.mt");
|
|
|
|
return world_mt.get("backend", "sqlite3");
|
2014-05-13 10:52:37 -07:00
|
|
|
}
|
|
|
|
|
2015-01-03 10:10:50 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-05-13 10:52:37 -07:00
|
|
|
void TileGenerator::openDb(const std::string &input)
|
|
|
|
{
|
2015-12-17 03:30:46 -08:00
|
|
|
m_backend = m_requestedBackend;
|
2014-05-13 10:52:37 -07:00
|
|
|
bool unsupported = false;
|
|
|
|
if (m_backend == "auto")
|
2015-12-17 03:30:46 -08:00
|
|
|
m_backend = getWorldDatabaseBackend(input);
|
2014-05-13 10:52:37 -07:00
|
|
|
|
2015-12-17 03:30:46 -08:00
|
|
|
if(m_backend == "sqlite3") {
|
2018-03-23 04:34:52 -07:00
|
|
|
#ifdef USE_SQLITE3
|
2014-03-25 16:23:33 -07:00
|
|
|
DBSQLite3 *db;
|
|
|
|
m_db = db = new DBSQLite3(input);
|
2015-12-17 02:54:03 -08:00
|
|
|
m_scanEntireWorld = true;
|
2014-05-13 10:52:37 -07:00
|
|
|
#else
|
|
|
|
unsupported = true;
|
2015-12-16 06:15:47 -08:00
|
|
|
#endif
|
|
|
|
}
|
2015-12-17 03:30:46 -08:00
|
|
|
else if (m_backend == "postgresql") {
|
2018-04-24 08:47:05 -07:00
|
|
|
#ifdef USE_POSTGRESQL
|
2015-12-16 06:15:47 -08:00
|
|
|
DBPostgreSQL *db;
|
|
|
|
m_db = db = new DBPostgreSQL(input);
|
|
|
|
#else
|
|
|
|
unsupported = true;
|
2014-05-13 03:28:13 -07:00
|
|
|
#endif
|
2014-05-13 10:52:37 -07:00
|
|
|
}
|
2015-12-17 03:30:46 -08:00
|
|
|
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);
|
2015-12-17 02:54:03 -08:00
|
|
|
m_scanEntireWorld = true;
|
2014-05-13 10:52:37 -07:00
|
|
|
#else
|
|
|
|
unsupported = true;
|
2014-05-12 03:17:49 -07:00
|
|
|
#endif
|
2014-05-13 10:52:37 -07:00
|
|
|
}
|
2015-12-17 03:30:46 -08:00
|
|
|
else if (m_backend == "redis") {
|
2018-04-24 08:47:05 -07:00
|
|
|
#ifdef USE_REDIS
|
2014-05-12 03:17:49 -07:00
|
|
|
m_db = new DBRedis(input);
|
2015-12-17 02:54:03 -08:00
|
|
|
m_scanEntireWorld = true;
|
2014-05-13 10:52:37 -07:00
|
|
|
#else
|
|
|
|
unsupported = true;
|
2014-03-05 12:41:27 -08:00
|
|
|
#endif
|
2014-05-13 10:52:37 -07:00
|
|
|
}
|
2015-12-17 03:30:46 -08:00
|
|
|
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
|
2015-12-17 03:30:46 -08:00
|
|
|
throw std::runtime_error(((std::string) "Internal error: unknown database backend: ") + m_requestedBackend);
|
2014-05-13 10:52:37 -07:00
|
|
|
|
|
|
|
if (unsupported)
|
2015-12-17 03:30:46 -08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2016-05-23 03:46:25 -07:00
|
|
|
void TileGenerator::closeDb()
|
|
|
|
{
|
2018-04-24 20:24:31 -07:00
|
|
|
delete m_db;
|
|
|
|
m_db = nullptr;
|
2016-05-23 03:46:25 -07:00
|
|
|
}
|
|
|
|
|
2012-08-23 04:32:22 -07:00
|
|
|
void TileGenerator::loadBlocks()
|
|
|
|
{
|
2014-03-23 12:52:58 -07:00
|
|
|
int mapXMin, mapXMax;
|
|
|
|
int mapYMin, mapYMax;
|
|
|
|
int mapZMin, mapZMax;
|
|
|
|
int geomYMin, geomYMax;
|
2014-03-23 12:39:02 -07:00
|
|
|
long long map_blocks;
|
2014-04-15 06:36:29 -07:00
|
|
|
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);
|
2015-02-14 05:31:25 -08:00
|
|
|
bool adjustedGeom = (m_mapXStartNodeOffsetOrig != m_mapXStartNodeOffset || m_mapYEndNodeOffsetOrig != m_mapYEndNodeOffset
|
2015-05-30 23:10:27 -07:00
|
|
|
|| m_mapXEndNodeOffsetOrig != m_mapXEndNodeOffset || m_mapYStartNodeOffsetOrig != m_mapYStartNodeOffset);
|
2015-02-14 05:31:25 -08:00
|
|
|
if (partialBlocks || !m_blockGeometry || adjustedGeom) {
|
2014-04-15 06:36:29 -07:00
|
|
|
cout
|
|
|
|
<< std::setw(MESSAGE_WIDTH) << std::left
|
|
|
|
<< (m_blockGeometry ? "Command-line Geometry:" : "Requested Geometry:")
|
|
|
|
<< std::right
|
2015-02-14 05:31:25 -08:00
|
|
|
<< std::setw(7) << m_reqXMin*16+m_mapXStartNodeOffsetOrig << ","
|
2014-04-15 06:36:29 -07:00
|
|
|
<< std::setw(7) << m_reqYMin*16+m_reqYMinNode << ","
|
2015-02-14 05:31:25 -08:00
|
|
|
<< std::setw(7) << m_reqZMin*16-m_mapYEndNodeOffsetOrig
|
2014-04-15 06:36:29 -07:00
|
|
|
<< " .. "
|
2015-02-14 05:31:25 -08:00
|
|
|
<< std::setw(7) << m_reqXMax*16+15+m_mapXEndNodeOffsetOrig << ","
|
2014-04-15 06:36:29 -07:00
|
|
|
<< std::setw(7) << m_reqYMax*16+m_reqYMaxNode << ","
|
2015-02-14 05:31:25 -08:00
|
|
|
<< 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
|
|
|
<< " ("
|
2014-04-15 06:36:29 -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) {
|
2014-04-15 06:36:29 -07:00
|
|
|
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
|
|
|
<< " ("
|
2014-04-15 06:36:29 -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";
|
|
|
|
}
|
2015-02-14 05:31:25 -08:00
|
|
|
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;
|
2014-03-23 10:35:00 -07:00
|
|
|
}
|
2015-03-10 04:56:02 -07:00
|
|
|
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;
|
2015-03-10 05:16:43 -07:00
|
|
|
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;
|
|
|
|
}
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_reportDatabaseFormat && m_generatePrefetch != BlockListPrefetch::Prefetch) {
|
2015-12-17 02:54:03 -08:00
|
|
|
std::cerr << "WARNING: querying database format: ignoring '--disable-blocklist-prefetch' and/or '--prescan-world=disabled'." << std::endl;
|
2018-04-29 05:44:34 -07:00
|
|
|
m_generatePrefetch = BlockListPrefetch::Prefetch;
|
2015-03-10 05:16:43 -07:00
|
|
|
}
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_generatePrefetch != BlockListPrefetch::Prefetch && !m_databaseFormatSet && m_backend == "leveldb") {
|
2015-03-10 05:16:43 -07:00
|
|
|
throw(std::runtime_error("When using --disable-blocklist-prefetch with a leveldb backend, database format must be set (--database-format)"));
|
|
|
|
}
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_generatePrefetch != BlockListPrefetch::Prefetch) {
|
|
|
|
if (m_generatePrefetch == BlockListPrefetch::NoPrefetch) {
|
2015-02-24 13:12:41 -08:00
|
|
|
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;
|
2015-12-17 02:54:03 -08:00
|
|
|
// 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
|
2015-02-24 13:12:41 -08:00
|
|
|
<< " (" << (m_reqXMax - m_reqXMin + 1)
|
|
|
|
<< " x " << (m_reqYMax - m_reqYMin + 1)
|
|
|
|
<< " x " << (m_reqZMax - m_reqZMin + 1)
|
|
|
|
<< " blocks of 16x16x16 nodes);"
|
2015-12-17 02:54:03 -08:00
|
|
|
<< 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)";
|
2015-02-24 13:12:41 -08:00
|
|
|
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 {
|
2015-02-24 13:12:41 -08:00
|
|
|
if (progressIndicator)
|
|
|
|
cout << "Scanning world (reading block list)...\r" << std::flush;
|
2018-04-24 20:24:31 -07:00
|
|
|
DB::BlockPosList blocks;
|
2015-12-17 02:54:03 -08:00
|
|
|
BlockPos posMin(m_reqXMin, m_reqYMin, m_reqZMin);
|
|
|
|
BlockPos posMax(m_reqXMax, m_reqYMax, m_reqZMax);
|
|
|
|
if (!m_scanEntireWorld && (posMin != BlockPosLimitMin || posMax != BlockPosLimitMax))
|
2018-04-24 20:24:31 -07:00
|
|
|
blocks = m_db->getBlockPosList(BlockPos(m_reqXMin, m_reqYMin, m_reqZMin), BlockPos(m_reqXMax, m_reqYMax, m_reqZMax));
|
2015-12-17 02:54:03 -08:00
|
|
|
else {
|
|
|
|
m_scanEntireWorld = true;
|
2018-04-24 20:24:31 -07:00
|
|
|
blocks = m_db->getBlockPosList();
|
2015-12-17 02:54:03 -08:00
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
for(const BlockPos &pos : blocks) {
|
2015-02-24 13:12:41 -08:00
|
|
|
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
|
|
|
}
|
2015-12-17 02:54:03 -08:00
|
|
|
if (verboseCoordinates >= 1 && m_scanEntireWorld) {
|
2015-03-10 07:37:30 -07:00
|
|
|
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
|
|
|
}
|
2015-02-24 13:12:41 -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
|
|
|
}
|
2015-02-24 13:12:41 -08:00
|
|
|
else {
|
|
|
|
if (verboseCoordinates >= 2) {
|
2015-03-10 07:37:30 -07:00
|
|
|
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) {
|
2015-02-24 13:12:41 -08:00
|
|
|
cout
|
|
|
|
<< std::setw(MESSAGE_WIDTH) << std::left
|
2015-03-10 07:37:30 -07:00
|
|
|
<< "Map Vertical Limits:" << std::right
|
|
|
|
<< std::setw(7) << "x" << ","
|
|
|
|
<< std::setw(7) << geomYMin*16 << ","
|
|
|
|
<< std::setw(7) << "z"
|
2015-02-24 13:12:41 -08:00
|
|
|
<< " .. "
|
2015-03-10 07:37:30 -07:00
|
|
|
<< std::setw(7) << "x" << ","
|
|
|
|
<< std::setw(7) << geomYMax*16+15 << ","
|
|
|
|
<< std::setw(7) << "z"
|
2015-02-24 13:12:41 -08:00
|
|
|
<< " ("
|
2015-03-10 07:37:30 -07:00
|
|
|
<< std::setw(6) << "x" << ","
|
|
|
|
<< std::setw(6) << geomYMin << ","
|
|
|
|
<< std::setw(6) << "z"
|
2015-02-24 13:12:41 -08:00
|
|
|
<< " .. "
|
2015-03-10 07:37:30 -07:00
|
|
|
<< 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"
|
2015-02-24 13:12:41 -08:00
|
|
|
<< ")\n";
|
|
|
|
}
|
2014-03-05 12:41:27 -08:00
|
|
|
}
|
2015-03-10 07:37:30 -07: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) {
|
2014-04-15 06:36:29 -07:00
|
|
|
cout
|
|
|
|
<< std::setw(MESSAGE_WIDTH) << std::left
|
2015-03-10 07:37:30 -07:00
|
|
|
<< "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
|
2014-04-15 06:36:29 -07:00
|
|
|
<< " .. "
|
2015-03-10 07:37:30 -07:00
|
|
|
<< 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
|
2014-02-16 12:24:32 -08:00
|
|
|
<< " ("
|
2015-03-10 07:37:30 -07:00
|
|
|
<< std::setw(6) << m_xMin << ","
|
|
|
|
<< std::setw(6) << m_yMin << ","
|
|
|
|
<< std::setw(6) << m_zMin
|
2014-04-15 06:36:29 -07:00
|
|
|
<< " .. "
|
2015-03-10 07:37:30 -07:00
|
|
|
<< 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";
|
2014-02-16 12:24:32 -08:00
|
|
|
}
|
2014-03-23 10:35:00 -07:00
|
|
|
}
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_backend == "leveldb" && m_generatePrefetch == BlockListPrefetch::Prefetch) {
|
2015-03-10 05:16:43 -07:00
|
|
|
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) {
|
2015-03-10 04:34:52 -07:00
|
|
|
cout
|
|
|
|
<< std::setw(MESSAGE_WIDTH) << std::left
|
|
|
|
<< "Database block format(s):" << std::endl
|
|
|
|
<< " " << std::setw(MESSAGE_WIDTH-4) << std::left << "Total blocks:"
|
2015-03-10 04:56:02 -07:00
|
|
|
<< std::setw(15) << std::right << m_worldBlocks
|
2015-03-10 04:34:52 -07:00
|
|
|
<< 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;
|
2015-03-10 04:56:02 -07:00
|
|
|
long long other_blocks = m_worldBlocks
|
2015-03-10 04:34:52 -07:00
|
|
|
- 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
|
|
|
}
|
|
|
|
|
2015-02-14 05:31:25 -08: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;
|
2015-02-14 05:31:25 -08:00
|
|
|
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++) {
|
2015-02-14 05:31:25 -08:00
|
|
|
#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;
|
2015-02-14 05:31:25 -08:00
|
|
|
{ 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)
|
2015-06-07 11:30:56 -07:00
|
|
|
// Make shading less pronounced when map is scaled down
|
|
|
|
// (the formula for the emphasis parameter was determined (tuned) experimentally...)
|
2015-02-14 05:31:25 -08:00
|
|
|
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;
|
2014-05-23 14:36:01 -07:00
|
|
|
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
|
2015-02-08 03:10:35 -08:00
|
|
|
{ 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
|
2014-05-23 04:16:07 -07:00
|
|
|
if (pixel.is_valid() || pixel.color().to_uint())
|
2017-10-16 01:58:32 -07:00
|
|
|
paintEngine->drawPixel(mapX2ImageX(mapX), mapY2ImageY(mapY), pixel.color());
|
2014-05-22 09:57:08 -07:00
|
|
|
#undef pixel
|
2014-04-10 13:57:37 -07:00
|
|
|
}
|
|
|
|
}
|
2015-02-14 05:31:25 -08:00
|
|
|
int yLimit = worldBlockZ2StoredY(zPosLimit) / m_scaleFactor;
|
2014-05-12 01:41:23 -07:00
|
|
|
if (y <= yLimit) {
|
2015-02-14 05:31:25 -08:00
|
|
|
pixelAttributes.scroll(yLimit);
|
2014-04-14 11:46:12 -07:00
|
|
|
}
|
2014-04-10 13:57:37 -07:00
|
|
|
}
|
|
|
|
|
2014-04-16 06:13:51 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-01-03 10:10:50 -08:00
|
|
|
void TileGenerator::computeMapParameters(const std::string &input)
|
2012-08-23 05:21:34 -07:00
|
|
|
{
|
2015-01-03 10:10:50 -08: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;
|
2015-02-14 05:31:25 -08:00
|
|
|
#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);
|
2014-04-07 19:40:09 -07:00
|
|
|
|
|
|
|
// Set special values for origin (which depend on other paramters)
|
|
|
|
if (m_tileWidth) {
|
2014-05-21 09:26:39 -07:00
|
|
|
switch (m_tileXOrigin) {
|
2015-01-03 10:10:19 -08:00
|
|
|
case TILECENTER_AT_WORLDCENTER:
|
2014-05-21 09:26:39 -07:00
|
|
|
m_tileXOrigin = -m_tileWidth / 2;
|
|
|
|
break;
|
2015-01-03 10:10:19 -08:00
|
|
|
case TILECORNER_AT_WORLDCENTER:
|
2014-05-21 09:26:39 -07:00
|
|
|
m_tileXOrigin = 0;
|
|
|
|
break;
|
2015-01-03 10:10:50 -08:00
|
|
|
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:
|
2014-05-21 09:26:39 -07:00
|
|
|
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;
|
2014-05-21 09:26:39 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (m_tileXCentered)
|
|
|
|
m_tileXOrigin -= m_tileWidth/2;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-14 05:31:25 -08:00
|
|
|
if (m_tileXOrigin >= 0)
|
|
|
|
m_tileXOrigin -= m_tileXOrigin % m_scaleFactor;
|
|
|
|
else
|
|
|
|
m_tileXOrigin -= -m_tileXOrigin % m_scaleFactor;
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
if (m_tileHeight) {
|
2014-05-21 09:26:39 -07:00
|
|
|
switch (m_tileZOrigin) {
|
2015-01-03 10:10:19 -08:00
|
|
|
case TILECENTER_AT_WORLDCENTER:
|
2014-05-21 09:26:39 -07:00
|
|
|
m_tileZOrigin = -m_tileHeight / 2;
|
|
|
|
break;
|
2015-01-03 10:10:19 -08:00
|
|
|
case TILECORNER_AT_WORLDCENTER:
|
2014-05-21 09:26:39 -07:00
|
|
|
m_tileZOrigin = 0;
|
|
|
|
break;
|
2015-01-03 10:10:50 -08:00
|
|
|
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:
|
2014-05-21 09:26:39 -07:00
|
|
|
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:
|
2014-05-21 09:26:39 -07:00
|
|
|
m_tileZOrigin = (m_zMax + 1) * 16 - 1 - m_mapYStartNodeOffset - mapHeight / 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (m_tileYCentered)
|
|
|
|
m_tileZOrigin -= m_tileHeight / 2;
|
|
|
|
break;
|
|
|
|
}
|
2015-02-14 05:31:25 -08:00
|
|
|
if (m_tileXOrigin >= 0)
|
|
|
|
m_tileZOrigin -= m_tileZOrigin % m_scaleFactor;
|
|
|
|
else
|
|
|
|
m_tileZOrigin -= -m_tileZOrigin % m_scaleFactor;
|
2014-04-07 19:40:09 -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
|
|
|
// Compute adjustments for tiles.
|
|
|
|
m_pictWidth = mapWidth;
|
|
|
|
m_pictHeight = mapHeight;
|
2014-04-07 19:40:09 -07:00
|
|
|
if (m_tileWidth && m_tileBorderSize) {
|
2014-04-16 06:13:51 -07:00
|
|
|
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);
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
if (m_tileHeight && m_tileBorderSize) {
|
2014-04-16 06:13:51 -07:00
|
|
|
int tileMapYEndOffset; // Dummy
|
|
|
|
TileGenerator::computeTileParameters(
|
|
|
|
// Input parameters
|
|
|
|
m_zMin,
|
|
|
|
m_zMax,
|
2014-05-21 07:29:59 -07:00
|
|
|
-m_mapYEndNodeOffset,
|
|
|
|
-m_mapYStartNodeOffset,
|
2014-04-16 06:13:51 -07:00
|
|
|
m_tileZOrigin,
|
|
|
|
m_tileHeight,
|
|
|
|
// Output parameters
|
|
|
|
m_tileBorderYCount,
|
|
|
|
tileMapYEndOffset,
|
|
|
|
m_tileMapYOffset,
|
|
|
|
// Behavior selection
|
|
|
|
false);
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
|
2015-02-14 05:31:25 -08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-04-09 15:56:49 -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()
|
|
|
|
{
|
2015-02-08 03:10:35 -08:00
|
|
|
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)) {
|
2014-04-09 09:56:04 -07:00
|
|
|
ostringstream oss;
|
2015-02-08 03:10:35 -08:00
|
|
|
oss << "Failed to allocate " << totalPictWidth << "x" << totalPictHeight << " image";
|
2014-04-09 09:56:04 -07:00
|
|
|
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);
|
2014-04-07 19:40:09 -07:00
|
|
|
|
|
|
|
// 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++) {
|
2015-02-14 05:31:25 -08:00
|
|
|
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
|
2015-02-17 15:25:21 -08:00
|
|
|
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);
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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++) {
|
2015-02-14 05:31:25 -08:00
|
|
|
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
|
2015-02-17 15:25:21 -08:00
|
|
|
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);
|
2014-04-07 19:40:09 -07:00
|
|
|
}
|
|
|
|
}
|
2012-08-23 05:21:34 -07:00
|
|
|
}
|
|
|
|
|
2018-04-22 06:07:55 -07:00
|
|
|
void TileGenerator::processMapBlock(const DB::Block &mapBlock)
|
2014-05-13 10:58:04 -07:00
|
|
|
{
|
2018-04-22 06:07:55 -07:00
|
|
|
if ((!m_drawAir && mapBlock.onlyAir())
|
|
|
|
|| (!m_drawIgnore && mapBlock.onlyIgnore())) {
|
|
|
|
// Nothing to draw :-)
|
|
|
|
return;
|
2014-05-13 10:58:04 -07:00
|
|
|
}
|
|
|
|
|
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)
|
2016-01-05 03:16:29 -08:00
|
|
|
m_nodeIDColor[nodeId] = &color->second;
|
2018-04-22 06:07:55 -07:00
|
|
|
else
|
|
|
|
m_nodeIDColor[nodeId] = NodeColorNotDrawn;
|
2014-05-22 09:57:08 -07:00
|
|
|
}
|
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.
|
2014-05-22 09:57:08 -07:00
|
|
|
else {
|
2018-04-22 06:07:55 -07:00
|
|
|
m_nodeIDColor[nodeId] = &color->second;
|
2014-05-22 09:57:08 -07:00
|
|
|
}
|
2014-05-13 10:58:04 -07:00
|
|
|
}
|
2018-04-22 06:07:55 -07:00
|
|
|
else {
|
|
|
|
m_nameMap[nodeId] = name;
|
|
|
|
m_nodeIDColor[nodeId] = nullptr;
|
|
|
|
}
|
2014-05-13 10:58:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-22 06:07:55 -07:00
|
|
|
renderMapBlock(mapBlock);
|
2014-05-13 10:58:04 -07:00
|
|
|
}
|
|
|
|
|
2015-02-24 13:12:41 -08:00
|
|
|
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; }
|
2016-06-14 08:34:00 -07:00
|
|
|
void breakDim(int i) override { m_iter.breakDim(i); }
|
2015-02-24 13:12:41 -08:00
|
|
|
private:
|
|
|
|
BlockPosIterator m_iter;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-03-05 12:41:27 -08:00
|
|
|
void TileGenerator::renderMap()
|
|
|
|
{
|
2014-05-13 10:58:04 -07:00
|
|
|
int unpackErrors = 0;
|
2015-03-10 04:56:02 -07:00
|
|
|
long long blocks_rendered = 0;
|
2014-03-26 01:17:56 -07:00
|
|
|
int area_rendered = 0;
|
2014-03-24 14:43:32 -07:00
|
|
|
BlockPos currentPos;
|
2015-02-26 01:02:49 -08:00
|
|
|
currentPos.x() = INT_MIN;
|
2015-03-10 04:56:02 -07:00
|
|
|
currentPos.y() = INT_MAX;
|
2015-02-26 01:02:49 -08:00
|
|
|
currentPos.z() = INT_MIN;
|
2014-03-24 14:43:32 -07:00
|
|
|
bool allReaded = false;
|
2015-02-24 13:12:41 -08:00
|
|
|
MapBlockIterator *position;
|
|
|
|
MapBlockIterator *begin;
|
|
|
|
MapBlockIterator *end;
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_generatePrefetch != BlockListPrefetch::Prefetch) {
|
2015-02-24 13:12:41 -08:00
|
|
|
position = new MapBlockIteratorBlockPos();
|
|
|
|
begin = new MapBlockIteratorBlockPos(BlockPosIterator(
|
2015-03-10 05:16:43 -07:00
|
|
|
BlockPos(m_xMin, m_yMax, m_zMax, m_databaseFormat),
|
|
|
|
BlockPos(m_xMax, m_yMin, m_zMin, m_databaseFormat)));
|
2015-02-24 13:12:41 -08:00
|
|
|
end = new MapBlockIteratorBlockPos(BlockPosIterator(
|
2015-03-10 05:16:43 -07:00
|
|
|
BlockPos(m_xMin, m_yMax, m_zMax, m_databaseFormat),
|
|
|
|
BlockPos(m_xMax, m_yMin, m_zMin, m_databaseFormat),
|
2015-02-24 13:12:41 -08:00
|
|
|
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()) {
|
2014-03-26 01:17:56 -07:00
|
|
|
area_rendered++;
|
2015-03-10 04:56:02 -07:00
|
|
|
if (currentPos.y() == m_yMin)
|
|
|
|
m_emptyMapArea++;
|
2015-02-26 01:02:49 -08:00
|
|
|
if (currentPos.z() != pos.z()) {
|
2015-02-14 05:31:25 -08:00
|
|
|
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);
|
2015-02-14 05:31:25 -08:00
|
|
|
}
|
|
|
|
else {
|
2015-02-26 01:02:49 -08:00
|
|
|
pushPixelRows(m_blockPixelAttributes, pos.z());
|
2015-02-14 05:31:25 -08:00
|
|
|
}
|
2015-02-26 01:02:49 -08:00
|
|
|
m_blockPixelAttributes.setLastY((m_zMax - pos.z()) * 16 + 15);
|
2014-04-14 11:46:12 -07:00
|
|
|
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;
|
2014-04-10 13:57:37 -07:00
|
|
|
}
|
2018-04-17 10:37:15 -07:00
|
|
|
|
|
|
|
m_readedPixels.fill(0);
|
2014-05-08 00:45:02 -07:00
|
|
|
allReaded = false;
|
2014-03-24 14:43:32 -07:00
|
|
|
currentPos = pos;
|
|
|
|
}
|
|
|
|
else if (allReaded) {
|
2015-02-24 13:12:41 -08:00
|
|
|
position->breakDim(1);
|
2014-03-24 14:43:32 -07:00
|
|
|
continue;
|
|
|
|
}
|
2015-03-10 04:56:02 -07:00
|
|
|
currentPos.y() = pos.y();
|
2018-04-22 06:07:55 -07:00
|
|
|
const DB::Block block = m_db->getBlockOnPos(pos);
|
|
|
|
if (!block.isEmpty()) {
|
2014-05-13 10:58:04 -07:00
|
|
|
try {
|
|
|
|
processMapBlock(block);
|
2014-03-24 14:43:32 -07:00
|
|
|
|
2014-05-13 10:58:04 -07:00
|
|
|
blocks_rendered++;
|
2012-08-24 13:51:17 -07:00
|
|
|
|
2014-05-13 10:58:04 -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
|
|
|
}
|
|
|
|
}
|
2014-03-24 14:43:32 -07:00
|
|
|
}
|
2014-05-13 10:58:04 -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()
|
2014-06-15 01:17:38 -07:00
|
|
|
<< " (id: " << pos.databasePosStr(BlockPos::I64) << "). Block corrupt ?"
|
2014-05-13 10:58:04 -07:00
|
|
|
<< std::endl
|
2015-02-26 01:02:49 -08:00
|
|
|
<< "\tCoordinates: " << pos.x()*16 << "," << pos.y()*16 << "," << pos.z()*16 << "+16+16+16"
|
2014-05-13 10:58:04 -07:00
|
|
|
<< "; Data: " << e.type << " at: " << e.offset << "(+" << e.length << ")/" << e.dataLength
|
|
|
|
<< std::endl;
|
|
|
|
unpackErrors++;
|
2014-03-24 14:43:32 -07:00
|
|
|
}
|
2014-05-13 10:58:04 -07:00
|
|
|
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()
|
2014-06-15 01:17:38 -07:00
|
|
|
<< " (id: " << pos.databasePosStr(BlockPos::I64) << "). Block corrupt ?"
|
2014-05-13 10:58:04 -07:00
|
|
|
<< std::endl
|
2015-02-26 01:02:49 -08:00
|
|
|
<< "\tCoordinates: " << pos.x()*16 << "," << pos.y()*16 << "," << pos.z()*16 << "+16+16+16"
|
2014-05-13 10:58:04 -07:00
|
|
|
<< "; Cause: " << e.message
|
|
|
|
<< std::endl;
|
|
|
|
unpackErrors++;
|
2012-08-24 13:51:17 -07:00
|
|
|
}
|
|
|
|
}
|
2014-05-13 10:58:04 -07:00
|
|
|
if (unpackErrors >= 100) {
|
|
|
|
throw(std::runtime_error("Too many block unpacking errors - bailing out"));
|
|
|
|
}
|
2012-08-24 13:51:17 -07:00
|
|
|
}
|
2015-02-24 13:12:41 -08:00
|
|
|
delete position;
|
|
|
|
delete begin;
|
|
|
|
delete end;
|
2015-02-26 01:02:49 -08:00
|
|
|
if (currentPos.z() != INT_MIN) {
|
2015-03-10 04:56:02 -07:00
|
|
|
if (currentPos.y() == m_yMin)
|
|
|
|
m_emptyMapArea++;
|
2015-02-14 05:31:25 -08:00
|
|
|
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);
|
2015-02-14 05:31:25 -08:00
|
|
|
}
|
|
|
|
else {
|
2015-02-26 01:02:49 -08:00
|
|
|
pushPixelRows(m_blockPixelAttributes, currentPos.z() - 1);
|
2015-02-14 05:31:25 -08:00
|
|
|
}
|
|
|
|
}
|
2015-03-10 04:18:41 -07:00
|
|
|
bool eraseProgress = true;
|
2015-03-03 15:09:56 -08:00
|
|
|
if (verboseCoordinates >= 1) {
|
2015-03-10 04:18:41 -07:00
|
|
|
eraseProgress = false;
|
2015-03-10 07:37:30 -07:00
|
|
|
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";
|
|
|
|
}
|
2015-03-03 15:09:56 -08:00
|
|
|
}
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_generatePrefetch == BlockListPrefetch::Prefetch && m_backend == "leveldb" && (m_reportDatabaseFormat || verboseStatistics >= 1)) {
|
2015-03-10 05:16:43 -07:00
|
|
|
cout
|
|
|
|
<< "Database format setting when using --disable-blocklist-prefetch: ";
|
2018-04-24 20:24:31 -07:00
|
|
|
if (!m_recommendedDatabaseFormat.empty())
|
2015-03-10 05:16:43 -07:00
|
|
|
cout << m_recommendedDatabaseFormat;
|
|
|
|
else
|
|
|
|
cout << "unknown - use 'mixed' to be safe";
|
|
|
|
cout << std::endl;
|
|
|
|
}
|
2015-03-10 04:18:41 -07:00
|
|
|
if (verboseStatistics >= 1) {
|
|
|
|
eraseProgress = false;
|
2014-03-25 16:23:33 -07:00
|
|
|
cout << "Statistics"
|
2015-02-25 13:49:09 -08:00
|
|
|
<< ": blocks read/queried: " << m_db->getBlocksReadCount()
|
|
|
|
<< " / " << m_db->getBlocksQueriedCount()
|
2014-03-25 16:23:33 -07:00
|
|
|
<< "; blocks rendered: " << blocks_rendered
|
2014-03-26 01:17:56 -07:00
|
|
|
<< "; area rendered: " << area_rendered
|
|
|
|
<< "/" << (m_xMax-m_xMin+1) * (m_zMax-m_zMin+1)
|
2014-05-13 10:58:04 -07:00
|
|
|
<< " (" << (long long)area_rendered*16*16 << " nodes)";
|
|
|
|
if (unpackErrors)
|
|
|
|
cout << " (" << unpackErrors << " errors)";
|
2018-04-24 20:24:31 -07:00
|
|
|
cout << std::endl;
|
2014-05-13 10:58:04 -07:00
|
|
|
}
|
2015-03-10 04:18:41 -07:00
|
|
|
if (progressIndicator && eraseProgress)
|
2014-06-23 22:47:15 -07:00
|
|
|
cout << std::setw(50) << "" << "\r";
|
2015-03-10 05:25:38 -07:00
|
|
|
|
2018-04-29 05:44:34 -07:00
|
|
|
if (m_generatePrefetch != BlockListPrefetch::Prefetch) {
|
2015-03-10 05:25:38 -07:00
|
|
|
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") {
|
2018-04-24 20:24:31 -07:00
|
|
|
std::cout << " The option --database-format=" << (!m_recommendedDatabaseFormat.empty() ? m_recommendedDatabaseFormat : "mixed")
|
2015-03-10 05:25:38 -07:00
|
|
|
<< " 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
|
|
|
}
|
|
|
|
|
2015-02-14 23:46:36 -08: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;
|
2018-04-24 20:24:31 -07:00
|
|
|
for (const HeightMapColor &colorSpec : m_heightMapColors) {
|
2015-02-14 23:46:36 -08:00
|
|
|
if (adjustedHeight >= colorSpec.height[0] && adjustedHeight <= colorSpec.height[1]) {
|
2018-04-24 20:24:31 -07:00
|
|
|
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;
|
2015-02-14 23:46:36 -08:00
|
|
|
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;
|
2015-03-03 15:09:56 -08:00
|
|
|
bool renderedAnything = false;
|
2012-08-24 13:51:17 -07:00
|
|
|
for (int z = 0; z < 16; ++z) {
|
2014-05-23 14:36:01 -07:00
|
|
|
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;
|
|
|
|
}
|
2014-05-22 09:57:08 -07:00
|
|
|
// 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()) {
|
2014-05-23 04:16:07 -07:00
|
|
|
rowIsEmpty = false;
|
2014-05-22 09:57:08 -07:00
|
|
|
pixel = PixelAttribute(m_blockDefaultColor, NAN);
|
2014-05-23 04:16:07 -07:00
|
|
|
}
|
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);
|
2015-01-24 10:40:42 -08:00
|
|
|
#define nodeColor (*m_nodeIDColor[content])
|
|
|
|
//const ColorEntry &nodeColor = *m_nodeIDColor[content];
|
2014-05-22 09:57:08 -07:00
|
|
|
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;
|
2015-01-24 10:40:42 -08:00
|
|
|
if (m_heightMap) {
|
|
|
|
if (m_nodeIDColor[content] && nodeColor.a != 0) {
|
2015-02-14 23:46:36 -08:00
|
|
|
if (!(m_readedPixels[z] & (1 << x))) {
|
|
|
|
if (height > m_surfaceHeight) m_surfaceHeight = height;
|
|
|
|
if (height < m_surfaceDepth) m_surfaceDepth = height;
|
2015-01-24 10:40:42 -08:00
|
|
|
}
|
2015-02-14 23:46:36 -08:00
|
|
|
rowIsEmpty = false;
|
2015-03-03 15:09:56 -08:00
|
|
|
renderedAnything = true;
|
2015-02-14 23:46:36 -08:00
|
|
|
pixel = PixelAttribute(computeMapHeightColor(height), height);
|
2015-01-24 10:40:42 -08:00
|
|
|
m_readedPixels[z] |= (1 << x);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (m_nodeIDColor[content]) {
|
2014-05-23 14:36:01 -07:00
|
|
|
rowIsEmpty = false;
|
2015-03-03 15:09:56 -08:00
|
|
|
renderedAnything = true;
|
2015-01-24 10:40:42 -08:00
|
|
|
pixel.mixUnder(PixelAttribute(nodeColor, height));
|
2014-05-22 09:57:08 -07:00
|
|
|
if ((m_drawAlpha && nodeColor.a == 0xff) || (!m_drawAlpha && nodeColor.a != 0)) {
|
2014-04-10 13:57:37 -07:00
|
|
|
m_readedPixels[z] |= (1 << x);
|
|
|
|
break;
|
|
|
|
}
|
2014-04-03 11:32:48 -07:00
|
|
|
} else {
|
2014-05-22 09:57:08 -07:00
|
|
|
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
|
|
|
}
|
2015-01-24 10:40:42 -08:00
|
|
|
#undef nodeColor
|
2012-08-24 02:01:48 -07:00
|
|
|
}
|
2014-05-22 09:57:08 -07:00
|
|
|
#undef pixel
|
2012-08-24 02:01:48 -07:00
|
|
|
}
|
2014-05-23 14:36:01 -07:00
|
|
|
if (!rowIsEmpty)
|
2015-02-14 05:31:25 -08:00
|
|
|
m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin).nextEmpty = false;
|
2012-08-24 00:46:14 -07:00
|
|
|
}
|
2015-03-03 15:09:56 -08: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()
|
|
|
|
{
|
2015-02-08 03:10:35 -08:00
|
|
|
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);
|
2015-02-08 03:10:35 -08:00
|
|
|
}
|
2015-02-14 12:25:40 -08:00
|
|
|
int major = m_sideScaleMajor ? m_sideScaleMajor : 4 * 16 * m_scaleFactor;
|
|
|
|
int minor = m_sideScaleMinor;
|
2012-08-25 06:06:11 -07:00
|
|
|
|
|
|
|
string scaleText;
|
|
|
|
|
2015-02-08 03:10:35 -08:00
|
|
|
if ((m_drawScale & DRAWSCALE_TOP)) {
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-08 03:10:35 -08:00
|
|
|
|
2015-02-14 12:25:40 -08:00
|
|
|
scaleText = buf.str();
|
2017-10-16 01:58:32 -07:00
|
|
|
paintEngine->drawText(xPos + 2, 0, PaintEngine::Font::MediumBold, scaleText, m_scaleColor);
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-14 12:25:40 -08:00
|
|
|
}
|
2017-10-16 01:58:32 -07:00
|
|
|
paintEngine->drawLine(xPos, 0, xPos, borderTop() - 1, m_scaleColor);
|
2015-02-08 03:10:35 -08:00
|
|
|
}
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-14 12:25:40 -08:00
|
|
|
}
|
|
|
|
}
|
2012-08-25 06:06:11 -07:00
|
|
|
}
|
2015-02-14 23:46:36 -08:00
|
|
|
|
2015-02-08 03:10:35 -08:00
|
|
|
if ((m_drawScale & DRAWSCALE_LEFT)) {
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-08 03:10:35 -08:00
|
|
|
|
2015-02-14 12:25:40 -08:00
|
|
|
scaleText = buf.str();
|
2017-10-16 01:58:32 -07:00
|
|
|
paintEngine->drawText(2, yPos, PaintEngine::Font::MediumBold, scaleText, m_scaleColor);
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-08 03:10:35 -08:00
|
|
|
}
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-14 12:25:40 -08:00
|
|
|
}
|
|
|
|
}
|
2012-08-25 06:06:11 -07:00
|
|
|
}
|
2015-02-08 03:10:35 -08:00
|
|
|
|
|
|
|
// DRAWSCALE_RIGHT and DRAWSCALE_BOTTOM not implemented - getting the text positioned right seems not trivial (??)
|
2012-08-25 05:11:55 -07:00
|
|
|
}
|
|
|
|
|
2015-02-14 23:46:36 -08: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;
|
|
|
|
}
|
2015-02-14 12:25:40 -08:00
|
|
|
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;
|
|
|
|
}
|
2015-02-14 23:46:36 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2016-06-15 23:03:29 -07:00
|
|
|
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);
|
2015-02-14 12:25:40 -08:00
|
|
|
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) {
|
2015-02-14 23:46:36 -08:00
|
|
|
// 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);
|
2015-02-14 23:46:36 -08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
stringstream buf;
|
2015-02-14 12:25:40 -08:00
|
|
|
buf << iheightMaj;
|
2015-02-14 23:46:36 -08:00
|
|
|
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);
|
2015-02-14 23:46:36 -08:00
|
|
|
}
|
|
|
|
}
|
2015-02-14 12:25:40 -08:00
|
|
|
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);
|
2015-02-14 12:25:40 -08:00
|
|
|
}
|
|
|
|
}
|
2015-02-14 23:46:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2012-09-01 07:40:18 -07:00
|
|
|
PlayerAttributes players(inputPath);
|
2018-04-24 20:24:31 -07:00
|
|
|
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);
|
2018-04-24 20:24:31 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2018-04-24 20:24:31 -07:00
|
|
|
void TileGenerator::renderDrawObjects()
|
2014-05-08 11:28:38 -07:00
|
|
|
{
|
2018-04-24 20:24:31 -07:00
|
|
|
for (DrawObject &drawObject : m_drawObjects) {
|
2014-05-08 11:28:38 -07:00
|
|
|
// Hack to adjust the center of an ellipse with even dimensions to align it correctly
|
2018-04-24 20:24:31 -07:00
|
|
|
bool ellipseAdjustCenter[2] = { false, true };
|
2014-05-08 11:28:38 -07:00
|
|
|
#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...
|
2018-04-24 20:24:31 -07:00
|
|
|
if (drawObject.type == DrawObject::Unknown)
|
2014-05-08 11:28:38 -07:00
|
|
|
continue;
|
2018-04-24 20:24:31 -07:00
|
|
|
if (drawObject.haveCenter)
|
|
|
|
drawObject.corner1 = drawObject.center;
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.center = drawObject.corner1;
|
|
|
|
if (drawObject.haveDimensions)
|
|
|
|
drawObject.corner2 = drawObject.dimensions;
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.dimensions = drawObject.corner2;
|
|
|
|
if (!drawObject.haveDimensions && drawObject.haveCenter)
|
|
|
|
drawObject.haveDimensions = true;
|
2014-05-08 11:28:38 -07:00
|
|
|
#endif
|
|
|
|
for (int i = 0; i < 2; i++) {
|
2018-04-24 20:24:31 -07:00
|
|
|
if (drawObject.world) {
|
2014-05-08 11:28:38 -07:00
|
|
|
int (TileGenerator::*world2Image)(int val) const;
|
|
|
|
if (i==0)
|
|
|
|
world2Image = &TileGenerator::worldX2ImageX;
|
|
|
|
else
|
|
|
|
world2Image = &TileGenerator::worldZ2ImageY;
|
2018-04-24 20:24:31 -07:00
|
|
|
if (drawObject.haveCenter)
|
|
|
|
drawObject.center.dimension[i] = (this->*world2Image)(drawObject.center.dimension[i]);
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.corner1.dimension[i] = (this->*world2Image)(drawObject.corner1.dimension[i]);
|
|
|
|
if (!drawObject.haveDimensions) {
|
|
|
|
drawObject.corner2.dimension[i] = (this->*world2Image)(drawObject.corner2.dimension[i]);
|
2014-05-08 11:28:38 -07:00
|
|
|
if (i == 1)
|
|
|
|
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
|
|
|
|
}
|
|
|
|
else if (i==1) {
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.dimensions.dimension[i] = -drawObject.dimensions.dimension[i];
|
2014-05-08 11:28:38 -07:00
|
|
|
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2018-04-24 20:24:31 -07:00
|
|
|
if (drawObject.haveCenter)
|
|
|
|
drawObject.center.dimension[i] += i ? borderTop() : borderLeft();
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.corner1.dimension[i] += i ? borderTop() : borderLeft();
|
|
|
|
if (!drawObject.haveDimensions)
|
|
|
|
drawObject.corner2.dimension[i] += i ? borderTop() : borderLeft();
|
2014-05-08 11:28:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2018-04-24 20:24:31 -07:00
|
|
|
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;
|
2014-05-08 11:28:38 -07:00
|
|
|
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
|
|
|
|
}
|
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
else if (drawObject.dimensions.dimension[i] < 0) {
|
|
|
|
if (!drawObject.haveCenter)
|
|
|
|
drawObject.corner1.dimension[i] += drawObject.dimensions.dimension[i] + 1;
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
|
|
|
// Even dimensions cause asymetry
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.center.dimension[i] += ((1 - drawObject.dimensions.dimension[i]) % 2);
|
|
|
|
drawObject.dimensions.dimension[i] = -drawObject.dimensions.dimension[i];
|
2014-05-08 11:28:38 -07:00
|
|
|
ellipseAdjustCenter[i] = !ellipseAdjustCenter[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert to the apropriate type of coordinates.
|
2018-04-24 20:24:31 -07:00
|
|
|
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;
|
2014-05-08 11:28:38 -07:00
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
else if (!drawObject.haveCenter) {
|
|
|
|
drawObject.center.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] / 2;
|
2014-05-08 11:28:38 -07:00
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
if (drawObject.world && ellipseAdjustCenter[i] && drawObject.dimensions.dimension[i] % 2 == 0)
|
|
|
|
drawObject.center.dimension[i] -= 1;
|
2014-05-08 11:28:38 -07:00
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
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;
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] - 1;
|
2014-05-08 11:28:38 -07:00
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
else if (drawObject.haveDimensions) {
|
|
|
|
if (drawObject.dimensions.dimension[i] < 0)
|
|
|
|
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] + 1;
|
2014-05-08 11:28:38 -07:00
|
|
|
else
|
2018-04-24 20:24:31 -07:00
|
|
|
drawObject.corner2.dimension[i] = drawObject.corner1.dimension[i] + drawObject.dimensions.dimension[i] - 1;
|
2014-05-08 11:28:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
else
|
|
|
|
assert(o->type == DrawObject::Point || o->type == DrawObject::Text);
|
|
|
|
#endif
|
|
|
|
}
|
2018-04-24 20:24:31 -07:00
|
|
|
switch(drawObject.type) {
|
2014-05-08 11:28:38 -07:00
|
|
|
case DrawObject::Point:
|
2018-04-24 20:24:31 -07:00
|
|
|
paintEngine->drawPixel(drawObject.center.x(), drawObject.center.y(), drawObject.color);
|
2014-05-08 11:28:38 -07:00
|
|
|
break;
|
|
|
|
case DrawObject::Line:
|
2018-04-24 20:24:31 -07:00
|
|
|
paintEngine->drawLine(drawObject.corner1.x(), drawObject.corner1.y(), drawObject.corner2.x(), drawObject.corner2.y(), drawObject.color);
|
2014-05-08 11:28:38 -07:00
|
|
|
break;
|
|
|
|
case DrawObject::Ellipse:
|
2018-04-24 20:24:31 -07:00
|
|
|
paintEngine->drawArc(drawObject.center.x(), drawObject.center.y(), drawObject.dimensions.x(), drawObject.dimensions.y(), 0, 360, drawObject.color);
|
2014-05-08 11:28:38 -07:00
|
|
|
break;
|
|
|
|
case DrawObject::Rectangle:
|
2018-04-24 20:24:31 -07:00
|
|
|
paintEngine->drawRect(drawObject.corner1.x(), drawObject.corner1.y(), drawObject.corner2.x(), drawObject.corner2.y(), drawObject.color);
|
2014-05-08 11:28:38 -07:00
|
|
|
break;
|
2017-10-16 01:58:32 -07:00
|
|
|
case DrawObject::Text:
|
2018-04-24 20:24:31 -07:00
|
|
|
paintEngine->drawText(drawObject.center.x(), drawObject.center.y(), PaintEngine::Font::MediumBold, drawObject.text, drawObject.color);
|
2014-05-08 11:28:38 -07:00
|
|
|
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;
|
2018-04-24 20:24:31 -07:00
|
|
|
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()
|
|
|
|
{
|
2018-04-24 20:24:31 -07:00
|
|
|
if (!m_unknownNodes.empty()) {
|
2012-08-25 07:41:53 -07:00
|
|
|
std::cerr << "Unknown nodes:" << std::endl;
|
2018-04-24 20:24:31 -07:00
|
|
|
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
|
|
|
{
|
2014-04-07 19:40:09 -07:00
|
|
|
if (m_tileWidth && m_tileBorderSize)
|
2015-02-14 05:31:25 -08:00
|
|
|
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
|
|
|
{
|
2015-02-14 05:31:25 -08: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;
|
2015-02-14 05:31:25 -08:00
|
|
|
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;
|
2015-02-14 05:31:25 -08:00
|
|
|
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
|
|
|
}
|
|
|
|
|