Allow scaling a map to a smaller size while generating. (1/2, 1/4 .. 1/16)
Scaling will not average nodes across block boundaries, This implies that the only scale factors supported are 1:2, 1:4, 1:8 and 1:16.
This commit is contained in:
parent
045540e8f9
commit
5ce7ff4bce
@ -26,7 +26,7 @@ PixelAttributes::~PixelAttributes()
|
||||
freeAttributes();
|
||||
}
|
||||
|
||||
void PixelAttributes::setParameters(int width, int lines, int nextY)
|
||||
void PixelAttributes::setParameters(int width, int lines, int nextY, int scale, bool defaultEmpty)
|
||||
{
|
||||
freeAttributes();
|
||||
m_width = width + 1; // 1px gradient calculation
|
||||
@ -39,6 +39,7 @@ void PixelAttributes::setParameters(int width, int lines, int nextY)
|
||||
m_nextY = nextY;
|
||||
m_lastY = -1;
|
||||
m_firstUnshadedY = 0;
|
||||
m_scale = scale;
|
||||
|
||||
m_pixelAttributes = new PixelAttribute *[m_lineCount];
|
||||
if (!m_pixelAttributes)
|
||||
@ -52,7 +53,10 @@ void PixelAttributes::setParameters(int width, int lines, int nextY)
|
||||
for (int i=0; i<m_lineCount; i++)
|
||||
for (int j=0; j<m_width; j++) {
|
||||
m_pixelAttributes[i][j].m_a=0;
|
||||
m_pixelAttributes[i][j].next16Empty = (j - 1) % 16 == 0;
|
||||
if (defaultEmpty)
|
||||
m_pixelAttributes[i][j].nextEmpty = (j - 1) % (16 / scale) == 0;
|
||||
else
|
||||
m_pixelAttributes[i][j].nextEmpty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,13 +112,13 @@ static inline double colorSafeBounds(double color)
|
||||
}
|
||||
|
||||
|
||||
void PixelAttributes::renderShading(bool drawAlpha)
|
||||
void PixelAttributes::renderShading(double emphasis, bool drawAlpha)
|
||||
{
|
||||
int y;
|
||||
for (y = yCoord2Line(m_firstUnshadedY); y <= yCoord2Line(m_lastY); y++) {
|
||||
for (int x = 1; x < m_width; x++) {
|
||||
if (m_pixelAttributes[y][x].next16Empty) {
|
||||
x += 15;
|
||||
if (m_pixelAttributes[y][x].nextEmpty) {
|
||||
x += 16 / m_scale - 1;
|
||||
continue;
|
||||
}
|
||||
if (!m_pixelAttributes[y][x].isNormalized())
|
||||
@ -136,7 +140,7 @@ void PixelAttributes::renderShading(bool drawAlpha)
|
||||
if (d > 3) {
|
||||
d = 3;
|
||||
}
|
||||
d = d * 12 / 255;
|
||||
d = d * 12 / 255 * emphasis;
|
||||
#define pixel (m_pixelAttributes[y][x])
|
||||
//PixelAttribute &pixel = m_pixelAttributes[y][x];
|
||||
if (drawAlpha)
|
||||
|
@ -27,11 +27,11 @@ public:
|
||||
AlphaMixAverage = 0x04,
|
||||
};
|
||||
static void setMixMode(AlphaMixingMode mode);
|
||||
PixelAttribute(): next16Empty(true), m_n(0), m_h(NAN), m_t(0), m_a(0), m_r(0), m_g(0), m_b(0) {};
|
||||
PixelAttribute(): nextEmpty(true), m_n(0), m_h(NAN), m_t(0), m_a(0), m_r(0), m_g(0), m_b(0) {};
|
||||
// PixelAttribute(const PixelAttribute &p);
|
||||
PixelAttribute(const Color &color, double height);
|
||||
PixelAttribute(const ColorEntry &entry, double height);
|
||||
bool next16Empty;
|
||||
bool nextEmpty;
|
||||
double h(void) const { return m_h / (m_n ? m_n : 1); }
|
||||
double t(void) const { return m_t / (m_n ? m_n : 1); }
|
||||
double a(void) const { return m_a / (m_n ? m_n : 1); }
|
||||
@ -70,10 +70,10 @@ class PixelAttributes
|
||||
public:
|
||||
PixelAttributes();
|
||||
virtual ~PixelAttributes();
|
||||
void setParameters(int width, int lines, int nextY);
|
||||
void setParameters(int width, int lines, int nextY, int scale, bool defaultEmpty);
|
||||
void scroll(int keepY);
|
||||
PixelAttribute &attribute(int y, int x);
|
||||
void renderShading(bool drawAlpha);
|
||||
void renderShading(double emphasis, bool drawAlpha);
|
||||
int getNextY(void) { return m_nextY; }
|
||||
void setLastY(int y);
|
||||
int getLastY(void) { return m_lastY; }
|
||||
@ -94,6 +94,7 @@ private:
|
||||
int m_nextY;
|
||||
int m_lastY;
|
||||
int m_firstUnshadedY;
|
||||
int m_scale;
|
||||
};
|
||||
|
||||
inline void PixelAttributes::setLastY(int y)
|
||||
@ -133,13 +134,13 @@ inline PixelAttribute &PixelAttributes::attribute(int y, int x)
|
||||
//}
|
||||
|
||||
inline PixelAttribute::PixelAttribute(const Color &color, double height) :
|
||||
next16Empty(false), m_n(0), m_h(height), m_t(0), m_a(color.a/255.0),
|
||||
nextEmpty(false), m_n(0), m_h(height), m_t(0), m_a(color.a/255.0),
|
||||
m_r(color.r/255.0), m_g(color.g/255.0), m_b(color.b/255.0)
|
||||
{
|
||||
}
|
||||
|
||||
inline PixelAttribute::PixelAttribute(const ColorEntry &entry, double height) :
|
||||
next16Empty(false), m_n(0), m_h(height), m_t(entry.t/255.0), m_a(entry.a/255.0),
|
||||
nextEmpty(false), m_n(0), m_h(height), m_t(entry.t/255.0), m_a(entry.a/255.0),
|
||||
m_r(entry.r/255.0), m_g(entry.g/255.0), m_b(entry.b/255.0)
|
||||
{
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
* Company: LinuxOS.sk
|
||||
* =====================================================================
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <climits>
|
||||
@ -150,6 +149,7 @@ TileGenerator::TileGenerator():
|
||||
m_backend(DEFAULT_BACKEND),
|
||||
m_shrinkGeometry(true),
|
||||
m_blockGeometry(false),
|
||||
m_scaleFactor(1),
|
||||
m_sqliteCacheWorldRow(false),
|
||||
m_chunkSize(0),
|
||||
m_image(0),
|
||||
@ -288,6 +288,11 @@ void TileGenerator::setTileCenter(int x, int y)
|
||||
m_tileYCentered = true;
|
||||
}
|
||||
|
||||
void TileGenerator::setScaleFactor(int f)
|
||||
{
|
||||
m_scaleFactor = f;
|
||||
}
|
||||
|
||||
void TileGenerator::setDrawOrigin(bool drawOrigin)
|
||||
{
|
||||
m_drawOrigin = drawOrigin;
|
||||
@ -348,8 +353,8 @@ void TileGenerator::setGeometry(const NodeCoord &corner1, const NodeCoord &corne
|
||||
else {
|
||||
m_reqZMin = (corner1.y - 15) / 16;
|
||||
}
|
||||
m_mapXStartNodeOffset = corner1.x - m_reqXMin * 16;
|
||||
m_mapYEndNodeOffset = m_reqZMin * 16 - corner1.y;
|
||||
m_mapXStartNodeOffsetOrig = m_mapXStartNodeOffset = corner1.x - m_reqXMin * 16;
|
||||
m_mapYEndNodeOffsetOrig = m_mapYEndNodeOffset = m_reqZMin * 16 - corner1.y;
|
||||
|
||||
if (corner2.x > 0) {
|
||||
m_reqXMax = corner2.x / 16;
|
||||
@ -363,8 +368,8 @@ void TileGenerator::setGeometry(const NodeCoord &corner1, const NodeCoord &corne
|
||||
else {
|
||||
m_reqZMax = (corner2.y - 15) / 16;
|
||||
}
|
||||
m_mapXEndNodeOffset = corner2.x - (m_reqXMax * 16 + 15);
|
||||
m_mapYStartNodeOffset = (m_reqZMax * 16 + 15) - corner2.y;
|
||||
m_mapXEndNodeOffsetOrig = m_mapXEndNodeOffset = corner2.x - (m_reqXMax * 16 + 15);
|
||||
m_mapYStartNodeOffsetOrig = m_mapYStartNodeOffset = (m_reqZMax * 16 + 15) - corner2.y;
|
||||
}
|
||||
|
||||
void TileGenerator::setMinY(int y)
|
||||
@ -437,6 +442,42 @@ void TileGenerator::setChunkSize(int size)
|
||||
m_chunkSize = size;
|
||||
}
|
||||
|
||||
void TileGenerator::sanitizeParameters(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileGenerator::generate(const std::string &input, const std::string &output)
|
||||
{
|
||||
string input_path = input;
|
||||
@ -445,6 +486,7 @@ void TileGenerator::generate(const std::string &input, const std::string &output
|
||||
}
|
||||
|
||||
openDb(input_path);
|
||||
sanitizeParameters();
|
||||
loadBlocks();
|
||||
computeMapParameters(input);
|
||||
createImage();
|
||||
@ -773,18 +815,20 @@ void TileGenerator::loadBlocks()
|
||||
long long map_blocks;
|
||||
if (verboseCoordinates >= 2) {
|
||||
bool partialBlocks = (m_mapXStartNodeOffset || m_mapXEndNodeOffset || m_mapYStartNodeOffset || m_mapYEndNodeOffset);
|
||||
if (partialBlocks || !m_blockGeometry) {
|
||||
bool adjustedGeom = (m_mapXStartNodeOffsetOrig != m_mapXStartNodeOffset || m_mapYEndNodeOffsetOrig != m_mapYEndNodeOffset
|
||||
|| m_mapXEndNodeOffsetOrig != m_mapXEndNodeOffset || m_mapYStartNodeOffsetOrig != m_mapYStartNodeOffsetOrig);
|
||||
if (partialBlocks || !m_blockGeometry || adjustedGeom) {
|
||||
cout
|
||||
<< std::setw(MESSAGE_WIDTH) << std::left
|
||||
<< (m_blockGeometry ? "Command-line Geometry:" : "Requested Geometry:")
|
||||
<< std::right
|
||||
<< std::setw(7) << m_reqXMin*16+m_mapXStartNodeOffset << ","
|
||||
<< std::setw(7) << m_reqXMin*16+m_mapXStartNodeOffsetOrig << ","
|
||||
<< std::setw(7) << m_reqYMin*16+m_reqYMinNode << ","
|
||||
<< std::setw(7) << m_reqZMin*16-m_mapYEndNodeOffset
|
||||
<< std::setw(7) << m_reqZMin*16-m_mapYEndNodeOffsetOrig
|
||||
<< " .. "
|
||||
<< std::setw(7) << m_reqXMax*16+15+m_mapXEndNodeOffset << ","
|
||||
<< std::setw(7) << m_reqXMax*16+15+m_mapXEndNodeOffsetOrig << ","
|
||||
<< std::setw(7) << m_reqYMax*16+m_reqYMaxNode << ","
|
||||
<< std::setw(7) << m_reqZMax*16+15-m_mapYStartNodeOffset
|
||||
<< std::setw(7) << m_reqZMax*16+15-m_mapYStartNodeOffsetOrig
|
||||
<< " ("
|
||||
<< std::setw(6) << m_reqXMin << ","
|
||||
<< std::setw(6) << m_reqYMin << ","
|
||||
@ -817,6 +861,28 @@ void TileGenerator::loadBlocks()
|
||||
<< std::setw(6) << m_reqZMax
|
||||
<< ")\n";
|
||||
}
|
||||
if (!m_blockGeometry && adjustedGeom) {
|
||||
cout
|
||||
<< std::setw(MESSAGE_WIDTH) << std::left
|
||||
<< "Adjusted Geometry:"
|
||||
<< std::right
|
||||
<< std::setw(7) << m_reqXMin*16+m_mapXStartNodeOffset << ","
|
||||
<< std::setw(7) << m_reqYMin*16+m_reqYMinNode << ","
|
||||
<< std::setw(7) << m_reqZMin*16-m_mapYEndNodeOffset
|
||||
<< " .. "
|
||||
<< std::setw(7) << m_reqXMax*16+15+m_mapXEndNodeOffset << ","
|
||||
<< std::setw(7) << m_reqYMax*16+m_reqYMaxNode << ","
|
||||
<< std::setw(7) << m_reqZMax*16+15-m_mapYStartNodeOffset
|
||||
<< " ("
|
||||
<< std::setw(6) << m_reqXMin << ","
|
||||
<< std::setw(6) << m_reqYMin << ","
|
||||
<< std::setw(6) << m_reqZMin
|
||||
<< " .. "
|
||||
<< std::setw(6) << m_reqXMax << ","
|
||||
<< std::setw(6) << m_reqYMax << ","
|
||||
<< std::setw(6) << m_reqZMax
|
||||
<< ")\n";
|
||||
}
|
||||
}
|
||||
if (m_blockGeometry) {
|
||||
m_mapXStartNodeOffset = 0;
|
||||
@ -993,18 +1059,59 @@ void TileGenerator::loadBlocks()
|
||||
#undef MESSAGE_WIDTH
|
||||
}
|
||||
|
||||
void TileGenerator::pushPixelRows(int zPosLimit) {
|
||||
if (m_shading)
|
||||
m_blockPixelAttributes.renderShading(m_drawAlpha);
|
||||
void TileGenerator::scalePixelRows(PixelAttributes &pixelAttributes, PixelAttributes &pixelAttributesScaled, int zPosLimit) {
|
||||
int y;
|
||||
for (y = m_blockPixelAttributes.getNextY(); y <= m_blockPixelAttributes.getLastY() && y < worldBlockZ2StoredY(m_zMin - 1) + m_mapYEndNodeOffset; y++) {
|
||||
for (y = pixelAttributes.getNextY(); y <= pixelAttributes.getLastY() && y < worldBlockZ2StoredY(m_zMin - 1) + m_mapYEndNodeOffset; y++) {
|
||||
for (int x = m_mapXStartNodeOffset; x < worldBlockX2StoredX(m_xMax + 1) + m_mapXEndNodeOffset; x++) {
|
||||
#define pixel pixelAttributes.attribute(y, x)
|
||||
//PixelAttribute &pixel = pixelAttributes.attribute(y, x);
|
||||
if (pixel.nextEmpty) {
|
||||
pixelAttributesScaled.attribute(y / m_scaleFactor, x/m_scaleFactor).nextEmpty = true;
|
||||
x += 15;
|
||||
continue;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
int mapX = x - m_mapXStartNodeOffset;
|
||||
int mapY = y - m_mapYStartNodeOffset;
|
||||
#define pixel m_blockPixelAttributes.attribute(y, x)
|
||||
//PixelAttribute &pixel = m_blockPixelAttributes.attribute(y, x);
|
||||
if (pixel.next16Empty) {
|
||||
x += 15;
|
||||
{ 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)
|
||||
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 (x < 2 && y < 2)
|
||||
if (pixel.nextEmpty) {
|
||||
x += 16 / m_scaleFactor - 1;
|
||||
continue;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
@ -1016,9 +1123,9 @@ void TileGenerator::pushPixelRows(int zPosLimit) {
|
||||
#undef pixel
|
||||
}
|
||||
}
|
||||
int yLimit = worldBlockZ2StoredY(zPosLimit);
|
||||
int yLimit = worldBlockZ2StoredY(zPosLimit) / m_scaleFactor;
|
||||
if (y <= yLimit) {
|
||||
m_blockPixelAttributes.scroll(yLimit);
|
||||
pixelAttributes.scroll(yLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1030,8 +1137,6 @@ void TileGenerator::computeTileParameters(
|
||||
int mapEndNodeOffset,
|
||||
int tileOrigin,
|
||||
int tileSize,
|
||||
// Input / Output parameters
|
||||
int &pictSize,
|
||||
// Output parameters
|
||||
int &tileBorderCount,
|
||||
int &tileMapStartOffset,
|
||||
@ -1072,7 +1177,6 @@ void TileGenerator::computeTileParameters(
|
||||
}
|
||||
tileMapStartOffset = (tileSize - start) % tileSize;
|
||||
tileMapEndOffset = limit - ((tileBorderLimit-tileBorderStart) * tileSize);
|
||||
pictSize += (tileBorderLimit - tileBorderStart) * m_tileBorderSize;
|
||||
tileBorderCount = tileBorderLimit - tileBorderStart;
|
||||
}
|
||||
|
||||
@ -1089,7 +1193,15 @@ void TileGenerator::computeMapParameters(const std::string &input)
|
||||
m_storedHeight = (m_zMax - m_zMin + 1) * 16;
|
||||
int mapWidth = m_storedWidth - m_mapXStartNodeOffset + m_mapXEndNodeOffset;
|
||||
int mapHeight = m_storedHeight - m_mapYStartNodeOffset + m_mapYEndNodeOffset;
|
||||
m_blockPixelAttributes.setParameters(m_storedWidth, 16, m_mapYStartNodeOffset);
|
||||
#ifdef DEBUG
|
||||
assert(mapWidth % m_scaleFactor == 0);
|
||||
assert(mapHeight % m_scaleFactor == 0);
|
||||
#else
|
||||
mapWidth += mapWidth % m_scaleFactor;
|
||||
mapHeight += mapHeight % m_scaleFactor;
|
||||
#endif
|
||||
m_blockPixelAttributes.setParameters(m_storedWidth, 16, m_mapYStartNodeOffset, 1, true);
|
||||
m_blockPixelAttributesScaled.setParameters(m_storedWidth / m_scaleFactor, 16 / m_scaleFactor, m_mapYStartNodeOffset / m_scaleFactor, m_scaleFactor, false);
|
||||
|
||||
// Set special values for origin (which depend on other paramters)
|
||||
if (m_tileWidth) {
|
||||
@ -1114,6 +1226,10 @@ void TileGenerator::computeMapParameters(const std::string &input)
|
||||
m_tileXOrigin -= m_tileWidth/2;
|
||||
break;
|
||||
}
|
||||
if (m_tileXOrigin >= 0)
|
||||
m_tileXOrigin -= m_tileXOrigin % m_scaleFactor;
|
||||
else
|
||||
m_tileXOrigin -= -m_tileXOrigin % m_scaleFactor;
|
||||
}
|
||||
if (m_tileHeight) {
|
||||
switch (m_tileZOrigin) {
|
||||
@ -1137,6 +1253,10 @@ void TileGenerator::computeMapParameters(const std::string &input)
|
||||
m_tileZOrigin -= m_tileHeight / 2;
|
||||
break;
|
||||
}
|
||||
if (m_tileXOrigin >= 0)
|
||||
m_tileZOrigin -= m_tileZOrigin % m_scaleFactor;
|
||||
else
|
||||
m_tileZOrigin -= -m_tileZOrigin % m_scaleFactor;
|
||||
}
|
||||
|
||||
// Compute adjustments for tiles.
|
||||
@ -1152,8 +1272,6 @@ void TileGenerator::computeMapParameters(const std::string &input)
|
||||
m_mapXEndNodeOffset,
|
||||
m_tileXOrigin,
|
||||
m_tileWidth,
|
||||
// Input / Output parameters
|
||||
m_pictWidth,
|
||||
// Output parameters
|
||||
m_tileBorderXCount,
|
||||
m_tileMapXOffset,
|
||||
@ -1171,8 +1289,6 @@ void TileGenerator::computeMapParameters(const std::string &input)
|
||||
-m_mapYStartNodeOffset,
|
||||
m_tileZOrigin,
|
||||
m_tileHeight,
|
||||
// Input / Output parameters
|
||||
m_pictHeight,
|
||||
// Output parameters
|
||||
m_tileBorderYCount,
|
||||
tileMapYEndOffset,
|
||||
@ -1181,18 +1297,25 @@ void TileGenerator::computeMapParameters(const std::string &input)
|
||||
false);
|
||||
}
|
||||
|
||||
m_pictWidth /= m_scaleFactor;
|
||||
m_pictWidth += m_tileBorderXCount * m_tileBorderSize;
|
||||
m_pictHeight /= m_scaleFactor;
|
||||
m_pictHeight += m_tileBorderYCount * m_tileBorderSize;
|
||||
|
||||
// Print some useful messages in cases where it may not be possible to generate the image...
|
||||
long long pixels = static_cast<long long>(m_pictWidth + borderLeft() + borderRight()) * (m_pictHeight + borderTop() + borderBottom());
|
||||
// Study the libgd code to known why the maximum is the following:
|
||||
long long max_pixels = INT_MAX - INT_MAX % m_pictHeight;
|
||||
if (pixels > max_pixels) {
|
||||
cerr << "WARNING: Image will have " << pixels << " pixels; the PNG graphics library will refuse to handle more than approximately " << INT_MAX << std::endl;
|
||||
cerr << " (If map generation fails, consider using --scalefactor to reduce the image size by a factor 2)" << std::endl;
|
||||
}
|
||||
// Estimated approximate maximum was determined by trial and error...
|
||||
// (24100x24100 succeeded; 24200x24200 failed)
|
||||
#define ESTIMATED_MAX_PIXELS_32BIT (24100*24100L)
|
||||
else if (sizeof(void *) == 4 && pixels > ESTIMATED_MAX_PIXELS_32BIT) {
|
||||
cerr << "WARNING: Image will have " << pixels << " pixels; The maximum achievable on a 32-bit system is approximately " << ESTIMATED_MAX_PIXELS_32BIT << std::endl;
|
||||
cerr << " (If map generation fails, consider using --scalefactor to reduce the image size by a factor 2 or 4)" << std::endl;
|
||||
}
|
||||
#undef ESTIMATED_MAX_PIXELS_32BIT
|
||||
}
|
||||
@ -1215,9 +1338,9 @@ void TileGenerator::createImage()
|
||||
if (m_tileWidth && m_tileBorderSize) {
|
||||
int borderColor = m_tileBorderColor.to_libgd();
|
||||
for (int i = 0; i < m_tileBorderXCount; i++) {
|
||||
int xPos = m_tileMapXOffset + i * (m_tileWidth + m_tileBorderSize);
|
||||
int xPos = m_tileMapXOffset / m_scaleFactor + i * (m_tileWidth / m_scaleFactor + m_tileBorderSize);
|
||||
#ifdef DEBUG
|
||||
int xPos2 = mapX2ImageX(m_tileMapXOffset + i * m_tileWidth) - borderLeft() - 1;
|
||||
int xPos2 = mapX2ImageX(m_tileMapXOffset / m_scaleFactor + i * m_tileWidth / m_scaleFactor) - borderLeft() - 1;
|
||||
assert(xPos == xPos2);
|
||||
#endif
|
||||
gdImageFilledRectangle(m_image, xPos + borderLeft(), borderTop(), xPos + (m_tileBorderSize-1) + borderLeft(), m_pictHeight + borderTop() - 1, borderColor);
|
||||
@ -1226,9 +1349,9 @@ void TileGenerator::createImage()
|
||||
if (m_tileHeight && m_tileBorderSize) {
|
||||
int borderColor = m_tileBorderColor.to_libgd();
|
||||
for (int i = 0; i < m_tileBorderYCount; i++) {
|
||||
int yPos = m_tileMapYOffset + i * (m_tileHeight + m_tileBorderSize);
|
||||
int yPos = m_tileMapYOffset / m_scaleFactor + i * (m_tileHeight / m_scaleFactor + m_tileBorderSize);
|
||||
#ifdef DEBUG
|
||||
int yPos2 = mapY2ImageY(m_tileMapYOffset + i * m_tileHeight) - borderTop() - 1;
|
||||
int yPos2 = mapY2ImageY(m_tileMapYOffset / m_scaleFactor + i * m_tileHeight / m_scaleFactor) - borderTop() - 1;
|
||||
assert(yPos == yPos2);
|
||||
#endif
|
||||
gdImageFilledRectangle(m_image, borderLeft(), yPos + borderTop(), m_pictWidth + borderLeft() - 1, yPos + (m_tileBorderSize-1) + borderTop(), borderColor);
|
||||
@ -1350,7 +1473,14 @@ void TileGenerator::renderMap()
|
||||
if (currentPos.x != pos.x || currentPos.z != pos.z) {
|
||||
area_rendered++;
|
||||
if (currentPos.z != pos.z) {
|
||||
pushPixelRows(pos.z);
|
||||
if (m_scaleFactor > 1) {
|
||||
scalePixelRows(m_blockPixelAttributes, m_blockPixelAttributesScaled, pos.z);
|
||||
pushPixelRows(m_blockPixelAttributesScaled, pos.z);
|
||||
m_blockPixelAttributesScaled.setLastY(((m_zMax - pos.z) * 16 + 15) / m_scaleFactor);
|
||||
}
|
||||
else {
|
||||
pushPixelRows(m_blockPixelAttributes, pos.z);
|
||||
}
|
||||
m_blockPixelAttributes.setLastY((m_zMax - pos.z) * 16 + 15);
|
||||
if (progressIndicator)
|
||||
cout << "Processing Z-coordinate: " << std::setw(6) << pos.z*16
|
||||
@ -1403,8 +1533,15 @@ void TileGenerator::renderMap()
|
||||
throw(std::runtime_error("Too many block unpacking errors - bailing out"));
|
||||
}
|
||||
}
|
||||
if (currentPos.z != INT_MIN)
|
||||
pushPixelRows(currentPos.z - 1);
|
||||
if (currentPos.z != INT_MIN) {
|
||||
if (m_scaleFactor > 1) {
|
||||
scalePixelRows(m_blockPixelAttributes, m_blockPixelAttributesScaled, currentPos.z - 1);
|
||||
pushPixelRows(m_blockPixelAttributesScaled, currentPos.z - 1);
|
||||
}
|
||||
else {
|
||||
pushPixelRows(m_blockPixelAttributes, currentPos.z - 1);
|
||||
}
|
||||
}
|
||||
if (verboseStatistics) {
|
||||
cout << "Statistics"
|
||||
<< ": blocks read: " << m_db->getBlocksReadCount()
|
||||
@ -1504,7 +1641,7 @@ inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPo
|
||||
#undef pixel
|
||||
}
|
||||
if (!rowIsEmpty)
|
||||
m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin).next16Empty = false;
|
||||
m_blockPixelAttributes.attribute(zBegin + 15 - z,xBegin).nextEmpty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1519,7 +1656,7 @@ void TileGenerator::renderScale()
|
||||
string scaleText;
|
||||
|
||||
if ((m_drawScale & DRAWSCALE_TOP)) {
|
||||
for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4) {
|
||||
for (int i = (m_xMin / 4) * 4; i <= m_xMax; i += 4 * m_scaleFactor) {
|
||||
stringstream buf1, buf2;
|
||||
buf1 << i * 16;
|
||||
buf2 << "(" << i << ")";
|
||||
@ -1534,7 +1671,7 @@ void TileGenerator::renderScale()
|
||||
}
|
||||
|
||||
if ((m_drawScale & DRAWSCALE_LEFT)) {
|
||||
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) {
|
||||
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4 * m_scaleFactor) {
|
||||
stringstream buf1, buf2;
|
||||
buf1 << i * 16;
|
||||
buf2 << "(" << i << ")";
|
||||
@ -1797,33 +1934,29 @@ void TileGenerator::printUnknown()
|
||||
inline int TileGenerator::mapX2ImageX(int val) const
|
||||
{
|
||||
if (m_tileWidth && m_tileBorderSize)
|
||||
val += ((val - m_tileMapXOffset + m_tileWidth) / m_tileWidth) * m_tileBorderSize + borderLeft();
|
||||
else
|
||||
val += borderLeft();
|
||||
return val;
|
||||
val += ((val - m_tileMapXOffset / m_scaleFactor + m_tileWidth / m_scaleFactor) / (m_tileWidth / m_scaleFactor)) * m_tileBorderSize;
|
||||
return val + borderLeft();
|
||||
}
|
||||
|
||||
// Adjust map coordinate for tiles and border
|
||||
inline int TileGenerator::mapY2ImageY(int val) const
|
||||
{
|
||||
if (m_tileHeight && m_tileBorderSize)
|
||||
val += ((val - m_tileMapYOffset + m_tileHeight) / m_tileHeight) * m_tileBorderSize + borderTop();
|
||||
else
|
||||
val += borderTop();
|
||||
return val;
|
||||
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();
|
||||
}
|
||||
|
||||
// Convert world coordinate to image coordinate
|
||||
inline int TileGenerator::worldX2ImageX(int val) const
|
||||
{
|
||||
val = (val - m_xMin * 16) - m_mapXStartNodeOffset;
|
||||
return mapX2ImageX(val);
|
||||
return mapX2ImageX(val / m_scaleFactor);
|
||||
}
|
||||
|
||||
// Convert world coordinate to image coordinate
|
||||
inline int TileGenerator::worldZ2ImageY(int val) const
|
||||
{
|
||||
val = (m_zMax * 16 + 15 - val) - m_mapYStartNodeOffset;
|
||||
return mapY2ImageY(val);
|
||||
return mapY2ImageY(val / m_scaleFactor);
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@ public:
|
||||
void setTileSize(int width, int heigth);
|
||||
void setTileOrigin(int x, int y);
|
||||
void setTileCenter(int x, int y);
|
||||
void setScaleFactor(int f);
|
||||
void enableProgressIndicator(void);
|
||||
void parseNodeColorsFile(const std::string &fileName);
|
||||
void parseHeightMapNodesFile(const std::string &fileName);
|
||||
@ -151,6 +152,7 @@ private:
|
||||
std::string getWorldDatabaseBackend(const std::string &input);
|
||||
int getMapChunkSize(const std::string &input);
|
||||
void openDb(const std::string &input);
|
||||
void sanitizeParameters(void);
|
||||
void loadBlocks();
|
||||
void createImage();
|
||||
void computeMapParameters(const std::string &input);
|
||||
@ -162,8 +164,6 @@ private:
|
||||
int mapEndNodeOffset,
|
||||
int tileOrigin,
|
||||
int tileSize,
|
||||
// Input / Output parameters
|
||||
int &pictSize,
|
||||
// Output parameters
|
||||
int &tileBorderCount,
|
||||
int &tileMapOffset,
|
||||
@ -172,7 +172,8 @@ private:
|
||||
bool ascending);
|
||||
void renderMap();
|
||||
std::list<int> getZValueList() const;
|
||||
void pushPixelRows(int zPosLimit);
|
||||
void pushPixelRows(PixelAttributes &pixelAttributes, int zPosLimit);
|
||||
void scalePixelRows(PixelAttributes &pixelAttributes, PixelAttributes &pixelAttributesScaled, int zPosLimit);
|
||||
void processMapBlock(const DB::Block &block);
|
||||
void renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version);
|
||||
void renderScale();
|
||||
@ -231,12 +232,14 @@ private:
|
||||
std::string m_backend;
|
||||
bool m_shrinkGeometry;
|
||||
bool m_blockGeometry;
|
||||
int m_scaleFactor;
|
||||
bool m_sqliteCacheWorldRow;
|
||||
int m_chunkSize;
|
||||
|
||||
DB *m_db;
|
||||
gdImagePtr m_image;
|
||||
PixelAttributes m_blockPixelAttributes;
|
||||
PixelAttributes m_blockPixelAttributesScaled;
|
||||
int m_xMin;
|
||||
int m_xMax;
|
||||
int m_zMin;
|
||||
@ -257,6 +260,10 @@ private:
|
||||
int m_mapYStartNodeOffset;
|
||||
int m_mapXEndNodeOffset;
|
||||
int m_mapYEndNodeOffset;
|
||||
int m_mapXStartNodeOffsetOrig;
|
||||
int m_mapYStartNodeOffsetOrig;
|
||||
int m_mapXEndNodeOffsetOrig;
|
||||
int m_mapYEndNodeOffsetOrig;
|
||||
int m_tileXOrigin;
|
||||
int m_tileZOrigin;
|
||||
int m_tileXCentered;
|
||||
|
29
mapper.cpp
29
mapper.cpp
@ -37,6 +37,7 @@ using namespace std;
|
||||
#define OPT_HEIGHTMAPNODESFILE 0x8b
|
||||
#define OPT_HEIGHTMAPCOLORSFILE 0x8c
|
||||
#define OPT_DRAWHEIGHTSCALE 0x8d
|
||||
#define OPT_SCALEFACTOR 0x8e
|
||||
|
||||
// Will be replaced with the actual name and location of the executable (if found)
|
||||
string executableName = "minetestmapper";
|
||||
@ -116,6 +117,7 @@ void usage()
|
||||
" --tiles <tilesize>[+<border>]|block|chunk\n"
|
||||
" --tileorigin <x>,<y>|world|map\n"
|
||||
" --tilecenter <x>,<y>|world|map\n"
|
||||
" --scalefactor 1:<n>\n"
|
||||
" --chunksize <size>\n"
|
||||
" --verbose[=n]\n"
|
||||
" --verbose-search-colors[=n]\n"
|
||||
@ -582,6 +584,7 @@ int main(int argc, char *argv[])
|
||||
{"tileorigin", required_argument, 0, 'T'},
|
||||
{"tilecenter", required_argument, 0, 'T'},
|
||||
{"tilebordercolor", required_argument, 0, 'B'},
|
||||
{"scalefactor", required_argument, 0, OPT_SCALEFACTOR},
|
||||
{"chunksize", required_argument, 0, OPT_CHUNKSIZE},
|
||||
{"verbose", optional_argument, 0, 'v'},
|
||||
{"verbose-search-colors", optional_argument, 0, OPT_VERBOSE_SEARCH_COLORS},
|
||||
@ -812,6 +815,32 @@ int main(int argc, char *argv[])
|
||||
generator.setChunkSize(size);
|
||||
}
|
||||
break;
|
||||
case OPT_SCALEFACTOR: {
|
||||
istringstream arg;
|
||||
arg.str(optarg);
|
||||
int one;
|
||||
char colon;
|
||||
int factor = 1;
|
||||
arg >> one >> std::ws;
|
||||
if (arg.fail() || one != 1) {
|
||||
std::cerr << "Invalid scale factor specification (" << optarg << ") - expected: 1:<n>" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
if (!arg.eof()) {
|
||||
arg >> colon >> factor >> std::ws;
|
||||
if (arg.fail() || colon != ':' || factor<0 || !arg.eof()) {
|
||||
std::cerr << "Invalid scale factor specification (" << optarg << ") - expected: 1:<n>" << std::endl;
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
if (factor != 1 && factor != 2 && factor != 4 && factor != 8 && factor != 16) {
|
||||
std::cerr << "Scale factor must be 1:1, 1:2, 1:4, 1:8 or 1:16" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
generator.setScaleFactor(factor);
|
||||
}
|
||||
break;
|
||||
case 't': {
|
||||
istringstream tilesize;
|
||||
tilesize.str(optarg);
|
||||
|
Loading…
x
Reference in New Issue
Block a user