Allow escaping of texture names when passed as an argument to a modifier

This commit is contained in:
sfan5 2016-09-03 17:53:15 +02:00 committed by paramat
parent 9dd22aebc7
commit b77cee146b
2 changed files with 56 additions and 23 deletions

@ -263,7 +263,17 @@ Textures can be grouped together by enclosing them in `(` and `)`.
Example: `cobble.png^(thing1.png^thing2.png)`
A texture for `thing1.png^thing2.png` is created and the resulting
texture is overlaid over `cobble.png`.
texture is overlaid on top of `cobble.png`.
### Escaping
Modifiers that accept texture names (e.g. `[combine`) accept escaping to allow
passing complex texture names as arguments. Escaping is done with backslash and
is required for `^` and `:`.
Example: `cobble.png^[lowpart:50:color.png\^[mask\:trans.png`
The lower 50 percent of `color.png^[mask:trans.png` are overlaid
on top of `cobble.png`.
### Advanced texture modifiers
@ -351,7 +361,7 @@ Example:
default_stone.png^[transformFXR90
#### `[inventorycube{<top>{<left>{<right>`
`^` is replaced by `&` in texture names.
Escaping does not apply here and `^` is replaced by `&` in texture names instead.
Create an inventory cube texture using the side textures.

@ -948,11 +948,10 @@ video::ITexture* TextureSource::generateTextureFromMesh(
video::IImage* TextureSource::generateImage(const std::string &name)
{
/*
Get the base image
*/
// Get the base image
const char separator = '^';
const char escape = '\\';
const char paren_open = '(';
const char paren_close = ')';
@ -960,6 +959,8 @@ video::IImage* TextureSource::generateImage(const std::string &name)
s32 last_separator_pos = -1;
u8 paren_bal = 0;
for (s32 i = name.size() - 1; i >= 0; i--) {
if (i > 0 && name[i-1] == escape)
continue;
switch (name[i]) {
case separator:
if (paren_bal == 0) {
@ -1028,10 +1029,12 @@ video::IImage* TextureSource::generateImage(const std::string &name)
return NULL;
}
core::dimension2d<u32> dim = tmp->getDimension();
if (!baseimg)
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
if (baseimg) {
blit_with_alpha(tmp, baseimg, v2s32(0, 0), v2s32(0, 0), dim);
tmp->drop();
} else {
baseimg = tmp;
}
} else if (!generateImagePart(last_part_of_name, baseimg)) {
// Generate image according to part of name
errorstream << "generateImage(): "
@ -1099,9 +1102,27 @@ video::IImage * Align2Npot2(video::IImage * image,
#endif
static std::string unescape_string(const std::string &str, const char esc = '\\')
{
std::string out;
size_t pos = 0, cpos;
out.reserve(str.size());
while (1) {
cpos = str.find_first_of(esc, pos);
if (cpos == std::string::npos) {
out += str.substr(pos);
break;
}
out += str.substr(pos, cpos - pos) + str[cpos + 1];
pos = cpos + 2;
}
return out;
}
bool TextureSource::generateImagePart(std::string part_of_name,
video::IImage *& baseimg)
{
const char escape = '\\'; // same as in generateImage()
video::IVideoDriver* driver = m_device->getVideoDriver();
sanity_check(driver);
@ -1251,7 +1272,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}
/*
[combine:WxH:X,Y=filename:X,Y=filename2
Creates a bigger texture from an amount of smaller ones
Creates a bigger texture from any amount of smaller ones
*/
else if (str_starts_with(part_of_name, "[combine"))
{
@ -1259,7 +1280,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
sf.next(":");
u32 w0 = stoi(sf.next("x"));
u32 h0 = stoi(sf.next(":"));
//infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
core::dimension2d<u32> dim(w0,h0);
if (baseimg == NULL) {
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
@ -1268,11 +1288,11 @@ bool TextureSource::generateImagePart(std::string part_of_name,
while (sf.at_end() == false) {
u32 x = stoi(sf.next(","));
u32 y = stoi(sf.next("="));
std::string filename = sf.next(":");
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
infostream<<"Adding \""<<filename
<<"\" to combined ("<<x<<","<<y<<")"
<<std::endl;
video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
video::IImage *img = generateImage(filename);
if (img) {
core::dimension2d<u32> dim = img->getDimension();
infostream<<"Size "<<dim.Width
@ -1295,7 +1315,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}
}
/*
"[brighten"
[brighten
*/
else if (str_starts_with(part_of_name, "[brighten"))
{
@ -1309,7 +1329,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
brighten(baseimg);
}
/*
"[noalpha"
[noalpha
Make image completely opaque.
Used for the leaves texture when in old leaves mode, so
that the transparent parts don't look completely black
@ -1336,7 +1356,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}
}
/*
"[makealpha:R,G,B"
[makealpha:R,G,B
Convert one color to transparent.
*/
else if (str_starts_with(part_of_name, "[makealpha:"))
@ -1375,7 +1395,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}
}
/*
"[transformN"
[transformN
Rotates and/or flips the image.
N can be a number (between 0 and 7) or a transform name.
@ -1543,12 +1563,11 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Strfnd sf(part_of_name);
sf.next(":");
u32 percent = stoi(sf.next(":"));
std::string filename = sf.next(":");
//infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl;
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
if (baseimg == NULL)
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16));
video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
video::IImage *img = generateImage(filename);
if (img)
{
core::dimension2d<u32> dim = img->getDimension();
@ -1628,9 +1647,9 @@ bool TextureSource::generateImagePart(std::string part_of_name,
}
Strfnd sf(part_of_name);
sf.next(":");
std::string filename = sf.next(":");
std::string filename = unescape_string(sf.next_esc(":", escape), escape);
video::IImage *img = m_sourcecache.getOrLoad(filename, m_device);
video::IImage *img = generateImage(filename);
if (img) {
apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0),
img->getDimension());
@ -1673,6 +1692,10 @@ bool TextureSource::generateImagePart(std::string part_of_name,
apply_colorize(baseimg, v2u32(0, 0), baseimg->getDimension(), color, ratio, keep_alpha);
}
/*
[applyfiltersformesh
Internal modifier
*/
else if (str_starts_with(part_of_name, "[applyfiltersformesh"))
{
// Apply the "clean transparent" filter, if configured.