From 01ae43c48009f816f4649fae2f7f6997452aa6cf Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Sat, 2 Apr 2016 23:35:42 -0700 Subject: [PATCH] Add an option to colorize to respect the destination alpha Also, rework the colorizing code to be more efficient. --- doc/lua_api.txt | 9 +++++-- src/client/tile.cpp | 63 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index a01e72889..4a4e345a9 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -357,8 +357,13 @@ The mask is applied using binary AND. #### `[colorize::` Colorize the textures with the given color. `` is specified as a `ColorString`. -`` is an int ranging from 0 to 255, and specifies how much of the -color to apply. If ommitted, the alpha will be used. +`` is an int ranging from 0 to 255 or the word "`alpha`". If +it is an int, then it specifies how far to interpolate between the +colors where 0 is only the texture color and 255 is only ``. If +omitted, the alpha of `` will be used as the ratio. If it is +the word "`alpha`", then the alpha of the color will be multiplied with +the alpha of the texture with the RGB of the color replacing the RGB of +the texture. Sounds ------ diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 7a9bc0159..f0c0b4e9e 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -558,6 +558,13 @@ static void blit_with_alpha_overlay(video::IImage *src, video::IImage *dst, static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst, v2s32 src_pos, v2s32 dst_pos, v2u32 size, int ratio); +// Apply a color to an image. Uses an int (0-255) to calculate the ratio. +// If the ratio is 255 or -1 and keep_alpha is true, then it multiples the +// color alpha with the destination alpha. +// Otherwise, any pixels that are not fully transparent get the color alpha. +static void apply_colorize(video::IImage *dst, v2s32 dst_pos, v2u32 size, + video::SColor color, int ratio, bool keep_alpha); + // Apply a mask to an image static void apply_mask(video::IImage *mask, video::IImage *dst, v2s32 mask_pos, v2s32 dst_pos, v2u32 size); @@ -1639,27 +1646,17 @@ bool TextureSource::generateImagePart(std::string part_of_name, video::SColor color; int ratio = -1; + bool keep_alpha = false; if (!parseColorString(color_str, color, false)) return false; if (is_number(ratio_str)) ratio = mystoi(ratio_str, 0, 255); + else if (ratio_str == "alpha") + keep_alpha = true; - core::dimension2d dim = baseimg->getDimension(); - video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim); - - if (!img) { - errorstream << "generateImagePart(): Could not create image " - << "for part_of_name=\"" << part_of_name - << "\", cancelling." << std::endl; - return false; - } - - img->fill(video::SColor(color)); - // Overlay the colored image - blit_with_interpolate_overlay(img, baseimg, v2s32(0,0), v2s32(0,0), dim, ratio); - img->drop(); + apply_colorize(baseimg, v2s32(0, 0), baseimg->getDimension(), color, ratio, keep_alpha); } else if (str_starts_with(part_of_name, "[applyfiltersformesh")) { @@ -1783,6 +1780,44 @@ static void blit_with_interpolate_overlay(video::IImage *src, video::IImage *dst } } +/* + Apply color to destination +*/ +static void apply_colorize(video::IImage *dst, v2s32 dst_pos, v2u32 size, + video::SColor color, int ratio, bool keep_alpha) +{ + u32 alpha = color.getAlpha(); + video::SColor dst_c; + if ((ratio == -1 && alpha == 255) || ratio == 255) { // full replacement of color + if (keep_alpha) { // replace the color with alpha = dest alpha * color alpha + dst_c = color; + for (s32 y = dst_pos.Y; y < dst_pos.Y + size.Y; y++) + for (s32 x = dst_pos.X; x < dst_pos.X + size.X; x++) { + u32 dst_alpha = dst->getPixel(x, y).getAlpha(); + if (dst_alpha > 0) { + dst_c.setAlpha(dst_alpha * alpha / 255); + dst->setPixel(x, y, dst_c); + } + } + } else { // replace the color including the alpha + for (s32 y = dst_pos.Y; y < dst_pos.Y + size.Y; y++) + for (s32 x = dst_pos.X; x < dst_pos.X + size.X; x++) + if (dst->getPixel(x, y).getAlpha() > 0) + dst->setPixel(x, y, color); + } + } else { // interpolate between the color and destination + float interp = (ratio == -1 ? color.getAlpha() / 255.0f : ratio / 255.0f); + for (s32 y = dst_pos.Y; y < dst_pos.Y + size.Y; y++) + for (s32 x = dst_pos.X; x < dst_pos.X + size.X; x++) { + dst_c = dst->getPixel(x, y); + if (dst_c.getAlpha() > 0) { + dst_c = color.getInterpolated(dst_c, interp); + dst->setPixel(x, y, dst_c); + } + } + } +} + /* Apply mask to destination */