sw_engine: fix color burn/dodge edge cases

Dodge d / (1 - s):
- handle d = 0 first to avoid 0/0 when s = 1
- for d != 0 and s = 1, the formula results in d/0 (infinity),
  which maps to 1 in the 0-1 range (or 255 in the 0-255 range)

Burn 1 - (1 - d) / s:
- handle d = 1 first to avoid 0/0 when s = 0
- for d != 1 and s = 0, the formula results in  1 - 0/0 -> 1 - inf = -inf
  Negative infinity in the 0-1 range corresponds to the minimum possible
  value, which is 0 (255 if we operate in 0-255 range).
This commit is contained in:
Mira Grudzinska 2025-01-28 12:14:26 +01:00
parent bca94d244c
commit 6a00eb8db0

View file

@ -448,9 +448,9 @@ static inline uint32_t opBlendColorDodge(uint32_t s, uint32_t d, TVG_UNUSED uint
{
// d / (1 - s)
s = 0xffffffff - s;
auto c1 = (C1(s) == 0) ? C1(d) : std::min(C1(d) * 255 / C1(s), 255);
auto c2 = (C2(s) == 0) ? C2(d) : std::min(C2(d) * 255 / C2(s), 255);
auto c3 = (C3(s) == 0) ? C3(d) : std::min(C3(d) * 255 / C3(s), 255);
auto c1 = C1(d) == 0 ? 0 : (C1(s) == 0 ? 255 : std::min(C1(d) * 255 / C1(s), 255));
auto c2 = C2(d) == 0 ? 0 : (C2(s) == 0 ? 255 : std::min(C2(d) * 255 / C2(s), 255));
auto c3 = C3(d) == 0 ? 0 : (C3(s) == 0 ? 255 : std::min(C3(d) * 255 / C3(s), 255));
return JOIN(255, c1, c2, c3);
}
@ -458,9 +458,9 @@ static inline uint32_t opBlendColorBurn(uint32_t s, uint32_t d, TVG_UNUSED uint8
{
// 1 - (1 - d) / s
auto id = 0xffffffff - d;
auto c1 = (C1(s) == 0) ? C1(d) : 255 - std::min(C1(id) * 255 / C1(s), 255);
auto c2 = (C2(s) == 0) ? C2(d) : 255 - std::min(C2(id) * 255 / C2(s), 255);
auto c3 = (C3(s) == 0) ? C3(d) : 255 - std::min(C3(id) * 255 / C3(s), 255);
auto c1 = C1(d) == 255 ? 255 : (C1(s) == 0 ? 0 : 255 - std::min(C1(id) * 255 / C1(s), 255));
auto c2 = C2(d) == 255 ? 255 : (C2(s) == 0 ? 0 : 255 - std::min(C2(id) * 255 / C2(s), 255));
auto c3 = C3(d) == 255 ? 255 : (C3(s) == 0 ? 0 : 255 - std::min(C3(id) * 255 / C3(s), 255));
return JOIN(255, c1, c2, c3);
}