Allow escaping of texture names when passed as an argument to a modifier
parent
9dd22aebc7
commit
b77cee146b
|
@ -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,7 +959,9 @@ 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--) {
|
||||
switch(name[i]) {
|
||||
if (i > 0 && name[i-1] == escape)
|
||||
continue;
|
||||
switch (name[i]) {
|
||||
case separator:
|
||||
if (paren_bal == 0) {
|
||||
last_separator_pos = i;
|
||||
|
@ -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);
|
||||
blit_with_alpha(tmp, baseimg, v2s32(0, 0), v2s32(0, 0), dim);
|
||||
tmp->drop();
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue