Merge pull request #31 from guzba/master
int blends, some simd, all around faster
This commit is contained in:
commit
8c3b30d610
5 changed files with 486 additions and 305 deletions
|
@ -1,5 +1,5 @@
|
||||||
## Blending modes.
|
## Blending modes.
|
||||||
import chroma, math
|
import chroma, math, 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
|
||||||
|
@ -69,42 +69,38 @@ proc `-`*(c: Color, v: float32): Color {.inline.} =
|
||||||
result.b = c.b - v
|
result.b = c.b - v
|
||||||
result.a = c.a - v
|
result.a = c.a - v
|
||||||
|
|
||||||
proc screen(Cb, Cs: float32): float32 {.inline.} =
|
proc screen(backdrop, source: float32): float32 {.inline.} =
|
||||||
1 - (1 - Cb) * (1 - Cs)
|
1 - (1 - backdrop) * (1 - source)
|
||||||
|
|
||||||
proc hardLight(Cb, Cs: float32): float32 {.inline.} =
|
proc hardLight(backdrop, source: float32): float32 {.inline.} =
|
||||||
if Cs <= 0.5:
|
if source <= 0.5:
|
||||||
Cb * 2 * Cs
|
backdrop * 2 * source
|
||||||
else:
|
else:
|
||||||
screen(Cb, 2 * Cs - 1)
|
screen(backdrop, 2 * source - 1)
|
||||||
|
|
||||||
proc softLight(a, b: float32): float32 {.inline.} =
|
proc softLight(backdrop, source: float32): float32 {.inline.} =
|
||||||
## Pegtop
|
## Pegtop
|
||||||
(1 - 2 * b) * a ^ 2 + 2 * b * a
|
(1 - 2 * source) * backdrop ^ 2 + 2 * source * backdrop
|
||||||
|
|
||||||
proc Lum(C: Color): float32 {.inline.} =
|
proc Lum(C: Color): float32 {.inline.} =
|
||||||
0.3 * C.r + 0.59 * C.g + 0.11 * C.b
|
0.3 * C.r + 0.59 * C.g + 0.11 * C.b
|
||||||
|
|
||||||
proc ClipColor(C: Color): Color {.inline.} =
|
proc ClipColor(C: var Color) {.inline.} =
|
||||||
let
|
let
|
||||||
L = Lum(C)
|
L = Lum(C)
|
||||||
n = min([C.r, C.g, C.b])
|
n = min([C.r, C.g, C.b])
|
||||||
x = max([C.r, C.g, C.b])
|
x = max([C.r, C.g, C.b])
|
||||||
var
|
|
||||||
C = C
|
|
||||||
if n < 0:
|
if n < 0:
|
||||||
C = L + (((C - L) * L) / (L - n))
|
C = L + (((C - L) * L) / (L - n))
|
||||||
if x > 1:
|
if x > 1:
|
||||||
C = L + (((C - L) * (1 - L)) / (x - L))
|
C = L + (((C - L) * (1 - L)) / (x - L))
|
||||||
return C
|
|
||||||
|
|
||||||
proc SetLum(C: Color, l: float32): Color {.inline.} =
|
proc SetLum(C: Color, l: float32): Color {.inline.} =
|
||||||
let
|
let d = l - Lum(C)
|
||||||
d = l - Lum(C)
|
|
||||||
result.r = C.r + d
|
result.r = C.r + d
|
||||||
result.g = C.g + d
|
result.g = C.g + d
|
||||||
result.b = C.b + d
|
result.b = C.b + d
|
||||||
return ClipColor(result)
|
ClipColor(result)
|
||||||
|
|
||||||
proc Sat(C: Color): float32 {.inline.} =
|
proc Sat(C: Color): float32 {.inline.} =
|
||||||
max([C.r, C.g, C.b]) - min([C.r, C.g, C.b])
|
max([C.r, C.g, C.b]) - min([C.r, C.g, C.b])
|
||||||
|
@ -114,323 +110,345 @@ proc SetSat(C: Color, s: float32): Color {.inline.} =
|
||||||
if satC > 0:
|
if satC > 0:
|
||||||
result = (C - min([C.r, C.g, C.b])) * s / satC
|
result = (C - min([C.r, C.g, C.b])) * s / satC
|
||||||
|
|
||||||
proc alphaFix(Cb, Cs, mixed: Color): Color {.inline.} =
|
proc alphaFix(backdrop, source, mixed: Color): Color =
|
||||||
let ab = Cb.a
|
result.a = (source.a + backdrop.a * (1.0 - source.a))
|
||||||
let As = Cs.a
|
if result.a == 0:
|
||||||
result.r = As * (1 - ab) * Cs.r + As * ab * mixed.r + (1 - As) * ab * Cb.r
|
return
|
||||||
result.g = As * (1 - ab) * Cs.g + As * ab * mixed.g + (1 - As) * ab * Cb.g
|
|
||||||
result.b = As * (1 - ab) * Cs.b + As * ab * mixed.b + (1 - As) * ab * Cb.b
|
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.a = (Cs.a + Cb.a * (1.0 - Cs.a))
|
|
||||||
result.r /= result.a
|
result.r /= result.a
|
||||||
result.g /= result.a
|
result.g /= result.a
|
||||||
result.b /= result.a
|
result.b /= result.a
|
||||||
|
|
||||||
proc blendDarkenFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendNormalFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
min(Cb, Cs)
|
result = source
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendMultiplyFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendDarkenFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
Cb * Cs
|
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 blendLinearBurnFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendMultiplyFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
Cb + Cs - 1
|
result.r = backdrop.r * source.r
|
||||||
|
result.g = backdrop.g * source.g
|
||||||
|
result.b = backdrop.b * source.b
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendColorBurnFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendLinearBurnFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
if Cb == 1: 1.0
|
result.r = backdrop.r + source.r - 1
|
||||||
elif Cs == 0: 0.0
|
result.g = backdrop.g + source.g - 1
|
||||||
else: 1.0 - min(1, (1 - Cb) / Cs)
|
result.b = backdrop.b + source.b - 1
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendLightenFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendColorBurnFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
max(Cb, Cs)
|
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 blendScreenFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendLightenFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
screen(Cb, Cs)
|
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 blendLinearDodgeFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendScreenFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
Cb + Cs
|
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 blendColorDodgeFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendLinearDodgeFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
if Cb == 0: 0.0
|
result.r = backdrop.r + source.r
|
||||||
elif Cs == 1: 1.0
|
result.g = backdrop.g + source.g
|
||||||
else: min(1, Cb / (1 - Cs))
|
result.b = backdrop.b + source.b
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendOverlayFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendColorDodgeFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
hardLight(Cs, Cb)
|
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 blendHardLightFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendOverlayFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
hardLight(Cb, Cs)
|
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 blendSoftLightFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendHardLightFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
softLight(Cb, Cs)
|
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 blendDifferenceFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendSoftLightFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
abs(Cb - Cs)
|
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 blendExclusionFloat(Cb, Cs: float32): float32 {.inline.} =
|
proc blendDifferenceFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
Cb + Cs - 2 * Cb * Cs
|
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 blendNormalFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendExclusionFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = Cs.r
|
proc blend(backdrop, source: float32): float32 {.inline.} =
|
||||||
result.g = Cs.g
|
backdrop + source - 2 * backdrop * source
|
||||||
result.b = Cs.b
|
result.r = blend(backdrop.r, source.r)
|
||||||
result = alphaFix(Cb, Cs, result)
|
result.g = blend(backdrop.g, source.g)
|
||||||
|
result.b = blend(backdrop.b, source.b)
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendDarkenFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendColorFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendDarkenFloat(Cb.r, Cs.r)
|
result = SetLum(source, Lum(backdrop))
|
||||||
result.g = blendDarkenFloat(Cb.g, Cs.g)
|
result = alphaFix(backdrop, source, result)
|
||||||
result.b = blendDarkenFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendMultiplyFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendLuminosityFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendMultiplyFloat(Cb.r, Cs.r)
|
result = SetLum(backdrop, Lum(source))
|
||||||
result.g = blendMultiplyFloat(Cb.g, Cs.g)
|
result = alphaFix(backdrop, source, result)
|
||||||
result.b = blendMultiplyFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendLinearBurnFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendHueFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendLinearBurnFloat(Cb.r, Cs.r)
|
result = SetLum(SetSat(source, Sat(backdrop)), Lum(backdrop))
|
||||||
result.g = blendLinearBurnFloat(Cb.g, Cs.g)
|
result = alphaFix(backdrop, source, result)
|
||||||
result.b = blendLinearBurnFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendColorBurnFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendSaturationFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendColorBurnFloat(Cb.r, Cs.r)
|
result = SetLum(SetSat(backdrop, Sat(source)), Lum(backdrop))
|
||||||
result.g = blendColorBurnFloat(Cb.g, Cs.g)
|
result = alphaFix(backdrop, source, result)
|
||||||
result.b = blendColorBurnFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendLightenFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendMaskFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendLightenFloat(Cb.r, Cs.r)
|
result = backdrop
|
||||||
result.g = blendLightenFloat(Cb.g, Cs.g)
|
result.a = min(backdrop.a, source.a)
|
||||||
result.b = blendLightenFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendScreenFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendSubtractMaskFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendScreenFloat(Cb.r, Cs.r)
|
result = backdrop
|
||||||
result.g = blendScreenFloat(Cb.g, Cs.g)
|
result.a = backdrop.a * (1 - source.a)
|
||||||
result.b = blendScreenFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendLinearDodgeFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendIntersectMaskFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendLinearDodgeFloat(Cb.r, Cs.r)
|
result = backdrop
|
||||||
result.g = blendLinearDodgeFloat(Cb.g, Cs.g)
|
result.a = backdrop.a * source.a
|
||||||
result.b = blendLinearDodgeFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendColorDodgeFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendExcludeMaskFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendColorDodgeFloat(Cb.r, Cs.r)
|
result = backdrop
|
||||||
result.g = blendColorDodgeFloat(Cb.g, Cs.g)
|
result.a = abs(backdrop.a - source.a)
|
||||||
result.b = blendColorDodgeFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendOverlayFloats(Cb, Cs: Color): Color {.inline.} =
|
proc blendOverwriteFloats(backdrop, source: Color): Color {.inline.} =
|
||||||
result.r = blendOverlayFloat(Cb.r, Cs.r)
|
source
|
||||||
result.g = blendOverlayFloat(Cb.g, Cs.g)
|
|
||||||
result.b = blendOverlayFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendHardLightFloats(Cb, Cs: Color): Color {.inline.} =
|
proc alphaFix(backdrop, source: ColorRGBA, vb, vs, vm: M128): ColorRGBA =
|
||||||
result.r = blendHardLightFloat(Cb.r, Cs.r)
|
let
|
||||||
result.g = blendHardLightFloat(Cb.g, Cs.g)
|
sa = source.a.float32
|
||||||
result.b = blendHardLightFloat(Cb.b, Cs.b)
|
ba = backdrop.a.float32
|
||||||
result = alphaFix(Cb, Cs, result)
|
a = sa + ba * (255 - sa) / 255
|
||||||
|
|
||||||
proc blendSoftLightFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
result.r = blendSoftLightFloat(Cb.r, Cs.r)
|
|
||||||
result.g = blendSoftLightFloat(Cb.g, Cs.g)
|
|
||||||
result.b = blendSoftLightFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendDifferenceFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
result.r = blendDifferenceFloat(Cb.r, Cs.r)
|
|
||||||
result.g = blendDifferenceFloat(Cb.g, Cs.g)
|
|
||||||
result.b = blendDifferenceFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendExclusionFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
result.r = blendExclusionFloat(Cb.r, Cs.r)
|
|
||||||
result.g = blendExclusionFloat(Cb.g, Cs.g)
|
|
||||||
result.b = blendExclusionFloat(Cb.b, Cs.b)
|
|
||||||
result = alphaFix(Cb, Cs, result)
|
|
||||||
|
|
||||||
proc blendColorFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
let mixed = SetLum(Cs, Lum(Cb))
|
|
||||||
alphaFix(Cb, Cs, mixed)
|
|
||||||
|
|
||||||
proc blendLuminosityFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
let mixed = SetLum(Cb, Lum(Cs))
|
|
||||||
alphaFix(Cb, Cs, mixed)
|
|
||||||
|
|
||||||
proc blendHueFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
let mixed = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
|
|
||||||
alphaFix(Cb, Cs, mixed)
|
|
||||||
|
|
||||||
proc blendSaturationFloats(Cb, Cs: Color): Color {.inline.} =
|
|
||||||
let mixed = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
|
|
||||||
alphaFix(Cb, Cs, mixed)
|
|
||||||
|
|
||||||
proc blendMaskFloats(target, blend: Color): Color {.inline.} =
|
|
||||||
result.r = target.r
|
|
||||||
result.g = target.g
|
|
||||||
result.b = target.b
|
|
||||||
result.a = min(target.a, blend.a)
|
|
||||||
|
|
||||||
proc blendSubtractMaskFloats(target, blend: Color): Color {.inline.} =
|
|
||||||
result.r = target.r
|
|
||||||
result.g = target.g
|
|
||||||
result.b = target.b
|
|
||||||
result.a = target.a * (1 - blend.a)
|
|
||||||
|
|
||||||
proc blendIntersectMaskFloats(target, blend: Color): Color {.inline.} =
|
|
||||||
result.r = target.r
|
|
||||||
result.g = target.g
|
|
||||||
result.b = target.b
|
|
||||||
result.a = target.a * blend.a
|
|
||||||
|
|
||||||
proc blendExcludeMaskFloats(target, blend: Color): Color {.inline.} =
|
|
||||||
result.r = target.r
|
|
||||||
result.g = target.g
|
|
||||||
result.b = target.b
|
|
||||||
result.a = abs(target.a - blend.a)
|
|
||||||
|
|
||||||
proc blendOverwriteFloats(target, blend: Color): Color {.inline.} =
|
|
||||||
result = blend
|
|
||||||
|
|
||||||
proc alphaFix(Cb, Cs, mixed: ColorRGBA): ColorRGBA {.inline.} =
|
|
||||||
let ab = Cb.a.int32
|
|
||||||
let As = Cs.a.int32
|
|
||||||
let r = As * (255 - ab) * Cs.r.int32 + As * ab * mixed.r.int32 + (255 - As) * ab * Cb.r.int32
|
|
||||||
let g = As * (255 - ab) * Cs.g.int32 + As * ab * mixed.g.int32 + (255 - As) * ab * Cb.g.int32
|
|
||||||
let b = As * (255 - ab) * Cs.b.int32 + As * ab * mixed.b.int32 + (255 - As) * ab * Cb.b.int32
|
|
||||||
|
|
||||||
let a = Cs.a.int32 + Cb.a.int32 * (255 - Cs.a.int32) div 255
|
|
||||||
if a == 0:
|
if a == 0:
|
||||||
return
|
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)
|
||||||
|
|
||||||
|
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:
|
else:
|
||||||
result.r = (r div a div 255).uint8
|
screen(backdrop, 2 * source - 255)
|
||||||
result.g = (g div a div 255).uint8
|
|
||||||
result.b = (b div a div 255).uint8
|
|
||||||
result.a = a.uint8
|
|
||||||
|
|
||||||
proc screen(a, b: uint8): uint8 {.inline.} =
|
proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
(255 - ((255 - a).uint32 * (255 - b).uint32) div 255).uint8
|
result = source
|
||||||
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc hardLight(a, b: uint8): uint8 {.inline.} =
|
proc blendDarken(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
if b <= 127:
|
result.r = min(backdrop.r, source.r)
|
||||||
((a * 2 * b) div 255).uint8
|
result.g = min(backdrop.g, source.g)
|
||||||
else:
|
result.b = min(backdrop.b, source.b)
|
||||||
screen(a, max(0, (2 * b.int32 - 255)).uint8)
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendNormal(a, b: ColorRGBA): ColorRGBA =
|
proc blendMultiply(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = b.r
|
result.r = ((backdrop.r.uint32 * source.r) div 255).uint8
|
||||||
result.g = b.g
|
result.g = ((backdrop.g.uint32 * source.g) div 255).uint8
|
||||||
result.b = b.b
|
result.b = ((backdrop.b.uint32 * source.b) div 255).uint8
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
# blendNormalFloats(a.color, b.color).rgba
|
|
||||||
|
|
||||||
proc blendDarken(a, b: ColorRGBA): ColorRGBA =
|
proc blendLinearBurn(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = min(a.r, b.r)
|
result.r = min(0, backdrop.r.int16 + source.r.int16 - 255).uint8
|
||||||
result.g = min(a.g, b.g)
|
result.g = min(0, backdrop.g.int16 + source.g.int16 - 255).uint8
|
||||||
result.b = min(a.b, b.b)
|
result.b = min(0, backdrop.b.int16 + source.b.int16 - 255).uint8
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
# blendDarkenFloats(a.color, b.color).rgba
|
|
||||||
|
|
||||||
proc blendMultiply(a, b: ColorRGBA): ColorRGBA =
|
proc blendColorBurn(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = ((a.r.uint32 * b.r.uint32) div 255).uint8
|
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||||
result.g = ((a.g.uint32 * b.g.uint32) div 255).uint8
|
if backdrop == 255:
|
||||||
result.b = ((a.b.uint32 * b.b.uint32) div 255).uint8
|
255.uint8
|
||||||
result = alphaFix(a, b, result)
|
elif source == 0:
|
||||||
# blendMultiplyFloats(a.color, b.color).rgba
|
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 blendLinearBurn(a, b: ColorRGBA): ColorRGBA =
|
proc blendLighten(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = max(0, a.r.int32 + b.r.int32 - 255).uint8
|
result.r = max(backdrop.r, source.r)
|
||||||
result.g = max(0, a.g.int32 + b.g.int32 - 255).uint8
|
result.g = max(backdrop.g, source.g)
|
||||||
result.b = max(0, a.b.int32 + b.b.int32 - 255).uint8
|
result.b = max(backdrop.b, source.b)
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendColorBurn(a, b: ColorRGBA): ColorRGBA =
|
proc blendScreen(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendColorBurnFloats(a.color, b.color).rgba
|
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 blendLighten(a, b: ColorRGBA): ColorRGBA =
|
proc blendLinearDodge(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = max(a.r, b.r)
|
result.r = min(backdrop.r.uint32 + source.r, 255).uint8
|
||||||
result.g = max(a.g, b.g)
|
result.g = min(backdrop.g.uint32 + source.g, 255).uint8
|
||||||
result.b = max(a.b, b.b)
|
result.b = min(backdrop.b.uint32 + source.b, 255).uint8
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendScreen(a, b: ColorRGBA): ColorRGBA =
|
proc blendColorDodge(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = screen(a.r, b.r)
|
proc blend(backdrop, source: uint32): uint8 {.inline.} =
|
||||||
result.g = screen(a.g, b.g)
|
if backdrop == 0:
|
||||||
result.b = screen(a.b, b.b)
|
0.uint8
|
||||||
result = alphaFix(a, b, result)
|
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 blendLinearDodge(a, b: ColorRGBA): ColorRGBA =
|
proc blendOverlay(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = (a.r.uint32 + b.r).uint8
|
result.r = hardLight(source.r, backdrop.r)
|
||||||
result.r = (a.g.uint32 + b.g).uint8
|
result.g = hardLight(source.g, backdrop.g)
|
||||||
result.r = (a.b.uint32 + b.b).uint8
|
result.b = hardLight(source.b, backdrop.b)
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendColorDodge(a, b: ColorRGBA): ColorRGBA =
|
proc blendHardLight(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendColorDodgeFloats(a.color, b.color).rgba
|
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 blendOverlay(a, b: ColorRGBA): ColorRGBA =
|
proc blendSoftLight(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = hardLight(b.r, a.r)
|
# proc softLight(backdrop, source: int32): uint8 {.inline.} =
|
||||||
result.g = hardLight(b.g, a.g)
|
# ## Pegtop
|
||||||
result.b = hardLight(b.b, a.b)
|
# (
|
||||||
result = alphaFix(a, b, result)
|
# ((255 - 2 * source) * backdrop ^ 2) div 255 ^ 2 +
|
||||||
|
# (2 * source * backdrop) div 255
|
||||||
|
# ).uint8
|
||||||
|
|
||||||
proc blendHardLight(a, b: ColorRGBA): ColorRGBA =
|
let
|
||||||
result.r = hardLight(a.r, b.r)
|
vb = mm_setr_ps(backdrop.r.float32, backdrop.g.float32, backdrop.b.float32, 0)
|
||||||
result.g = hardLight(a.g, b.g)
|
vs = mm_setr_ps(source.r.float32, source.g.float32, source.b.float32, 0)
|
||||||
result.b = hardLight(a.b, b.b)
|
v2 = mm_set1_ps(2)
|
||||||
result = alphaFix(a, b, result)
|
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))
|
||||||
|
|
||||||
proc blendSoftLight(a, b: ColorRGBA): ColorRGBA =
|
result.r = values[0].uint8
|
||||||
blendSoftLightFloats(a.color, b.color).rgba
|
result.g = values[1].uint8
|
||||||
|
result.b = values[2].uint8
|
||||||
|
result = alphaFix(backdrop, source, vb, vs, vm)
|
||||||
|
|
||||||
proc blendDifference(a, b: ColorRGBA): ColorRGBA =
|
proc blendDifference(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.r = max(a.r, b.r) - min(a.r, b.r)
|
result.r = max(backdrop.r, source.r) - min(backdrop.r, source.r)
|
||||||
result.g = max(a.g, b.g) - min(a.g, b.g)
|
result.g = max(backdrop.g, source.g) - min(backdrop.g, source.g)
|
||||||
result.b = max(a.b, b.b) - min(a.b, b.b)
|
result.b = max(backdrop.b, source.b) - min(backdrop.b, source.b)
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendExclusion(a, b: ColorRGBA): ColorRGBA =
|
proc blendExclusion(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
template blend(a, b: int32): uint8 =
|
proc blend(backdrop, source: int32): uint8 {.inline.} =
|
||||||
max(0, a + b - (2 * a * b) div 255).uint8
|
max(0, backdrop + source - (2 * backdrop * source) div 255).uint8
|
||||||
result.r = blend(a.r.int32, b.r.int32)
|
result.r = blend(backdrop.r.int32, source.r.int32)
|
||||||
result.g = blend(a.g.int32, b.g.int32)
|
result.g = blend(backdrop.g.int32, source.g.int32)
|
||||||
result.b = blend(a.b.int32, b.b.int32)
|
result.b = blend(backdrop.b.int32, source.b.int32)
|
||||||
result = alphaFix(a, b, result)
|
result = alphaFix(backdrop, source, result)
|
||||||
|
|
||||||
proc blendColor(a, b: ColorRGBA): ColorRGBA =
|
proc blendColor(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendColorFloats(a.color, b.color).rgba
|
blendColorFloats(backdrop.color, source.color).rgba
|
||||||
|
|
||||||
proc blendLuminosity(a, b: ColorRGBA): ColorRGBA =
|
proc blendLuminosity(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendLuminosityFloats(a.color, b.color).rgba
|
blendLuminosityFloats(backdrop.color, source.color).rgba
|
||||||
|
|
||||||
proc blendHue(a, b: ColorRGBA): ColorRGBA =
|
proc blendHue(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendHueFloats(a.color, b.color).rgba
|
blendHueFloats(backdrop.color, source.color).rgba
|
||||||
|
|
||||||
proc blendSaturation(a, b: ColorRGBA): ColorRGBA =
|
proc blendSaturation(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendSaturationFloats(a.color, b.color).rgba
|
blendSaturationFloats(backdrop.color, source.color).rgba
|
||||||
|
|
||||||
proc blendMask(a, b: ColorRGBA): ColorRGBA =
|
proc blendMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result = a
|
result = backdrop
|
||||||
result.a = min(a.a, b.a)
|
result.a = min(backdrop.a, source.a)
|
||||||
|
|
||||||
proc blendSubtractMask(a, b: ColorRGBA): ColorRGBA =
|
proc blendSubtractMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result = a
|
result = backdrop
|
||||||
result.a = max(0, (a.a.int32 * (255 - b.a.int32)) div 255).uint8
|
result.a = max(0, (backdrop.a.int32 * (255 - source.a.int32)) div 255).uint8
|
||||||
|
|
||||||
proc blendIntersectMask(a, b: ColorRGBA): ColorRGBA =
|
proc blendIntersectMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result = a
|
result = backdrop
|
||||||
result.a = ((a.a.uint32 * (b.a.uint32)) div 255).uint8
|
result.a = ((backdrop.a.uint32 * (source.a.uint32)) div 255).uint8
|
||||||
|
|
||||||
proc blendExcludeMask(a, b: ColorRGBA): ColorRGBA =
|
proc blendExcludeMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result = a
|
result = backdrop
|
||||||
result.a = max(a.a, b.a) - min(a.a, b.a)
|
result.a = max(backdrop.a, source.a) - min(backdrop.a, source.a)
|
||||||
|
|
||||||
proc blendOverwrite(a, b: ColorRGBA): ColorRGBA =
|
proc blendOverwrite(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
b
|
source
|
||||||
|
|
||||||
proc mixer*(blendMode: BlendMode): Mixer =
|
proc mixer*(blendMode: BlendMode): Mixer =
|
||||||
case blendMode
|
case blendMode
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import chroma, blends, vmath, common, nimsimd/sse2
|
import chroma, blends, vmath, common, nimsimd/sse2
|
||||||
|
|
||||||
|
const h = 0.5.float32
|
||||||
|
|
||||||
type
|
type
|
||||||
Image* = ref object
|
Image* = ref object
|
||||||
## Main image object that holds the bitmap data in RGBA format.
|
## Main image object that holds the bitmap data in RGBA format.
|
||||||
|
@ -198,9 +200,7 @@ proc fromAlphy*(image: Image) =
|
||||||
|
|
||||||
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
||||||
## Gets a pixel as (x, y) floats.
|
## Gets a pixel as (x, y) floats.
|
||||||
var
|
let
|
||||||
x = x # TODO: look at maybe +0.5
|
|
||||||
y = y # TODO: look at maybe +0.5
|
|
||||||
minX = x.floor.int
|
minX = x.floor.int
|
||||||
difX = x - x.floor
|
difX = x - x.floor
|
||||||
minY = y.floor.int
|
minY = y.floor.int
|
||||||
|
@ -351,10 +351,7 @@ proc spread*(image: Image, spread: float32) =
|
||||||
image[x, y] = rgba(0, 0, 0, maxAlpha)
|
image[x, y] = rgba(0, 0, 0, maxAlpha)
|
||||||
|
|
||||||
proc shadow*(
|
proc shadow*(
|
||||||
mask: Image,
|
mask: Image, offset: Vec2, spread, blur: float32, color: ColorRGBA
|
||||||
offset: Vec2,
|
|
||||||
spread, blur: float32,
|
|
||||||
color: ColorRGBA
|
|
||||||
): Image =
|
): Image =
|
||||||
## Create a shadow of the image with the offset, spread and blur.
|
## Create a shadow of the image with the offset, spread and blur.
|
||||||
var shadow = mask
|
var shadow = mask
|
||||||
|
@ -390,8 +387,7 @@ proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
var
|
var
|
||||||
matInv = mat.inverse()
|
matInv = mat.inverse()
|
||||||
# compute movement vectors
|
# Compute movement vectors
|
||||||
h = 0.5.float32
|
|
||||||
p = matInv * vec2(0 + h, 0 + h)
|
p = matInv * vec2(0 + h, 0 + h)
|
||||||
dx = matInv * vec2(1 + h, 0 + h) - p
|
dx = matInv * vec2(1 + h, 0 + h) - p
|
||||||
dy = matInv * vec2(0 + h, 1 + h) - p
|
dy = matInv * vec2(0 + h, 1 + h) - p
|
||||||
|
@ -411,12 +407,12 @@ proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
for x in 0 ..< a.width:
|
for x in 0 ..< a.width:
|
||||||
let
|
let
|
||||||
srcPos = matInv * vec2(x.float32 + h, y.float32 + h)
|
srcPos = matInv * vec2(x.float32 + h, y.float32 + h)
|
||||||
|
xFloat = srcPos.x - h
|
||||||
|
yFloat = srcPos.y - h
|
||||||
rgba = a.getRgbaUnsafe(x, y)
|
rgba = a.getRgbaUnsafe(x, y)
|
||||||
rgba2 = b.getRgbaSmooth(srcPos.x - h, srcPos.y - h)
|
rgba2 = b.getRgbaSmooth(xFloat, yFloat)
|
||||||
a.setRgbaUnsafe(x, y, mixer(rgba, rgba2))
|
a.setRgbaUnsafe(x, y, mixer(rgba, rgba2))
|
||||||
|
|
||||||
const h = 0.5.float32
|
|
||||||
|
|
||||||
proc drawUber(
|
proc drawUber(
|
||||||
a, b: Image,
|
a, b: Image,
|
||||||
p, dx, dy: Vec2,
|
p, dx, dy: Vec2,
|
||||||
|
@ -427,9 +423,8 @@ proc drawUber(
|
||||||
let mixer = blendMode.mixer()
|
let mixer = blendMode.mixer()
|
||||||
for y in 0 ..< a.height:
|
for y in 0 ..< a.height:
|
||||||
var
|
var
|
||||||
xMin = 0
|
xMin = a.width
|
||||||
xMax = 0
|
xMax = 0
|
||||||
hasIntersection = false
|
|
||||||
for yOffset in [0.float32, 1]:
|
for yOffset in [0.float32, 1]:
|
||||||
var scanLine = segment(
|
var scanLine = segment(
|
||||||
vec2(-100000, y.float32 + yOffset),
|
vec2(-100000, y.float32 + yOffset),
|
||||||
|
@ -438,13 +433,8 @@ proc drawUber(
|
||||||
for l in lines:
|
for l in lines:
|
||||||
var at: Vec2
|
var at: Vec2
|
||||||
if intersects(l, scanLine, at):
|
if intersects(l, scanLine, at):
|
||||||
if hasIntersection:
|
xMin = min(xMin, at.x.floor.int)
|
||||||
xMin = min(xMin, at.x.floor.int)
|
xMax = max(xMax, at.x.ceil.int)
|
||||||
xMax = max(xMax, at.x.ceil.int)
|
|
||||||
else:
|
|
||||||
hasIntersection = true
|
|
||||||
xMin = at.x.floor.int
|
|
||||||
xMax = at.x.ceil.int
|
|
||||||
|
|
||||||
xMin = xMin.clamp(0, a.width)
|
xMin = xMin.clamp(0, a.width)
|
||||||
xMax = xMax.clamp(0, a.width)
|
xMax = xMax.clamp(0, a.width)
|
||||||
|
@ -463,7 +453,7 @@ proc drawUber(
|
||||||
if smooth:
|
if smooth:
|
||||||
b.getRgbaSmooth(xFloat, yFloat)
|
b.getRgbaSmooth(xFloat, yFloat)
|
||||||
else:
|
else:
|
||||||
b.getRgbaUnsafe(xFloat.round.int, yFloat.round.int)
|
b.getRgbaUnsafe(xFloat.int, yFloat.int)
|
||||||
a.setRgbaUnsafe(x, y, mixer(rgba, rgba2))
|
a.setRgbaUnsafe(x, y, mixer(rgba, rgba2))
|
||||||
|
|
||||||
if blendMode == bmIntersectMask:
|
if blendMode == bmIntersectMask:
|
||||||
|
@ -489,7 +479,7 @@ proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
|
|
||||||
var
|
var
|
||||||
matInv = mat.inverse()
|
matInv = mat.inverse()
|
||||||
# compute movement vectors
|
# Compute movement vectors
|
||||||
p = matInv * vec2(0 + h, 0 + h)
|
p = matInv * vec2(0 + h, 0 + h)
|
||||||
dx = matInv * vec2(1 + h, 0 + h) - p
|
dx = matInv * vec2(1 + h, 0 + h) - p
|
||||||
dy = matInv * vec2(0 + h, 1 + h) - p
|
dy = matInv * vec2(0 + h, 1 + h) - p
|
||||||
|
|
|
@ -2,20 +2,184 @@ import benchy, chroma, vmath
|
||||||
|
|
||||||
include pixie/blends
|
include pixie/blends
|
||||||
|
|
||||||
const iterations = 100_000_000
|
const iterations = 1_000_000
|
||||||
|
|
||||||
let
|
let
|
||||||
a = rgba(100, 200, 100, 255)
|
a = rgba(100, 200, 100, 255)
|
||||||
b = rgba(25, 33, 100, 127)
|
b = rgba(25, 33, 100, 127)
|
||||||
|
|
||||||
timeIt "bmNormal":
|
timeIt "blendNormal":
|
||||||
for i in 0 ..< iterations:
|
for i in 0 ..< iterations:
|
||||||
keep blendNormal(a, b)
|
keep blendNormal(a, b)
|
||||||
|
|
||||||
timeIt "bmDarken":
|
timeIt "blendNormalFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendNormalFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendDarken":
|
||||||
for i in 0 ..< iterations:
|
for i in 0 ..< iterations:
|
||||||
keep blendDarken(a, b)
|
keep blendDarken(a, b)
|
||||||
|
|
||||||
timeIt "bmMultiply":
|
timeIt "blendDarkenFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendDarkenFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendMultiply":
|
||||||
for i in 0 ..< iterations:
|
for i in 0 ..< iterations:
|
||||||
keep blendMultiply(a, b)
|
keep blendMultiply(a, b)
|
||||||
|
|
||||||
|
timeIt "blendMultiplyFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendMultiplyFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendLinearBurn":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLinearBurn(a, b)
|
||||||
|
|
||||||
|
timeIt "blendLinearBurnFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLinearBurnFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendColorBurn":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendColorBurn(a, b)
|
||||||
|
|
||||||
|
timeIt "blendColorBurnFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendColorBurnFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendLighten":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLighten(a, b)
|
||||||
|
|
||||||
|
timeIt "blendLightenFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLightenFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendScreen":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendScreen(a, b)
|
||||||
|
|
||||||
|
timeIt "blendScreenFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendScreenFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendLinearDodge":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLinearDodge(a, b)
|
||||||
|
|
||||||
|
timeIt "blendLinearDodgeFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLinearDodgeFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendColorDodge":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendColorDodge(a, b)
|
||||||
|
|
||||||
|
timeIt "blendColorDodgeFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendColorDodgeFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendOverlay":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendOverlay(a, b)
|
||||||
|
|
||||||
|
timeIt "blendOverlayFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendOverlayFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendSoftLight":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendSoftLight(a, b)
|
||||||
|
|
||||||
|
timeIt "blendSoftLightFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendSoftLightFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendHardLight":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendHardLight(a, b)
|
||||||
|
|
||||||
|
timeIt "blendHardLightFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendHardLightFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendDifference":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendDifference(a, b)
|
||||||
|
|
||||||
|
timeIt "blendDifferenceFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendDifferenceFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendExclusion":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendExclusion(a, b)
|
||||||
|
|
||||||
|
timeIt "blendExclusionFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendExclusionFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendHue":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendHue(a, b)
|
||||||
|
|
||||||
|
timeIt "blendHueFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendHueFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendSaturation":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendSaturation(a, b)
|
||||||
|
|
||||||
|
timeIt "blendSaturationFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendSaturationFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendColor":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendColor(a, b)
|
||||||
|
|
||||||
|
timeIt "blendColorFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendColorFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendLuminosity":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLuminosity(a, b)
|
||||||
|
|
||||||
|
timeIt "blendLuminosityFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendLuminosityFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendMask":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendMask(a, b)
|
||||||
|
|
||||||
|
timeIt "blendMaskFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendMaskFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendSubtractMask":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendSubtractMask(a, b)
|
||||||
|
|
||||||
|
timeIt "blendSubtractMaskFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendSubtractMaskFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendIntersectMask":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendIntersectMask(a, b)
|
||||||
|
|
||||||
|
timeIt "blendIntersectMaskFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendIntersectMaskFloats(a.color, b.color).rgba
|
||||||
|
|
||||||
|
timeIt "blendExcludeMask":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendExcludeMask(a, b)
|
||||||
|
|
||||||
|
timeIt "blendExcludeMaskFloats":
|
||||||
|
for i in 0 ..< iterations:
|
||||||
|
keep blendExcludeMaskFloats(a.color, b.color).rgba
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import pixie, chroma, vmath, benchy
|
import pixie, chroma, vmath, benchy
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var c: Image
|
|
||||||
var a = newImage(1000, 1000)
|
var a = newImage(1000, 1000)
|
||||||
a.fill(rgba(255, 0, 0, 255))
|
a.fill(rgba(255, 0, 0, 255))
|
||||||
var b = newImage(500, 500)
|
var b = newImage(500, 500)
|
||||||
|
@ -21,6 +20,16 @@ block:
|
||||||
a.draw(b, translate(vec2(25, 25)), bmNormal)
|
a.draw(b, translate(vec2(25, 25)), bmNormal)
|
||||||
keep(b)
|
keep(b)
|
||||||
|
|
||||||
|
block:
|
||||||
|
var a = newImage(1000, 1000)
|
||||||
|
a.fill(rgba(255, 0, 0, 255))
|
||||||
|
var b = newImage(500, 500)
|
||||||
|
b.fill(rgba(0, 255, 0, 255))
|
||||||
|
|
||||||
|
timeIt "drawCorrect Smooth bmNormal":
|
||||||
|
a.drawCorrect(b, translate(vec2(25.2, 25.2)), bmNormal)
|
||||||
|
keep(b)
|
||||||
|
|
||||||
block:
|
block:
|
||||||
var a = newImage(1000, 1000)
|
var a = newImage(1000, 1000)
|
||||||
a.fill(rgba(255, 0, 0, 255))
|
a.fill(rgba(255, 0, 0, 255))
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 346 KiB After Width: | Height: | Size: 346 KiB |
Loading…
Reference in a new issue