faster, less code

This commit is contained in:
Ryan Oldenburg 2020-12-08 21:34:05 -06:00
parent 7b58d4bf9a
commit 9ad9817959
3 changed files with 165 additions and 265 deletions

View file

@ -4,31 +4,34 @@ import chroma, math
# 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
type BlendMode* = enum type
bmNormal BlendMode* = enum
bmDarken bmNormal
bmMultiply bmDarken
bmLinearBurn bmMultiply
bmColorBurn bmLinearBurn
bmLighten bmColorBurn
bmScreen bmLighten
bmLinearDodge bmScreen
bmColorDodge bmLinearDodge
bmOverlay bmColorDodge
bmSoftLight bmOverlay
bmHardLight bmSoftLight
bmDifference bmHardLight
bmExclusion bmDifference
bmHue bmExclusion
bmSaturation bmHue
bmColor bmSaturation
bmLuminosity bmColor
bmLuminosity
bmMask ## Special blend mode that is used for masking bmMask ## Special blend mode that is used for masking
bmOverwrite ## Special that does not blend but copies the pixels from target. bmOverwrite ## Special that does not blend but copies the pixels from target.
bmSubtractMask ## Inverse mask bmSubtractMask ## Inverse mask
bmIntersectMask bmIntersectMask
bmExcludeMask bmExcludeMask
Mixer* = proc(a, b: ColorRGBA): ColorRGBA
proc `+`*(a, b: Color): Color {.inline.} = proc `+`*(a, b: Color): Color {.inline.} =
result.r = a.r + b.r result.r = a.r + b.r
@ -123,202 +126,176 @@ proc alphaFix(Cb, Cs, mixed: Color): Color {.inline.} =
result.g /= result.a result.g /= result.a
result.b /= result.a result.b /= result.a
proc blendDarken(Cb, Cs: float32): float32 {.inline.} = proc blendDarkenFloat(Cb, Cs: float32): float32 {.inline.} =
min(Cb, Cs) min(Cb, Cs)
proc blendMultiply(Cb, Cs: float32): float32 {.inline.} = proc blendMultiplyFloat(Cb, Cs: float32): float32 {.inline.} =
Cb * Cs Cb * Cs
proc blendLinearBurn(Cb, Cs: float32): float32 {.inline.} = proc blendLinearBurnFloat(Cb, Cs: float32): float32 {.inline.} =
Cb + Cs - 1 Cb + Cs - 1
proc blendColorBurn(Cb, Cs: float32): float32 {.inline.} = proc blendColorBurnFloat(Cb, Cs: float32): float32 {.inline.} =
if Cb == 1: 1.0 if Cb == 1: 1.0
elif Cs == 0: 0.0 elif Cs == 0: 0.0
else: 1.0 - min(1, (1 - Cb) / Cs) else: 1.0 - min(1, (1 - Cb) / Cs)
proc blendLighten(Cb, Cs: float32): float32 {.inline.} = proc blendLightenFloat(Cb, Cs: float32): float32 {.inline.} =
max(Cb, Cs) max(Cb, Cs)
proc blendScreen(Cb, Cs: float32): float32 {.inline.} = proc blendScreenFloat(Cb, Cs: float32): float32 {.inline.} =
screen(Cb, Cs) screen(Cb, Cs)
proc blendLinearDodge(Cb, Cs: float32): float32 {.inline.} = proc blendLinearDodgeFloat(Cb, Cs: float32): float32 {.inline.} =
Cb + Cs Cb + Cs
proc blendColorDodge(Cb, Cs: float32): float32 {.inline.} = proc blendColorDodgeFloat(Cb, Cs: float32): float32 {.inline.} =
if Cb == 0: 0.0 if Cb == 0: 0.0
elif Cs == 1: 1.0 elif Cs == 1: 1.0
else: min(1, Cb / (1 - Cs)) else: min(1, Cb / (1 - Cs))
proc blendOverlay(Cb, Cs: float32): float32 {.inline.} = proc blendOverlayFloat(Cb, Cs: float32): float32 {.inline.} =
hardLight(Cs, Cb) hardLight(Cs, Cb)
proc blendHardLight(Cb, Cs: float32): float32 {.inline.} = proc blendHardLightFloat(Cb, Cs: float32): float32 {.inline.} =
hardLight(Cb, Cs) hardLight(Cb, Cs)
proc blendSoftLight(Cb, Cs: float32): float32 {.inline.} = proc blendSoftLightFloat(Cb, Cs: float32): float32 {.inline.} =
softLight(Cb, Cs) softLight(Cb, Cs)
proc blendDifference(Cb, Cs: float32): float32 {.inline.} = proc blendDifferenceFloat(Cb, Cs: float32): float32 {.inline.} =
abs(Cb - Cs) abs(Cb - Cs)
proc blendExclusion(Cb, Cs: float32): float32 {.inline.} = proc blendExclusionFloat(Cb, Cs: float32): float32 {.inline.} =
Cb + Cs - 2 * Cb * Cs Cb + Cs - 2 * Cb * Cs
proc blendNormal(Cb, Cs: Color): Color {.inline.} = proc blendNormalFloats(Cb, Cs: Color): Color {.inline.} =
result.r = Cs.r result.r = Cs.r
result.g = Cs.g result.g = Cs.g
result.b = Cs.b result.b = Cs.b
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendDarken(Cb, Cs: Color): Color {.inline.} = proc blendDarkenFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendDarken(Cb.r, Cs.r) result.r = blendDarkenFloat(Cb.r, Cs.r)
result.g = blendDarken(Cb.g, Cs.g) result.g = blendDarkenFloat(Cb.g, Cs.g)
result.b = blendDarken(Cb.b, Cs.b) result.b = blendDarkenFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendMultiply(Cb, Cs: Color): Color {.inline.} = proc blendMultiplyFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendMultiply(Cb.r, Cs.r) result.r = blendMultiplyFloat(Cb.r, Cs.r)
result.g = blendMultiply(Cb.g, Cs.g) result.g = blendMultiplyFloat(Cb.g, Cs.g)
result.b = blendMultiply(Cb.b, Cs.b) result.b = blendMultiplyFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendLinearBurn(Cb, Cs: Color): Color {.inline.} = proc blendLinearBurnFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendLinearBurn(Cb.r, Cs.r) result.r = blendLinearBurnFloat(Cb.r, Cs.r)
result.g = blendLinearBurn(Cb.g, Cs.g) result.g = blendLinearBurnFloat(Cb.g, Cs.g)
result.b = blendLinearBurn(Cb.b, Cs.b) result.b = blendLinearBurnFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendColorBurn(Cb, Cs: Color): Color {.inline.} = proc blendColorBurnFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendColorBurn(Cb.r, Cs.r) result.r = blendColorBurnFloat(Cb.r, Cs.r)
result.g = blendColorBurn(Cb.g, Cs.g) result.g = blendColorBurnFloat(Cb.g, Cs.g)
result.b = blendColorBurn(Cb.b, Cs.b) result.b = blendColorBurnFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendLighten(Cb, Cs: Color): Color {.inline.} = proc blendLightenFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendLighten(Cb.r, Cs.r) result.r = blendLightenFloat(Cb.r, Cs.r)
result.g = blendLighten(Cb.g, Cs.g) result.g = blendLightenFloat(Cb.g, Cs.g)
result.b = blendLighten(Cb.b, Cs.b) result.b = blendLightenFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendScreen(Cb, Cs: Color): Color {.inline.} = proc blendScreenFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendScreen(Cb.r, Cs.r) result.r = blendScreenFloat(Cb.r, Cs.r)
result.g = blendScreen(Cb.g, Cs.g) result.g = blendScreenFloat(Cb.g, Cs.g)
result.b = blendScreen(Cb.b, Cs.b) result.b = blendScreenFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendLinearDodge(Cb, Cs: Color): Color {.inline.} = proc blendLinearDodgeFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendLinearDodge(Cb.r, Cs.r) result.r = blendLinearDodgeFloat(Cb.r, Cs.r)
result.g = blendLinearDodge(Cb.g, Cs.g) result.g = blendLinearDodgeFloat(Cb.g, Cs.g)
result.b = blendLinearDodge(Cb.b, Cs.b) result.b = blendLinearDodgeFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendColorDodge(Cb, Cs: Color): Color {.inline.} = proc blendColorDodgeFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendColorDodge(Cb.r, Cs.r) result.r = blendColorDodgeFloat(Cb.r, Cs.r)
result.g = blendColorDodge(Cb.g, Cs.g) result.g = blendColorDodgeFloat(Cb.g, Cs.g)
result.b = blendColorDodge(Cb.b, Cs.b) result.b = blendColorDodgeFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendOverlay(Cb, Cs: Color): Color {.inline.} = proc blendOverlayFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendOverlay(Cb.r, Cs.r) result.r = blendOverlayFloat(Cb.r, Cs.r)
result.g = blendOverlay(Cb.g, Cs.g) result.g = blendOverlayFloat(Cb.g, Cs.g)
result.b = blendOverlay(Cb.b, Cs.b) result.b = blendOverlayFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendHardLight(Cb, Cs: Color): Color {.inline.} = proc blendHardLightFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendHardLight(Cb.r, Cs.r) result.r = blendHardLightFloat(Cb.r, Cs.r)
result.g = blendHardLight(Cb.g, Cs.g) result.g = blendHardLightFloat(Cb.g, Cs.g)
result.b = blendHardLight(Cb.b, Cs.b) result.b = blendHardLightFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendSoftLight(Cb, Cs: Color): Color {.inline.} = proc blendSoftLightFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendSoftLight(Cb.r, Cs.r) result.r = blendSoftLightFloat(Cb.r, Cs.r)
result.g = blendSoftLight(Cb.g, Cs.g) result.g = blendSoftLightFloat(Cb.g, Cs.g)
result.b = blendSoftLight(Cb.b, Cs.b) result.b = blendSoftLightFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendDifference(Cb, Cs: Color): Color {.inline.} = proc blendDifferenceFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendDifference(Cb.r, Cs.r) result.r = blendDifferenceFloat(Cb.r, Cs.r)
result.g = blendDifference(Cb.g, Cs.g) result.g = blendDifferenceFloat(Cb.g, Cs.g)
result.b = blendDifference(Cb.b, Cs.b) result.b = blendDifferenceFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendExclusion(Cb, Cs: Color): Color {.inline.} = proc blendExclusionFloats(Cb, Cs: Color): Color {.inline.} =
result.r = blendExclusion(Cb.r, Cs.r) result.r = blendExclusionFloat(Cb.r, Cs.r)
result.g = blendExclusion(Cb.g, Cs.g) result.g = blendExclusionFloat(Cb.g, Cs.g)
result.b = blendExclusion(Cb.b, Cs.b) result.b = blendExclusionFloat(Cb.b, Cs.b)
result = alphaFix(Cb, Cs, result) result = alphaFix(Cb, Cs, result)
proc blendColor(Cb, Cs: Color): Color {.inline.} = proc blendColorFloats(Cb, Cs: Color): Color {.inline.} =
let mixed = SetLum(Cs, Lum(Cb)) let mixed = SetLum(Cs, Lum(Cb))
alphaFix(Cb, Cs, mixed) alphaFix(Cb, Cs, mixed)
proc blendLuminosity(Cb, Cs: Color): Color {.inline.} = proc blendLuminosityFloats(Cb, Cs: Color): Color {.inline.} =
let mixed = SetLum(Cb, Lum(Cs)) let mixed = SetLum(Cb, Lum(Cs))
alphaFix(Cb, Cs, mixed) alphaFix(Cb, Cs, mixed)
proc blendHue(Cb, Cs: Color): Color {.inline.} = proc blendHueFloats(Cb, Cs: Color): Color {.inline.} =
let mixed = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)) let mixed = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
alphaFix(Cb, Cs, mixed) alphaFix(Cb, Cs, mixed)
proc blendSaturation(Cb, Cs: Color): Color {.inline.} = proc blendSaturationFloats(Cb, Cs: Color): Color {.inline.} =
let mixed = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)) let mixed = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
alphaFix(Cb, Cs, mixed) alphaFix(Cb, Cs, mixed)
proc blendMask(target, blend: Color): Color {.inline.} = proc blendMaskFloats(target, blend: Color): Color {.inline.} =
result.r = target.r result.r = target.r
result.g = target.g result.g = target.g
result.b = target.b result.b = target.b
result.a = min(target.a, blend.a) result.a = min(target.a, blend.a)
proc blendSubtractMask(target, blend: Color): Color {.inline.} = proc blendSubtractMaskFloats(target, blend: Color): Color {.inline.} =
result.r = target.r result.r = target.r
result.g = target.g result.g = target.g
result.b = target.b result.b = target.b
result.a = target.a * (1 - blend.a) result.a = target.a * (1 - blend.a)
proc blendIntersectMask(target, blend: Color): Color {.inline.} = proc blendIntersectMaskFloats(target, blend: Color): Color {.inline.} =
result.r = target.r result.r = target.r
result.g = target.g result.g = target.g
result.b = target.b result.b = target.b
result.a = target.a * blend.a result.a = target.a * blend.a
proc blendExcludeMask(target, blend: Color): Color {.inline.} = proc blendExcludeMaskFloats(target, blend: Color): Color {.inline.} =
result.r = target.r result.r = target.r
result.g = target.g result.g = target.g
result.b = target.b result.b = target.b
result.a = abs(target.a - blend.a) result.a = abs(target.a - blend.a)
proc blendOverwrite(target, blend: Color): Color {.inline.} = proc blendOverwriteFloats(target, blend: Color): Color {.inline.} =
result = blend result = blend
# proc mix*(blendMode: BlendMode, dest, src: Color): Color {.inline.} =
# case blendMode
# of bmNormal: blendNormal(dest, src)
# of bmDarken: blendDarken(dest, src)
# of bmMultiply: blendMultiply(dest, src)
# of bmLinearBurn: blendLinearBurn(dest, src)
# of bmColorBurn: blendColorBurn(dest, src)
# of bmLighten: blendLighten(dest, src)
# of bmScreen: blendScreen(dest, src)
# of bmLinearDodge: blendLinearDodge(dest, src)
# of bmColorDodge: blendColorDodge(dest, src)
# of bmOverlay: blendOverlay(dest, src)
# of bmSoftLight: blendSoftLight(dest, src)
# of bmHardLight: blendHardLight(dest, src)
# of bmDifference: blendDifference(dest, src)
# of bmExclusion: blendExclusion(dest, src)
# of bmHue: blendHue(dest, src)
# of bmSaturation: blendSaturation(dest, src)
# of bmColor: blendColor(dest, src)
# of bmLuminosity: blendLuminosity(dest, src)
# of bmMask: blendMask(dest, src)
# of bmOverwrite: blendOverwrite(dest, src)
# of bmSubtractMask: blendSubtractMask(dest, src)
# of bmIntersectMask: blendIntersectMask(dest, src)
# of bmExcludeMask: blendExcludeMask(dest, src)
proc alphaFix(Cb, Cs, mixed: ColorRGBA): ColorRGBA {.inline.} = proc alphaFix(Cb, Cs, mixed: ColorRGBA): ColorRGBA {.inline.} =
let ab = Cb.a.int32 let ab = Cb.a.int32
let As = Cs.a.int32 let As = Cs.a.int32
@ -335,63 +312,62 @@ proc alphaFix(Cb, Cs, mixed: ColorRGBA): ColorRGBA {.inline.} =
result.b = (b div a div 255).uint8 result.b = (b div a div 255).uint8
result.a = a.uint8 result.a = a.uint8
proc blendNormal*(a, b: ColorRGBA): ColorRGBA = proc blendNormal(a, b: ColorRGBA): ColorRGBA =
# blendNormal(a.color, b.color).rgba
result.r = b.r result.r = b.r
result.g = b.g result.g = b.g
result.b = b.b result.b = b.b
result = alphaFix(a, b, result) result = alphaFix(a, b, result)
proc blendDarken(a, b: ColorRGBA): ColorRGBA = proc blendDarken(a, b: ColorRGBA): ColorRGBA =
blendDarken(a.color, b.color).rgba blendDarkenFloats(a.color, b.color).rgba
proc blendMultiply(a, b: ColorRGBA): ColorRGBA = proc blendMultiply(a, b: ColorRGBA): ColorRGBA =
blendMultiply(a.color, b.color).rgba blendMultiplyFloats(a.color, b.color).rgba
proc blendLinearBurn(a, b: ColorRGBA): ColorRGBA = proc blendLinearBurn(a, b: ColorRGBA): ColorRGBA =
blendLinearBurn(a.color, b.color).rgba blendLinearBurnFloats(a.color, b.color).rgba
proc blendColorBurn(a, b: ColorRGBA): ColorRGBA = proc blendColorBurn(a, b: ColorRGBA): ColorRGBA =
blendColorBurn(a.color, b.color).rgba blendColorBurnFloats(a.color, b.color).rgba
proc blendLighten(a, b: ColorRGBA): ColorRGBA = proc blendLighten(a, b: ColorRGBA): ColorRGBA =
blendLighten(a.color, b.color).rgba blendLightenFloats(a.color, b.color).rgba
proc blendScreen(a, b: ColorRGBA): ColorRGBA = proc blendScreen(a, b: ColorRGBA): ColorRGBA =
blendScreen(a.color, b.color).rgba blendScreenFloats(a.color, b.color).rgba
proc blendLinearDodge(a, b: ColorRGBA): ColorRGBA = proc blendLinearDodge(a, b: ColorRGBA): ColorRGBA =
blendLinearDodge(a.color, b.color).rgba blendLinearDodgeFloats(a.color, b.color).rgba
proc blendColorDodge(a, b: ColorRGBA): ColorRGBA = proc blendColorDodge(a, b: ColorRGBA): ColorRGBA =
blendColorDodge(a.color, b.color).rgba blendColorDodgeFloats(a.color, b.color).rgba
proc blendOverlay(a, b: ColorRGBA): ColorRGBA = proc blendOverlay(a, b: ColorRGBA): ColorRGBA =
blendOverlay(a.color, b.color).rgba blendOverlayFloats(a.color, b.color).rgba
proc blendHardLight(a, b: ColorRGBA): ColorRGBA = proc blendHardLight(a, b: ColorRGBA): ColorRGBA =
blendHardLight(a.color, b.color).rgba blendHardLightFloats(a.color, b.color).rgba
proc blendSoftLight(a, b: ColorRGBA): ColorRGBA = proc blendSoftLight(a, b: ColorRGBA): ColorRGBA =
blendSoftLight(a.color, b.color).rgba blendSoftLightFloats(a.color, b.color).rgba
proc blendDifference(a, b: ColorRGBA): ColorRGBA = proc blendDifference(a, b: ColorRGBA): ColorRGBA =
blendDifference(a.color, b.color).rgba blendDifferenceFloats(a.color, b.color).rgba
proc blendExclusion(a, b: ColorRGBA): ColorRGBA = proc blendExclusion(a, b: ColorRGBA): ColorRGBA =
blendExclusion(a.color, b.color).rgba blendExclusionFloats(a.color, b.color).rgba
proc blendColor(a, b: ColorRGBA): ColorRGBA = proc blendColor(a, b: ColorRGBA): ColorRGBA =
blendColor(a.color, b.color).rgba blendColorFloats(a.color, b.color).rgba
proc blendLuminosity(a, b: ColorRGBA): ColorRGBA = proc blendLuminosity(a, b: ColorRGBA): ColorRGBA =
blendLuminosity(a.color, b.color).rgba blendLuminosityFloats(a.color, b.color).rgba
proc blendHue(a, b: ColorRGBA): ColorRGBA = proc blendHue(a, b: ColorRGBA): ColorRGBA =
blendHue(a.color, b.color).rgba blendHueFloats(a.color, b.color).rgba
proc blendSaturation(a, b: ColorRGBA): ColorRGBA = proc blendSaturation(a, b: ColorRGBA): ColorRGBA =
blendSaturation(a.color, b.color).rgba blendSaturationFloats(a.color, b.color).rgba
proc blendMask(a, b: ColorRGBA): ColorRGBA = proc blendMask(a, b: ColorRGBA): ColorRGBA =
result.r = a.r result.r = a.r
@ -400,66 +376,39 @@ proc blendMask(a, b: ColorRGBA): ColorRGBA =
result.a = min(a.a, b.a) result.a = min(a.a, b.a)
proc blendSubtractMask(a, b: ColorRGBA): ColorRGBA = proc blendSubtractMask(a, b: ColorRGBA): ColorRGBA =
blendSubtractMask(a.color, b.color).rgba blendSubtractMaskFloats(a.color, b.color).rgba
proc blendIntersectMask(a, b: ColorRGBA): ColorRGBA = proc blendIntersectMask(a, b: ColorRGBA): ColorRGBA =
blendIntersectMask(a.color, b.color).rgba blendIntersectMaskFloats(a.color, b.color).rgba
proc blendExcludeMask(a, b: ColorRGBA): ColorRGBA = proc blendExcludeMask(a, b: ColorRGBA): ColorRGBA =
blendExcludeMask(a.color, b.color).rgba blendExcludeMaskFloats(a.color, b.color).rgba
proc blendOverwrite(a, b: ColorRGBA): ColorRGBA = proc blendOverwrite(a, b: ColorRGBA): ColorRGBA =
blendOverwrite(a.color, b.color).rgba blendOverwriteFloats(a.color, b.color).rgba
proc mix*(blendMode: BlendMode, dest, src: ColorRGBA): ColorRGBA {.inline.} = proc mixer*(blendMode: BlendMode): Mixer =
case blendMode case blendMode
of bmNormal: blendNormal(dest, src) of bmNormal: blendNormal
of bmDarken: blendDarken(dest, src) of bmDarken: blendDarken
of bmMultiply: blendMultiply(dest, src) of bmMultiply: blendMultiply
of bmLinearBurn: blendLinearBurn(dest, src) of bmLinearBurn: blendLinearBurn
of bmColorBurn: blendColorBurn(dest, src) of bmColorBurn: blendColorBurn
of bmLighten: blendLighten(dest, src) of bmLighten: blendLighten
of bmScreen: blendScreen(dest, src) of bmScreen: blendScreen
of bmLinearDodge: blendLinearDodge(dest, src) of bmLinearDodge: blendLinearDodge
of bmColorDodge: blendColorDodge(dest, src) of bmColorDodge: blendColorDodge
of bmOverlay: blendOverlay(dest, src) of bmOverlay: blendOverlay
of bmSoftLight: blendSoftLight(dest, src) of bmSoftLight: blendSoftLight
of bmHardLight: blendHardLight(dest, src) of bmHardLight: blendHardLight
of bmDifference: blendDifference(dest, src) of bmDifference: blendDifference
of bmExclusion: blendExclusion(dest, src) of bmExclusion: blendExclusion
of bmHue: blendHue(dest, src) of bmHue: blendHue
of bmSaturation: blendSaturation(dest, src) of bmSaturation: blendSaturation
of bmColor: blendColor(dest, src) of bmColor: blendColor
of bmLuminosity: blendLuminosity(dest, src) of bmLuminosity: blendLuminosity
of bmMask: blendMask(dest, src) of bmMask: blendMask
of bmOverwrite: blendOverwrite(dest, src) of bmOverwrite: blendOverwrite
of bmSubtractMask: blendSubtractMask(dest, src) of bmSubtractMask: blendSubtractMask
of bmIntersectMask: blendIntersectMask(dest, src) of bmIntersectMask: blendIntersectMask
of bmExcludeMask: blendExcludeMask(dest, src) of bmExcludeMask: blendExcludeMask
proc mixStatic*(
blendMode: static[BlendMode], dest, src: ColorRGBA
): ColorRGBA {.inline.} =
when blendMOde == bmNormal: blendNormal(dest, src)
elif blendMOde == bmDarken: blendDarken(dest, src)
elif blendMOde == bmMultiply: blendMultiply(dest, src)
elif blendMOde == bmLinearBurn: blendLinearBurn(dest, src)
elif blendMOde == bmColorBurn: blendColorBurn(dest, src)
elif blendMOde == bmLighten: blendLighten(dest, src)
elif blendMOde == bmScreen: blendScreen(dest, src)
elif blendMOde == bmLinearDodge: blendLinearDodge(dest, src)
elif blendMOde == bmColorDodge: blendColorDodge(dest, src)
elif blendMOde == bmOverlay: blendOverlay(dest, src)
elif blendMOde == bmSoftLight: blendSoftLight(dest, src)
elif blendMOde == bmHardLight: blendHardLight(dest, src)
elif blendMOde == bmDifference: blendDifference(dest, src)
elif blendMOde == bmExclusion: blendExclusion(dest, src)
elif blendMOde == bmHue: blendHue(dest, src)
elif blendMOde == bmSaturation: blendSaturation(dest, src)
elif blendMOde == bmColor: blendColor(dest, src)
elif blendMOde == bmLuminosity: blendLuminosity(dest, src)
elif blendMOde == bmMask: blendMask(dest, src)
elif blendMOde == bmOverwrite: blendOverwrite(dest, src)
elif blendMOde == bmSubtractMask: blendSubtractMask(dest, src)
elif blendMOde == bmIntersectMask: blendIntersectMask(dest, src)
elif blendMOde == bmExcludeMask: blendExcludeMask(dest, src)

