blends, blurs, masks checkpoint
This commit is contained in:
parent
913c7e9498
commit
29047d6a46
7 changed files with 193 additions and 152 deletions
|
@ -32,19 +32,15 @@ type
|
||||||
bmExcludeMask
|
bmExcludeMask
|
||||||
|
|
||||||
Blender* = proc(backdrop, source: ColorRGBA): ColorRGBA
|
Blender* = proc(backdrop, source: ColorRGBA): ColorRGBA
|
||||||
|
Masker* = proc(backdrop, source: uint8): uint8
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
|
||||||
import nimsimd/sse2
|
|
||||||
|
|
||||||
type BlenderSimd* = proc(blackdrop, source: M128i): M128i
|
|
||||||
|
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.push checks: off.}
|
{.push checks: off.}
|
||||||
|
|
||||||
proc blendAlpha(backdrop, source: uint8): uint8 {.inline.} =
|
proc blendAlpha*(backdrop, source: uint8): uint8 {.inline.} =
|
||||||
source + ((backdrop.uint32 * (255 - source)) div 255).uint8
|
source + ((backdrop.uint32 * (255 - source)) div 255).uint8
|
||||||
|
|
||||||
proc blendNormalPremultiplied*(backdrop, source: ColorRGBA): ColorRGBA =
|
proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
if backdrop.a == 0:
|
if backdrop.a == 0:
|
||||||
return source
|
return source
|
||||||
if source.a == 255:
|
if source.a == 255:
|
||||||
|
@ -65,18 +61,36 @@ proc blendMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result.b = ((backdrop.b * k) div 255).uint8
|
result.b = ((backdrop.b * k) div 255).uint8
|
||||||
result.a = ((backdrop.a * k) div 255).uint8
|
result.a = ((backdrop.a * k) div 255).uint8
|
||||||
|
|
||||||
proc blendOverwrite*(backdrop, source: ColorRGBA): ColorRGBA =
|
proc blendOverwrite(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
source
|
source
|
||||||
|
|
||||||
proc blenderPremultiplied*(blendMode: BlendMode): Blender =
|
proc blender*(blendMode: BlendMode): Blender =
|
||||||
case blendMode:
|
case blendMode:
|
||||||
of bmNormal: blendNormalPremultiplied
|
of bmNormal: blendNormal
|
||||||
of bmOverwrite: blendOverwrite
|
|
||||||
of bmMask: blendMask
|
of bmMask: blendMask
|
||||||
|
of bmOverwrite: blendOverwrite
|
||||||
else:
|
else:
|
||||||
raise newException(PixieError, "No premultiplied blender for " & $blendMode)
|
blendNormal
|
||||||
|
# raise newException(PixieError, "No blender for " & $blendMode)
|
||||||
|
|
||||||
|
proc maskMask(backdrop, source: uint8): uint8 =
|
||||||
|
((backdrop.uint32 * source) div 255).uint8
|
||||||
|
|
||||||
|
proc maskOverwrite(backdrop, source: uint8): uint8 =
|
||||||
|
source
|
||||||
|
|
||||||
|
proc masker*(blendMode: BlendMode): Masker =
|
||||||
|
case blendMode:
|
||||||
|
of bmMask: maskMask
|
||||||
|
of bmOverwrite: maskOverwrite
|
||||||
|
else:
|
||||||
|
raise newException(PixieError, "No masker for " & $blendMode)
|
||||||
|
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
|
import nimsimd/sse2
|
||||||
|
|
||||||
|
type BlenderSimd* = proc(blackdrop, source: M128i): M128i
|
||||||
|
|
||||||
proc blendNormalPremultipliedSimd*(backdrop, source: M128i): M128i =
|
proc blendNormalPremultipliedSimd*(backdrop, source: M128i): M128i =
|
||||||
let
|
let
|
||||||
alphaMask = mm_set1_epi32(cast[int32](0xff000000))
|
alphaMask = mm_set1_epi32(cast[int32](0xff000000))
|
||||||
|
@ -116,7 +130,6 @@ when defined(amd64) and not defined(pixieNoSimd):
|
||||||
else:
|
else:
|
||||||
raise newException(PixieError, "No SIMD blender for " & $blendMode)
|
raise newException(PixieError, "No SIMD blender for " & $blendMode)
|
||||||
|
|
||||||
|
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
@ -415,8 +428,8 @@ proc hardLight(backdrop, source: uint32): uint8 {.inline.} =
|
||||||
else:
|
else:
|
||||||
screen(backdrop, 2 * source - 255)
|
screen(backdrop, 2 * source - 255)
|
||||||
|
|
||||||
proc blendNormal(backdrop, source: ColorRGBA): ColorRGBA =
|
proc blendNormalOld(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
blendNormalPremultiplied(
|
blendNormal(
|
||||||
backdrop.toPremultipliedAlpha(),
|
backdrop.toPremultipliedAlpha(),
|
||||||
source.toPremultipliedAlpha()
|
source.toPremultipliedAlpha()
|
||||||
).toStraightAlpha()
|
).toStraightAlpha()
|
||||||
|
@ -558,28 +571,28 @@ proc blendExcludeMask(backdrop, source: ColorRGBA): ColorRGBA =
|
||||||
result = backdrop
|
result = backdrop
|
||||||
result.a = max(backdrop.a, source.a) - min(backdrop.a, source.a)
|
result.a = max(backdrop.a, source.a) - min(backdrop.a, source.a)
|
||||||
|
|
||||||
proc blender*(blendMode: BlendMode): Blender =
|
# proc blender*(blendMode: BlendMode): Blender =
|
||||||
case blendMode:
|
# case blendMode:
|
||||||
of bmNormal: blendNormal
|
# of bmNormal: blendNormal
|
||||||
of bmDarken: blendDarken
|
# of bmDarken: blendDarken
|
||||||
of bmMultiply: blendMultiply
|
# of bmMultiply: blendMultiply
|
||||||
of bmLinearBurn: blendLinearBurn
|
# of bmLinearBurn: blendLinearBurn
|
||||||
of bmColorBurn: blendColorBurn
|
# of bmColorBurn: blendColorBurn
|
||||||
of bmLighten: blendLighten
|
# of bmLighten: blendLighten
|
||||||
of bmScreen: blendScreen
|
# of bmScreen: blendScreen
|
||||||
of bmLinearDodge: blendLinearDodge
|
# of bmLinearDodge: blendLinearDodge
|
||||||
of bmColorDodge: blendColorDodge
|
# of bmColorDodge: blendColorDodge
|
||||||
of bmOverlay: blendOverlay
|
# of bmOverlay: blendOverlay
|
||||||
of bmSoftLight: blendSoftLight
|
# of bmSoftLight: blendSoftLight
|
||||||
of bmHardLight: blendHardLight
|
# of bmHardLight: blendHardLight
|
||||||
of bmDifference: blendDifference
|
# of bmDifference: blendDifference
|
||||||
of bmExclusion: blendExclusion
|
# of bmExclusion: blendExclusion
|
||||||
of bmHue: blendHue
|
# of bmHue: blendHue
|
||||||
of bmSaturation: blendSaturation
|
# of bmSaturation: blendSaturation
|
||||||
of bmColor: blendColor
|
# of bmColor: blendColor
|
||||||
of bmLuminosity: blendLuminosity
|
# of bmLuminosity: blendLuminosity
|
||||||
of bmMask: blendMask
|
# of bmMask: blendMask
|
||||||
of bmOverwrite: blendOverwrite
|
# of bmOverwrite: blendOverwrite
|
||||||
of bmSubtractMask: blendSubtractMask
|
# of bmSubtractMask: blendSubtractMask
|
||||||
of bmIntersectMask: blendIntersectMask
|
# of bmIntersectMask: blendIntersectMask
|
||||||
of bmExcludeMask: blendExcludeMask
|
# of bmExcludeMask: blendExcludeMask
|
||||||
|
|
|
@ -369,6 +369,13 @@ proc invert*(target: Image | Mask) =
|
||||||
for j in i ..< target.data.len:
|
for j in i ..< target.data.len:
|
||||||
target.data[j] = (255 - target.data[j]).uint8
|
target.data[j] = (255 - target.data[j]).uint8
|
||||||
|
|
||||||
|
proc newMask*(image: Image): Mask =
|
||||||
|
## Returns a new mask using the alpha values of the parameter image.
|
||||||
|
result = newMask(image.width, image.height)
|
||||||
|
|
||||||
|
for i, rgba in image.data:
|
||||||
|
result.data[i] = rgba.a
|
||||||
|
|
||||||
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA =
|
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA =
|
||||||
let
|
let
|
||||||
minX = floor(x)
|
minX = floor(x)
|
||||||
|
@ -393,21 +400,10 @@ proc drawCorrect(
|
||||||
) =
|
) =
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
|
|
||||||
proc validateMaskBlendMode() =
|
|
||||||
if blendMode notin {bmMask}:
|
|
||||||
raise newException(
|
|
||||||
PixieError,
|
|
||||||
"Blend mode " & $blendMode & " not supported for masks"
|
|
||||||
)
|
|
||||||
|
|
||||||
when type(a) is Image:
|
when type(a) is Image:
|
||||||
when type(b) is Image:
|
let blender = blendMode.blender()
|
||||||
let blender = blendMode.blenderPremultiplied()
|
|
||||||
else: # b is a Mask
|
|
||||||
validateMaskBlendMode()
|
|
||||||
else: # a is a Mask
|
else: # a is a Mask
|
||||||
when type(b) is Mask:
|
let masker = blendMode.masker()
|
||||||
validateMaskBlendMode()
|
|
||||||
|
|
||||||
var
|
var
|
||||||
matInv = mat.inverse()
|
matInv = mat.inverse()
|
||||||
|
@ -435,27 +431,23 @@ proc drawCorrect(
|
||||||
yFloat = samplePos.y - h
|
yFloat = samplePos.y - h
|
||||||
|
|
||||||
when type(a) is Image:
|
when type(a) is Image:
|
||||||
let rgba = a.getRgbaUnsafe(x, y)
|
let backdrop = a.getRgbaUnsafe(x, y)
|
||||||
var blended: ColorRGBA
|
|
||||||
when type(b) is Image:
|
when type(b) is Image:
|
||||||
let sample = b.getRgbaSmooth(xFloat, yFloat)
|
let
|
||||||
blended = blender(rgba, sample)
|
sample = b.getRgbaSmooth(xFloat, yFloat)
|
||||||
|
blended = blender(backdrop, sample)
|
||||||
else: # b is a Mask
|
else: # b is a Mask
|
||||||
let sample = b.getValueSmooth(xFloat, yFloat).uint32
|
let
|
||||||
blended = rgba(
|
sample = b.getValueSmooth(xFloat, yFloat)
|
||||||
((rgba.r * sample) div 255).uint8,
|
blended = blender(backdrop, rgba(0, 0, 0, sample))
|
||||||
((rgba.g * sample) div 255).uint8,
|
|
||||||
((rgba.b * sample) div 255).uint8,
|
|
||||||
((rgba.a * sample) div 255).uint8
|
|
||||||
)
|
|
||||||
a.setRgbaUnsafe(x, y, blended)
|
a.setRgbaUnsafe(x, y, blended)
|
||||||
else: # a is a Mask, b must be a mask
|
else: # a is a Mask
|
||||||
let value = a.getValueUnsafe(x, y)
|
let backdrop = a.getValueUnsafe(x, y)
|
||||||
when type(b) is Image:
|
when type(b) is Image:
|
||||||
let sample = b.getRgbaSmooth(xFloat, yFloat).a.uint32
|
let sample = b.getRgbaSmooth(xFloat, yFloat).a
|
||||||
else: # a is a Mask
|
else: # b is a Mask
|
||||||
let sample = b.getValueSmooth(xFloat, yFloat).uint32
|
let sample = b.getValueSmooth(xFloat, yFloat)
|
||||||
a.setValueUnsafe(x, y, ((value * sample) div 255).uint8)
|
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
||||||
|
|
||||||
proc draw*(image: Image, mask: Mask, mat: Mat3, blendMode = bmMask) =
|
proc draw*(image: Image, mask: Mask, mat: Mat3, blendMode = bmMask) =
|
||||||
image.drawCorrect(mask, mat, blendMode)
|
image.drawCorrect(mask, mat, blendMode)
|
||||||
|
@ -496,7 +488,7 @@ proc gaussianLookup(radius: int): seq[float32] =
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc blur*(image: Image, radius: float32) =
|
proc blur*(target: Image | Mask, radius: float32) =
|
||||||
## Applies Gaussian blur to the image given a radius.
|
## Applies Gaussian blur to the image given a radius.
|
||||||
let radius = round(radius).int
|
let radius = round(radius).int
|
||||||
if radius == 0:
|
if radius == 0:
|
||||||
|
@ -504,73 +496,68 @@ proc blur*(image: Image, radius: float32) =
|
||||||
|
|
||||||
let lookup = gaussianLookup(radius)
|
let lookup = gaussianLookup(radius)
|
||||||
|
|
||||||
# Blur in the X direction.
|
when type(target) is Image:
|
||||||
var blurX = newImage(image.width, image.height)
|
# Blur in the X direction.
|
||||||
for y in 0 ..< image.height:
|
var blurX = newImage(target.width, target.height)
|
||||||
for x in 0 ..< image.width:
|
for y in 0 ..< target.height:
|
||||||
var c: Color
|
for x in 0 ..< target.width:
|
||||||
var totalA = 0.0
|
var c: Color
|
||||||
for xb in -radius .. radius:
|
var totalA = 0.0
|
||||||
let c2 = image[x + xb, y].color
|
for xb in -radius .. radius:
|
||||||
let a = lookup[xb + radius]
|
let c2 = target[x + xb, y].color
|
||||||
let aa = c2.a * a
|
let a = lookup[xb + radius]
|
||||||
totalA += aa
|
let aa = c2.a * a
|
||||||
c.r += c2.r * aa
|
totalA += aa
|
||||||
c.g += c2.g * aa
|
c.r += c2.r * aa
|
||||||
c.b += c2.b * aa
|
c.g += c2.g * aa
|
||||||
c.a += c2.a * a
|
c.b += c2.b * aa
|
||||||
c.r = c.r / totalA
|
c.a += c2.a * a
|
||||||
c.g = c.g / totalA
|
c.r = c.r / totalA
|
||||||
c.b = c.b / totalA
|
c.g = c.g / totalA
|
||||||
blurX.setRgbaUnsafe(x, y, c.rgba)
|
c.b = c.b / totalA
|
||||||
|
blurX.setRgbaUnsafe(x, y, c.rgba)
|
||||||
|
|
||||||
# Blur in the Y direction.
|
# Blur in the Y direction.
|
||||||
for y in 0 ..< image.height:
|
for y in 0 ..< target.height:
|
||||||
for x in 0 ..< image.width:
|
for x in 0 ..< target.width:
|
||||||
var c: Color
|
var c: Color
|
||||||
var totalA = 0.0
|
var totalA = 0.0
|
||||||
for yb in -radius .. radius:
|
for yb in -radius .. radius:
|
||||||
let c2 = blurX[x, y + yb].color
|
let c2 = blurX[x, y + yb].color
|
||||||
let a = lookup[yb + radius]
|
let a = lookup[yb + radius]
|
||||||
let aa = c2.a * a
|
let aa = c2.a * a
|
||||||
totalA += aa
|
totalA += aa
|
||||||
c.r += c2.r * aa
|
c.r += c2.r * aa
|
||||||
c.g += c2.g * aa
|
c.g += c2.g * aa
|
||||||
c.b += c2.b * aa
|
c.b += c2.b * aa
|
||||||
c.a += c2.a * a
|
c.a += c2.a * a
|
||||||
c.r = c.r / totalA
|
c.r = c.r / totalA
|
||||||
c.g = c.g / totalA
|
c.g = c.g / totalA
|
||||||
c.b = c.b / totalA
|
c.b = c.b / totalA
|
||||||
image.setRgbaUnsafe(x, y, c.rgba)
|
target.setRgbaUnsafe(x, y, c.rgba)
|
||||||
|
|
||||||
proc blurAlpha*(image: Image, radius: float32) =
|
else: # target is a Mask
|
||||||
## Applies Gaussian blur to the image given a radius.
|
|
||||||
let radius = round(radius).int
|
|
||||||
if radius == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
let lookup = gaussianLookup(radius)
|
# Blur in the X direction.
|
||||||
|
var blurX = newMask(target.width, target.height)
|
||||||
|
for y in 0 ..< target.height:
|
||||||
|
for x in 0 ..< target.width:
|
||||||
|
var alpha: float32
|
||||||
|
for xb in -radius .. radius:
|
||||||
|
let c2 = target[x + xb, y]
|
||||||
|
let a = lookup[xb + radius]
|
||||||
|
alpha += c2.float32 * a
|
||||||
|
blurX.setValueUnsafe(x, y, alpha.uint8)
|
||||||
|
|
||||||
# Blur in the X direction.
|
# Blur in the Y direction and modify image.
|
||||||
var blurX = newImage(image.width, image.height)
|
for y in 0 ..< target.height:
|
||||||
for y in 0 ..< image.height:
|
for x in 0 ..< target.width:
|
||||||
for x in 0 ..< image.width:
|
var alpha: float32
|
||||||
var alpha: float32
|
for yb in -radius .. radius:
|
||||||
for xb in -radius .. radius:
|
let c2 = blurX[x, y + yb]
|
||||||
let c2 = image[x + xb, y]
|
let a = lookup[yb + radius]
|
||||||
let a = lookup[xb + radius]
|
alpha += c2.float32 * a
|
||||||
alpha += c2.a.float32 * a
|
target.setValueUnsafe(x, y, alpha.uint8)
|
||||||
blurX.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
|
|
||||||
|
|
||||||
# Blur in the Y direction and modify image.
|
|
||||||
for y in 0 ..< image.height:
|
|
||||||
for x in 0 ..< image.width:
|
|
||||||
var alpha: float32
|
|
||||||
for yb in -radius .. radius:
|
|
||||||
let c2 = blurX[x, y + yb]
|
|
||||||
let a = lookup[yb + radius]
|
|
||||||
alpha += c2.a.float32 * a
|
|
||||||
image.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
|
|
||||||
|
|
||||||
proc sharpOpacity*(image: Image) =
|
proc sharpOpacity*(image: Image) =
|
||||||
## Sharpens the opacity to extreme.
|
## Sharpens the opacity to extreme.
|
||||||
|
@ -688,15 +675,19 @@ proc resize*(srcImage: Image, width, height: int): Image =
|
||||||
bmOverwrite
|
bmOverwrite
|
||||||
)
|
)
|
||||||
|
|
||||||
proc shift*(image: Image, offset: Vec2) =
|
proc shift*(target: Image | Mask, offset: Vec2) =
|
||||||
## Shifts the image by offset.
|
## Shifts the target by offset.
|
||||||
if offset != vec2(0, 0):
|
if offset != vec2(0, 0):
|
||||||
let copy = image.copy() # Copy to read from.
|
let copy = target.copy() # Copy to read from
|
||||||
image.fill(rgba(0, 0, 0, 0)) # Reset this for being drawn to.
|
# Reset target for being drawn to
|
||||||
image.draw(copy, offset, bmOverwrite) # Draw copy into image.
|
when type(target) is Image:
|
||||||
|
target.fill(rgba(0, 0, 0, 0))
|
||||||
|
else:
|
||||||
|
target.fill(0)
|
||||||
|
target.draw(copy, offset, bmOverwrite) # Draw copy at offset
|
||||||
|
|
||||||
proc spread*(image: Image, spread: float32) =
|
proc spread*(image: Image, spread: float32) =
|
||||||
## Grows the image as a mask by spread.
|
## Grows the target as a mask by spread.
|
||||||
if spread == 0:
|
if spread == 0:
|
||||||
return
|
return
|
||||||
if spread < 0:
|
if spread < 0:
|
||||||
|
@ -719,18 +710,16 @@ proc spread*(image: Image, spread: float32) =
|
||||||
image.setRgbaUnsafe(x, y, rgba(0, 0, 0, maxAlpha))
|
image.setRgbaUnsafe(x, y, rgba(0, 0, 0, maxAlpha))
|
||||||
|
|
||||||
proc shadow*(
|
proc shadow*(
|
||||||
mask: Image, offset: Vec2, spread, blur: float32, color: ColorRGBA
|
image: Image, 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.
|
||||||
# TODO: copying is bad here due to this being slow already,
|
let mask = image.newMask()
|
||||||
# we're doing it tho to avoid mutating param and returning new Image.
|
|
||||||
let copy = mask.copy()
|
|
||||||
if offset != vec2(0, 0):
|
if offset != vec2(0, 0):
|
||||||
copy.shift(offset)
|
mask.shift(offset)
|
||||||
if spread > 0:
|
if spread > 0:
|
||||||
copy.spread(spread)
|
mask.spread(spread)
|
||||||
if blur > 0:
|
if blur > 0:
|
||||||
copy.blurAlpha(blur)
|
mask.blur(blur)
|
||||||
result = newImage(mask.width, mask.height)
|
result = newImage(mask.width, mask.height)
|
||||||
result.fill(color)
|
result.fill(color)
|
||||||
result.draw(copy, blendMode = bmMask)
|
result.draw(mask, blendMode = bmMask)
|
||||||
|
|
|
@ -109,5 +109,28 @@ proc getValueSmooth*(mask: Mask, x, y: float32): uint8 =
|
||||||
|
|
||||||
lerp(bottomMix, topMix, diffY)
|
lerp(bottomMix, topMix, diffY)
|
||||||
|
|
||||||
|
proc spread*(mask: Mask, spread: float32) =
|
||||||
|
## Grows the mask by spread.
|
||||||
|
if spread == 0:
|
||||||
|
return
|
||||||
|
if spread < 0:
|
||||||
|
raise newException(PixieError, "Cannot apply negative spread")
|
||||||
|
|
||||||
|
let
|
||||||
|
copy = mask.copy()
|
||||||
|
spread = round(spread).int
|
||||||
|
for y in 0 ..< mask.height:
|
||||||
|
for x in 0 ..< mask.width:
|
||||||
|
var maxValue: uint8
|
||||||
|
block blurBox:
|
||||||
|
for bx in -spread .. spread:
|
||||||
|
for by in -spread .. spread:
|
||||||
|
let value = copy[x + bx, y + by]
|
||||||
|
if value > maxValue:
|
||||||
|
maxValue = value
|
||||||
|
if maxValue == 255:
|
||||||
|
break blurBox
|
||||||
|
mask.setValueUnsafe(x, y, maxValue)
|
||||||
|
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
|
@ -931,7 +931,7 @@ proc fillShapes(
|
||||||
startX = max(0, bounds.x.int)
|
startX = max(0, bounds.x.int)
|
||||||
startY = max(0, bounds.y.int)
|
startY = max(0, bounds.y.int)
|
||||||
stopY = min(image.height, (bounds.y + bounds.h).int)
|
stopY = min(image.height, (bounds.y + bounds.h).int)
|
||||||
blender = blendMode.blenderPremultiplied()
|
blender = blendMode.blender()
|
||||||
|
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
let blenderSimd = blendMode.blenderSimd()
|
let blenderSimd = blendMode.blenderSimd()
|
||||||
|
@ -1136,8 +1136,7 @@ proc fillShapes(
|
||||||
if coverage != 0:
|
if coverage != 0:
|
||||||
let
|
let
|
||||||
backdrop = mask.getValueUnsafe(x, y)
|
backdrop = mask.getValueUnsafe(x, y)
|
||||||
blended =
|
blended = blendAlpha(backdrop, coverage)
|
||||||
coverage + ((backdrop.uint32 * (255 - coverage)) div 255).uint8
|
|
||||||
mask.setValueUnsafe(x, y, blended)
|
mask.setValueUnsafe(x, y, blended)
|
||||||
inc x
|
inc x
|
||||||
|
|
||||||
|
|
BIN
tests/images/masks/shifted.png
Normal file
BIN
tests/images/masks/shifted.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 163 B |
BIN
tests/images/masks/spread.png
Normal file
BIN
tests/images/masks/spread.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 192 B |
|
@ -1,4 +1,4 @@
|
||||||
import chroma, pixie, pixie/fileformats/png
|
import chroma, pixie, pixie/fileformats/png, vmath
|
||||||
|
|
||||||
block:
|
block:
|
||||||
let mask = newMask(100, 100)
|
let mask = newMask(100, 100)
|
||||||
|
@ -74,3 +74,20 @@ block:
|
||||||
|
|
||||||
a.draw(b)
|
a.draw(b)
|
||||||
writeFile("tests/images/masks/imageMaskedMask.png", a.encodePng())
|
writeFile("tests/images/masks/imageMaskedMask.png", a.encodePng())
|
||||||
|
|
||||||
|
block:
|
||||||
|
let a = newMask(100, 100)
|
||||||
|
a.fill(255)
|
||||||
|
a.shift(vec2(10, 10))
|
||||||
|
writeFile("tests/images/masks/shifted.png", a.encodePng())
|
||||||
|
|
||||||
|
block:
|
||||||
|
var path: Path
|
||||||
|
path.rect(40, 40, 20, 20)
|
||||||
|
|
||||||
|
let a = newMask(100, 100)
|
||||||
|
a.fillPath(path)
|
||||||
|
|
||||||
|
a.spread(10)
|
||||||
|
|
||||||
|
writeFile("tests/images/masks/spread.png", a.encodePng())
|
||||||
|
|
Loading…
Reference in a new issue