premultiplied blends for most
This commit is contained in:
parent
8aab927127
commit
052e114db1
1 changed files with 168 additions and 78 deletions
|
@ -39,6 +39,24 @@ type
|
|||
when defined(release):
|
||||
{.push checks: off.}
|
||||
|
||||
proc min(a, b: uint32): uint32 {.inline.} =
|
||||
if a < b: a else: b
|
||||
|
||||
proc max(a, b: uint32): uint32 {.inline.} =
|
||||
if a > b: a else: b
|
||||
|
||||
proc screenPremultiplied(backdrop, source: uint32): uint8 {.inline.} =
|
||||
(255 - ((255 - backdrop) * (255 - source)) div 255).uint8
|
||||
|
||||
proc hardLightPremultiplied(backdrop, source: uint32): uint8 {.inline.} =
|
||||
if source <= 127:
|
||||
((backdrop * 2 * source) div 255).uint8
|
||||
else:
|
||||
screenPremultiplied(backdrop, 2 * source - 255)
|
||||
|
||||
proc blendAlpha(backdrop, source: uint8): uint8 {.inline.} =
|
||||
source + ((backdrop.uint32 * (255 - source)) div 255).uint8
|
||||
|
||||
proc blendNormalPremultiplied*(backdrop, source: ColorRGBA): ColorRGBA {.inline.} =
|
||||
if backdrop.a == 0:
|
||||
return source
|
||||
|
@ -51,7 +69,95 @@ proc blendNormalPremultiplied*(backdrop, source: ColorRGBA): ColorRGBA {.inline.
|
|||
result.r = source.r + ((backdrop.r.uint32 * k) div 255).uint8
|
||||
result.g = source.g + ((backdrop.g.uint32 * k) div 255).uint8
|
||||
result.b = source.b + ((backdrop.b.uint32 * k) div 255).uint8
|
||||
result.a = source.a + ((backdrop.a.uint32 * k) div 255).uint8
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendDarkenPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = min(backdrop.r, source.r)
|
||||
result.g = min(backdrop.g, source.g)
|
||||
result.b = min(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendMultiplyPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = ((backdrop.r.uint32 * source.r) div 255).uint8
|
||||
result.g = ((backdrop.g.uint32 * source.g) div 255).uint8
|
||||
result.b = ((backdrop.b.uint32 * source.b) div 255).uint8
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendLinearBurnPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = min(0, backdrop.r.uint32 + source.r.uint32 - 255).uint8
|
||||
result.g = min(0, backdrop.g.uint32 + source.g.uint32 - 255).uint8
|
||||
result.b = min(0, backdrop.b.uint32 + source.b.uint32 - 255).uint8
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendLightenPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = max(backdrop.r, source.r)
|
||||
result.g = max(backdrop.g, source.g)
|
||||
result.b = max(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendColorBurnPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||
if backdrop == 255:
|
||||
255.uint8
|
||||
elif source == 0:
|
||||
0
|
||||
else:
|
||||
255 - min(255, (255 * (255 - backdrop)) div source).uint8
|
||||
result.r = blend(backdrop.r, source.r)
|
||||
result.g = blend(backdrop.g, source.g)
|
||||
result.b = blend(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendScreenPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = screenPremultiplied(backdrop.r, source.r)
|
||||
result.g = screenPremultiplied(backdrop.g, source.g)
|
||||
result.b = screenPremultiplied(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendLinearDodgePremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = min(backdrop.r.uint32 + source.r, 255).uint8
|
||||
result.g = min(backdrop.g.uint32 + source.g, 255).uint8
|
||||
result.b = min(backdrop.b.uint32 + source.b, 255).uint8
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendColorDodgePremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||
if backdrop == 0:
|
||||
0.uint8
|
||||
elif source == 255:
|
||||
255
|
||||
else:
|
||||
min(255, (255 * backdrop) div (255 - source)).uint8
|
||||
result.r = blend(backdrop.r, source.r)
|
||||
result.g = blend(backdrop.g, source.g)
|
||||
result.b = blend(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendOverlayPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = hardLightPremultiplied(source.r, backdrop.r)
|
||||
result.g = hardLightPremultiplied(source.g, backdrop.g)
|
||||
result.b = hardLightPremultiplied(source.b, backdrop.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendHardLightyPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = hardLightPremultiplied(backdrop.r, source.r)
|
||||
result.g = hardLightPremultiplied(backdrop.g, source.g)
|
||||
result.b = hardLightPremultiplied(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendDifferencePremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = max(backdrop.r, source.r) - min(backdrop.r, source.r)
|
||||
result.g = max(backdrop.g, source.g) - min(backdrop.g, source.g)
|
||||
result.b = max(backdrop.b, source.b) - min(backdrop.b, source.b)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
proc blendExclusionPremultiplied(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||
max(0, backdrop + source - (2 * backdrop * source) div 255).uint8
|
||||
result.r = blend(backdrop.r.uint32, source.r.uint32)
|
||||
result.g = blend(backdrop.g.uint32, source.g.uint32)
|
||||
result.b = blend(backdrop.b.uint32, source.b.uint32)
|
||||
result.a = blendAlpha(backdrop.a, source.a)
|
||||
|
||||
when defined(amd64) and not defined(pixieNoSimd):
|
||||
proc blendNormalPremultiplied*(backdrop, source: M128i): M128i {.inline.} =
|
||||
|
@ -371,18 +477,6 @@ else:
|
|||
result.b = (b div a div 255).uint8
|
||||
result.a = a.uint8
|
||||
|
||||
proc min(a, b: uint32): uint32 {.inline.} =
|
||||
if a < b: a else: b
|
||||
|
||||
proc screen(backdrop, source: uint32): uint8 {.inline.} =
|
||||
(255 - ((255 - backdrop) * (255 - source)) div 255).uint8
|
||||
|
||||
proc hardLight(backdrop, source: uint32): uint8 {.inline.} =
|
||||
if source <= 127:
|
||||
((backdrop * 2 * source) div 255).uint8
|
||||
else:
|
||||
screen(backdrop, 2 * source - 255)
|
||||
|
||||
proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
blendNormalPremultiplied(
|
||||
backdrop.toPremultipliedAlpha(),
|
||||
|
@ -390,78 +484,74 @@ proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
|||
).toStraightAlpha()
|
||||
|
||||
proc blendDarken(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = min(backdrop.r, source.r)
|
||||
result.g = min(backdrop.g, source.g)
|
||||
result.b = min(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendDarkenPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendMultiply(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = ((backdrop.r.uint32 * source.r) div 255).uint8
|
||||
result.g = ((backdrop.g.uint32 * source.g) div 255).uint8
|
||||
result.b = ((backdrop.b.uint32 * source.b) div 255).uint8
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendMultiplyPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendLinearBurn(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = min(0, backdrop.r.int16 + source.r.int16 - 255).uint8
|
||||
result.g = min(0, backdrop.g.int16 + source.g.int16 - 255).uint8
|
||||
result.b = min(0, backdrop.b.int16 + source.b.int16 - 255).uint8
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendLinearBurnPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendColorBurn(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||
if backdrop == 255:
|
||||
255.uint8
|
||||
elif source == 0:
|
||||
0
|
||||
else:
|
||||
255 - min(255, (255 * (255 - backdrop)) div source).uint8
|
||||
result.r = blend(backdrop.r, source.r)
|
||||
result.g = blend(backdrop.g, source.g)
|
||||
result.b = blend(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendColorBurnPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendLighten(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = max(backdrop.r, source.r)
|
||||
result.g = max(backdrop.g, source.g)
|
||||
result.b = max(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendLightenPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendScreen(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = screen(backdrop.r, source.r)
|
||||
result.g = screen(backdrop.g, source.g)
|
||||
result.b = screen(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendScreenPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendLinearDodge(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = min(backdrop.r.uint32 + source.r, 255).uint8
|
||||
result.g = min(backdrop.g.uint32 + source.g, 255).uint8
|
||||
result.b = min(backdrop.b.uint32 + source.b, 255).uint8
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendLinearDodgePremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendColorDodge(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||
if backdrop == 0:
|
||||
0.uint8
|
||||
elif source == 255:
|
||||
255
|
||||
else:
|
||||
min(255, (255 * backdrop) div (255 - source)).uint8
|
||||
result.r = blend(backdrop.r, source.r)
|
||||
result.g = blend(backdrop.g, source.g)
|
||||
result.b = blend(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendColorDodgePremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendOverlay(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = hardLight(source.r, backdrop.r)
|
||||
result.g = hardLight(source.g, backdrop.g)
|
||||
result.b = hardLight(source.b, backdrop.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendOverlayPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendHardLight(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = hardLight(backdrop.r, source.r)
|
||||
result.g = hardLight(backdrop.g, source.g)
|
||||
result.b = hardLight(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendHardLightyPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendSoftLight(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
# proc softLight(backdrop, source: int32): uint8 {.inline.} =
|
||||
|
@ -489,18 +579,18 @@ proc blendSoftLight(backdrop, source: ColorRGBA): ColorRGBA =
|
|||
blendSoftLightFloats(backdrop.color, source.color).rgba
|
||||
|
||||
proc blendDifference(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result.r = max(backdrop.r, source.r) - min(backdrop.r, source.r)
|
||||
result.g = max(backdrop.g, source.g) - min(backdrop.g, source.g)
|
||||
result.b = max(backdrop.b, source.b) - min(backdrop.b, source.b)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendDifferencePremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendExclusion(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
proc blend(backdrop, source: int32): uint8 {.inline.} =
|
||||
max(0, backdrop + source - (2 * backdrop * source) div 255).uint8
|
||||
result.r = blend(backdrop.r.int32, source.r.int32)
|
||||
result.g = blend(backdrop.g.int32, source.g.int32)
|
||||
result.b = blend(backdrop.b.int32, source.b.int32)
|
||||
result = alphaFix(backdrop, source, result)
|
||||
let
|
||||
backdrop = backdrop.toPremultipliedAlpha()
|
||||
source = source.toPremultipliedAlpha()
|
||||
result = blendExclusionPremultiplied(backdrop, source)
|
||||
result = result.toStraightAlpha()
|
||||
|
||||
proc blendColor(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
blendColorFloats(backdrop.color, source.color).rgba
|
||||
|
@ -520,7 +610,7 @@ proc blendMask(backdrop, source: ColorRGBA): ColorRGBA =
|
|||
|
||||
proc blendSubtractMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result = backdrop
|
||||
result.a = max(0, (backdrop.a.int32 * (255 - source.a.int32)) div 255).uint8
|
||||
result.a = max(0, (backdrop.a.uint32 * (255 - source.a.uint32)) div 255).uint8
|
||||
|
||||
proc blendIntersectMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||
result = backdrop
|
||||
|
|
Loading…
Reference in a new issue