1
0
mirror of synced 2024-11-12 01:00:46 +01:00

Implement (incorrect) version of blend mode 13.

This commit is contained in:
Jennifer Taylor 2021-09-20 18:22:56 +00:00
parent 38f8c94ed0
commit 6569925b18
3 changed files with 54 additions and 15 deletions

View File

@ -121,6 +121,26 @@ def blend_multiply(
)
def blend_overlay(
# RGBA color tuple representing what's already at the dest.
dest: Sequence[int],
# RGBA color tuple representing the source we want to blend to the dest.
src: Sequence[int],
) -> Sequence[int]:
# "Overlay" blend mode. Various games use the DX equation Src * Dst + Dst * Src. It appears that
# jubeat uses the alternative formula Src * Dst + Dst * (1 - As).
# Calculate final color blending.
src_alpha = src[3] / 255.0
src_remainder = 1.0 - src_alpha
return (
clamp((255 * (2.0 * (dest[0] / 255.0) * (src[0] / 255.0) * src_alpha)) + (dest[0] * src_remainder)),
clamp((255 * (2.0 * (dest[1] / 255.0) * (src[1] / 255.0) * src_alpha)) + (dest[1] * src_remainder)),
clamp((255 * (2.0 * (dest[2] / 255.0) * (src[2] / 255.0) * src_alpha)) + (dest[2] * src_remainder)),
dest[3],
)
def blend_mask_create(
# RGBA color tuple representing what's already at the dest.
dest: Sequence[int],
@ -175,14 +195,14 @@ def blend_point(
# premultiply by alpha, but the GL/DX equation is max(Src * As, Dst * 1).
# TODO: blend mode 6, which is "darken" blending according to SWF references. Jubeat does not
# premultiply by alpha, but the GL/DX equation is min(Src * As, Dst * 1).
# TODO: blend mode 10, which is "invert" according to SWF references. The only game I could find
# that implemented this had equation Src * (1 - Dst) + Dst * (1 - As).
# TODO: blend mode 13, which is "overlay" according to SWF references. The equation seems to be
# Src * Dst + Dst * Src but Jubeat thinks it should be Src * Dst + Dst * (1 - As).
elif blendfunc == 8:
return blend_addition(dest_color, src_color)
elif blendfunc == 9 or blendfunc == 70:
return blend_subtraction(dest_color, src_color)
# TODO: blend mode 10, which is "invert" according to SWF references. The only game I could find
# that implemented this had equation Src * (1 - Dst) + Dst * (1 - As).
if blendfunc == 13:
return blend_overlay(dest_color, src_color)
# TODO: blend mode 75, which is not in the SWF spec and appears to have the equation
# Src * (1 - Dst) + Dst * (1 - Src).
elif blendfunc == 256:
@ -440,7 +460,7 @@ def affine_composite(
return img
# Warn if we have an unsupported blend.
if blendfunc not in {0, 1, 2, 3, 8, 9, 70, 256, 257}:
if blendfunc not in {0, 1, 2, 3, 8, 9, 13, 70, 256, 257}:
print(f"WARNING: Unsupported blend {blendfunc}")
return img
@ -656,7 +676,7 @@ def perspective_composite(
aa_mode: int = AAMode.SSAA_ONLY,
) -> Image.Image:
# Warn if we have an unsupported blend.
if blendfunc not in {0, 1, 2, 3, 8, 9, 70, 256, 257}:
if blendfunc not in {0, 1, 2, 3, 8, 9, 13, 70, 256, 257}:
print(f"WARNING: Unsupported blend {blendfunc}")
return img

View File

@ -59,6 +59,10 @@ def affine_composite(
single_threaded: bool = False,
aa_mode: int = AAMode.SSAA_OR_BILINEAR,
) -> Image.Image:
if blendfunc not in {0, 1, 2, 3, 8, 9, 13, 70, 256, 257}:
print(f"WARNING: Unsupported blend {blendfunc}")
return img
# Calculate the inverse so we can map canvas space back to texture space.
try:
inverse = transform.inverse()
@ -68,10 +72,6 @@ def affine_composite(
# be drawn.
return img
if blendfunc not in {0, 1, 2, 3, 8, 9, 70, 256, 257}:
print(f"WARNING: Unsupported blend {blendfunc}")
return img
# These are calculated properties and caching them outside of the loop
# speeds things up a bit.
imgwidth = img.width
@ -166,7 +166,7 @@ def perspective_composite(
single_threaded: bool = False,
aa_mode: int = AAMode.SSAA_ONLY,
) -> Image.Image:
if blendfunc not in {0, 1, 2, 3, 8, 9, 70, 256, 257}:
if blendfunc not in {0, 1, 2, 3, 8, 9, 13, 70, 256, 257}:
print(f"WARNING: Unsupported blend {blendfunc}")
return img

View File

@ -196,6 +196,24 @@ extern "C"
};
}
intcolor_t blend_overlay(
intcolor_t dest,
intcolor_t src
) {
// "Overlay" blend mode. Various games use the DX equation Src * Dst + Dst * Src. It appears that
// jubeat uses the alternative formula Src * Dst + Dst * (1 - As).
// Calculate final color blending.
double src_alpha = src.a / 255.0;
double src_remainder = 1.0 - src_alpha;
return (intcolor_t){
clamp((255 * (2.0 * (dest.r / 255.0) * (src.r / 255.0) * src_alpha)) + (dest.r * src_remainder)),
clamp((255 * (2.0 * (dest.g / 255.0) * (src.g / 255.0) * src_alpha)) + (dest.g * src_remainder)),
clamp((255 * (2.0 * (dest.b / 255.0) * (src.b / 255.0) * src_alpha)) + (dest.b * src_remainder)),
dest.a,
};
}
intcolor_t blend_mask_create(
intcolor_t dest,
intcolor_t src
@ -247,16 +265,17 @@ extern "C"
// premultiply by alpha, but the GL/DX equation is max(Src * As, Dst * 1).
// TODO: blend mode 6, which is "darken" blending according to SWF references. Jubeat does not
// premultiply by alpha, but the GL/DX equation is min(Src * As, Dst * 1).
// TODO: blend mode 10, which is "invert" according to SWF references. The only game I could find
// that implemented this had equation Src * (1 - Dst) + Dst * (1 - As).
// TODO: blend mode 13, which is "overlay" according to SWF references. The equation seems to be
// Src * Dst + Dst * Src but Jubeat thinks it should be Src * Dst + Dst * (1 - As).
if (blendfunc == 8) {
return blend_addition(dest_color, src_color);
}
if (blendfunc == 9 || blendfunc == 70) {
return blend_subtraction(dest_color, src_color);
}
// TODO: blend mode 10, which is "invert" according to SWF references. The only game I could find
// that implemented this had equation Src * (1 - Dst) + Dst * (1 - As).
if (blendfunc == 13) {
return blend_overlay(dest_color, src_color);
}
if (blendfunc == 256) {
return blend_mask_combine(dest_color, src_color);
}