Skip to content

Commit

Permalink
Add an option to colorize to respect the destination alpha
Browse files Browse the repository at this point in the history
Also, rework the colorizing code to be more efficient.
  • Loading branch information
Samuel Sieb authored and kwolekr committed Apr 3, 2016
1 parent 66af984 commit 01ae43c
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 16 deletions.
9 changes: 7 additions & 2 deletions doc/lua_api.txt
Expand Up @@ -357,8 +357,13 @@ The mask is applied using binary AND.
#### `[colorize:<color>:<ratio>`
Colorize the textures with the given color.
`<color>` is specified as a `ColorString`.
`<ratio>` is an int ranging from 0 to 255, and specifies how much of the
color to apply. If ommitted, the alpha will be used.
`<ratio>` 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 `<color>`. If
omitted, the alpha of `<color>` 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
------
Expand Down
63 changes: 49 additions & 14 deletions src/client/tile.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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<u32> 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"))
{
Expand Down Expand Up @@ -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
*/
Expand Down

1 comment on commit 01ae43c

@est31
Copy link
Contributor

@est31 est31 commented on 01ae43c Apr 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kwolekr can you please tell who gave the second 👍 to this change?

The compiler warnings this commit added are fixed fortunately, but the documentation of the new feature is a bit weird and needs improvement.

Its good to have you back after your pause but the rules didn't change since then, and this feature certainly isn't trivial.

It would be great if you could motivate another dev to +1 this commit (or another dev already +1ed it) in the next three days, and get possibly suggested changes/fixes merged. If no dev +1es it in that time, I'll revert the commit (and the commit that fixes the compilation warnings, because otherwise stuff wont work anymore).

Please respond in this thread (I'm not closely reading every IRC line) or the pull request #3899.

Please sign in to comment.