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)
|
||||
|
||||
proc drawCorrect(
|
||||
a: Image | Mask, b: Image | Mask, mat = mat3(), blendMode = bmNormal
|
||||
) =
|
||||
proc drawCorrect(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
|
||||
## Draws one image onto another using matrix with color blending.
|
||||
|
||||
when type(a) is Image:
|
||||
|
@ -587,36 +585,49 @@ proc drawCorrect(
|
|||
let sample = b.getValueSmooth(xFloat, yFloat)
|
||||
a.setValueUnsafe(x, y, masker(backdrop, sample))
|
||||
|
||||
proc draw*(image: Image, mask: Mask, mat: Mat3, blendMode = bmMask) =
|
||||
image.drawCorrect(mask, mat, blendMode)
|
||||
proc drawUber(a, b: Image | Mask, mat = mat3(), blendMode = bmNormal) =
|
||||
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*(
|
||||
image: Image, mask: Mask, pos = vec2(0, 0), blendMode = bmMask
|
||||
) {.inline.} =
|
||||
image.drawCorrect(mask, translate(pos), blendMode)
|
||||
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
|
||||
|
||||
proc draw*(a, b: Mask, mat: Mat3, blendMode = bmMask) =
|
||||
a.drawCorrect(b, mat, blendMode)
|
||||
while minFilterBy2 > 2.0:
|
||||
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.} =
|
||||
a.draw(b, translate(pos), 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
|
||||
)
|
||||
|
||||
proc draw*(mask: Mask, image: Image, mat: Mat3, blendMode = bmMask) =
|
||||
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()
|
||||
when type(a) is Image:
|
||||
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
|
||||
var yMin, yMax: int
|
||||
|
@ -662,89 +673,103 @@ proc drawUber(
|
|||
srcPos = p + dx * x.float32 + dy * y.float32
|
||||
xFloat = srcPos.x - h
|
||||
yFloat = srcPos.y - h
|
||||
backdrop = a.getRgbaUnsafe(x, y)
|
||||
source = b.getRgbaSmooth(xFloat, yFloat)
|
||||
a.setRgbaUnsafe(x, y, blender(backdrop, source))
|
||||
when type(a) is Image:
|
||||
let backdrop = a.getRgbaUnsafe(x, y)
|
||||
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:
|
||||
var x = xMin
|
||||
when defined(amd64) and not defined(pixieNoSimd):
|
||||
if blendMode.hasSimdBlender():
|
||||
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
|
||||
let blenderSimd = blendMode.blenderSimd()
|
||||
for _ in countup(x, xMax - 4, 4):
|
||||
let
|
||||
srcPos = p + dx * x.float32 + dy * y.float32
|
||||
sx = srcPos.x.int
|
||||
sy = srcPos.y.int
|
||||
backdrop = mm_loadu_si128(a.data[a.dataIndex(x, y)].addr)
|
||||
source = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
||||
mm_storeu_si128(
|
||||
a.data[a.dataIndex(x, y)].addr,
|
||||
blenderSimd(backdrop, source)
|
||||
)
|
||||
x += 4
|
||||
# when defined(amd64) and not defined(pixieNoSimd):
|
||||
# if blendMode.hasSimdBlender():
|
||||
# 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
|
||||
# let blenderSimd = blendMode.blenderSimd()
|
||||
# for _ in countup(x, xMax - 4, 4):
|
||||
# let
|
||||
# srcPos = p + dx * x.float32 + dy * y.float32
|
||||
# sx = srcPos.x.int
|
||||
# sy = srcPos.y.int
|
||||
# backdrop = mm_loadu_si128(a.data[a.dataIndex(x, y)].addr)
|
||||
# source = mm_loadu_si128(b.data[b.dataIndex(sx, sy)].addr)
|
||||
# mm_storeu_si128(
|
||||
# a.data[a.dataIndex(x, y)].addr,
|
||||
# blenderSimd(backdrop, source)
|
||||
# )
|
||||
# x += 4
|
||||
|
||||
for _ in x ..< xMax:
|
||||
let
|
||||
srcPos = p + dx * x.float32 + dy * y.float32
|
||||
xFloat = srcPos.x - h
|
||||
yFloat = srcPos.y - h
|
||||
backdrop = a.getRgbaUnsafe(x, y)
|
||||
source = b.getRgbaUnsafe(xFloat.int, yFloat.int)
|
||||
a.setRgbaUnsafe(x, y, blender(backdrop, source))
|
||||
|
||||
when type(a) is Image:
|
||||
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
|
||||
|
||||
if blendMode == bmIntersectMask:
|
||||
if a.width - xMax > 0:
|
||||
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.
|
||||
|
||||
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)
|
||||
a.drawUber(b, mat, blendMode)
|
||||
|
||||
proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} =
|
||||
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 =
|
||||
if width == srcImage.width and height == srcImage.height:
|
||||
result = srcImage.copy()
|
||||
|
|
Loading…
Reference in a new issue