Use matrix in all draw paths.

This commit is contained in:
treeform 2020-11-21 16:58:53 -08:00
parent acc6822d0e
commit cd612f9a6c
4 changed files with 31 additions and 60 deletions

View file

@ -154,27 +154,31 @@ proc fraction(v: float32): float32 =
result = abs(v) result = abs(v)
result = result - floor(result) result = result - floor(result)
proc drawFast1*(a: Image, b: Image, x, y: int): Image = proc drawFast1*(a: Image, b: Image, mat: Mat3): Image =
## Draws one image onto another using integer x,y offset with COPY. ## Draws one image onto another using integer x,y offset with COPY.
result = newImage(a.width, a.height) result = newImage(a.width, a.height)
for yd in 0 ..< a.width: var matInv = mat.inverse()
for xd in 0 ..< a.height: for y in 0 ..< a.width:
var rgba = a.getRgbaUnsafe(xd, yd) for x in 0 ..< a.height:
if b.inside(xd - x, yd - y): var rgba = a.getRgbaUnsafe(x, y)
rgba = b.getRgbaUnsafe(xd - x, yd - y) let srcPos = matInv * vec2(x.float32, y.float32)
result.setRgbaUnsafe(xd, yd, rgba) if b.inside(srcPos.x.floor.int, srcPos.y.floor.int):
rgba = b.getRgbaUnsafe(srcPos.x.floor.int, srcPos.y.floor.int)
result.setRgbaUnsafe(x, y, rgba)
proc drawFast2*(a: Image, b: Image, x, y: int, blendMode: BlendMode): Image = proc drawFast2*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image =
## Draws one image onto another using integer x,y offset with color blending. ## Draws one image onto another using matrix with color blending.
result = newImage(a.width, a.height) result = newImage(a.width, a.height)
for yd in 0 ..< a.width: var matInv = mat.inverse()
for xd in 0 ..< a.height: for y in 0 ..< a.width:
var rgba = a.getRgbaUnsafe(xd, yd) for x in 0 ..< a.height:
if b.inside(xd - x, yd - y): var rgba = a.getRgbaUnsafe(x, y)
var rgba2 = b.getRgbaUnsafe(xd - x, yd - y) let srcPos = matInv * vec2(x.float32, y.float32)
if b.inside(srcPos.x.floor.int, srcPos.y.floor.int):
let rgba2 = b.getRgbaUnsafe(srcPos.x.floor.int, srcPos.y.floor.int)
if blendMode.hasEffect(rgba2): if blendMode.hasEffect(rgba2):
rgba = blendMode.mix(rgba, rgba2) rgba = blendMode.mix(rgba, rgba2)
result.setRgbaUnsafe(xd, yd, rgba) result.setRgbaUnsafe(x, y, rgba)
proc drawFast3*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image = proc drawFast3*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image =
## Draws one image onto another using matrix with color blending. ## Draws one image onto another using matrix with color blending.
@ -190,52 +194,21 @@ proc drawFast3*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image =
rgba = blendMode.mix(rgba, rgba2) rgba = blendMode.mix(rgba, rgba2)
result.setRgbaUnsafe(x, y, rgba) result.setRgbaUnsafe(x, y, rgba)
proc drawFast4*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image =
## Draws one image onto another using matrix with color blending.
result = newImage(a.width, a.height)
var matInv = mat.inverse()
for y in 0 ..< a.width:
for x in 0 ..< a.height:
var rgba = a.getRgbaUnsafe(x, y)
let srcPos = matInv * vec2(x.float32, y.float32)
if b.inside(srcPos.x.floor.int, srcPos.y.floor.int):
let rgba2 = b.getRgbaUnsafe(srcPos.x.floor.int, srcPos.y.floor.int)
if blendMode.hasEffect(rgba2):
rgba = blendMode.mix(rgba, rgba2)
result.setRgbaUnsafe(x, y, rgba)
proc draw*(a: Image, b: Image, mat: Mat3, blendMode = bmNormal): Image = proc draw*(a: Image, b: Image, mat: Mat3, blendMode = bmNormal): Image =
## Draws one image onto another using matrix with color blending. ## Draws one image onto another using matrix with color blending.
if mat[0, 0] == 1 and mat[0, 1] == 0 and
mat[1, 0] == 0 and mat[1, 1] == 1 and
mat[2, 0].fraction == 0.0 and mat[2, 1].fraction == 0.0:
# Matrix is simple integer translation fast path:
if blendMode == bmCopy:
#echo "use 1"
return drawFast1(
a, b, mat[2, 0].int, mat[2, 1].int
)
else:
#echo "use 2"
return drawFast2(
a, b, mat[2, 0].int, mat[2, 1].int, blendMode
)
let ns = [-1.float32, 0, 1] let ns = [-1.float32, 0, 1]
if mat[0, 0] in ns and mat[0, 1] in ns and if mat[0, 0] in ns and mat[0, 1] in ns and
mat[1, 0] in ns and mat[1, 1] in ns and mat[1, 0] in ns and mat[1, 1] in ns and
mat[2, 0].fraction == 0.0 and mat[2, 1].fraction == 0.0: mat[2, 0].fraction == 0.0 and mat[2, 1].fraction == 0.0:
echo "use 4" if blendMode == bmCopy:
return drawFast4( return drawFast1(
a, b, mat, blendMode a, b, mat
) )
else:
# Todo: if matrix is a simple flip -> fast path return drawFast2(
# 4 rotation x 3 flips = 12 combo a, b, mat, blendMode
#echo "use 3" )
return drawFast3(a, b, mat, blendMode) return drawFast3(a, b, mat, blendMode)
proc draw*(a: Image, b: Image, pos = vec2(0, 0), blendMode = bmNormal): Image = proc draw*(a: Image, b: Image, pos = vec2(0, 0), blendMode = bmNormal): Image =
a.draw(b, translate(pos), blendMode) a.draw(b, translate(pos), blendMode)

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

