diff --git a/src/pixie/draw.nim b/src/pixie/draw.nim deleted file mode 100644 index 830653b..0000000 --- a/src/pixie/draw.nim +++ /dev/null @@ -1,145 +0,0 @@ -import chroma, blends, vmath, common, images - -proc drawUberTemplate( - a: Image, - b: Image, - c: Image, - mat: Mat3, - lines: array[4, Segment], - blendMode: BlendMode, - inPlace: bool, - smooth: bool, -) = - for y in 0 ..< a.height: - var - xMin = 0 - xMax = 0 - hasIntersection = false - for yOffset in [0.float32, 1]: - var scanLine = segment( - vec2(-100000, y.float32 + yOffset), - vec2(10000, y.float32 + yOffset) - ) - for l in lines: - var at: Vec2 - if intersects(l, scanLine, at): - if hasIntersection: - xMin = min(xMin, at.x.floor.int) - xMax = max(xMax, at.x.ceil.int) - else: - hasIntersection = true - xMin = at.x.floor.int - xMax = at.x.ceil.int - - xMin = xMin.clamp(0, a.width) - xMax = xMax.clamp(0, a.width) - - # for x in 0 ..< xMin: - # result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y)) - if xMin > 0: - copyMem(c.getAddr(0, y), a.getAddr(0, y), 4*xMin) - - for x in xMin ..< xMax: - let srcPos = start + stepX * float32(x) + stepY * float32(y) - #let srcPos = matInv * vec2(x.float32 + h, y.float32 + h) - var rgba = a.getRgbaUnsafe(x, y) - let rgba2 = b.getRgbaFn(srcPos.x - h, srcPos.y - h) - rgba = mixer(rgba, rgba2) - c.setRgbaUnsafe(x, y, rgba) - - #for x in xMax ..< a.width: - # result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y)) - if a.width - xMax > 0: - copyMem(c.getAddr(xMax, y), a.getAddr(xMax, y), 4*(a.width - xMax)) - -proc drawUber*(a: Image, b: Image, c: Image, mat: Mat3, blendMode: BlendMode, inPlace: bool) = - ## Draws one image onto another using matrix with color blending. - - var - matInv = mat.inverse() - # compute movement vectors - h = 0.5.float32 - start = matInv * vec2(0 + h, 0 + h) - stepX = matInv * vec2(1 + h, 0 + h) - start - stepY = matInv * vec2(0 + h, 1 + h) - start - minFilterBy2 = max(stepX.length, stepY.length) - b = b - - 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) - ] - - let lines = [ - segment(corners[0], corners[1]), - segment(corners[1], corners[2]), - segment(corners[2], corners[3]), - segment(corners[3], corners[0]) - ] - - while minFilterBy2 > 2.0: - b = b.minifyBy2() - start /= 2 - stepX /= 2 - stepY /= 2 - minFilterBy2 /= 2 - matInv = matInv * scale(vec2(0.5, 0.5)) - - proc getRgbaUnsafe(a: Image, x, y: float32): ColorRGBA {.inline.} = - a.getRgbaUnsafe(x.round.int, y.round.int) - - if stepX.length == 1.0 and stepY.length == 1.0 and - mat[2, 0].fractional == 0.0 and mat[2, 1].fractional == 0.0: - #echo "copy non-smooth" - case blendMode - of bmNormal: forBlend(blendNormal, getRgbaUnsafe) - of bmDarken: forBlend(blendDarken, getRgbaUnsafe) - of bmMultiply: forBlend(blendMultiply, getRgbaUnsafe) - of bmLinearBurn: forBlend(blendLinearBurn, getRgbaUnsafe) - of bmColorBurn: forBlend(blendColorBurn, getRgbaUnsafe) - of bmLighten: forBlend(blendLighten, getRgbaUnsafe) - of bmScreen: forBlend(blendScreen, getRgbaUnsafe) - of bmLinearDodge: forBlend(blendLinearDodge, getRgbaUnsafe) - of bmColorDodge: forBlend(blendColorDodge, getRgbaUnsafe) - of bmOverlay: forBlend(blendOverlay, getRgbaUnsafe) - of bmSoftLight: forBlend(blendSoftLight, getRgbaUnsafe) - of bmHardLight: forBlend(blendHardLight, getRgbaUnsafe) - of bmDifference: forBlend(blendDifference, getRgbaUnsafe) - of bmExclusion: forBlend(blendExclusion, getRgbaUnsafe) - of bmHue: forBlend(blendHue, getRgbaUnsafe) - of bmSaturation: forBlend(blendSaturation, getRgbaUnsafe) - of bmColor: forBlend(blendColor, getRgbaUnsafe) - of bmLuminosity: forBlend(blendLuminosity, getRgbaUnsafe) - of bmMask: forBlend(blendMask, getRgbaUnsafe) - of bmOverwrite: forBlend(blendOverwrite, getRgbaUnsafe) - of bmSubtractMask: forBlend(blendSubtractMask, getRgbaUnsafe) - of bmIntersectMask: forBlend(blendIntersectMask, getRgbaUnsafe) - of bmExcludeMask: forBlend(blendExcludeMask, getRgbaUnsafe) - else: - #echo "copy smooth" - case blendMode - of bmNormal: forBlend(blendNormal, getRgbaSmooth) - of bmDarken: forBlend(blendDarken, getRgbaSmooth) - of bmMultiply: forBlend(blendMultiply, getRgbaSmooth) - of bmLinearBurn: forBlend(blendLinearBurn, getRgbaSmooth) - of bmColorBurn: forBlend(blendColorBurn, getRgbaSmooth) - of bmLighten: forBlend(blendLighten, getRgbaSmooth) - of bmScreen: forBlend(blendScreen, getRgbaSmooth) - of bmLinearDodge: forBlend(blendLinearDodge, getRgbaSmooth) - of bmColorDodge: forBlend(blendColorDodge, getRgbaSmooth) - of bmOverlay: forBlend(blendOverlay, getRgbaSmooth) - of bmSoftLight: forBlend(blendSoftLight, getRgbaSmooth) - of bmHardLight: forBlend(blendHardLight, getRgbaSmooth) - of bmDifference: forBlend(blendDifference, getRgbaSmooth) - of bmExclusion: forBlend(blendExclusion, getRgbaSmooth) - of bmHue: forBlend(blendHue, getRgbaSmooth) - of bmSaturation: forBlend(blendSaturation, getRgbaSmooth) - of bmColor: forBlend(blendColor, getRgbaSmooth) - of bmLuminosity: forBlend(blendLuminosity, getRgbaSmooth) - of bmMask: forBlend(blendMask, getRgbaSmooth) - of bmOverwrite: forBlend(blendOverwrite, getRgbaSmooth) - of bmSubtractMask: forBlend(blendSubtractMask, getRgbaSmooth) - of bmIntersectMask: forBlend(blendIntersectMask, getRgbaSmooth) - of bmExcludeMask: forBlend(blendExcludeMask, getRgbaSmooth) diff --git a/src/pixie/images.nim b/src/pixie/images.nim index 21a664a..97e03c6 100644 --- a/src/pixie/images.nim +++ b/src/pixie/images.nim @@ -155,29 +155,62 @@ proc magnifyBy2*(image: Image, scale2x: int): Image = proc magnifyBy2*(image: Image): Image = image.magnifyBy2(2) +proc flipHorizontal*(image: Image): Image = + ## Flips the image around the Y axis. + result = newImage(image.width, image.height) + for y in 0 ..< image.height: + for x in 0 ..< image.width: + let rgba = image.getRgbaUnsafe(x, y) + result.setRgbaUnsafe(image.width - x - 1, y, rgba) + +proc flipVertical*(image: Image): Image = + ## Flips the image around the X axis. + result = newImage(image.width, image.height) + for y in 0 ..< image.height: + for x in 0 ..< image.width: + let rgba = image.getRgbaUnsafe(x, y) + result.setRgbaUnsafe(x, image.height - y - 1, rgba) + func lerp(a, b: Color, v: float32): Color {.inline.} = result.r = lerp(a.r, b.r, v) result.g = lerp(a.g, b.g, v) result.b = lerp(a.b, b.b, v) result.a = lerp(a.a, b.a, v) +proc toAlphy*(c: Color): Color = + ## Converts a color to premultiplied alpha from straight. + result.r = c.r * c.a + result.g = c.g * c.a + result.b = c.b * c.a + result.a = c.a + +proc fromAlphy*(c: Color): Color = + ## Converts a color to from premultiplied alpha to straight. + if c.a == 0: + return + result.r = c.r / c.a + result.g = c.g / c.a + result.b = c.b / c.a + result.a = c.a + +proc toAlphy*(image: Image) = + ## Converts an image to premultiplied alpha from straight. + for c in image.data.mitems: + c.g = ((c.r.uint32 * c.a.uint32) div 255).uint8 + c.r = ((c.r.uint32 * c.a.uint32) div 255).uint8 + c.b = ((c.r.uint32 * c.a.uint32) div 255).uint8 + +proc fromAlphy*(image: Image) = + ## Converts an image to from premultiplied alpha to straight. + for c in image.data.mitems: + if c.a == 0: + continue + c.r = ((c.r.int32 * 255) div c.a.int32).uint8 + c.g = ((c.g.int32 * 255) div c.a.int32).uint8 + c.b = ((c.b.int32 * 255) div c.a.int32).uint8 + proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} = ## Gets a pixel as (x, y) floats. - - proc toAlphy(c: Color): Color = - result.r = c.r * c.a - result.g = c.g * c.a - result.b = c.b * c.a - result.a = c.a - - proc fromAlphy(c: Color): Color = - if c.a == 0: - return - result.r = c.r / c.a - result.g = c.g / c.a - result.b = c.b / c.a - result.a = c.a - var x = x # TODO: look at maybe +0.5 y = y # TODO: look at maybe +0.5 diff --git a/tests/images/transCompose.png b/tests/images/transCompose.png index 53194e9..39553df 100644 Binary files a/tests/images/transCompose.png and b/tests/images/transCompose.png differ