diff --git a/src/pixie/blends.nim b/src/pixie/blends.nim index b139d42..3b02119 100644 --- a/src/pixie/blends.nim +++ b/src/pixie/blends.nim @@ -4,31 +4,34 @@ import chroma, math # See https://www.w3.org/TR/compositing-1/ # See https://www.khronos.org/registry/OpenGL/extensions/KHR/KHR_blend_equation_advanced.txt -type BlendMode* = enum - bmNormal - bmDarken - bmMultiply - bmLinearBurn - bmColorBurn - bmLighten - bmScreen - bmLinearDodge - bmColorDodge - bmOverlay - bmSoftLight - bmHardLight - bmDifference - bmExclusion - bmHue - bmSaturation - bmColor - bmLuminosity +type + BlendMode* = enum + bmNormal + bmDarken + bmMultiply + bmLinearBurn + bmColorBurn + bmLighten + bmScreen + bmLinearDodge + bmColorDodge + bmOverlay + bmSoftLight + bmHardLight + bmDifference + bmExclusion + bmHue + bmSaturation + bmColor + bmLuminosity - bmMask ## Special blend mode that is used for masking - bmOverwrite ## Special that does not blend but copies the pixels from target. - bmSubtractMask ## Inverse mask - bmIntersectMask - bmExcludeMask + bmMask ## Special blend mode that is used for masking + bmOverwrite ## Special that does not blend but copies the pixels from target. + bmSubtractMask ## Inverse mask + bmIntersectMask + bmExcludeMask + + Mixer* = proc(a, b: ColorRGBA): ColorRGBA proc `+`*(a, b: Color): Color {.inline.} = result.r = a.r + b.r @@ -123,202 +126,176 @@ proc alphaFix(Cb, Cs, mixed: Color): Color {.inline.} = result.g /= result.a result.b /= result.a -proc blendDarken(Cb, Cs: float32): float32 {.inline.} = +proc blendDarkenFloat(Cb, Cs: float32): float32 {.inline.} = min(Cb, Cs) -proc blendMultiply(Cb, Cs: float32): float32 {.inline.} = +proc blendMultiplyFloat(Cb, Cs: float32): float32 {.inline.} = Cb * Cs -proc blendLinearBurn(Cb, Cs: float32): float32 {.inline.} = +proc blendLinearBurnFloat(Cb, Cs: float32): float32 {.inline.} = Cb + Cs - 1 -proc blendColorBurn(Cb, Cs: float32): float32 {.inline.} = +proc blendColorBurnFloat(Cb, Cs: float32): float32 {.inline.} = if Cb == 1: 1.0 elif Cs == 0: 0.0 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) -proc blendScreen(Cb, Cs: float32): float32 {.inline.} = +proc blendScreenFloat(Cb, Cs: float32): float32 {.inline.} = screen(Cb, Cs) -proc blendLinearDodge(Cb, Cs: float32): float32 {.inline.} = +proc blendLinearDodgeFloat(Cb, Cs: float32): float32 {.inline.} = Cb + Cs -proc blendColorDodge(Cb, Cs: float32): float32 {.inline.} = +proc blendColorDodgeFloat(Cb, Cs: float32): float32 {.inline.} = if Cb == 0: 0.0 elif Cs == 1: 1.0 else: min(1, Cb / (1 - Cs)) -proc blendOverlay(Cb, Cs: float32): float32 {.inline.} = +proc blendOverlayFloat(Cb, Cs: float32): float32 {.inline.} = hardLight(Cs, Cb) -proc blendHardLight(Cb, Cs: float32): float32 {.inline.} = +proc blendHardLightFloat(Cb, Cs: float32): float32 {.inline.} = hardLight(Cb, Cs) -proc blendSoftLight(Cb, Cs: float32): float32 {.inline.} = +proc blendSoftLightFloat(Cb, Cs: float32): float32 {.inline.} = softLight(Cb, Cs) -proc blendDifference(Cb, Cs: float32): float32 {.inline.} = +proc blendDifferenceFloat(Cb, Cs: float32): float32 {.inline.} = abs(Cb - Cs) -proc blendExclusion(Cb, Cs: float32): float32 {.inline.} = +proc blendExclusionFloat(Cb, Cs: float32): float32 {.inline.} = Cb + Cs - 2 * Cb * Cs -proc blendNormal(Cb, Cs: Color): Color {.inline.} = +proc blendNormalFloats(Cb, Cs: Color): Color {.inline.} = result.r = Cs.r result.g = Cs.g result.b = Cs.b result = alphaFix(Cb, Cs, result) -proc blendDarken(Cb, Cs: Color): Color {.inline.} = - result.r = blendDarken(Cb.r, Cs.r) - result.g = blendDarken(Cb.g, Cs.g) - result.b = blendDarken(Cb.b, Cs.b) +proc blendDarkenFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendDarkenFloat(Cb.r, Cs.r) + result.g = blendDarkenFloat(Cb.g, Cs.g) + result.b = blendDarkenFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendMultiply(Cb, Cs: Color): Color {.inline.} = - result.r = blendMultiply(Cb.r, Cs.r) - result.g = blendMultiply(Cb.g, Cs.g) - result.b = blendMultiply(Cb.b, Cs.b) +proc blendMultiplyFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendMultiplyFloat(Cb.r, Cs.r) + result.g = blendMultiplyFloat(Cb.g, Cs.g) + result.b = blendMultiplyFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendLinearBurn(Cb, Cs: Color): Color {.inline.} = - result.r = blendLinearBurn(Cb.r, Cs.r) - result.g = blendLinearBurn(Cb.g, Cs.g) - result.b = blendLinearBurn(Cb.b, Cs.b) +proc blendLinearBurnFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendLinearBurnFloat(Cb.r, Cs.r) + result.g = blendLinearBurnFloat(Cb.g, Cs.g) + result.b = blendLinearBurnFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendColorBurn(Cb, Cs: Color): Color {.inline.} = - result.r = blendColorBurn(Cb.r, Cs.r) - result.g = blendColorBurn(Cb.g, Cs.g) - result.b = blendColorBurn(Cb.b, Cs.b) +proc blendColorBurnFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendColorBurnFloat(Cb.r, Cs.r) + result.g = blendColorBurnFloat(Cb.g, Cs.g) + result.b = blendColorBurnFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendLighten(Cb, Cs: Color): Color {.inline.} = - result.r = blendLighten(Cb.r, Cs.r) - result.g = blendLighten(Cb.g, Cs.g) - result.b = blendLighten(Cb.b, Cs.b) +proc blendLightenFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendLightenFloat(Cb.r, Cs.r) + result.g = blendLightenFloat(Cb.g, Cs.g) + result.b = blendLightenFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendScreen(Cb, Cs: Color): Color {.inline.} = - result.r = blendScreen(Cb.r, Cs.r) - result.g = blendScreen(Cb.g, Cs.g) - result.b = blendScreen(Cb.b, Cs.b) +proc blendScreenFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendScreenFloat(Cb.r, Cs.r) + result.g = blendScreenFloat(Cb.g, Cs.g) + result.b = blendScreenFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendLinearDodge(Cb, Cs: Color): Color {.inline.} = - result.r = blendLinearDodge(Cb.r, Cs.r) - result.g = blendLinearDodge(Cb.g, Cs.g) - result.b = blendLinearDodge(Cb.b, Cs.b) +proc blendLinearDodgeFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendLinearDodgeFloat(Cb.r, Cs.r) + result.g = blendLinearDodgeFloat(Cb.g, Cs.g) + result.b = blendLinearDodgeFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendColorDodge(Cb, Cs: Color): Color {.inline.} = - result.r = blendColorDodge(Cb.r, Cs.r) - result.g = blendColorDodge(Cb.g, Cs.g) - result.b = blendColorDodge(Cb.b, Cs.b) +proc blendColorDodgeFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendColorDodgeFloat(Cb.r, Cs.r) + result.g = blendColorDodgeFloat(Cb.g, Cs.g) + result.b = blendColorDodgeFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendOverlay(Cb, Cs: Color): Color {.inline.} = - result.r = blendOverlay(Cb.r, Cs.r) - result.g = blendOverlay(Cb.g, Cs.g) - result.b = blendOverlay(Cb.b, Cs.b) +proc blendOverlayFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendOverlayFloat(Cb.r, Cs.r) + result.g = blendOverlayFloat(Cb.g, Cs.g) + result.b = blendOverlayFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendHardLight(Cb, Cs: Color): Color {.inline.} = - result.r = blendHardLight(Cb.r, Cs.r) - result.g = blendHardLight(Cb.g, Cs.g) - result.b = blendHardLight(Cb.b, Cs.b) +proc blendHardLightFloats(Cb, Cs: Color): Color {.inline.} = + result.r = blendHardLightFloat(Cb.r, Cs.r) + result.g = blendHardLightFloat(Cb.g, Cs.g) + result.b = blendHardLightFloat(Cb.b, Cs.b) result = alphaFix(Cb, Cs, result) -proc blendSoftLight(Cb, Cs: Color): Color {.inline.} = - result.r = blendSoftLight(Cb.r, Cs.r) - result.g = blendSoftLight(Cb.g, Cs.g) - result.b = blendSoftLight(Cb.b, Cs.b) +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 blendDifference(Cb, Cs: Color): Color {.inline.} = - result.r = blendDifference(Cb.r, Cs.r) - result.g = blendDifference(Cb.g, Cs.g) - result.b = blendDifference(Cb.b, Cs.b) +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 blendExclusion(Cb, Cs: Color): Color {.inline.} = - result.r = blendExclusion(Cb.r, Cs.r) - result.g = blendExclusion(Cb.g, Cs.g) - result.b = blendExclusion(Cb.b, Cs.b) +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 blendColor(Cb, Cs: Color): Color {.inline.} = +proc blendColorFloats(Cb, Cs: Color): Color {.inline.} = let mixed = SetLum(Cs, Lum(Cb)) alphaFix(Cb, Cs, mixed) -proc blendLuminosity(Cb, Cs: Color): Color {.inline.} = +proc blendLuminosityFloats(Cb, Cs: Color): Color {.inline.} = let mixed = SetLum(Cb, Lum(Cs)) 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)) 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)) alphaFix(Cb, Cs, mixed) -proc blendMask(target, blend: Color): Color {.inline.} = +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 blendSubtractMask(target, blend: Color): Color {.inline.} = +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 blendIntersectMask(target, blend: Color): Color {.inline.} = +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 blendExcludeMask(target, blend: Color): Color {.inline.} = +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 blendOverwrite(target, blend: Color): Color {.inline.} = +proc blendOverwriteFloats(target, blend: Color): Color {.inline.} = 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.} = let ab = Cb.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.a = a.uint8 -proc blendNormal*(a, b: ColorRGBA): ColorRGBA = - # blendNormal(a.color, b.color).rgba +proc blendNormal(a, b: ColorRGBA): ColorRGBA = result.r = b.r result.g = b.g result.b = b.b result = alphaFix(a, b, result) proc blendDarken(a, b: ColorRGBA): ColorRGBA = - blendDarken(a.color, b.color).rgba + blendDarkenFloats(a.color, b.color).rgba proc blendMultiply(a, b: ColorRGBA): ColorRGBA = - blendMultiply(a.color, b.color).rgba + blendMultiplyFloats(a.color, b.color).rgba proc blendLinearBurn(a, b: ColorRGBA): ColorRGBA = - blendLinearBurn(a.color, b.color).rgba + blendLinearBurnFloats(a.color, b.color).rgba proc blendColorBurn(a, b: ColorRGBA): ColorRGBA = - blendColorBurn(a.color, b.color).rgba + blendColorBurnFloats(a.color, b.color).rgba proc blendLighten(a, b: ColorRGBA): ColorRGBA = - blendLighten(a.color, b.color).rgba + blendLightenFloats(a.color, b.color).rgba proc blendScreen(a, b: ColorRGBA): ColorRGBA = - blendScreen(a.color, b.color).rgba + blendScreenFloats(a.color, b.color).rgba proc blendLinearDodge(a, b: ColorRGBA): ColorRGBA = - blendLinearDodge(a.color, b.color).rgba + blendLinearDodgeFloats(a.color, b.color).rgba proc blendColorDodge(a, b: ColorRGBA): ColorRGBA = - blendColorDodge(a.color, b.color).rgba + blendColorDodgeFloats(a.color, b.color).rgba proc blendOverlay(a, b: ColorRGBA): ColorRGBA = - blendOverlay(a.color, b.color).rgba + blendOverlayFloats(a.color, b.color).rgba proc blendHardLight(a, b: ColorRGBA): ColorRGBA = - blendHardLight(a.color, b.color).rgba + blendHardLightFloats(a.color, b.color).rgba proc blendSoftLight(a, b: ColorRGBA): ColorRGBA = - blendSoftLight(a.color, b.color).rgba + blendSoftLightFloats(a.color, b.color).rgba proc blendDifference(a, b: ColorRGBA): ColorRGBA = - blendDifference(a.color, b.color).rgba + blendDifferenceFloats(a.color, b.color).rgba proc blendExclusion(a, b: ColorRGBA): ColorRGBA = - blendExclusion(a.color, b.color).rgba + blendExclusionFloats(a.color, b.color).rgba proc blendColor(a, b: ColorRGBA): ColorRGBA = - blendColor(a.color, b.color).rgba + blendColorFloats(a.color, b.color).rgba proc blendLuminosity(a, b: ColorRGBA): ColorRGBA = - blendLuminosity(a.color, b.color).rgba + blendLuminosityFloats(a.color, b.color).rgba proc blendHue(a, b: ColorRGBA): ColorRGBA = - blendHue(a.color, b.color).rgba + blendHueFloats(a.color, b.color).rgba proc blendSaturation(a, b: ColorRGBA): ColorRGBA = - blendSaturation(a.color, b.color).rgba + blendSaturationFloats(a.color, b.color).rgba proc blendMask(a, b: ColorRGBA): ColorRGBA = result.r = a.r @@ -400,66 +376,39 @@ proc blendMask(a, b: ColorRGBA): ColorRGBA = result.a = min(a.a, b.a) proc blendSubtractMask(a, b: ColorRGBA): ColorRGBA = - blendSubtractMask(a.color, b.color).rgba + blendSubtractMaskFloats(a.color, b.color).rgba proc blendIntersectMask(a, b: ColorRGBA): ColorRGBA = - blendIntersectMask(a.color, b.color).rgba + blendIntersectMaskFloats(a.color, b.color).rgba proc blendExcludeMask(a, b: ColorRGBA): ColorRGBA = - blendExcludeMask(a.color, b.color).rgba + blendExcludeMaskFloats(a.color, b.color).rgba 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 - 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 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) + of bmNormal: blendNormal + of bmDarken: blendDarken + of bmMultiply: blendMultiply + of bmLinearBurn: blendLinearBurn + of bmColorBurn: blendColorBurn + of bmLighten: blendLighten + of bmScreen: blendScreen + of bmLinearDodge: blendLinearDodge + of bmColorDodge: blendColorDodge + of bmOverlay: blendOverlay + of bmSoftLight: blendSoftLight + of bmHardLight: blendHardLight + of bmDifference: blendDifference + of bmExclusion: blendExclusion + of bmHue: blendHue + of bmSaturation: blendSaturation + of bmColor: blendColor + of bmLuminosity: blendLuminosity + of bmMask: blendMask + of bmOverwrite: blendOverwrite + of bmSubtractMask: blendSubtractMask + of bmIntersectMask: blendIntersectMask + of bmExcludeMask: blendExcludeMask diff --git a/src/pixie/images.nim b/src/pixie/images.nim index f71c762..bc0e56e 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -409,13 +409,14 @@ proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) = minFilterBy2 /= 2 matInv = matInv * scale(vec2(0.5, 0.5)) + let mixer = blendMode.mixer() for y in 0 ..< a.height: for x in 0 ..< a.width: - let srcPos = matInv * vec2(x.float32 + h, y.float32 + h) - var rgba = a.getRgbaUnsafe(x, y) - let rgba2 = b.getRgbaSmooth(srcPos.x - h, srcPos.y - h) - rgba = blendMode.mix(rgba, rgba2) - a.setRgbaUnsafe(x, y, rgba) + let + srcPos = matInv * vec2(x.float32 + h, y.float32 + h) + rgba = a.getRgbaUnsafe(x, y) + rgba2 = b.getRgbaSmooth(srcPos.x - h, srcPos.y - h) + a.setRgbaUnsafe(x, y, mixer(rgba, rgba2)) const h = 0.5.float32 @@ -423,9 +424,10 @@ proc drawUber( a, b: Image, p, dx, dy: Vec2, lines: array[0..3, Segment], - blendMode: static[BlendMode], - smooth: static[bool] + blendMode: BlendMode, + smooth: bool ) = + let mixer = blendMode.mixer() for y in 0 ..< a.height: var xMin = 0 @@ -450,7 +452,7 @@ proc drawUber( xMin = xMin.clamp(0, a.width) xMax = xMax.clamp(0, a.width) - when blendMode == bmIntersectMask: + if blendMode == bmIntersectMask: if xMin > 0: zeroMem(a.getAddr(0, y), 4 * xMin) @@ -459,17 +461,15 @@ proc drawUber( srcPos = p + dx * float32(x) + dy * float32(y) xFloat = srcPos.x - h yFloat = srcPos.y - h - var rgba = a.getRgbaUnsafe(x, y) rgba2 = - when smooth: + if smooth: b.getRgbaSmooth(xFloat, yFloat) else: b.getRgbaUnsafe(xFloat.round.int, yFloat.round.int) - rgba = blendMode.mixStatic(rgba, rgba2) - a.setRgbaUnsafe(x, y, rgba) + a.setRgbaUnsafe(x, y, mixer(rgba, rgba2)) - when blendMode == bmIntersectMask: + if blendMode == bmIntersectMask: if a.width - xMax > 0: 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 mat[2, 0].fractional == 0.0 and mat[2, 1].fractional == 0.0) - if not 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) + a.drawUber(b, p, dx, dy, lines, blendMode, smooth) proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} = a.draw(b, translate(pos), blendMode) diff --git a/tests/benchmark_images_draw.nim b/tests/benchmark_images_draw.nim index ddd733a..65200ca 100644 --- a/tests/benchmark_images_draw.nim +++ b/tests/benchmark_images_draw.nim @@ -4,7 +4,7 @@ block: var c: Image var a = newImage(1000, 1000) a.fill(rgba(255, 0, 0, 255)) - var b = newImage(1000, 1000) + var b = newImage(500, 500) b.fill(rgba(0, 255, 0, 255)) timeIt "drawCorrect bmNormal": @@ -14,7 +14,7 @@ block: block: var a = newImage(1000, 1000) a.fill(rgba(255, 0, 0, 255)) - var b = newImage(1000, 1000) + var b = newImage(500, 500) b.fill(rgba(0, 255, 0, 255)) timeIt "draw bmNormal": @@ -24,7 +24,7 @@ block: block: var a = newImage(1000, 1000) a.fill(rgba(255, 0, 0, 255)) - var b = newImage(1000, 1000) + var b = newImage(500, 500) b.fill(rgba(0, 255, 0, 255)) timeIt "draw Smooth bmNormal":