View file

@ -26,7 +26,7 @@ block:
a.fill(rgba(255, 0, 0, 255)) a.fill(rgba(255, 0, 0, 255))
var b = newImage(100, 100) var b = newImage(100, 100)
b.fill(rgba(0, 255, 0, 255)) b.fill(rgba(0, 255, 0, 255))
var c = a.drawFast1(b, x=25, y=25) var c = a.drawFast1(b, translate(vec2(25, 25)))
c.writeAndCheck("tests/images/drawFast1.png") c.writeAndCheck("tests/images/drawFast1.png")
block: block:
@ -34,7 +34,7 @@ block:
a.fill(rgba(255, 0, 0, 255)) a.fill(rgba(255, 0, 0, 255))
var b = newImage(100, 100) var b = newImage(100, 100)
b.fill(rgba(0, 255, 0, 255)) b.fill(rgba(0, 255, 0, 255))
var c = a.drawFast2(b, x=25, y=25, bmCopy) var c = a.drawFast2(b, translate(vec2(25, 25)), bmCopy)
c.writeAndCheck("tests/images/drawFast2.png") c.writeAndCheck("tests/images/drawFast2.png")
block: block:
@ -50,8 +50,6 @@ block:
a.fill(rgba(255, 0, 0, 255)) a.fill(rgba(255, 0, 0, 255))
var b = newImage(100, 100) var b = newImage(100, 100)
b.fill(rgba(0, 255, 0, 255)) b.fill(rgba(0, 255, 0, 255))
var c = a.drawFast4(b, translate(vec2(25.15, 25.15)) * rotationMat3(PI/2), bmCopy)
c.writeAndCheck("tests/images/drawFast4Rot.png")
var d = a.drawFast3(b, translate(vec2(25.15, 25.15)) * rotationMat3(PI/2), bmCopy) var c = a.drawFast1(b, translate(vec2(25, 25)) * rotationMat3(PI/2))
d.writeAndCheck("tests/images/drawFast3Rot.png") c.writeAndCheck("tests/images/drawFast1Rot.png")