From f21dae63390aa872062bcfc96fc6817b0fcfe601 Mon Sep 17 00:00:00 2001 From: Thomas--S Date: Sat, 2 Jul 2016 17:58:08 +0200 Subject: Add an [opacity: texture modifier. Makes the base image transparent according to the given ratio. r must be between 0 and 255. 0 means totally transparent. 255 means totally opaque. Useful for texture overlaying. --- src/client/tile.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/client/tile.cpp') diff --git a/src/client/tile.cpp b/src/client/tile.cpp index ec8c95f02..3b5d2a3ae 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -1735,6 +1735,36 @@ bool TextureSource::generateImagePart(std::string part_of_name, baseimg->drop(); baseimg = image; } + /* + [opacity:R + Makes the base image transparent according to the given ratio. + R must be between 0 and 255. + 0 means totally transparent. + 255 means totally opaque. + */ + else if (str_starts_with(part_of_name, "[opacity:")) { + if (baseimg == NULL) { + errorstream << "generateImagePart(): baseimg == NULL " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + Strfnd sf(part_of_name); + sf.next(":"); + + u32 ratio = mystoi(sf.next(""), 0, 255); + + core::dimension2d dim = baseimg->getDimension(); + + for (u32 y = 0; y < dim.Height; y++) + for (u32 x = 0; x < dim.Width; x++) + { + video::SColor c = baseimg->getPixel(x,y); + c.setAlpha(floor((c.getAlpha() * ratio) / 255 + 0.5)); + baseimg->setPixel(x,y,c); + } + } else { errorstream << "generateImagePart(): Invalid " -- cgit v1.2.3 From b77cee146b0029d377f1028b942857d062bc1374 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 3 Sep 2016 17:53:15 +0200 Subject: Allow escaping of texture names when passed as an argument to a modifier --- doc/lua_api.txt | 14 ++++++++++-- src/client/tile.cpp | 65 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 56 insertions(+), 23 deletions(-) (limited to 'src/client/tile.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 1da45ad66..74d4b90d5 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -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{{{` -`^` 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. diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 3b5d2a3ae..67d5d8d1a 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -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 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="< dim = img->getDimension(); infostream<<"Size "<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 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. -- cgit v1.2.3 From 1475c1b1c8bb1a2a2812d485d3590e1f817f7c7b Mon Sep 17 00:00:00 2001 From: Thomas--S Date: Fri, 12 Aug 2016 17:56:31 +0200 Subject: Add an [invert: texture modifier Inverts the given channels of the base image. Mode may contain the characters "r", "g", "b", "a". Only the channels that are mentioned in the mode string will be inverted. --- doc/lua_api.txt | 9 +++++++++ src/client/tile.cpp | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) (limited to 'src/client/tile.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index aa4f129f0..41e7c00eb 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -318,6 +318,15 @@ Example: default_sandstone.png^[opacity:127 +#### `[invert:` +Inverts the given channels of the base image. +Mode may contain the characters "r", "g", "b", "a". +Only the channels that are mentioned in the mode string will be inverted. + +Example: + + default_apple.png^[invert:rgb + #### `[brighten` Brightens the texture. diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 67d5d8d1a..8f0c39465 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -1783,9 +1783,48 @@ bool TextureSource::generateImagePart(std::string part_of_name, for (u32 y = 0; y < dim.Height; y++) for (u32 x = 0; x < dim.Width; x++) { - video::SColor c = baseimg->getPixel(x,y); + video::SColor c = baseimg->getPixel(x, y); c.setAlpha(floor((c.getAlpha() * ratio) / 255 + 0.5)); - baseimg->setPixel(x,y,c); + baseimg->setPixel(x, y, c); + } + } + /* + [invert:mode + Inverts the given channels of the base image. + Mode may contain the characters "r", "g", "b", "a". + Only the channels that are mentioned in the mode string + will be inverted. + */ + else if (str_starts_with(part_of_name, "[invert:")) { + if (baseimg == NULL) { + errorstream << "generateImagePart(): baseimg == NULL " + << "for part_of_name=\"" << part_of_name + << "\", cancelling." << std::endl; + return false; + } + + Strfnd sf(part_of_name); + sf.next(":"); + + std::string mode = sf.next(""); + u32 mask = 0; + if (mode.find("a") != std::string::npos) + mask |= 0xff000000UL; + if (mode.find("r") != std::string::npos) + mask |= 0x00ff0000UL; + if (mode.find("g") != std::string::npos) + mask |= 0x0000ff00UL; + if (mode.find("b") != std::string::npos) + mask |= 0x000000ffUL; + + core::dimension2d dim = baseimg->getDimension(); + + for (u32 y = 0; y < dim.Height; y++) + for (u32 x = 0; x < dim.Width; x++) + { + video::SColor c = baseimg->getPixel(x, y); + c.color ^= mask; + baseimg->setPixel(x, y, c); } } else -- cgit v1.2.3