Add the option to draw a height scale for the height map

This commit is contained in:
Rogier 2015-02-15 08:46:36 +01:00
parent 4476de429d
commit 994e9d7171
3 changed files with 111 additions and 27 deletions

View File

@ -177,7 +177,9 @@ TileGenerator::TileGenerator():
m_tileHeight(0),
m_tileBorderSize(1),
m_tileMapXOffset(0),
m_tileMapYOffset(0)
m_tileMapYOffset(0),
m_surfaceHeight(INT_MIN),
m_surfaceDepth(INT_MAX)
{
// Load default grey colors.
m_heightMapColors.push_back(HeightMapColor(INT_MIN, Color(0,0,0), -129, Color(0,0,0)));
@ -298,7 +300,18 @@ void TileGenerator::setDrawPlayers(bool drawPlayers)
void TileGenerator::setDrawScale(int scale)
{
m_drawScale = (scale & DRAWSCALE_MASK);
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));
}
void TileGenerator::setDrawAlpha(bool drawAlpha)
@ -436,9 +449,12 @@ void TileGenerator::generate(const std::string &input, const std::string &output
computeMapParameters(input);
createImage();
renderMap();
if (m_drawScale) {
if ((m_drawScale & DRAWSCALE_MASK)) {
renderScale();
}
if (m_heightMap && (m_drawScale & DRAWHEIGHTSCALE_MASK)) {
renderHeightScale();
}
if (m_drawOrigin) {
renderOrigin();
}
@ -1406,6 +1422,29 @@ void TileGenerator::renderMap()
cout << std::setw(50) << "" << "\r";
}
Color TileGenerator::computeMapHeightColor(int height)
{
int adjustedHeight = int((height - m_seaLevel) * m_heightMapYScale + 0.5);
float r = 0;
float g = 0;
float b = 0;
int n = 0;
for (HeightMapColorList::iterator i = m_heightMapColors.begin(); i != m_heightMapColors.end(); i++) {
HeightMapColor &colorSpec = *i;
if (adjustedHeight >= colorSpec.height[0] && adjustedHeight <= colorSpec.height[1]) {
float weight = (float) (colorSpec.height[1] - adjustedHeight + 1) / (colorSpec.height[1] - colorSpec.height[0] + 1);
for (int j = 0; j < 2; j++) {
r += colorSpec.color[j].r * weight;
g += colorSpec.color[j].g * weight;
b += colorSpec.color[j].b * weight;
weight = 1 - weight;
}
n++;
}
}
return Color(int(r / n + 0.5), int(g / n + 0.5), int(b / n + 0.5));
}
inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version)
{
checkBlockNodeDataLimit(version, mapBlock.length());
@ -1438,26 +1477,12 @@ inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPo
int height = pos.y * 16 + y;
if (m_heightMap) {
if (m_nodeIDColor[content] && nodeColor.a != 0) {
int adjustedHeight = int((height - m_seaLevel) * m_heightMapYScale + 0.5);
rowIsEmpty = false;
float r = 0;
float g = 0;
float b = 0;
int n = 0;
for (HeightMapColorList::iterator i = m_heightMapColors.begin(); i != m_heightMapColors.end(); i++) {
HeightMapColor &colorSpec = *i;
if (adjustedHeight >= colorSpec.height[0] && adjustedHeight <= colorSpec.height[1]) {
float weight = (float) (colorSpec.height[1] - adjustedHeight + 1) / (colorSpec.height[1] - colorSpec.height[0] + 1);
for (int j = 0; j < 2; j++) {
r += colorSpec.color[j].r * weight;
g += colorSpec.color[j].g * weight;
b += colorSpec.color[j].b * weight;
weight = 1 - weight;
}
n++;
}
if (!(m_readedPixels[z] & (1 << x))) {
if (height > m_surfaceHeight) m_surfaceHeight = height;
if (height < m_surfaceDepth) m_surfaceDepth = height;
}
pixel = PixelAttribute(Color(int(r / n + 0.5), int(g / n + 0.5), int(b / n + 0.5)), height);
rowIsEmpty = false;
pixel = PixelAttribute(computeMapHeightColor(height), height);
m_readedPixels[z] |= (1 << x);
break;
}
@ -1507,7 +1532,7 @@ void TileGenerator::renderScale()
gdImageLine(m_image, xPos, 0, xPos, borderTop() - 1, color);
}
}
if ((m_drawScale & DRAWSCALE_LEFT)) {
for (int i = (m_zMax / 4) * 4; i >= m_zMin; i -= 4) {
stringstream buf1, buf2;
@ -1526,6 +1551,48 @@ void TileGenerator::renderScale()
// DRAWSCALE_RIGHT and DRAWSCALE_BOTTOM not implemented - getting the text positioned right seems not trivial (??)
}
void TileGenerator::renderHeightScale()
{
int scaleColor = m_scaleColor.to_libgd();
int height_min = m_surfaceDepth - 16;
int height_limit = m_surfaceHeight + 16;
int xBorderOffset = borderLeft();
int yBorderOffset = borderTop() + m_pictHeight;
double height_step = (double)(height_limit - height_min) / m_pictWidth;
if (height_step < 1.0 / 16) {
height_step = 1.0 / 16;
}
double number_step = 64;
while (number_step / height_step < 48)
number_step *= 2;
while (number_step / height_step > 96)
number_step /= 2;
double height = height_min;
for (int x = 0; height < height_limit; x++, height += height_step) {
Color color = computeMapHeightColor(int(height + 0.5));
gdImageLine(m_image, xBorderOffset + x, yBorderOffset + 8, xBorderOffset + x, yBorderOffset + borderBottom() - 20, color.to_libgd());
int iheight = int(height + (height > 0 ? 0.5 : -0.5));
int iheight64 = int(iheight / number_step + (height > 0 ? 0.5 : -0.5)) * number_step;
if (fabs(height - iheight64) <= height_step / 2 && (height - iheight64) > -height_step / 2) {
if (iheight64 / int(number_step) % 2 == 1 && fabs(height) > 9999 && number_step / height_step < 56) {
// Maybe not enough room for the number. Draw a tick mark instead
gdImageLine(m_image, xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 16, scaleColor);
}
else {
stringstream buf;
buf << iheight64;
string scaleText = buf.str();
gdImageString(m_image, gdFontGetMediumBold(), xBorderOffset + x + 2, yBorderOffset + borderBottom() - 16,
reinterpret_cast<unsigned char *>(const_cast<char *>(scaleText.c_str())), scaleColor);
gdImageLine(m_image, xBorderOffset + x, yBorderOffset + borderBottom() - 19, xBorderOffset + x, yBorderOffset + borderBottom() - 1, scaleColor);
}
}
}
}
void TileGenerator::renderOrigin()
{
int imageX = worldX2ImageX(0);

View File

@ -44,9 +44,15 @@
#define DRAWSCALE_RIGHT 0x02
#define DRAWSCALE_TOP 0x04
#define DRAWSCALE_BOTTOM 0x08
#define DRAWHEIGHTSCALE_MASK 0xf0
#define DRAWHEIGHTSCALE_LEFT 0x10
#define DRAWHEIGHTSCALE_RIGHT 0x20
#define DRAWHEIGHTSCALE_TOP 0x40
#define DRAWHEIGHTSCALE_BOTTOM 0x80
#define SCALESIZE_HOR 40
#define SCALESIZE_VERT 50
#define HEIGHTSCALESIZE 60
class TileGenerator
{
@ -116,6 +122,7 @@ public:
void setDrawOrigin(bool drawOrigin);
void setDrawPlayers(bool drawPlayers);
void setDrawScale(int scale);
void setDrawHeightScale(int scale);
void setDrawAlpha(bool drawAlpha);
void setDrawAir(bool drawAir);
void drawObject(const DrawObject &object) { m_drawObjects.push_back(object); }
@ -138,6 +145,7 @@ public:
void setBackend(std::string backend);
void setChunkSize(int size);
void generate(const std::string &input, const std::string &output);
Color computeMapHeightColor(int height);
private:
std::string getWorldDatabaseBackend(const std::string &input);
@ -168,6 +176,7 @@ private:
void processMapBlock(const DB::Block &block);
void renderMapBlock(const ustring &mapBlock, const BlockPos &pos, int version);
void renderScale();
void renderHeightScale();
void renderOrigin();
void renderPlayers(const std::string &inputPath);
void renderDrawObjects();
@ -179,10 +188,10 @@ private:
int worldZ2ImageY(int val) const;
int worldBlockX2StoredX(int xPos) const { return (xPos - m_xMin) * 16; }
int worldBlockZ2StoredY(int zPos) const { return (m_zMax - zPos) * 16; }
int borderTop() const { return ((m_drawScale & DRAWSCALE_TOP) ? SCALESIZE_HOR : 0); }
int borderBottom() const { return ((m_drawScale & DRAWSCALE_BOTTOM) ? SCALESIZE_HOR : 0); }
int borderLeft() const { return ((m_drawScale & DRAWSCALE_LEFT) ? SCALESIZE_VERT : 0); }
int borderRight() const { return ((m_drawScale & DRAWSCALE_RIGHT) ? SCALESIZE_VERT : 0); }
int borderTop() const { return ((m_drawScale & DRAWSCALE_TOP) ? SCALESIZE_HOR : 0) + (m_heightMap && (m_drawScale & DRAWHEIGHTSCALE_TOP) ? HEIGHTSCALESIZE : 0); }
int borderBottom() const { return ((m_drawScale & DRAWSCALE_BOTTOM) ? SCALESIZE_HOR : 0) + (m_heightMap && (m_drawScale & DRAWHEIGHTSCALE_BOTTOM) ? HEIGHTSCALESIZE : 0); }
int borderLeft() const { return ((m_drawScale & DRAWSCALE_LEFT) ? SCALESIZE_VERT : 0) + (m_heightMap && (m_drawScale & DRAWHEIGHTSCALE_LEFT) ? HEIGHTSCALESIZE : 0); }
int borderRight() const { return ((m_drawScale & DRAWSCALE_RIGHT) ? SCALESIZE_VERT : 0) + (m_heightMap && (m_drawScale & DRAWHEIGHTSCALE_RIGHT) ? HEIGHTSCALESIZE : 0); }
void parseDataFile(const std::string &fileName, int depth, const char *type,
void (TileGenerator::*parseLine)(const std::string &line, std::string name,
@ -261,6 +270,8 @@ private:
int m_tileBorderYCount;
int m_pictWidth;
int m_pictHeight;
int m_surfaceHeight;
int m_surfaceDepth;
std::list<BlockPos> m_positions;
NodeID2NameMap m_nameMap;
static const ColorEntry *NodeColorNotDrawn;

View File

@ -36,6 +36,7 @@ using namespace std;
#define OPT_HEIGHT_LEVEL0 0x8a
#define OPT_HEIGHTMAPNODESFILE 0x8b
#define OPT_HEIGHTMAPCOLORSFILE 0x8c
#define OPT_DRAWHEIGHTSCALE 0x8d
// Will be replaced with the actual name and location of the executable (if found)
string executableName = "minetestmapper";
@ -85,6 +86,7 @@ void usage()
" --origincolor <color>\n"
" --tilebordercolor <color>\n"
" --drawscale[=left,top]\n"
" --drawheightscale\n"
" --drawplayers\n"
" --draworigin\n"
" --drawalpha[=cumulative|cumulative-darken|average|none]\n"
@ -551,6 +553,7 @@ int main(int argc, char *argv[])
{"draworigin", no_argument, 0, 'R'},
{"drawplayers", no_argument, 0, 'P'},
{"drawscale", optional_argument, 0, 'S'},
{"drawheightscale", no_argument, 0, OPT_DRAWHEIGHTSCALE},
{"drawalpha", optional_argument, 0, 'e'},
{"drawair", no_argument, 0, OPT_DRAWAIR},
{"drawpoint", required_argument, 0, OPT_DRAW_OBJECT},
@ -724,6 +727,9 @@ int main(int argc, char *argv[])
generator.setDrawScale(DRAWSCALE_LEFT | DRAWSCALE_TOP);
}
break;
case OPT_DRAWHEIGHTSCALE :
generator.setDrawHeightScale(DRAWHEIGHTSCALE_BOTTOM);
break;
case 'v':
if (optarg && isdigit(optarg[0]) && optarg[1] == '\0') {
if (optarg[0] == '0')