From e6322f29115b91fff0247978bc32b403c36a9d9f Mon Sep 17 00:00:00 2001 From: Rogier Date: Mon, 9 Jun 2014 08:32:06 +0200 Subject: [PATCH] Add an include directive for colors files A colors file can now specify other colors files, from which additional node color specifications will be read. This allows, for instance, using system-installed colors file for most colors, and only overriding some of its colors in a custom colors file. As a purpose of using a custom colors file may be to leave the colors for some nodes undefined, it is now also possible to undefine a previously defined node color (i.e. after reading another colors file which defines a color for the node). --- README.rst | 17 +++++++ TileGenerator.cpp | 112 ++++++++++++++++++++++++++++++---------------- TileGenerator.h | 4 +- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/README.rst b/README.rst index 9c571da..0cbf3a4 100644 --- a/README.rst +++ b/README.rst @@ -89,6 +89,23 @@ colors : # Entry that is used with 'drawalpha': default:water-source 78 132 212 64 224 + The colors file can include other colors files using: + `@include filename` + Any entries after the inclusion point override entries from the + included file. Already defined colors can be 'undefined' by specifying + '-' as color: + +:: + + default:stone 71 68 67 + # default-colors.txt might override the color of default:stone + @include default-colors.txt + # color of default:dirt_with_grass from default-colors.txt is overridden: + default:dirt_with_grass 82 117 54 + # Color of water is undefined here: + default:water_source - + default:water_flowing - + bgcolor: Background color of image, `--bgcolor #ffffff` diff --git a/TileGenerator.cpp b/TileGenerator.cpp index ce2e3e9..5524bfd 100644 --- a/TileGenerator.cpp +++ b/TileGenerator.cpp @@ -325,9 +325,11 @@ void TileGenerator::setMaxY(int y) m_reqYMaxNode = y - 16 * m_reqYMax; } -void TileGenerator::parseColorsFile(const std::string &fileName) +void TileGenerator::parseColorsFile(const std::string &fileName, int depth) { - if (verboseReadColors >= 2) + if (depth > 100) + throw std::runtime_error(std::string("Excessive inclusion depth of colors files - suspected recursion (i.e. cycle); current file: '") + fileName + "'"); + if (depth == 0 && verboseReadColors >= 2) cout << "Checking for colors file: " << fileName << std::endl; ifstream in; in.open(fileName.c_str(), ifstream::in); @@ -337,7 +339,7 @@ void TileGenerator::parseColorsFile(const std::string &fileName) } if (verboseReadColors >= 1) cout << "Reading colors file: " << fileName << std::endl; - parseColorsStream(in, fileName.c_str()); + parseColorsStream(in, fileName.c_str(), depth); in.close(); } @@ -374,7 +376,7 @@ void TileGenerator::generate(const std::string &input, const std::string &output printUnknown(); } -void TileGenerator::parseColorsStream(std::istream &in, const std::string &filename) +void TileGenerator::parseColorsStream(std::istream &in, const std::string &filename, int depth) { string line; int linenr = 0; @@ -388,45 +390,79 @@ void TileGenerator::parseColorsStream(std::istream &in, const std::string &filen iline >> std::skipws; string name; ColorEntry color; - iline >> name; + iline >> name >> std::ws; if (name.length() == 0) continue; - int r, g, b, a, t; - iline >> r; - iline >> g; - iline >> b; - if (iline.fail()) { - std::cerr << filename << ":" << linenr << ": bad line in colors file (" << line << ")" << std::endl; - continue; - } - a = 0xff; - iline >> a; - t = 0; - iline >> t; - color = ColorEntry(r,g,b,a,t); - if ((m_drawAlpha && a == 0xff) || (!m_drawAlpha && a != 0xff)) { - // If drawing alpha, and the colors file contains both - // an opaque entry and a non-opaque entry for a name, prefer - // the non-opaque entry - // If not drawing alpha, and the colors file contains both - // an opaque entry and a non-opaque entry for a name, prefer - // the opaque entry - // Otherwise, any later entry overrides any previous entry - ColorMap::iterator it = m_colors.find(name); - if (it != m_colors.end()) { - if (m_drawAlpha && (a == 0xff && it->second.a != 0xff)) { - // drawing alpha: don't use opaque color to override - // non-opaque color - continue; - } - if (!m_drawAlpha && (a != 0xff && it->second.a == 0xff)) { - // not drawing alpha: don't use non-opaque color to - // override opaque color - continue; + if (name == "@include") { + string includeFile; + getline(iline,includeFile); + size_t lastChar = includeFile.find_last_not_of(" \t\r\n"); + if (lastChar != string::npos) + includeFile.erase(lastChar + 1); + if (includeFile == "") { + std::cerr << filename << ":" << linenr << ": include filename missing in colors file (" << line << ")" << std::endl; + continue; + } +#if ! (MSDOS || __OS2__ || __NT__ || _WIN32) + // This same feature seems needlessly complicated on windows - so it is not supported + if (includeFile[0] != '/') { + string includePath = filename; + size_t offset = includePath.find_last_of('/'); + if (offset != string::npos) { + includePath.erase(offset); + includeFile = includePath + '/' + includeFile; } } +#endif + parseColorsFile(includeFile, depth + 1); + } + else if (iline.good() && iline.peek() == '-') { + char c; + iline >> c >> std::ws; + if (iline.bad() || !iline.eof()) { + std::cerr << filename << ":" << linenr << ": bad line in colors file (" << line << ")" << std::endl; + continue; + } + m_colors.erase(name); + } + else { + int r, g, b, a, t; + iline >> r; + iline >> g; + iline >> b; + if (iline.fail()) { + std::cerr << filename << ":" << linenr << ": bad line in colors file (" << line << ")" << std::endl; + continue; + } + a = 0xff; + iline >> a; + t = 0; + iline >> t; + color = ColorEntry(r,g,b,a,t); + if ((m_drawAlpha && a == 0xff) || (!m_drawAlpha && a != 0xff)) { + // If drawing alpha, and the colors file contains both + // an opaque entry and a non-opaque entry for a name, prefer + // the non-opaque entry + // If not drawing alpha, and the colors file contains both + // an opaque entry and a non-opaque entry for a name, prefer + // the opaque entry + // Otherwise, any later entry overrides any previous entry + ColorMap::iterator it = m_colors.find(name); + if (it != m_colors.end()) { + if (m_drawAlpha && (a == 0xff && it->second.a != 0xff)) { + // drawing alpha: don't use opaque color to override + // non-opaque color + continue; + } + if (!m_drawAlpha && (a != 0xff && it->second.a == 0xff)) { + // not drawing alpha: don't use non-opaque color to + // override opaque color + continue; + } + } + } + m_colors[name] = color; } - m_colors[name] = color; } if (!in.eof()) { std::cerr << filename << ": error reading colors file after line " << linenr << std::endl; diff --git a/TileGenerator.h b/TileGenerator.h index 23b8584..af2679b 100644 --- a/TileGenerator.h +++ b/TileGenerator.h @@ -105,12 +105,12 @@ public: void setTileOrigin(int x, int y); void setTileCenter(int x, int y); void enableProgressIndicator(void); - void parseColorsFile(const std::string &fileName); + void parseColorsFile(const std::string &fileName, int depth = 0); void setBackend(std::string backend); void generate(const std::string &input, const std::string &output); private: - void parseColorsStream(std::istream &in, const std::string &filename); + void parseColorsStream(std::istream &in, const std::string &filename, int depth); std::string getWorldDatabaseBackend(const std::string &input); void openDb(const std::string &input); void loadBlocks();