+ else if (ratio_str == "alpha")
+ keep_alpha = true;
+
+ apply_colorize(baseimg, v2u32(0, 0), baseimg->getDimension(), color, ratio, keep_alpha);
+ }
+ /*
+ [applyfiltersformesh
+ Internal modifier
+ */
+ else if (str_starts_with(part_of_name, "[applyfiltersformesh"))
+ {
+ /* IMPORTANT: When changing this, getTextureForMesh() needs to be
+ * updated too. */
+
+ if (!baseimg) {
+ errorstream << "generateImagePart(): baseimg == NULL "
+ << "for part_of_name=\"" << part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+
+ // Apply the "clean transparent" filter, if needed
+ if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent"))
+ imageCleanTransparent(baseimg, 127);
+
+ /* Upscale textures to user's requested minimum size. This is a trick to make
+ * filters look as good on low-res textures as on high-res ones, by making
+ * low-res textures BECOME high-res ones. This is helpful for worlds that
+ * mix high- and low-res textures, or for mods with least-common-denominator
+ * textures that don't have the resources to offer high-res alternatives.
+ */
+ const bool filter = m_setting_trilinear_filter || m_setting_bilinear_filter;
+ const s32 scaleto = filter ? g_settings->getS32("texture_min_size") : 1;
+ if (scaleto > 1) {
+ const core::dimension2d<u32> dim = baseimg->getDimension();
+
+ /* Calculate scaling needed to make the shortest texture dimension
+ * equal to the target minimum. If e.g. this is a vertical frames
+ * animation, the short dimension will be the real size.
+ */
+ if ((dim.Width == 0) || (dim.Height == 0)) {
+ errorstream << "generateImagePart(): Illegal 0 dimension "
+ << "for part_of_name=\""<< part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+ u32 xscale = scaleto / dim.Width;
+ u32 yscale = scaleto / dim.Height;
+ u32 scale = (xscale > yscale) ? xscale : yscale;
+
+ // Never downscale; only scale up by 2x or more.
+ if (scale > 1) {
+ u32 w = scale * dim.Width;
+ u32 h = scale * dim.Height;
+ const core::dimension2d<u32> newdim = core::dimension2d<u32>(w, h);
+ video::IImage *newimg = driver->createImage(
+ baseimg->getColorFormat(), newdim);
+ baseimg->copyToScaling(newimg);
+ baseimg->drop();
+ baseimg = newimg;
+ }
+ }
+ }
+ /*
+ [resize:WxH
+ Resizes the base image to the given dimensions
+ */
+ else if (str_starts_with(part_of_name, "[resize"))
+ {
+ 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 width = stoi(sf.next("x"));
+ u32 height = stoi(sf.next(""));
+ core::dimension2d<u32> dim(width, height);
+
+ video::IImage *image = RenderingEngine::get_video_driver()->
+ createImage(video::ECF_A8R8G8B8, dim);
+ baseimg->copyToScaling(image);
+ 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;