rest of blends work by converting back to straight alpha first (except 2 missing tests)
This commit is contained in:
parent
0cdb84407b
commit
cc63165c9b
2 changed files with 350 additions and 581 deletions
|
@ -1,6 +1,9 @@
|
||||||
## Blending modes.
|
## Blending modes.
|
||||||
import chroma, math, common
|
import chroma, math, common
|
||||||
|
|
||||||
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
|
import nimsimd/sse2
|
||||||
|
|
||||||
# See https://www.w3.org/TR/compositing-1/
|
# See https://www.w3.org/TR/compositing-1/
|
||||||
# See https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_blend_equation_advanced.txt
|
# See https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_blend_equation_advanced.txt
|
||||||
|
|
||||||
|
@ -37,9 +40,120 @@ type
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.push checks: off.}
|
{.push checks: off.}
|
||||||
|
|
||||||
|
proc min(a, b: uint32): uint32 {.inline.} =
|
||||||
|
if a < b: a else: b
|
||||||
|
|
||||||
|
proc alphaFix(backdrop, source, mixed: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
sa = source.a.uint32
|
||||||
|
ba = backdrop.a.uint32
|
||||||
|
t0 = sa * (255 - ba)
|
||||||
|
t1 = sa * ba
|
||||||
|
t2 = (255 - sa) * ba
|
||||||
|
|
||||||
|
let
|
||||||
|
r = t0 * source.r.uint32 + t1 * mixed.r.uint32 + t2 * backdrop.r.uint32
|
||||||
|
g = t0 * source.g.uint32 + t1 * mixed.g.uint32 + t2 * backdrop.g.uint32
|
||||||
|
b = t0 * source.b.uint32 + t1 * mixed.b.uint32 + t2 * backdrop.b.uint32
|
||||||
|
a = sa + ba * (255 - sa) div 255
|
||||||
|
|
||||||
|
if a == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
result.r = (r div a div 255).uint8
|
||||||
|
result.g = (g div a div 255).uint8
|
||||||
|
result.b = (b div a div 255).uint8
|
||||||
|
result.a = a.uint8
|
||||||
|
|
||||||
|
proc alphaFix(backdrop, source, mixed: Color): Color =
|
||||||
|
result.a = (source.a + backdrop.a * (1.0 - source.a))
|
||||||
|
if result.a == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
let
|
||||||
|
t0 = source.a * (1 - backdrop.a)
|
||||||
|
t1 = source.a * backdrop.a
|
||||||
|
t2 = (1 - source.a) * backdrop.a
|
||||||
|
|
||||||
|
result.r = t0 * source.r + t1 * mixed.r + t2 * backdrop.r
|
||||||
|
result.g = t0 * source.g + t1 * mixed.g + t2 * backdrop.g
|
||||||
|
result.b = t0 * source.b + t1 * mixed.b + t2 * backdrop.b
|
||||||
|
|
||||||
|
result.r /= result.a
|
||||||
|
result.g /= result.a
|
||||||
|
result.b /= result.a
|
||||||
|
|
||||||
proc blendAlpha*(backdrop, source: uint8): uint8 {.inline.} =
|
proc blendAlpha*(backdrop, source: uint8): uint8 {.inline.} =
|
||||||
source + ((backdrop.uint32 * (255 - source)) div 255).uint8
|
source + ((backdrop.uint32 * (255 - source)) div 255).uint8
|
||||||
|
|
||||||
|
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 softLight(backdrop, source: float32): float32 {.inline.} =
|
||||||
|
## Pegtop
|
||||||
|
(1 - 2 * source) * backdrop ^ 2 + 2 * source * backdrop
|
||||||
|
|
||||||
|
proc `+`(c: Color, v: float32): Color {.inline.} =
|
||||||
|
result.r = c.r + v
|
||||||
|
result.g = c.g + v
|
||||||
|
result.b = c.b + v
|
||||||
|
result.a = c.a + v
|
||||||
|
|
||||||
|
proc `+`(v: float32, c: Color): Color {.inline.} =
|
||||||
|
c + v
|
||||||
|
|
||||||
|
proc `*`(c: Color, v: float32): Color {.inline.} =
|
||||||
|
result.r = c.r * v
|
||||||
|
result.g = c.g * v
|
||||||
|
result.b = c.b * v
|
||||||
|
result.a = c.a * v
|
||||||
|
|
||||||
|
proc `/`(c: Color, v: float32): Color {.inline.} =
|
||||||
|
result.r = c.r / v
|
||||||
|
result.g = c.g / v
|
||||||
|
result.b = c.b / v
|
||||||
|
result.a = c.a / v
|
||||||
|
|
||||||
|
proc `-`(c: Color, v: float32): Color {.inline.} =
|
||||||
|
result.r = c.r - v
|
||||||
|
result.g = c.g - v
|
||||||
|
result.b = c.b - v
|
||||||
|
result.a = c.a - v
|
||||||
|
|
||||||
|
proc Lum(C: Color): float32 {.inline.} =
|
||||||
|
0.3 * C.r + 0.59 * C.g + 0.11 * C.b
|
||||||
|
|
||||||
|
proc ClipColor(C: var Color) {.inline.} =
|
||||||
|
let
|
||||||
|
L = Lum(C)
|
||||||
|
n = min([C.r, C.g, C.b])
|
||||||
|
x = max([C.r, C.g, C.b])
|
||||||
|
if n < 0:
|
||||||
|
C = L + (((C - L) * L) / (L - n))
|
||||||
|
if x > 1:
|
||||||
|
C = L + (((C - L) * (1 - L)) / (x - L))
|
||||||
|
|
||||||
|
proc SetLum(C: Color, l: float32): Color {.inline.} =
|
||||||
|
let d = l - Lum(C)
|
||||||
|
result.r = C.r + d
|
||||||
|
result.g = C.g + d
|
||||||
|
result.b = C.b + d
|
||||||
|
ClipColor(result)
|
||||||
|
|
||||||
|
proc Sat(C: Color): float32 {.inline.} =
|
||||||
|
max([C.r, C.g, C.b]) - min([C.r, C.g, C.b])
|
||||||
|
|
||||||
|
proc SetSat(C: Color, s: float32): Color {.inline.} =
|
||||||
|
let satC = Sat(C)
|
||||||
|
if satC > 0:
|
||||||
|
result = (C - min([C.r, C.g, C.b])) * s / satC
|
||||||
|
|
||||||
proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
if backdrop.a == 0:
|
if backdrop.a == 0:
|
||||||
return source
|
return source
|
||||||
|
@ -54,6 +168,198 @@ proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.b = source.b + ((backdrop.b.uint32 * k) div 255).uint8
|
result.b = source.b + ((backdrop.b.uint32 * k) div 255).uint8
|
||||||
result.a = blendAlpha(backdrop.a, source.a)
|
result.a = blendAlpha(backdrop.a, source.a)
|
||||||
|
|
||||||
|
proc blendDarken(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendMultiply(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendLinearBurn(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
result.r = min(0, backdrop.r.int32 + source.r.int32 - 255).uint8
|
||||||
|
result.g = min(0, backdrop.g.int32 + source.g.int32 - 255).uint8
|
||||||
|
result.b = min(0, backdrop.b.int32 + source.b.int32 - 255).uint8
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendColorBurn(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendLighten(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendScreen(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendLinearDodge(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendColorDodge(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendOverlay(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendSoftLight(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
# proc softLight(backdrop, source: int32): uint8 {.inline.} =
|
||||||
|
# ## Pegtop
|
||||||
|
# (
|
||||||
|
# ((255 - 2 * source) * backdrop ^ 2) div 255 ^ 2 +
|
||||||
|
# (2 * source * backdrop) div 255
|
||||||
|
# ).uint8
|
||||||
|
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
|
||||||
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
|
let
|
||||||
|
vb = mm_setr_ps(backdrop.r.float32, backdrop.g.float32, backdrop.b.float32, 0)
|
||||||
|
vs = mm_setr_ps(source.r.float32, source.g.float32, source.b.float32, 0)
|
||||||
|
v2 = mm_set1_ps(2)
|
||||||
|
v255 = mm_set1_ps(255)
|
||||||
|
v255sq = mm_set1_ps(255 * 255)
|
||||||
|
vm = ((v255 - v2 * vs) * vb * vb) / v255sq + (v2 * vs * vb) / v255
|
||||||
|
values = cast[array[4, uint32]](mm_cvtps_epi32(vm))
|
||||||
|
|
||||||
|
result.r = values[0].uint8
|
||||||
|
result.g = values[1].uint8
|
||||||
|
result.b = values[2].uint8
|
||||||
|
|
||||||
|
# proc alphaFix(backdrop, source, mixed: ColorRGBA): ColorRGBA {.inline.} =
|
||||||
|
# if backdrop.a == 0 and source.a == 0:
|
||||||
|
# return
|
||||||
|
# let
|
||||||
|
# vb = mm_setr_ps(backdrop.r.float32, backdrop.g.float32, backdrop.b.float32, 0)
|
||||||
|
# vs = mm_setr_ps(source.r.float32, source.g.float32, source.b.float32, 0)
|
||||||
|
# vm = mm_setr_ps(mixed.r.float32, mixed.g.float32, mixed.b.float32, 0)
|
||||||
|
# alphaFix(backdrop, source, vb, vs, vm)
|
||||||
|
|
||||||
|
let
|
||||||
|
sa = source.a.float32
|
||||||
|
ba = backdrop.a.float32
|
||||||
|
a = sa + ba * (255 - sa) / 255
|
||||||
|
if a == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
let
|
||||||
|
t0 = mm_set1_ps(sa * (255 - ba))
|
||||||
|
t1 = mm_set1_ps(sa * ba)
|
||||||
|
t2 = mm_set1_ps((255 - sa) * ba)
|
||||||
|
va = mm_set1_ps(a)
|
||||||
|
final = cast[array[4, uint32]](
|
||||||
|
mm_cvtps_epi32((t0 * vs + t1 * vm + t2 * vb) / va / v255)
|
||||||
|
)
|
||||||
|
|
||||||
|
result.r = final[0].uint8
|
||||||
|
result.g = final[1].uint8
|
||||||
|
result.b = final[2].uint8
|
||||||
|
result.a = a.uint8
|
||||||
|
else:
|
||||||
|
let
|
||||||
|
b = backdrop.color
|
||||||
|
s = source.color
|
||||||
|
var blended: Color
|
||||||
|
blended.r = softLight(b.r, s.r)
|
||||||
|
blended.g = softLight(b.g, s.g)
|
||||||
|
blended.b = softLight(b.b, s.b)
|
||||||
|
blended = alphaFix(b, s, blended)
|
||||||
|
result = blended.rgba
|
||||||
|
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendHardLight(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendDifference(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha()
|
||||||
|
source = source.toStraightAlpha()
|
||||||
|
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)
|
||||||
|
result = result.toPremultipliedAlpha()
|
||||||
|
|
||||||
proc blendExclusion(backdrop, source: ColorRGBA): ColorRGBA =
|
proc blendExclusion(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||||
let v = (backdrop + source).int32 - ((2 * backdrop * source) div 255).int32
|
let v = (backdrop + source).int32 - ((2 * backdrop * source) div 255).int32
|
||||||
|
@ -63,6 +369,34 @@ proc blendExclusion(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.b = blend(backdrop.b.uint32, source.b.uint32)
|
result.b = blend(backdrop.b.uint32, source.b.uint32)
|
||||||
result.a = blendAlpha(backdrop.a, source.a)
|
result.a = blendAlpha(backdrop.a, source.a)
|
||||||
|
|
||||||
|
proc blendColor(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha().color
|
||||||
|
source = source.toStraightAlpha().color
|
||||||
|
blended = SetLum(source, Lum(backdrop))
|
||||||
|
result = alphaFix(backdrop, source, blended).rgba.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendLuminosity(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha().color
|
||||||
|
source = source.toStraightAlpha().color
|
||||||
|
blended = SetLum(backdrop, Lum(source))
|
||||||
|
result = alphaFix(backdrop, source, blended).rgba.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendHue(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha().color
|
||||||
|
source = source.toStraightAlpha().color
|
||||||
|
blended = SetLum(SetSat(source, Sat(backdrop)), Lum(backdrop))
|
||||||
|
result = alphaFix(backdrop, source, blended).rgba.toPremultipliedAlpha()
|
||||||
|
|
||||||
|
proc blendSaturation(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
|
let
|
||||||
|
backdrop = backdrop.toStraightAlpha().color
|
||||||
|
source = source.toStraightAlpha().color
|
||||||
|
blended = SetLum(SetSat(backdrop, Sat(source)), Lum(backdrop))
|
||||||
|
result = alphaFix(backdrop, source, blended).rgba.toPremultipliedAlpha()
|
||||||
|
|
||||||
proc blendMask(backdrop, source: ColorRGBA): ColorRGBA =
|
proc blendMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
let k = source.a.uint32
|
let k = source.a.uint32
|
||||||
result.r = ((backdrop.r * k) div 255).uint8
|
result.r = ((backdrop.r * k) div 255).uint8
|
||||||
|
@ -97,31 +431,31 @@ proc blendWhite(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
proc blender*(blendMode: BlendMode): Blender =
|
proc blender*(blendMode: BlendMode): Blender =
|
||||||
case blendMode:
|
case blendMode:
|
||||||
of bmNormal: blendNormal
|
of bmNormal: blendNormal
|
||||||
# of bmDarken: blendDarken
|
of bmDarken: blendDarken
|
||||||
# of bmMultiply: blendMultiply
|
of bmMultiply: blendMultiply
|
||||||
# of bmLinearBurn: blendLinearBurn
|
# of bmLinearBurn: blendLinearBurn
|
||||||
# of bmColorBurn: blendColorBurn
|
of bmColorBurn: blendColorBurn
|
||||||
# of bmLighten: blendLighten
|
of bmLighten: blendLighten
|
||||||
# of bmScreen: blendScreen
|
of bmScreen: blendScreen
|
||||||
# of bmLinearDodge: blendLinearDodge
|
# of bmLinearDodge: blendLinearDodge
|
||||||
# of bmColorDodge: blendColorDodge
|
of bmColorDodge: blendColorDodge
|
||||||
# of bmOverlay: blendOverlay
|
of bmOverlay: blendOverlay
|
||||||
# of bmSoftLight: blendSoftLight
|
of bmSoftLight: blendSoftLight
|
||||||
# of bmHardLight: blendHardLight
|
of bmHardLight: blendHardLight
|
||||||
# of bmDifference: blendDifference
|
of bmDifference: blendDifference
|
||||||
of bmExclusion: blendExclusion
|
of bmExclusion: blendExclusion
|
||||||
# of bmHue: blendHue
|
of bmHue: blendHue
|
||||||
# of bmSaturation: blendSaturation
|
of bmSaturation: blendSaturation
|
||||||
# of bmColor: blendColor
|
of bmColor: blendColor
|
||||||
# of bmLuminosity: blendLuminosity
|
of bmLuminosity: blendLuminosity
|
||||||
of bmMask: blendMask
|
of bmMask: blendMask
|
||||||
of bmOverwrite: blendOverwrite
|
of bmOverwrite: blendOverwrite
|
||||||
of bmSubtractMask: blendSubtractMask
|
of bmSubtractMask: blendSubtractMask
|
||||||
of bmIntersectMask: blendIntersectMask
|
of bmIntersectMask: blendIntersectMask
|
||||||
of bmExcludeMask: blendExcludeMask
|
of bmExcludeMask: blendExcludeMask
|
||||||
else:
|
else:
|
||||||
# blendWhite
|
blendWhite
|
||||||
blendNormal
|
# blendNormal
|
||||||
# raise newException(PixieError, "No blender for " & $blendMode)
|
# raise newException(PixieError, "No blender for " & $blendMode)
|
||||||
|
|
||||||
proc maskMask(backdrop, source: uint8): uint8 =
|
proc maskMask(backdrop, source: uint8): uint8 =
|
||||||
|
@ -195,392 +529,3 @@ when defined(amd64) and not defined(pixieNoSimd):
|
||||||
|
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc `+`*(a, b: Color): Color {.inline.} =
|
|
||||||
result.r = a.r + b.r
|
|
||||||
result.g = a.g + b.g
|
|
||||||
result.b = a.b + b.b
|
|
||||||
result.a = a.a + b.a
|
|
||||||
|
|
||||||
proc `+`*(c: Color, v: float32): Color {.inline.} =
|
|
||||||
result.r = c.r + v
|
|
||||||
result.g = c.g + v
|
|
||||||
result.b = c.b + v
|
|
||||||
result.a = c.a + v
|
|
||||||
|
|
||||||
proc `+`*(v: float32, c: Color): Color {.inline.} =
|
|
||||||
c + v
|
|
||||||
|
|
||||||
proc `*`*(c: Color, v: float32): Color {.inline.} =
|
|
||||||
result.r = c.r * v
|
|
||||||
result.g = c.g * v
|
|
||||||
result.b = c.b * v
|
|
||||||
result.a = c.a * v
|
|
||||||
|
|
||||||
proc `*`*(v: float32, target: Color): Color {.inline.} =
|
|
||||||
target * v
|
|
||||||
|
|
||||||
proc `/`*(c: Color, v: float32): Color {.inline.} =
|
|
||||||
result.r = c.r / v
|
|
||||||
result.g = c.g / v
|
|
||||||
result.b = c.b / v
|
|
||||||
result.a = c.a / v
|
|
||||||
|
|
||||||
proc `-`*(c: Color, v: float32): Color {.inline.} =
|
|
||||||
result.r = c.r - v
|
|
||||||
result.g = c.g - v
|
|
||||||
result.b = c.b - v
|
|
||||||
result.a = c.a - v
|
|
||||||
|
|
||||||
proc screen(backdrop, source: float32): float32 {.inline.} =
|
|
||||||
1 - (1 - backdrop) * (1 - source)
|
|
||||||
|
|
||||||
proc hardLight(backdrop, source: float32): float32 {.inline.} =
|
|
||||||
if source <= 0.5:
|
|
||||||
backdrop * 2 * source
|
|
||||||
else:
|
|
||||||
screen(backdrop, 2 * source - 1)
|
|
||||||
|
|
||||||
proc softLight(backdrop, source: float32): float32 {.inline.} =
|
|
||||||
## Pegtop
|
|
||||||
(1 - 2 * source) * backdrop ^ 2 + 2 * source * backdrop
|
|
||||||
|
|
||||||
proc Lum(C: Color): float32 {.inline.} =
|
|
||||||
0.3 * C.r + 0.59 * C.g + 0.11 * C.b
|
|
||||||
|
|
||||||
proc ClipColor(C: var Color) {.inline.} =
|
|
||||||
let
|
|
||||||
L = Lum(C)
|
|
||||||
n = min([C.r, C.g, C.b])
|
|
||||||
x = max([C.r, C.g, C.b])
|
|
||||||
if n < 0:
|
|
||||||
C = L + (((C - L) * L) / (L - n))
|
|
||||||
if x > 1:
|
|
||||||
C = L + (((C - L) * (1 - L)) / (x - L))
|
|
||||||
|
|
||||||
proc SetLum(C: Color, l: float32): Color {.inline.} =
|
|
||||||
let d = l - Lum(C)
|
|
||||||
result.r = C.r + d
|
|
||||||
result.g = C.g + d
|
|
||||||
result.b = C.b + d
|
|
||||||
ClipColor(result)
|
|
||||||
|
|
||||||
proc Sat(C: Color): float32 {.inline.} =
|
|
||||||
max([C.r, C.g, C.b]) - min([C.r, C.g, C.b])
|
|
||||||
|
|
||||||
proc SetSat(C: Color, s: float32): Color {.inline.} =
|
|
||||||
let satC = Sat(C)
|
|
||||||
if satC > 0:
|
|
||||||
result = (C - min([C.r, C.g, C.b])) * s / satC
|
|
||||||
|
|
||||||
proc alphaFix(backdrop, source, mixed: Color): Color =
|
|
||||||
result.a = (source.a + backdrop.a * (1.0 - source.a))
|
|
||||||
if result.a == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
let
|
|
||||||
t0 = source.a * (1 - backdrop.a)
|
|
||||||
t1 = source.a * backdrop.a
|
|
||||||
t2 = (1 - source.a) * backdrop.a
|
|
||||||
|
|
||||||
result.r = t0 * source.r + t1 * mixed.r + t2 * backdrop.r
|
|
||||||
result.g = t0 * source.g + t1 * mixed.g + t2 * backdrop.g
|
|
||||||
result.b = t0 * source.b + t1 * mixed.b + t2 * backdrop.b
|
|
||||||
|
|
||||||
result.r /= result.a
|
|
||||||
result.g /= result.a
|
|
||||||
result.b /= result.a
|
|
||||||
|
|
||||||
proc blendDarkenFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendMultiplyFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result.r = backdrop.r * source.r
|
|
||||||
result.g = backdrop.g * source.g
|
|
||||||
result.b = backdrop.b * source.b
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendLinearBurnFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result.r = backdrop.r + source.r - 1
|
|
||||||
result.g = backdrop.g + source.g - 1
|
|
||||||
result.b = backdrop.b + source.b - 1
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendColorBurnFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
proc blend(backdrop, source: float32): float32 {.inline.} =
|
|
||||||
if backdrop == 1:
|
|
||||||
1.0
|
|
||||||
elif source == 0:
|
|
||||||
0.0
|
|
||||||
else:
|
|
||||||
1.0 - min(1, (1 - backdrop) / source)
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendLightenFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendScreenFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendLinearDodgeFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result.r = backdrop.r + source.r
|
|
||||||
result.g = backdrop.g + source.g
|
|
||||||
result.b = backdrop.b + source.b
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendColorDodgeFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
proc blend(backdrop, source: float32): float32 {.inline.} =
|
|
||||||
if backdrop == 0:
|
|
||||||
0.0
|
|
||||||
elif source == 1:
|
|
||||||
1.0
|
|
||||||
else:
|
|
||||||
min(1, backdrop / (1 - source))
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendOverlayFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendHardLightFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendSoftLightFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result.r = softLight(backdrop.r, source.r)
|
|
||||||
result.g = softLight(backdrop.g, source.g)
|
|
||||||
result.b = softLight(backdrop.b, source.b)
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendDifferenceFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result.r = abs(backdrop.r - source.r)
|
|
||||||
result.g = abs(backdrop.g - source.g)
|
|
||||||
result.b = abs(backdrop.b - source.b)
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendExclusionFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
proc blend(backdrop, source: float32): float32 {.inline.} =
|
|
||||||
backdrop + source - 2 * backdrop * source
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendColorFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result = SetLum(source, Lum(backdrop))
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendLuminosityFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result = SetLum(backdrop, Lum(source))
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendHueFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result = SetLum(SetSat(source, Sat(backdrop)), Lum(backdrop))
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
proc blendSaturationFloats*(backdrop, source: Color): Color {.inline.} =
|
|
||||||
result = SetLum(SetSat(backdrop, Sat(source)), Lum(backdrop))
|
|
||||||
result = alphaFix(backdrop, source, result)
|
|
||||||
|
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
|
||||||
proc alphaFix(backdrop, source: ColorRGBA, vb, vs, vm: M128): ColorRGBA =
|
|
||||||
let
|
|
||||||
sa = source.a.float32
|
|
||||||
ba = backdrop.a.float32
|
|
||||||
a = sa + ba * (255 - sa) / 255
|
|
||||||
if a == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
let
|
|
||||||
t0 = mm_set1_ps(sa * (255 - ba))
|
|
||||||
t1 = mm_set1_ps(sa * ba)
|
|
||||||
t2 = mm_set1_ps((255 - sa) * ba)
|
|
||||||
va = mm_set1_ps(a)
|
|
||||||
v255 = mm_set1_ps(255)
|
|
||||||
values = cast[array[4, uint32]](
|
|
||||||
mm_cvtps_epi32((t0 * vs + t1 * vm + t2 * vb) / va / v255)
|
|
||||||
)
|
|
||||||
|
|
||||||
result.r = values[0].uint8
|
|
||||||
result.g = values[1].uint8
|
|
||||||
result.b = values[2].uint8
|
|
||||||
result.a = a.uint8
|
|
||||||
|
|
||||||
proc alphaFix(backdrop, source, mixed: ColorRGBA): ColorRGBA {.inline.} =
|
|
||||||
if backdrop.a == 0 and source.a == 0:
|
|
||||||
return
|
|
||||||
let
|
|
||||||
vb = mm_setr_ps(backdrop.r.float32, backdrop.g.float32, backdrop.b.float32, 0)
|
|
||||||
vs = mm_setr_ps(source.r.float32, source.g.float32, source.b.float32, 0)
|
|
||||||
vm = mm_setr_ps(mixed.r.float32, mixed.g.float32, mixed.b.float32, 0)
|
|
||||||
alphaFix(backdrop, source, vb, vs, vm)
|
|
||||||
else:
|
|
||||||
proc alphaFix(backdrop, source, mixed: ColorRGBA): ColorRGBA {.inline.} =
|
|
||||||
let
|
|
||||||
sa = source.a.uint32
|
|
||||||
ba = backdrop.a.uint32
|
|
||||||
t0 = sa * (255 - ba)
|
|
||||||
t1 = sa * ba
|
|
||||||
t2 = (255 - sa) * ba
|
|
||||||
|
|
||||||
let
|
|
||||||
r = t0 * source.r.uint32 + t1 * mixed.r.uint32 + t2 * backdrop.r.uint32
|
|
||||||
g = t0 * source.g.uint32 + t1 * mixed.g.uint32 + t2 * backdrop.g.uint32
|
|
||||||
b = t0 * source.b.uint32 + t1 * mixed.b.uint32 + t2 * backdrop.b.uint32
|
|
||||||
a = sa + ba * (255 - sa) div 255
|
|
||||||
|
|
||||||
if a == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
result.r = (r div a div 255).uint8
|
|
||||||
result.g = (g div a div 255).uint8
|
|
||||||
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 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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendSoftLight(backdrop, source: ColorRGBA): ColorRGBA =
|
|
||||||
# proc softLight(backdrop, source: int32): uint8 {.inline.} =
|
|
||||||
# ## Pegtop
|
|
||||||
# (
|
|
||||||
# ((255 - 2 * source) * backdrop ^ 2) div 255 ^ 2 +
|
|
||||||
# (2 * source * backdrop) div 255
|
|
||||||
# ).uint8
|
|
||||||
|
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
|
||||||
let
|
|
||||||
vb = mm_setr_ps(backdrop.r.float32, backdrop.g.float32, backdrop.b.float32, 0)
|
|
||||||
vs = mm_setr_ps(source.r.float32, source.g.float32, source.b.float32, 0)
|
|
||||||
v2 = mm_set1_ps(2)
|
|
||||||
v255 = mm_set1_ps(255)
|
|
||||||
v255sq = mm_set1_ps(255 * 255)
|
|
||||||
vm = ((v255 - v2 * vs) * vb * vb) / v255sq + (v2 * vs * vb) / v255
|
|
||||||
values = cast[array[4, uint32]](mm_cvtps_epi32(vm))
|
|
||||||
|
|
||||||
result.r = values[0].uint8
|
|
||||||
result.g = values[1].uint8
|
|
||||||
result.b = values[2].uint8
|
|
||||||
result = alphaFix(backdrop, source, vb, vs, vm)
|
|
||||||
else:
|
|
||||||
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)
|
|
||||||
|
|
||||||
proc blendColor(backdrop, source: ColorRGBA): ColorRGBA =
|
|
||||||
blendColorFloats(backdrop.color, source.color).rgba
|
|
||||||
|
|
||||||
proc blendLuminosity(backdrop, source: ColorRGBA): ColorRGBA =
|
|
||||||
blendLuminosityFloats(backdrop.color, source.color).rgba
|
|
||||||
|
|
||||||
proc blendHue(backdrop, source: ColorRGBA): ColorRGBA =
|
|
||||||
blendHueFloats(backdrop.color, source.color).rgba
|
|
||||||
|
|
||||||
proc blendSaturation(backdrop, source: ColorRGBA): ColorRGBA =
|
|
||||||
blendSaturationFloats(backdrop.color, source.color).rgba
|
|
||||||
|
|
|
@ -153,179 +153,3 @@ when defined(amd64) and not defined(pixieNoSimd):
|
||||||
b = mm_loadu_si128(backdrop.data[i].addr)
|
b = mm_loadu_si128(backdrop.data[i].addr)
|
||||||
s = mm_loadu_si128(source.data[i].addr)
|
s = mm_loadu_si128(source.data[i].addr)
|
||||||
mm_storeu_si128(backdrop.data[i].addr, blendNormalSimd(b, s))
|
mm_storeu_si128(backdrop.data[i].addr, blendNormalSimd(b, s))
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendDarkenFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendDarkenFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendNormalFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendNormalFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendMultiplyFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendMultiplyFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendLinearBurnFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendLinearBurnFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendColorBurnFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendColorBurnFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendLightenFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendLightenFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendScreenFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendScreenFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendLinearDodgeFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendLinearDodgeFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendColorDodgeFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendColorDodgeFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendOverlayFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendOverlayFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendSoftLightFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendSoftLightFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendHardLightFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendHardLightFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendDifferenceFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendDifferenceFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendExclusionFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendExclusionFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendHueFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendHueFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendSaturationFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendSaturationFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendColorFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendColorFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendLuminosityFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendLuminosityFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendMaskFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendMaskFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendSubtractMaskFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendSubtractMaskFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendIntersectMaskFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendIntersectMaskFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
||||||
reset()
|
|
||||||
|
|
||||||
timeIt "blendExcludeMaskFloats":
|
|
||||||
for i in 0 ..< backdrop.data.len:
|
|
||||||
backdrop.data[i] = blendExcludeMaskFloats(
|
|
||||||
backdrop.data[i].color, source.data[i].color
|
|
||||||
).rgba
|
|
||||||
|
|
Loading…
Reference in a new issue