Skip to content
Snippets Groups Projects
Commit b77cee14 authored by sfan5's avatar sfan5 Committed by paramat
Browse files

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

parent 9dd22aeb
No related branches found
No related tags found
No related merge requests found
...@@ -263,7 +263,17 @@ Textures can be grouped together by enclosing them in `(` and `)`. ...@@ -263,7 +263,17 @@ Textures can be grouped together by enclosing them in `(` and `)`.
Example: `cobble.png^(thing1.png^thing2.png)` Example: `cobble.png^(thing1.png^thing2.png)`
A texture for `thing1.png^thing2.png` is created and the resulting 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 ### Advanced texture modifiers
...@@ -351,7 +361,7 @@ Example: ...@@ -351,7 +361,7 @@ Example:
default_stone.png^[transformFXR90 default_stone.png^[transformFXR90
#### `[inventorycube{<top>{<left>{<right>` #### `[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. Create an inventory cube texture using the side textures.
......
...@@ -948,11 +948,10 @@ video::ITexture* TextureSource::generateTextureFromMesh( ...@@ -948,11 +948,10 @@ video::ITexture* TextureSource::generateTextureFromMesh(
video::IImage* TextureSource::generateImage(const std::string &name) video::IImage* TextureSource::generateImage(const std::string &name)
{ {
/* // Get the base image
Get the base image
*/
const char separator = '^'; const char separator = '^';
const char escape = '\\';
const char paren_open = '('; const char paren_open = '(';
const char paren_close = ')'; const char paren_close = ')';
...@@ -960,7 +959,9 @@ video::IImage* TextureSource::generateImage(const std::string &name) ...@@ -960,7 +959,9 @@ video::IImage* TextureSource::generateImage(const std::string &name)
s32 last_separator_pos = -1; s32 last_separator_pos = -1;
u8 paren_bal = 0; u8 paren_bal = 0;
for (s32 i = name.size() - 1; i >= 0; i--) { for (s32 i = name.size() - 1; i >= 0; i--) {
switch(name[i]) { if (i > 0 && name[i-1] == escape)
continue;
switch (name[i]) {
case separator: case separator:
if (paren_bal == 0) { if (paren_bal == 0) {
last_separator_pos = i; last_separator_pos = i;
...@@ -1028,10 +1029,12 @@ video::IImage* TextureSource::generateImage(const std::string &name) ...@@ -1028,10 +1029,12 @@ video::IImage* TextureSource::generateImage(const std::string &name)
return NULL; return NULL;
} }
core::dimension2d<u32> dim = tmp->getDimension(); core::dimension2d<u32> dim = tmp->getDimension();
if (!baseimg) if (baseimg) {
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); blit_with_alpha(tmp, baseimg, v2s32(0, 0), v2s32(0, 0), dim);
blit_with_alpha(tmp, baseimg, v2s32(0, 0), v2s32(0, 0), dim); tmp->drop();
tmp->drop(); } else {
baseimg = tmp;
}
} else if (!generateImagePart(last_part_of_name, baseimg)) { } else if (!generateImagePart(last_part_of_name, baseimg)) {
// Generate image according to part of name // Generate image according to part of name
errorstream << "generateImage(): " errorstream << "generateImage(): "
...@@ -1099,9 +1102,27 @@ video::IImage * Align2Npot2(video::IImage * image, ...@@ -1099,9 +1102,27 @@ video::IImage * Align2Npot2(video::IImage * image,
#endif #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, bool TextureSource::generateImagePart(std::string part_of_name,
video::IImage *& baseimg) video::IImage *& baseimg)
{ {
const char escape = '\\'; // same as in generateImage()
video::IVideoDriver* driver = m_device->getVideoDriver(); video::IVideoDriver* driver = m_device->getVideoDriver();
sanity_check(driver); sanity_check(driver);
...@@ -1251,7 +1272,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1251,7 +1272,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
/* /*
[combine:WxH:X,Y=filename:X,Y=filename2 [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")) else if (str_starts_with(part_of_name, "[combine"))
{ {
...@@ -1259,7 +1280,6 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1259,7 +1280,6 @@ bool TextureSource::generateImagePart(std::string part_of_name,
sf.next(":"); sf.next(":");
u32 w0 = stoi(sf.next("x")); u32 w0 = stoi(sf.next("x"));
u32 h0 = stoi(sf.next(":")); u32 h0 = stoi(sf.next(":"));
//infostream<<"combined w="<<w0<<" h="<<h0<<std::endl;
core::dimension2d<u32> dim(w0,h0); core::dimension2d<u32> dim(w0,h0);
if (baseimg == NULL) { if (baseimg == NULL) {
baseimg = driver->createImage(video::ECF_A8R8G8B8, dim); baseimg = driver->createImage(video::ECF_A8R8G8B8, dim);
...@@ -1268,11 +1288,11 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1268,11 +1288,11 @@ bool TextureSource::generateImagePart(std::string part_of_name,
while (sf.at_end() == false) { while (sf.at_end() == false) {
u32 x = stoi(sf.next(",")); u32 x = stoi(sf.next(","));
u32 y = 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 infostream<<"Adding \""<<filename
<<"\" to combined ("<<x<<","<<y<<")" <<"\" to combined ("<<x<<","<<y<<")"
<<std::endl; <<std::endl;
video::IImage *img = m_sourcecache.getOrLoad(filename, m_device); video::IImage *img = generateImage(filename);
if (img) { if (img) {
core::dimension2d<u32> dim = img->getDimension(); core::dimension2d<u32> dim = img->getDimension();
infostream<<"Size "<<dim.Width infostream<<"Size "<<dim.Width
...@@ -1295,7 +1315,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1295,7 +1315,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
} }
/* /*
"[brighten" [brighten
*/ */
else if (str_starts_with(part_of_name, "[brighten")) else if (str_starts_with(part_of_name, "[brighten"))
{ {
...@@ -1309,7 +1329,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1309,7 +1329,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
brighten(baseimg); brighten(baseimg);
} }
/* /*
"[noalpha" [noalpha
Make image completely opaque. Make image completely opaque.
Used for the leaves texture when in old leaves mode, so Used for the leaves texture when in old leaves mode, so
that the transparent parts don't look completely black that the transparent parts don't look completely black
...@@ -1336,7 +1356,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -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. Convert one color to transparent.
*/ */
else if (str_starts_with(part_of_name, "[makealpha:")) else if (str_starts_with(part_of_name, "[makealpha:"))
...@@ -1375,7 +1395,7 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1375,7 +1395,7 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
} }
/* /*
"[transformN" [transformN
Rotates and/or flips the image. Rotates and/or flips the image.
N can be a number (between 0 and 7) or a transform name. 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, ...@@ -1543,12 +1563,11 @@ bool TextureSource::generateImagePart(std::string part_of_name,
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); sf.next(":");
u32 percent = stoi(sf.next(":")); u32 percent = stoi(sf.next(":"));
std::string filename = sf.next(":"); std::string filename = unescape_string(sf.next_esc(":", escape), escape);
//infostream<<"power part "<<percent<<"%% of "<<filename<<std::endl;
if (baseimg == NULL) if (baseimg == NULL)
baseimg = driver->createImage(video::ECF_A8R8G8B8, v2u32(16,16)); 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) if (img)
{ {
core::dimension2d<u32> dim = img->getDimension(); core::dimension2d<u32> dim = img->getDimension();
...@@ -1628,9 +1647,9 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1628,9 +1647,9 @@ bool TextureSource::generateImagePart(std::string part_of_name,
} }
Strfnd sf(part_of_name); Strfnd sf(part_of_name);
sf.next(":"); 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) { if (img) {
apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0), apply_mask(img, baseimg, v2s32(0, 0), v2s32(0, 0),
img->getDimension()); img->getDimension());
...@@ -1673,6 +1692,10 @@ bool TextureSource::generateImagePart(std::string part_of_name, ...@@ -1673,6 +1692,10 @@ bool TextureSource::generateImagePart(std::string part_of_name,
apply_colorize(baseimg, v2u32(0, 0), baseimg->getDimension(), color, ratio, keep_alpha); apply_colorize(baseimg, v2u32(0, 0), baseimg->getDimension(), color, ratio, keep_alpha);
} }
/*
[applyfiltersformesh
Internal modifier
*/
else if (str_starts_with(part_of_name, "[applyfiltersformesh")) else if (str_starts_with(part_of_name, "[applyfiltersformesh"))
{ {
// Apply the "clean transparent" filter, if configured. // Apply the "clean transparent" filter, if configured.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment