diff options
Diffstat (limited to 'src/client/tile.cpp')
-rw-r--r-- | src/client/tile.cpp | 134 |
1 files changed, 113 insertions, 21 deletions
diff --git a/src/client/tile.cpp b/src/client/tile.cpp index ec8c95f02..8f0c39465 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<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. @@ -1735,6 +1758,75 @@ 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<u32> 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); + } + } + /* + [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<u32> 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 { errorstream << "generateImagePart(): Invalid " |