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).
master
Rogier 2014-06-09 08:32:06 +02:00
parent 224c6b1df7
commit e6322f2911
3 changed files with 93 additions and 40 deletions

View File

@ -89,6 +89,23 @@ colors <file>:
# 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`

View File

@ -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;

View File

@ -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();