Add options to generate a height map of the world.
--heightmap: generate the height map, in colors --heightmap-grey: use shades of grey instead of colors --sealevel <n>: define the sea level (below sea level is drawn in blue) --heightmap-scale <f>: scale the heights by f (for the purpose of color selection) When generating a heightmap, a special colors file is needed, that defines just the blocks that should be considered part of the ground. That means that normally, any plants, special nodes and water should not be included.
This commit is contained in:
parent
2d3eaff736
commit
3812e31fc9
@ -296,6 +296,7 @@ if(WIN32)
|
||||
|
||||
install(FILES ${META_FILES} DESTINATION ".")
|
||||
install(FILES "colors.txt" DESTINATION ".")
|
||||
install(FILES "colors-heightmap.txt" DESTINATION ".")
|
||||
install(FILES "colors-average-alpha.txt" DESTINATION ".")
|
||||
install(FILES "colors-cumulative-alpha.txt" DESTINATION ".")
|
||||
install(PROGRAMS "${PROJECT_BINARY_DIR}/minetestmapper.exe" DESTINATION ".")
|
||||
@ -318,6 +319,7 @@ elseif(CREATE_FLAT_PACKAGE)
|
||||
|
||||
install(FILES ${META_FILES} DESTINATION ".")
|
||||
install(FILES "colors.txt" DESTINATION ".")
|
||||
install(FILES "colors-heightmap.txt" DESTINATION ".")
|
||||
install(FILES "colors-average-alpha.txt" DESTINATION ".")
|
||||
install(FILES "colors-cumulative-alpha.txt" DESTINATION ".")
|
||||
install(PROGRAMS "${PROJECT_BINARY_DIR}/minetestmapper" DESTINATION ".")
|
||||
@ -352,6 +354,7 @@ else(WIN32)
|
||||
|
||||
install(FILES ${META_FILES} DESTINATION "share/doc/${PROJECT_NAME}" COMPONENT mapper)
|
||||
install(FILES colors.txt DESTINATION "share/games/${PROJECT_NAME}" COMPONENT mapper)
|
||||
install(FILES colors-heightmap.txt DESTINATION "share/games/${PROJECT_NAME}" COMPONENT mapper)
|
||||
install(FILES colors-average-alpha.txt DESTINATION "share/games/${PROJECT_NAME}" COMPONENT mapper)
|
||||
install(FILES colors-cumulative-alpha.txt DESTINATION "share/games/${PROJECT_NAME}" COMPONENT mapper)
|
||||
install(TARGETS minetestmapper RUNTIME DESTINATION bin COMPONENT mapper)
|
||||
|
31
README.rst
31
README.rst
@ -142,6 +142,37 @@ colors <file>:
|
||||
default:water_source -
|
||||
default:water_flowing -
|
||||
|
||||
heightmap[-grey]:
|
||||
Draw a height-map instead of a regular map.
|
||||
|
||||
A height map needs a custom colors file that contains only the nodes that
|
||||
define the height. As a general directive, plants and other special nodes
|
||||
should not be included in the file. Normally, water nodes should not be
|
||||
included either.
|
||||
|
||||
The colors used are predefined and not yet configurable.
|
||||
|
||||
The colors support a maximum depth below sea level of 60, although below a
|
||||
depth of 30 they become progressively darker.
|
||||
Above sea level, they support a maximum height of 250.
|
||||
Starting from height level 70, greyish colors are used (think: 'rocky')
|
||||
Starting from height level 111, shades of white are used (think: 'snowy').
|
||||
|
||||
For '--heightmap-grey', a 255-level greyscale map is generated, with colors
|
||||
ranging from black for level 0 and below, to white for 255 and above.
|
||||
|
||||
heightmap-scale
|
||||
Scale the heights of the map before computing the colors.
|
||||
|
||||
Note that the water level is not rendered correctly for scale factors
|
||||
smaller than 1, nor for small non-integer scale factors.
|
||||
|
||||
sealevel:
|
||||
Set the sea level for the height map. Nodes at or below sea level are
|
||||
drawn in blue, nodes above sea level are drawn in other colors.
|
||||
|
||||
The sea level *does* *not* reflect the presence of actual water.
|
||||
|
||||
bgcolor:
|
||||
Background color of image, `--bgcolor #ffffff`
|
||||
|
||||
|
@ -121,11 +121,21 @@ static inline int readBlockContent(const unsigned char *mapData, int version, in
|
||||
static const ColorEntry nodeColorNotDrawnObject;
|
||||
const ColorEntry *TileGenerator::NodeColorNotDrawn = &nodeColorNotDrawnObject;
|
||||
|
||||
struct HeightMapColor
|
||||
{
|
||||
int height[2];
|
||||
Color color[2];
|
||||
};
|
||||
|
||||
TileGenerator::TileGenerator():
|
||||
verboseCoordinates(0),
|
||||
verboseReadColors(0),
|
||||
verboseStatistics(false),
|
||||
progressIndicator(false),
|
||||
m_heightMap(false),
|
||||
m_heightMapGrey(false),
|
||||
m_heightMapYScale(1),
|
||||
m_seaLevel(0),
|
||||
m_bgColor(255, 255, 255),
|
||||
m_blockDefaultColor(0, 0, 0, 0),
|
||||
m_scaleColor(0, 0, 0),
|
||||
@ -176,6 +186,45 @@ TileGenerator::~TileGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
void TileGenerator::setHeightMap(bool enable, bool grey)
|
||||
{
|
||||
m_heightMap = enable;
|
||||
m_heightMapGrey = grey;
|
||||
m_heightMapColors.clear();
|
||||
if (m_heightMapGrey) {
|
||||
m_heightMapColors.push_back(HeightMapColor(INT_MIN, Color(0,0,0), -1, Color(0,0,0)));
|
||||
m_heightMapColors.push_back(HeightMapColor(0, Color(0,0,0), 255, Color(255,255,255)));
|
||||
m_heightMapColors.push_back(HeightMapColor(256, Color(255,255,255), INT_MAX, Color(255,255,255)));
|
||||
}
|
||||
else {
|
||||
m_heightMapColors.push_back(HeightMapColor(INT_MIN, Color(4,4,4), -60, Color(4,4,4)));
|
||||
m_heightMapColors.push_back(HeightMapColor(-60, Color(4,4,4), -45, Color(16,16,16)));
|
||||
m_heightMapColors.push_back(HeightMapColor(-45, Color(16,16,16), -30, Color(16,32,64)));
|
||||
m_heightMapColors.push_back(HeightMapColor(-30, Color(16,32,64), 0, Color(32,64,255)));
|
||||
|
||||
m_heightMapColors.push_back(HeightMapColor(1, Color(32,128,32), 10, Color(64,192,64))); // Green
|
||||
m_heightMapColors.push_back(HeightMapColor(10, Color(64,192,64), 20, Color(192,192,64))); // Green -> Yellow
|
||||
m_heightMapColors.push_back(HeightMapColor(20, Color(192,192,64), 40, Color(128,128,64))); // Yellow
|
||||
m_heightMapColors.push_back(HeightMapColor(40, Color(128,128,64), 50, Color(128,64,64))); // Yellow -> Red
|
||||
m_heightMapColors.push_back(HeightMapColor(50, Color(128,64,64), 70, Color(64,32,32))); // Red
|
||||
m_heightMapColors.push_back(HeightMapColor(70, Color(64,32,32), 80, Color(48,48,48))); // Red -> Grey
|
||||
m_heightMapColors.push_back(HeightMapColor(80, Color(48,48,48), 140, Color(96,96,96))); // Grey
|
||||
// Above 100, white suggests snowy :-)
|
||||
m_heightMapColors.push_back(HeightMapColor(141, Color(160,160,160), 250, Color(250,250,250))); // Grey -> White
|
||||
m_heightMapColors.push_back(HeightMapColor(250, Color(250,250,250), INT_MAX, Color(250,250,250)));
|
||||
}
|
||||
}
|
||||
|
||||
void TileGenerator::setHeightMapYScale(float scale)
|
||||
{
|
||||
m_heightMapYScale = scale;
|
||||
}
|
||||
|
||||
void TileGenerator::setSeaLevel(int level)
|
||||
{
|
||||
m_seaLevel = level;
|
||||
}
|
||||
|
||||
void TileGenerator::setBgColor(const Color &bgColor)
|
||||
{
|
||||
m_bgColor = bgColor;
|
||||
@ -1294,24 +1343,51 @@ inline void TileGenerator::renderMapBlock(const ustring &mapBlock, const BlockPo
|
||||
for (int y = maxY; y >= minY; --y) {
|
||||
int position = x + (y << 4) + (z << 8);
|
||||
int content = readBlockContent(mapData, version, position);
|
||||
#define nodeColor (*m_nodeIDColor[content])
|
||||
//const ColorEntry &nodeColor = *m_nodeIDColor[content];
|
||||
if (m_nodeIDColor[content] == NodeColorNotDrawn) {
|
||||
continue;
|
||||
}
|
||||
if (m_nodeIDColor[content]) {
|
||||
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;
|
||||
#define nodeColor (*m_nodeIDColor[content])
|
||||
//const ColorEntry &nodeColor = *m_nodeIDColor[content];
|
||||
pixel.mixUnder(PixelAttribute(nodeColor, pos.y * 16 + y));
|
||||
float r = 0;
|
||||
float g = 0;
|
||||
float b = 0;
|
||||
int n = 0;
|
||||
for (std::list<HeightMapColor>::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++;
|
||||
}
|
||||
}
|
||||
pixel = PixelAttribute(Color(int(r / n + 0.5), int(g / n + 0.5), int(b / n + 0.5)), height);
|
||||
m_readedPixels[z] |= (1 << x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (m_nodeIDColor[content]) {
|
||||
rowIsEmpty = false;
|
||||
pixel.mixUnder(PixelAttribute(nodeColor, height));
|
||||
if ((m_drawAlpha && nodeColor.a == 0xff) || (!m_drawAlpha && nodeColor.a != 0)) {
|
||||
m_readedPixels[z] |= (1 << x);
|
||||
break;
|
||||
}
|
||||
#undef nodeColor
|
||||
} else {
|
||||
NodeID2NameMap::iterator blockName = m_nameMap.find(content);
|
||||
if (blockName != m_nameMap.end())
|
||||
m_unknownNodes.insert(blockName->second);
|
||||
}
|
||||
#undef nodeColor
|
||||
}
|
||||
#undef pixel
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <map>
|
||||
#endif
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string>
|
||||
@ -57,6 +58,12 @@ private:
|
||||
typedef std::map<int, std::string> NodeID2NameMap;
|
||||
#endif
|
||||
public:
|
||||
struct HeightMapColor
|
||||
{
|
||||
HeightMapColor(int h0, Color c0, int h1, Color c1) : height{h0, h1}, color{c0, c1} {}
|
||||
int height[2];
|
||||
Color color[2];
|
||||
};
|
||||
struct DrawObject {
|
||||
void setCenter(const NodeCoord &c) { haveCenter = true; center = c; }
|
||||
void setCorner1(const NodeCoord &c) { haveCenter = false; corner1 = c; }
|
||||
@ -94,6 +101,9 @@ public:
|
||||
|
||||
TileGenerator();
|
||||
~TileGenerator();
|
||||
void setHeightMap(bool enable, bool grey);
|
||||
void setHeightMapYScale(float scale);
|
||||
void setSeaLevel(int level);
|
||||
void setBgColor(const Color &bgColor);
|
||||
void setBlockDefaultColor(const Color &olor);
|
||||
void setScaleColor(const Color &scaleColor);
|
||||
@ -177,6 +187,11 @@ public:
|
||||
bool progressIndicator;
|
||||
|
||||
private:
|
||||
bool m_heightMap;
|
||||
bool m_heightMapGrey;
|
||||
float m_heightMapYScale;
|
||||
int m_seaLevel;
|
||||
std::list<HeightMapColor> m_heightMapColors;
|
||||
Color m_bgColor;
|
||||
Color m_blockDefaultColor;
|
||||
Color m_scaleColor;
|
||||
|
1130
colors-heightmap.txt
Normal file
1130
colors-heightmap.txt
Normal file
File diff suppressed because it is too large
Load Diff
41
mapper.cpp
41
mapper.cpp
@ -31,6 +31,11 @@ using namespace std;
|
||||
#define OPT_DRAWAIR 0x85
|
||||
#define OPT_VERBOSE_SEARCH_COLORS 0x86
|
||||
#define OPT_CHUNKSIZE 0x87
|
||||
#define OPT_HEIGHTMAP 0x88
|
||||
#define OPT_HEIGHTMAPGREY 0x89
|
||||
#define OPT_HEIGHTMAPYSCALE 0x8a
|
||||
#define OPT_HEIGHT_LEVEL0 0x8b
|
||||
|
||||
|
||||
// Will be replaced with the actual name and location of the executable (if found)
|
||||
string executableName = "minetestmapper";
|
||||
@ -66,6 +71,9 @@ void usage()
|
||||
" -i/--input <world_path>\n"
|
||||
" -o/--output <output_image.png>\n"
|
||||
" --colors <file>\n"
|
||||
" --heightmap[-grey]\n"
|
||||
" --heightmap-scale <scale>\n"
|
||||
" --height-level-0 <level>\n"
|
||||
" --bgcolor <color>\n"
|
||||
" --blockcolor <color>\n"
|
||||
" --scalecolor <color>\n"
|
||||
@ -522,6 +530,11 @@ int main(int argc, char *argv[])
|
||||
{"input", required_argument, 0, 'i'},
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"colors", required_argument, 0, 'C'},
|
||||
{"heightmap", no_argument, 0, OPT_HEIGHTMAP},
|
||||
{"heightmap-grey", no_argument, 0, OPT_HEIGHTMAPGREY},
|
||||
{"heightmap-gray", no_argument, 0, OPT_HEIGHTMAPGREY},
|
||||
{"heightmap-scale", required_argument, 0, OPT_HEIGHTMAPYSCALE},
|
||||
{"height-level-0", required_argument, 0, OPT_HEIGHT_LEVEL0},
|
||||
{"bgcolor", required_argument, 0, 'b'},
|
||||
{"blockcolor", required_argument, 0, OPT_BLOCKCOLOR},
|
||||
{"scalecolor", required_argument, 0, 's'},
|
||||
@ -606,6 +619,34 @@ int main(int argc, char *argv[])
|
||||
case 'b':
|
||||
generator.setBgColor(Color(optarg, 0));
|
||||
break;
|
||||
case OPT_HEIGHTMAP:
|
||||
generator.setHeightMap(true, false);
|
||||
break;
|
||||
case OPT_HEIGHTMAPGREY:
|
||||
generator.setHeightMap(true, true);
|
||||
break;
|
||||
case OPT_HEIGHTMAPYSCALE:
|
||||
if (isdigit(optarg[0]) || ((optarg[0]=='-' || optarg[0]=='+') && isdigit(optarg[1]))) {
|
||||
float scale = atof(optarg);
|
||||
generator.setHeightMapYScale(scale);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << optarg << "'" << std::endl;
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case OPT_HEIGHT_LEVEL0:
|
||||
if (isdigit(optarg[0]) || ((optarg[0]=='-' || optarg[0]=='+') && isdigit(optarg[1]))) {
|
||||
int level = atoi(optarg);
|
||||
generator.setSeaLevel(level);
|
||||
}
|
||||
else {
|
||||
std::cerr << "Invalid parameter to '" << long_options[option_index].name << "': '" << optarg << "'" << std::endl;
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case OPT_BLOCKCOLOR:
|
||||
generator.setBlockDefaultColor(Color(optarg, 0));
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user