View file

@ -409,13 +409,14 @@ proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
minFilterBy2 /= 2 minFilterBy2 /= 2
matInv = matInv * scale(vec2(0.5, 0.5)) matInv = matInv * scale(vec2(0.5, 0.5))
let mixer = blendMode.mixer()
for y in 0 ..< a.height: for y in 0 ..< a.height:
for x in 0 ..< a.width: for x in 0 ..< a.width:
let srcPos = matInv * vec2(x.float32 + h, y.float32 + h) let
var rgba = a.getRgbaUnsafe(x, y) srcPos = matInv * vec2(x.float32 + h, y.float32 + h)
let rgba2 = b.getRgbaSmooth(srcPos.x - h, srcPos.y - h) rgba = a.getRgbaUnsafe(x, y)
rgba = blendMode.mix(rgba, rgba2) rgba2 = b.getRgbaSmooth(srcPos.x - h, srcPos.y - h)
a.setRgbaUnsafe(x, y, rgba) a.setRgbaUnsafe(x, y, mixer(rgba, rgba2))
const h = 0.5.float32 const h = 0.5.float32
@ -423,9 +424,10 @@ proc drawUber(
a, b: Image, a, b: Image,
p, dx, dy: Vec2, p, dx, dy: Vec2,
lines: array[0..3, Segment], lines: array[0..3, Segment],
blendMode: static[BlendMode], blendMode: BlendMode,
smooth: static[bool] smooth: bool
) = ) =
let mixer = blendMode.mixer()
for y in 0 ..< a.height: for y in 0 ..< a.height:
var var
xMin = 0 xMin = 0
@ -450,7 +452,7 @@ proc drawUber(
xMin = xMin.clamp(0, a.width) xMin = xMin.clamp(0, a.width)
xMax = xMax.clamp(0, a.width) xMax = xMax.clamp(0, a.width)
when blendMode == bmIntersectMask: if blendMode == bmIntersectMask:
if xMin > 0: if xMin > 0:
zeroMem(a.getAddr(0, y), 4 * xMin) zeroMem(a.getAddr(0, y), 4 * xMin)
@ -459,17 +461,15 @@ proc drawUber(
srcPos = p + dx * float32(x) + dy * float32(y) srcPos = p + dx * float32(x) + dy * float32(y)
xFloat = srcPos.x - h xFloat = srcPos.x - h
yFloat = srcPos.y - h yFloat = srcPos.y - h
var
rgba = a.getRgbaUnsafe(x, y) rgba = a.getRgbaUnsafe(x, y)
rgba2 = rgba2 =
when smooth: if smooth:
b.getRgbaSmooth(xFloat, yFloat) b.getRgbaSmooth(xFloat, yFloat)
else: else:
b.getRgbaUnsafe(xFloat.round.int, yFloat.round.int) b.getRgbaUnsafe(xFloat.round.int, yFloat.round.int)
rgba = blendMode.mixStatic(rgba, rgba2) a.setRgbaUnsafe(x, y, mixer(rgba, rgba2))
a.setRgbaUnsafe(x, y, rgba)
when blendMode == bmIntersectMask: if blendMode == bmIntersectMask:
if a.width - xMax > 0: if a.width - xMax > 0:
zeroMem(a.getAddr(xMax, y), 4 * (a.width - xMax)) zeroMem(a.getAddr(xMax, y), 4 * (a.width - xMax))
@ -510,56 +510,7 @@ proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
let smooth = not(dx.length == 1.0 and dy.length == 1.0 and let smooth = not(dx.length == 1.0 and dy.length == 1.0 and
mat[2, 0].fractional == 0.0 and mat[2, 1].fractional == 0.0) mat[2, 0].fractional == 0.0 and mat[2, 1].fractional == 0.0)
if not smooth: a.drawUber(b, p, dx, dy, lines, blendMode, smooth)
case blendMode
of bmNormal: a.drawUber(b, p, dx, dy, lines, bmNormal, false)
of bmDarken: a.drawUber(b, p, dx, dy, lines, bmDarken, false)
of bmMultiply: a.drawUber(b, p, dx, dy, lines, bmMultiply, false)
of bmLinearBurn: a.drawUber(b, p, dx, dy, lines, bmLinearBurn, false)
of bmColorBurn: a.drawUber(b, p, dx, dy, lines, bmColorBurn, false)
of bmLighten: a.drawUber(b, p, dx, dy, lines, bmLighten, false)
of bmScreen: a.drawUber(b, p, dx, dy, lines, bmScreen, false)
of bmLinearDodge: a.drawUber(b, p, dx, dy, lines, bmLinearDodge, false)
of bmColorDodge: a.drawUber(b, p, dx, dy, lines, bmColorDodge, false)
of bmOverlay: a.drawUber(b, p, dx, dy, lines, bmOverlay, false)
of bmSoftLight: a.drawUber(b, p, dx, dy, lines, bmSoftLight, false)
of bmHardLight: a.drawUber(b, p, dx, dy, lines, bmHardLight, false)
of bmDifference: a.drawUber(b, p, dx, dy, lines, bmDifference, false)
of bmExclusion: a.drawUber(b, p, dx, dy, lines, bmExclusion, false)
of bmHue: a.drawUber(b, p, dx, dy, lines, bmHue, false)
of bmSaturation: a.drawUber(b, p, dx, dy, lines, bmSaturation, false)
of bmColor: a.drawUber(b, p, dx, dy, lines, bmColor, false)
of bmLuminosity: a.drawUber(b, p, dx, dy, lines, bmLuminosity, false)
of bmMask: a.drawUber(b, p, dx, dy, lines, bmMask, false)
of bmOverwrite: a.drawUber(b, p, dx, dy, lines, bmOverwrite, false)
of bmSubtractMask: a.drawUber(b, p, dx, dy, lines, bmSubtractMask, false)
of bmIntersectMask: a.drawUber(b, p, dx, dy, lines, bmIntersectMask, false)
of bmExcludeMask: a.drawUber(b, p, dx, dy, lines, bmExcludeMask, false)
else:
case blendMode
of bmNormal: a.drawUber(b, p, dx, dy, lines, bmNormal, true)
of bmDarken: a.drawUber(b, p, dx, dy, lines, bmDarken, true)
of bmMultiply: a.drawUber(b, p, dx, dy, lines, bmMultiply, true)
of bmLinearBurn: a.drawUber(b, p, dx, dy, lines, bmLinearBurn, true)
of bmColorBurn: a.drawUber(b, p, dx, dy, lines, bmColorBurn, true)
of bmLighten: a.drawUber(b, p, dx, dy, lines, bmLighten, true)
of bmScreen: a.drawUber(b, p, dx, dy, lines, bmScreen, true)
of bmLinearDodge: a.drawUber(b, p, dx, dy, lines, bmLinearDodge, true)
of bmColorDodge: a.drawUber(b, p, dx, dy, lines, bmColorDodge, true)
of bmOverlay: a.drawUber(b, p, dx, dy, lines, bmOverlay, true)
of bmSoftLight: a.drawUber(b, p, dx, dy, lines, bmSoftLight, true)
of bmHardLight: a.drawUber(b, p, dx, dy, lines, bmHardLight, true)
of bmDifference: a.drawUber(b, p, dx, dy, lines, bmDifference, true)
of bmExclusion: a.drawUber(b, p, dx, dy, lines, bmExclusion, true)
of bmHue: a.drawUber(b, p, dx, dy, lines, bmHue, true)
of bmSaturation: a.drawUber(b, p, dx, dy, lines, bmSaturation, true)
of bmColor: a.drawUber(b, p, dx, dy, lines, bmColor, true)
of bmLuminosity: a.drawUber(b, p, dx, dy, lines, bmLuminosity, true)
of bmMask: a.drawUber(b, p, dx, dy, lines, bmMask, true)
of bmOverwrite: a.drawUber(b, p, dx, dy, lines, bmOverwrite, true)
of bmSubtractMask: a.drawUber(b, p, dx, dy, lines, bmSubtractMask, true)
of bmIntersectMask: a.drawUber(b, p, dx, dy, lines, bmIntersectMask, true)
of bmExcludeMask: a.drawUber(b, p, dx, dy, lines, bmExcludeMask, true)
proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} = proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} =
a.draw(b, translate(pos), blendMode) a.draw(b, translate(pos), blendMode)

View file

@ -4,7 +4,7 @@ block:
var c: Image 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(1000, 1000) var b = newImage(500, 500)
b.fill(rgba(0, 255, 0, 255)) b.fill(rgba(0, 255, 0, 255))
timeIt "drawCorrect bmNormal": timeIt "drawCorrect bmNormal":
@ -14,7 +14,7 @@ block:
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))
var b = newImage(1000, 1000) var b = newImage(500, 500)
b.fill(rgba(0, 255, 0, 255)) b.fill(rgba(0, 255, 0, 255))
timeIt "draw bmNormal": timeIt "draw bmNormal":
@ -24,7 +24,7 @@ block:
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))
var b = newImage(1000, 1000) var b = newImage(500, 500)
b.fill(rgba(0, 255, 0, 255)) b.fill(rgba(0, 255, 0, 255))
timeIt "draw Smooth bmNormal": timeIt "draw Smooth bmNormal":