diff --git a/source/blender/blenlib/intern/math_color_blend_inline.cc b/source/blender/blenlib/intern/math_color_blend_inline.cc index 0a047f1645e..02baa3b2ad5 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.cc +++ b/source/blender/blenlib/intern/math_color_blend_inline.cc @@ -329,21 +329,19 @@ MINLINE void blend_color_screen_byte(uchar dst[4], const uchar src1[4], const uc MINLINE void blend_color_softlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4]) { - const int fac = src2[3]; + const float fac = (float)(src2[3]) / 255.0f; if (fac != 0) { - const int mfac = 255 - fac; + const float mfac = 1.0f - fac; int i = 3; while (i--) { - int temp; - - if (src1[i] < 127) { - temp = ((2 * ((src2[i] / 2) + 64)) * src1[i]) / 255; - } - else { - temp = 255 - (2 * (255 - ((src2[i] / 2) + 64)) * (255 - src1[i]) / 255); - } - dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255); + /* Using "Pegtop" formula: dst = (1 - 2b) * a^2 + 2ab where a=bottom and b=top color. + * See https://en.wikipedia.org/wiki/Blend_modes */ + const float src1val = (float)(src1[i]) / 255.0f; + const float src2val = (float)(src2[i]) / 255.0f; + float screen = 1.0f - (1.0f - src1val) * (1.0f - src2val); + float soft_light = ((1.0f - src1val) * src2val + screen) * src1val; + dst[i] = round_fl_to_uchar_clamp((src1val * mfac + soft_light * fac) * 255.0f); } } else { diff --git a/source/blender/blenlib/tests/BLI_math_color_test.cc b/source/blender/blenlib/tests/BLI_math_color_test.cc index 7ce20b3a096..c4eb1247cf7 100644 --- a/source/blender/blenlib/tests/BLI_math_color_test.cc +++ b/source/blender/blenlib/tests/BLI_math_color_test.cc @@ -5,6 +5,7 @@ #include "testing/testing.h" #include "BLI_math_color.h" +#include "BLI_math_color_blend.h" TEST(math_color, RGBToHSVRoundtrip) { @@ -138,3 +139,41 @@ TEST(math_color, srgb_to_linearrgb_v3_v3) EXPECT_NEAR(56.2383270264f, linear_color[2], kTolerance); } } + +TEST(math_color, BlendModeConsistency_SoftLight) +{ + float fdst[4]; + float fcolora[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float fcolorb[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float fcolorc[4] = {1.0f, 1.0f, 1.0f, 0.5f}; + float fcolord[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + uchar bdst[4]; + uchar bcolora[4] = {0, 0, 0, 255}; + uchar bcolorb[4] = {255, 255, 255, 255}; + uchar bcolorc[4] = {255, 255, 255, 128}; + uchar bcolord[4] = {128, 128, 128, 128}; + + blend_color_softlight_float(fdst, fcolora, fcolorb); + blend_color_softlight_byte(bdst, bcolora, bcolorb); + EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f); + EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f); + EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f); + + blend_color_softlight_float(fdst, fcolorb, fcolora); + blend_color_softlight_byte(bdst, bcolorb, bcolora); + EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f); + EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f); + EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f); + + blend_color_softlight_float(fdst, fcolorc, fcolora); + blend_color_softlight_byte(bdst, bcolorc, bcolora); + EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f); + EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f); + EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f); + + blend_color_softlight_float(fdst, fcolorc, fcolord); + blend_color_softlight_byte(bdst, bcolorc, bcolord); + EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f); + EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f); + EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f); +} diff --git a/tests/data b/tests/data index b46f3933207..2de4677cbd2 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit b46f39332078df1a91541f920ee52ae820b707bf +Subproject commit 2de4677cbd20fe011de33ae76c3e97d119b9748c