draw uber takes Image | Mask + works w/o simd so far
This commit is contained in:
parent
04c7bd87d8
commit
70ab79b607
1 changed files with 118 additions and 93 deletions
|
@ -533,9 +533,7 @@ proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA =
|
||||||
|
|
||||||
lerp(bottomMix, topMix, diffY)
|
lerp(bottomMix, topMix, diffY)
|
||||||
|
|
||||||
proc drawCorrect(
|
proc drawCorrect(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
|
||||||
a: Image | Mask, b: Image | Mask, mat = mat3(), blendMode = bmNormal
|
|
||||||
) =
|
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
|
|
||||||
when type(a) is Image:
|
when type(a) is Image:
|
||||||
|
@ -587,36 +585,49 @@ proc drawCorrect(
|
||||||
let sample = b.getValueSmooth(xFloat, yFloat)
|
let sample = b.getValueSmooth(xFloat, yFloat)
|
||||||
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
||||||
|
|
||||||
proc draw*(image: Image, mask: Mask, mat: Mat3, blendMode = bmMask) =
|
proc drawUber(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
|
||||||
image.drawCorrect(mask, mat, blendMode)
|
let
|
||||||
|
corners = [
|
||||||
|
mat * vec2(0, 0),
|
||||||
|
mat * vec2(b.width.float32, 0),
|
||||||
|
mat * vec2(b.width.float32, b.height.float32),
|
||||||
|
mat * vec2(0, b.height.float32)
|
||||||
|
]
|
||||||
|
perimeter = [
|
||||||
|
segment(corners[0], corners[1]),
|
||||||
|
segment(corners[1], corners[2]),
|
||||||
|
segment(corners[2], corners[3]),
|
||||||
|
segment(corners[3], corners[0])
|
||||||
|
]
|
||||||
|
|
||||||
proc draw*(
|
var
|
||||||
image: Image, mask: Mask, pos = vec2(0, 0), blendMode = bmMask
|
matInv = mat.inverse()
|
||||||
) {.inline.} =
|
# Compute movement vectors
|
||||||
image.drawCorrect(mask, translate(pos), blendMode)
|
p = matInv * vec2(0 + h, 0 + h)
|
||||||
|
dx = matInv * vec2(1 + h, 0 + h) - p
|
||||||
|
dy = matInv * vec2(0 + h, 1 + h) - p
|
||||||
|
minFilterBy2 = max(dx.length, dy.length)
|
||||||
|
b = b
|
||||||
|
|
||||||
proc draw*(a, b: Mask, mat: Mat3, blendMode = bmMask) =
|
while minFilterBy2 > 2.0:
|
||||||
a.drawCorrect(b, mat, blendMode)
|
b = b.minifyBy2()
|
||||||
|
p /= 2
|
||||||
|
dx /= 2
|
||||||
|
dy /= 2
|
||||||
|
minFilterBy2 /= 2
|
||||||
|
matInv = matInv * scale(vec2(0.5, 0.5))
|
||||||
|
|
||||||
proc draw*(a, b: Mask, pos = vec2(0, 0), blendMode = bmMask) {.inline.} =
|
let smooth = not(
|
||||||
a.draw(b, translate(pos), blendMode)
|
dx.length == 1.0 and
|
||||||
|
dy.length == 1.0 and
|
||||||
|
mat[2, 0].fractional == 0.0 and
|
||||||
|
mat[2, 1].fractional == 0.0
|
||||||
|
)
|
||||||
|
|
||||||
proc draw*(mask: Mask, image: Image, mat: Mat3, blendMode = bmMask) =
|
when type(a) is Image:
|
||||||
mask.drawCorrect(image, mat, blendMode)
|
|
||||||
|
|
||||||
proc draw*(
|
|
||||||
mask: Mask, image: Image, pos = vec2(0, 0), blendMode = bmMask
|
|
||||||
) {.inline.} =
|
|
||||||
mask.draw(image, translate(pos), blendMode)
|
|
||||||
|
|
||||||
proc drawUber(
|
|
||||||
a, b: Image,
|
|
||||||
p, dx, dy: Vec2,
|
|
||||||
perimeter: array[0..3, Segment],
|
|
||||||
blendMode: BlendMode,
|
|
||||||
smooth: bool
|
|
||||||
) =
|
|
||||||
let blender = blendMode.blender()
|
let blender = blendMode.blender()
|
||||||
|
else: # a is a Mask
|
||||||
|
let masker = blendMode.masker()
|
||||||
|
|
||||||
# Determine where we should start and stop drawing in the y dimension
|
# Determine where we should start and stop drawing in the y dimension
|
||||||
var yMin, yMax: int
|
var yMin, yMax: int
|
||||||
|
@ -662,89 +673,103 @@ proc drawUber(
|
||||||
srcPos = p + dx * x.float32 + dy * y.float32
|
srcPos = p + dx * x.float32 + dy * y.float32
|
||||||
xFloat = srcPos.x - h
|
xFloat = srcPos.x - h
|
||||||
yFloat = srcPos.y - h
|
yFloat = srcPos.y - h
|
||||||
backdrop = a.getRgbaUnsafe(x, y)
|
when type(a) is Image:
|
||||||
source = b.getRgbaSmooth(xFloat, yFloat)
|
let backdrop = a.getRgbaUnsafe(x, y)
|
||||||
a.setRgbaUnsafe(x, y, blender(backdrop, source))
|
when type(b) is Image:
|
||||||
|
let
|
||||||
|
sample = b.getRgbaSmooth(xFloat, yFloat)
|
||||||
|
blended = blender(backdrop, sample)
|
||||||
|
else: # b is a Mask
|
||||||
|
let
|
||||||
|
sample = b.getValueSmooth(xFloat, yFloat)
|
||||||
|
blended = blender(backdrop, rgba(0, 0, 0, sample))
|
||||||
|
a.setRgbaUnsafe(x, y, blended)
|
||||||
|
else: # a is a Mask
|
||||||
|
let backdrop = a.getValueUnsafe(x, y)
|
||||||
|
when type(b) is Image:
|
||||||
|
let sample = b.getRgbaSmooth(xFloat, yFloat).a
|
||||||
|
else: # b is a Mask
|
||||||
|
let sample = b.getValueSmooth(xFloat, yFloat)
|
||||||
|
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
||||||
else:
|
else:
|
||||||
var x = xMin
|
var x = xMin
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
# when defined(amd64) and not defined(pixieNoSimd):
|
||||||
if blendMode.hasSimdBlender():
|
# if blendMode.hasSimdBlender():
|
||||||
if dx.x == 1 and dx.y == 0 and dy.x == 0 and dy.y == 1:
|
# if dx.x == 1 and dx.y == 0 and dy.x == 0 and dy.y == 1:
|
||||||
# Check we are not rotated before using SIMD blends
|
# # Check we are not rotated before using SIMD blends
|
||||||
let blenderSimd = blendMode.blenderSimd()
|
# let blenderSimd = blendMode.blenderSimd()
|
||||||
for _ in countup(x, xMax - 4, 4):
|
# for _ in countup(x, xMax - 4, 4):
|
||||||
let
|
# let
|
||||||
srcPos = p + dx * x.float32 + dy * y.float32
|
# srcPos = p + dx * x.float32 + dy * y.float32
|
||||||
sx = srcPos.x.int
|
# sx = srcPos.x.int
|
||||||
sy = srcPos.y.int
|
# sy = srcPos.y.int
|
||||||
backdrop = mm_loadu_si128(a.data[a.dataIndex(x, y)].addr)
|
# backdrop = mm_loadu_si128(a.data[a.dataIndex(x, y)].addr)
|
||||||
source = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
# source = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
||||||
mm_storeu_si128(
|
# mm_storeu_si128(
|
||||||
a.data[a.dataIndex(x, y)].addr,
|
# a.data[a.dataIndex(x, y)].addr,
|
||||||
blenderSimd(backdrop, source)
|
# blenderSimd(backdrop, source)
|
||||||
)
|
# )
|
||||||
x += 4
|
# x += 4
|
||||||
|
|
||||||
for _ in x ..< xMax:
|
for _ in x ..< xMax:
|
||||||
let
|
let
|
||||||
srcPos = p + dx * x.float32 + dy * y.float32
|
srcPos = p + dx * x.float32 + dy * y.float32
|
||||||
xFloat = srcPos.x - h
|
xFloat = srcPos.x - h
|
||||||
yFloat = srcPos.y - h
|
yFloat = srcPos.y - h
|
||||||
backdrop = a.getRgbaUnsafe(x, y)
|
|
||||||
source = b.getRgbaUnsafe(xFloat.int, yFloat.int)
|
when type(a) is Image:
|
||||||
a.setRgbaUnsafe(x, y, blender(backdrop, source))
|
let backdrop = a.getRgbaUnsafe(x, y)
|
||||||
|
when type(b) is Image:
|
||||||
|
let
|
||||||
|
sample = b.getRgbaUnsafe(xFloat.int, yFloat.int)
|
||||||
|
blended = blender(backdrop, sample)
|
||||||
|
else: # b is a Mask
|
||||||
|
let
|
||||||
|
sample = b.getValueUnsafe(xFloat.int, yFloat.int)
|
||||||
|
blended = blender(backdrop, rgba(0, 0, 0, sample))
|
||||||
|
a.setRgbaUnsafe(x, y, blended)
|
||||||
|
else: # a is a Mask
|
||||||
|
let backdrop = a.getValueUnsafe(x, y)
|
||||||
|
when type(b) is Image:
|
||||||
|
let sample = b.getRgbaUnsafe(xFloat.int, yFloat.int).a
|
||||||
|
else: # b is a Mask
|
||||||
|
let sample = b.getValueUnsafe(xFloat.int, yFloat.int)
|
||||||
|
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
||||||
inc x
|
inc x
|
||||||
|
|
||||||
if blendMode == bmIntersectMask:
|
if blendMode == bmIntersectMask:
|
||||||
if a.width - xMax > 0:
|
if a.width - xMax > 0:
|
||||||
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
|
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
|
||||||
|
|
||||||
proc draw*(a, b: Image, mat: Mat3, blendMode = bmNormal) =
|
proc draw*(a, b: Image, mat: Mat3, blendMode = bmNormal) {.inline.} =
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
|
a.drawUber(b, mat, blendMode)
|
||||||
let
|
|
||||||
corners = [
|
|
||||||
mat * vec2(0, 0),
|
|
||||||
mat * vec2(b.width.float32, 0),
|
|
||||||
mat * vec2(b.width.float32, b.height.float32),
|
|
||||||
mat * vec2(0, b.height.float32)
|
|
||||||
]
|
|
||||||
perimeter = [
|
|
||||||
segment(corners[0], corners[1]),
|
|
||||||
segment(corners[1], corners[2]),
|
|
||||||
segment(corners[2], corners[3]),
|
|
||||||
segment(corners[3], corners[0])
|
|
||||||
]
|
|
||||||
|
|
||||||
var
|
|
||||||
matInv = mat.inverse()
|
|
||||||
# Compute movement vectors
|
|
||||||
p = matInv * vec2(0 + h, 0 + h)
|
|
||||||
dx = matInv * vec2(1 + h, 0 + h) - p
|
|
||||||
dy = matInv * vec2(0 + h, 1 + h) - p
|
|
||||||
minFilterBy2 = max(dx.length, dy.length)
|
|
||||||
b = b
|
|
||||||
|
|
||||||
while minFilterBy2 > 2.0:
|
|
||||||
b = b.minifyBy2()
|
|
||||||
p /= 2
|
|
||||||
dx /= 2
|
|
||||||
dy /= 2
|
|
||||||
minFilterBy2 /= 2
|
|
||||||
matInv = matInv * scale(vec2(0.5, 0.5))
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
a.drawUber(b, p, dx, dy, perimeter, blendMode, smooth)
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
proc draw*(image: Image, mask: Mask, mat: Mat3, blendMode = bmMask) {.inline.} =
|
||||||
|
image.drawUber(mask, mat, blendMode)
|
||||||
|
|
||||||
|
proc draw*(
|
||||||
|
image: Image, mask: Mask, pos = vec2(0, 0), blendMode = bmMask
|
||||||
|
) {.inline.} =
|
||||||
|
image.drawUber(mask, translate(pos), blendMode)
|
||||||
|
|
||||||
|
proc draw*(a, b: Mask, mat: Mat3, blendMode = bmMask) {.inline.} =
|
||||||
|
a.drawUber(b, mat, blendMode)
|
||||||
|
|
||||||
|
proc draw*(a, b: Mask, pos = vec2(0, 0), blendMode = bmMask) {.inline.} =
|
||||||
|
a.draw(b, translate(pos), blendMode)
|
||||||
|
|
||||||
|
proc draw*(mask: Mask, image: Image, mat: Mat3, blendMode = bmMask) {.inline.} =
|
||||||
|
mask.drawUber(image, mat, blendMode)
|
||||||
|
|
||||||
|
proc draw*(
|
||||||
|
mask: Mask, image: Image, pos = vec2(0, 0), blendMode = bmMask
|
||||||
|
) {.inline.} =
|
||||||
|
mask.draw(image, translate(pos), blendMode)
|
||||||
|
|
||||||
proc resize*(srcImage: Image, width, height: int): Image =
|
proc resize*(srcImage: Image, width, height: int): Image =
|
||||||
if width == srcImage.width and height == srcImage.height:
|
if width == srcImage.width and height == srcImage.height:
|
||||||
result = srcImage.copy()
|
result = srcImage.copy()
|
||||||
|
|
Loading…
Reference in a new issue