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)`
|
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:
|
||||||
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(
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
#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,
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
[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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
"[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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
"[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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
"[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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
|
||||||
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.
|
||||||
|
|
Loading…
Reference in New Issue