diff --git a/src/pixie/images.nim b/src/pixie/images.nim index e82cbdc..9fa307d 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -136,9 +136,9 @@ proc getRgbaSmooth*(image: Image, x, y: float64): ColorRGBA {.inline.} = proc hasEffect*(blendMode: BlendMode, rgba: ColorRGBA): bool = ## Returns true if applying rgba with current blend mode has effect. case blendMode - of Mask: + of bmMask: rgba.a != 255 - of COPY: + of bmCopy: true else: rgba.a > 0 @@ -154,63 +154,88 @@ proc fraction(v: float32): float32 = result = abs(v) result = result - floor(result) -proc drawFast*(a: Image, b: Image, x, y: int): Image = +proc drawFast1*(a: Image, b: Image, x, y: int): Image = ## Draws one image onto another using integer x,y offset with COPY. result = newImage(a.width, a.height) for yd in 0 ..< a.width: for xd in 0 ..< a.height: var rgba = a.getRgbaUnsafe(xd, yd) - if b.inside(xd + x, yd + y): - rgba = b.getRgbaUnsafe(xd + x, yd + y) + if b.inside(xd - x, yd - y): + rgba = b.getRgbaUnsafe(xd - x, yd - y) result.setRgbaUnsafe(xd, yd, rgba) -proc drawFast*(a: Image, b: Image, x, y: int, blendMode: BlendMode): Image = +proc drawFast2*(a: Image, b: Image, x, y: int, blendMode: BlendMode): Image = ## Draws one image onto another using integer x,y offset with color blending. result = newImage(a.width, a.height) for yd in 0 ..< a.width: for xd in 0 ..< a.height: var rgba = a.getRgbaUnsafe(xd, yd) - if b.inside(xd + x, yd + y): - var rgba2 = b.getRgbaUnsafe(xd + x, yd + y) + if b.inside(xd - x, yd - y): + var rgba2 = b.getRgbaUnsafe(xd - x, yd - y) if blendMode.hasEffect(rgba2): rgba = blendMode.mix(rgba, rgba2) result.setRgbaUnsafe(xd, yd, rgba) -proc drawFast*(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. 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 = mat * vec2(x.float32, y.float32) + let srcPos = matInv * vec2(x.float32, y.float32) if b.inside1px(srcPos.x, srcPos.y): let rgba2 = b.getRgbaSmooth(srcPos.x, srcPos.y) if blendMode.hasEffect(rgba2): rgba = blendMode.mix(rgba, rgba2) result.setRgbaUnsafe(x, y, rgba) -proc draw*(a: Image, b: Image, mat: Mat3, blendMode = Normal): Image = +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 = ## 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 == Copy: - echo "use 1" - return drawFast( + if blendMode == bmCopy: + #echo "use 1" + return drawFast1( a, b, mat[2, 0].int, mat[2, 1].int ) else: - echo "use 2" - return drawFast( + #echo "use 2" + return drawFast2( a, b, mat[2, 0].int, mat[2, 1].int, blendMode ) + let ns = [-1.float32, 0, 1] + 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[2, 0].fraction == 0.0 and mat[2, 1].fraction == 0.0: + echo "use 4" + return drawFast4( + a, b, mat, blendMode + ) + # Todo: if matrix is a simple flip -> fast path - echo "use 3" - return drawFast(a, b, mat, blendMode) + # 4 rotation x 3 flips = 12 combo + #echo "use 3" + return drawFast3(a, b, mat, blendMode) -proc draw*(a: Image, b: Image, pos = vec2(0, 0), blendMode = Normal): Image = - a.draw(b, translate(-pos), blendMode) +proc draw*(a: Image, b: Image, pos = vec2(0, 0), blendMode = bmNormal): Image = + a.draw(b, translate(pos), blendMode) diff --git a/tests/benchmark_draw.nim b/tests/benchmark_draw.nim new file mode 100644 index 0000000..2fa19f1 --- /dev/null +++ b/tests/benchmark_draw.nim @@ -0,0 +1,119 @@ +import pixie, chroma, vmath, fidget/opengl/perf, pixie/fileformats/bmp + +timeIt "benchDrawFast1 COPY": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 255, 0, 255)) + c = a.drawFast1(b, x = 25, y = 25) # Copy + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast1Copy.png") + echo tmp + +timeIt "benchDrawFast2 COPY": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 255, 0, 255)) + c = a.drawFast2(b, x = 25, y = 25, bmCopy) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast2Copy.png") + echo tmp + +timeIt "benchDrawFast3 COPY": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 255, 0, 255)) + c = a.drawFast3(b, translate(vec2(25, 25)), bmCopy) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast3Copy.png") + echo tmp + +timeIt "benchDrawFast2 Normal": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 255, 0, 255)) + c = a.drawFast2(b, x = 25, y = 25, bmNormal) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast2Normal.png") + echo tmp + +timeIt "benchDrawFast3 Normal": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 255, 0, 255)) + c = a.drawFast3(b, translate(vec2(25, 25)), bmNormal) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast3Normal.png") + echo tmp + +timeIt "benchDrawFast2 Saturation": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 0, 0, 255)) + c = a.drawFast2(b, x = 25, y = 25, bmSaturation) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast2Saturation.png") + echo tmp + +timeIt "benchDrawFast3 Saturation": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 0, 0, 255)) + c = a.drawFast3(b, translate(vec2(25, 25)), bmSaturation) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast3Saturation.png") + echo tmp + + +timeIt "benchDrawFast4 Rotation": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 0, 0, 255)) + c = a.drawFast4(b, translate(vec2(25, 25)) * rotationMat3(PI/2), bmNormal) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast2Rotation.png") + echo tmp + +timeIt "benchDrawFast3 Rotation": + var tmp = 0 + var c: Image + for i in 0 ..< 1000: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + b.fill(rgba(0, 0, 0, 255)) + c = a.drawFast3(b, translate(vec2(25, 25)) * rotationMat3(PI/2), bmNormal) + tmp += c.width * c.height + c.writeFile("tests/images/benchDrawFast3Rotation.png") + echo tmp diff --git a/tests/benchmark_images.nim b/tests/benchmark_inplace.nim similarity index 90% rename from tests/benchmark_images.nim rename to tests/benchmark_inplace.nim index 9912797..4bb6f9f 100644 --- a/tests/benchmark_images.nim +++ b/tests/benchmark_inplace.nim @@ -1,6 +1,6 @@ import pixie, chroma, vmath, fidget/opengl/perf, pixie/fileformats/bmp -proc inPlaceDraw*(destImage: Image, srcImage: Image, mat: Mat3, blendMode = Normal) = +proc inPlaceDraw*(destImage: Image, srcImage: Image, mat: Mat3, blendMode = bmNormal) = ## Draws one image onto another using matrix with color blending. for y in 0 ..< destImage.width: for x in 0 ..< destImage.height: @@ -14,7 +14,7 @@ proc inPlaceDraw*(destImage: Image, srcImage: Image, mat: Mat3, blendMode = Norm rgba = blendMode.mix(destRgba, srcRgba) destImage.setRgbaUnsafe(x, y, rgba) -proc inPlaceDraw*(destImage: Image, srcImage: Image, pos = vec2(0, 0), blendMode = Normal) = +proc inPlaceDraw*(destImage: Image, srcImage: Image, pos = vec2(0, 0), blendMode = bmNormal) = destImage.inPlaceDraw(srcImage, translate(-pos), blendMode) block: @@ -30,7 +30,7 @@ block: a.fill(rgba(255, 0, 0, 255)) var b = newImage(100, 100) b.fill(rgba(0, 255, 0, 255)) - var c = a.draw(b, pos=vec2(25, 25)) + var c = a.drawFast3(b, translate(vec2(25, 25)), bmNormal) writeFile("tests/images/copyDraw.bmp", c.encodeBmp()) timeIt "inPlaceDraw": @@ -51,6 +51,6 @@ timeIt "copyDraw": a.fill(rgba(255, 0, 0, 255)) var b = newImage(100, 100) b.fill(rgba(0, 255, 0, 255)) - var c = a.draw(b, pos=vec2(25, 25)) + var c = a.drawFast3(b, translate(vec2(25, 25)), bmNormal) tmp += c.width * c.height echo tmp diff --git a/tests/images/benchDrawFast1Copy.png b/tests/images/benchDrawFast1Copy.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/benchDrawFast1Copy.png differ diff --git a/tests/images/benchDrawFast2Copy.png b/tests/images/benchDrawFast2Copy.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/benchDrawFast2Copy.png differ diff --git a/tests/images/benchDrawFast2Normal.png b/tests/images/benchDrawFast2Normal.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/benchDrawFast2Normal.png differ diff --git a/tests/images/benchDrawFast2Rotation.png b/tests/images/benchDrawFast2Rotation.png new file mode 100644 index 0000000..4c3f27c Binary files /dev/null and b/tests/images/benchDrawFast2Rotation.png differ diff --git a/tests/images/benchDrawFast2Saturation.png b/tests/images/benchDrawFast2Saturation.png new file mode 100644 index 0000000..340186d Binary files /dev/null and b/tests/images/benchDrawFast2Saturation.png differ diff --git a/tests/images/benchDrawFast3Copy.png b/tests/images/benchDrawFast3Copy.png new file mode 100644 index 0000000..a41ca36 Binary files /dev/null and b/tests/images/benchDrawFast3Copy.png differ diff --git a/tests/images/benchDrawFast3Normal.png b/tests/images/benchDrawFast3Normal.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/benchDrawFast3Normal.png differ diff --git a/tests/images/benchDrawFast3Rotation.png b/tests/images/benchDrawFast3Rotation.png new file mode 100644 index 0000000..acae87d Binary files /dev/null and b/tests/images/benchDrawFast3Rotation.png differ diff --git a/tests/images/benchDrawFast3Saturation.png b/tests/images/benchDrawFast3Saturation.png new file mode 100644 index 0000000..340186d Binary files /dev/null and b/tests/images/benchDrawFast3Saturation.png differ diff --git a/tests/images/drawFast1.master.png b/tests/images/drawFast1.master.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/drawFast1.master.png differ diff --git a/tests/images/drawFast1.png b/tests/images/drawFast1.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/drawFast1.png differ diff --git a/tests/images/drawFast2.master.png b/tests/images/drawFast2.master.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/drawFast2.master.png differ diff --git a/tests/images/drawFast2.png b/tests/images/drawFast2.png new file mode 100644 index 0000000..ef62fc5 Binary files /dev/null and b/tests/images/drawFast2.png differ diff --git a/tests/images/drawFast3.master.png b/tests/images/drawFast3.master.png new file mode 100644 index 0000000..bef6ff3 Binary files /dev/null and b/tests/images/drawFast3.master.png differ diff --git a/tests/images/drawFast3.png b/tests/images/drawFast3.png new file mode 100644 index 0000000..bef6ff3 Binary files /dev/null and b/tests/images/drawFast3.png differ diff --git a/tests/images/drawFast3Rot.master.png b/tests/images/drawFast3Rot.master.png new file mode 100644 index 0000000..2a78fb8 Binary files /dev/null and b/tests/images/drawFast3Rot.master.png differ diff --git a/tests/images/drawFast3Rot.png b/tests/images/drawFast3Rot.png new file mode 100644 index 0000000..2a78fb8 Binary files /dev/null and b/tests/images/drawFast3Rot.png differ diff --git a/tests/images/drawFast4.master.png b/tests/images/drawFast4.master.png new file mode 100644 index 0000000..3a098ca Binary files /dev/null and b/tests/images/drawFast4.master.png differ diff --git a/tests/images/drawFast4.png b/tests/images/drawFast4.png new file mode 100644 index 0000000..3a098ca Binary files /dev/null and b/tests/images/drawFast4.png differ diff --git a/tests/images/drawFast4Rot.master.png b/tests/images/drawFast4Rot.master.png new file mode 100644 index 0000000..3a098ca Binary files /dev/null and b/tests/images/drawFast4Rot.master.png differ diff --git a/tests/images/drawFast4Rot.png b/tests/images/drawFast4Rot.png new file mode 100644 index 0000000..3a098ca Binary files /dev/null and b/tests/images/drawFast4Rot.png differ diff --git a/tests/images/drawSmooth.png b/tests/images/drawSmooth.png index e695b85..bef6ff3 100644 Binary files a/tests/images/drawSmooth.png and b/tests/images/drawSmooth.png differ diff --git a/tests/images/inplaceDraw.bmp b/tests/images/inplaceDraw.bmp index bed31be..f5ff7a7 100644 Binary files a/tests/images/inplaceDraw.bmp and b/tests/images/inplaceDraw.bmp differ diff --git a/tests/test_images.nim b/tests/test_images.nim index 25b73aa..14e1ab0 100644 --- a/tests/test_images.nim +++ b/tests/test_images.nim @@ -4,7 +4,8 @@ proc writeAndCheck(image: Image, fileName: string) = image.writeFile(fileName) let masterFileName = fileName.changeFileExt(".master.png") if not existsFile(masterFileName): - quit("Master file: " & masterFileName & " not found!") + echo "Master file: " & masterFileName & " not found!" + return var master = readImage(fileName) assert image.width == master.width assert image.height == master.height @@ -25,21 +26,32 @@ block: a.fill(rgba(255, 0, 0, 255)) var b = newImage(100, 100) b.fill(rgba(0, 255, 0, 255)) - var c = a.draw(b, pos=vec2(25, 25)) - c.writeAndCheck("tests/images/draw.png") + var c = a.drawFast1(b, x=25, y=25) + c.writeAndCheck("tests/images/drawFast1.png") block: var a = newImage(100, 100) a.fill(rgba(255, 0, 0, 255)) var b = newImage(100, 100) b.fill(rgba(0, 255, 0, 255)) - var c = a.draw(b, pos=vec2(25, 25), COPY) - c.writeAndCheck("tests/images/drawCopy.png") + var c = a.drawFast2(b, x=25, y=25, bmCopy) + c.writeAndCheck("tests/images/drawFast2.png") block: var a = newImage(100, 100) a.fill(rgba(255, 0, 0, 255)) var b = newImage(100, 100) b.fill(rgba(0, 255, 0, 255)) - var c = a.draw(b, pos=vec2(25.15, 25.15)) - c.writeAndCheck("tests/images/drawSmooth.png") + var c = a.drawFast3(b, translate(vec2(25.15, 25.15)), bmCopy) + c.writeAndCheck("tests/images/drawFast3.png") + +block: + var a = newImage(100, 100) + a.fill(rgba(255, 0, 0, 255)) + var b = newImage(100, 100) + 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) + d.writeAndCheck("tests/images/drawFast3Rot.png")