commit
cf6443a63c
8 changed files with 174 additions and 316 deletions
|
@ -70,20 +70,16 @@ proc `[]=`*(image: Image, x, y: int, rgba: ColorRGBA) {.inline.} =
|
|||
|
||||
proc fill*(image: Image, rgba: ColorRgba) =
|
||||
## Fills the image with a solid color.
|
||||
for y in 0 ..< image.height:
|
||||
for x in 0 ..< image.width:
|
||||
image.setRgbaUnsafe(x, y, rgba)
|
||||
for c in image.data.mitems:
|
||||
c = rgba
|
||||
|
||||
proc invert*(image: Image) =
|
||||
## Inverts all of the colors and alpha.
|
||||
for y in 0 ..< image.height:
|
||||
for x in 0 ..< image.width:
|
||||
var rgba = image.getRgbaUnsafe(x, y)
|
||||
rgba.r = 255 - rgba.r
|
||||
rgba.g = 255 - rgba.g
|
||||
rgba.b = 255 - rgba.b
|
||||
rgba.a = 255 - rgba.a
|
||||
image.setRgbaUnsafe(x, y, rgba)
|
||||
for rgba in image.data.mitems:
|
||||
rgba.r = 255 - rgba.r
|
||||
rgba.g = 255 - rgba.g
|
||||
rgba.b = 255 - rgba.b
|
||||
rgba.a = 255 - rgba.a
|
||||
|
||||
proc subImage*(image: Image, x, y, w, h: int): Image =
|
||||
## Gets a sub image of the main image.
|
||||
|
@ -210,17 +206,17 @@ proc resize*(srcImage: Image, width, height: int): Image =
|
|||
|
||||
proc blur*(image: Image, radius: float32): Image =
|
||||
## Applies Gaussian blur to the image given a radius.
|
||||
let radius = (radius).int
|
||||
let radius = radius.int
|
||||
if radius == 0:
|
||||
return image.copy()
|
||||
|
||||
# Compute lookup table for 1d Gaussian kernel.
|
||||
var lookup = newSeq[float](radius*2+1)
|
||||
var lookup = newSeq[float](radius * 2 + 1)
|
||||
var total = 0.0
|
||||
for xb in -radius .. radius:
|
||||
let s = radius.float32 / 2.2 # 2.2 matches Figma.
|
||||
let x = xb.float32
|
||||
let a = 1/sqrt(2*PI*s^2) * exp(-1*x^2/(2*s^2))
|
||||
let a = 1 / sqrt(2 * PI * s^2) * exp(-1 * x^2 / (2 * s^2))
|
||||
lookup[xb + radius] = a
|
||||
total += a
|
||||
for xb in -radius .. radius:
|
||||
|
@ -270,17 +266,18 @@ proc blur*(image: Image, radius: float32): Image =
|
|||
|
||||
proc blurAlpha*(image: Image, radius: float32): Image =
|
||||
## Applies Gaussian blur to the image given a radius.
|
||||
let radius = (radius).int
|
||||
let radius = radius.int
|
||||
if radius == 0:
|
||||
return image.copy()
|
||||
|
||||
# Compute lookup table for 1d Gaussian kernel.
|
||||
var lookup = newSeq[float](radius*2+1)
|
||||
var total = 0.0
|
||||
var
|
||||
lookup = newSeq[float](radius * 2 + 1)
|
||||
total = 0.0
|
||||
for xb in -radius .. radius:
|
||||
let s = radius.float32 / 2.2 # 2.2 matches Figma.
|
||||
let x = xb.float32
|
||||
let a = 1/sqrt(2*PI*s^2) * exp(-1*x^2/(2*s^2))
|
||||
let a = 1 / sqrt(2 * PI * s^2) * exp(-1 * x^2 / (2 * s^2))
|
||||
lookup[xb + radius] = a
|
||||
total += a
|
||||
for xb in -radius .. radius:
|
||||
|
@ -295,7 +292,7 @@ proc blurAlpha*(image: Image, radius: float32): Image =
|
|||
let c2 = image[x + xb, y]
|
||||
let a = lookup[xb + radius]
|
||||
alpha += c2.a.float32 * a
|
||||
blurX.setRgbaUnsafe(x, y, rgba(0,0,0, (alpha).uint8))
|
||||
blurX.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
|
||||
|
||||
# Blur in the Y direction.
|
||||
var blurY = newImage(image.width, image.height)
|
||||
|
@ -306,7 +303,7 @@ proc blurAlpha*(image: Image, radius: float32): Image =
|
|||
let c2 = blurX[x, y + yb]
|
||||
let a = lookup[yb + radius]
|
||||
alpha += c2.a.float32 * a
|
||||
blurY.setRgbaUnsafe(x, y, rgba(0,0,0, (alpha).uint8))
|
||||
blurY.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
|
||||
|
||||
return blurY
|
||||
|
||||
|
@ -351,27 +348,23 @@ proc shadow*(
|
|||
result.fill(color)
|
||||
result.draw(shadow, blendMode = bmMask)
|
||||
|
||||
proc applyOpacity*(image: Image, opacity: float32): Image =
|
||||
proc applyOpacity*(image: Image, opacity: float32) =
|
||||
## Multiplies alpha of the image by opacity.
|
||||
result = newImage(image.width, image.height)
|
||||
let op = (255 * opacity).uint32
|
||||
for y in 0 ..< image.height:
|
||||
for x in 0 ..< image.width:
|
||||
var rgba = image.getRgbaUnsafe(x, y)
|
||||
rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
|
||||
result.setRgbaUnsafe(x, y, rgba)
|
||||
for i in 0 ..< image.data.len:
|
||||
var rgba = image.data[i]
|
||||
rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
|
||||
image.data[i] = rgba
|
||||
|
||||
proc sharpOpacity*(image: Image): Image =
|
||||
proc sharpOpacity*(image: Image) =
|
||||
## Sharpens the opacity to extreme.
|
||||
## A = 0 stays 0. Anything else turns into 255.
|
||||
result = newImage(image.width, image.height)
|
||||
for y in 0 ..< image.height:
|
||||
for x in 0 ..< image.width:
|
||||
var rgba = image.getRgbaUnsafe(x, y)
|
||||
if rgba.a == 0:
|
||||
result.setRgbaUnsafe(x, y, rgba(0, 0, 0, 0))
|
||||
else:
|
||||
result.setRgbaUnsafe(x, y, rgba(255, 255, 255, 255))
|
||||
for i in 0 ..< image.data.len:
|
||||
var rgba = image.data[i]
|
||||
if rgba.a == 0:
|
||||
image.data[i] = rgba(0, 0, 0, 0)
|
||||
else:
|
||||
image.data[i] = rgba(255, 255, 255, 255)
|
||||
|
||||
proc drawCorrect*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode): Image =
|
||||
## Draws one image onto another using matrix with color blending.
|
||||
|
@ -410,7 +403,6 @@ proc drawUberStatic(
|
|||
start, stepX, stepY: Vec2,
|
||||
lines: array[0..3, Segment],
|
||||
blendMode: static[BlendMode],
|
||||
inPlace: static[bool],
|
||||
smooth: static[bool],
|
||||
) =
|
||||
for y in 0 ..< a.height:
|
||||
|
@ -440,12 +432,6 @@ proc drawUberStatic(
|
|||
when blendMode == bmIntersectMask:
|
||||
if xMin > 0:
|
||||
zeroMem(c.getAddr(0, y), 4*xMin)
|
||||
else:
|
||||
when not inPlace:
|
||||
# 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)
|
||||
|
@ -464,12 +450,6 @@ proc drawUberStatic(
|
|||
when blendMode == bmIntersectMask:
|
||||
if a.width - xMax > 0:
|
||||
zeroMem(c.getAddr(xMax, y), 4*(a.width - xMax))
|
||||
else:
|
||||
when not inPlace:
|
||||
# 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 draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||
## Draws one image onto another using matrix with color blending.
|
||||
|
@ -511,54 +491,54 @@ proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
|||
|
||||
if not smooth:
|
||||
case blendMode
|
||||
of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, true, false)
|
||||
of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, true, false)
|
||||
of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, true, false)
|
||||
of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, true, false)
|
||||
of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, true, false)
|
||||
of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, true, false)
|
||||
of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, true, false)
|
||||
of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, true, false)
|
||||
of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, true, false)
|
||||
of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, true, false)
|
||||
of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, true, false)
|
||||
of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, true, false)
|
||||
of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, true, false)
|
||||
of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, true, false)
|
||||
of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, true, false)
|
||||
of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, true, false)
|
||||
of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, true, false)
|
||||
of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, true, false)
|
||||
of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, true, false)
|
||||
of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, true, false)
|
||||
of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, true, false)
|
||||
of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, true, false)
|
||||
of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, true, false)
|
||||
of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, false)
|
||||
of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, false)
|
||||
of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, false)
|
||||
of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, false)
|
||||
of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, false)
|
||||
of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, false)
|
||||
of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, false)
|
||||
of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, false)
|
||||
of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, false)
|
||||
of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, false)
|
||||
of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, false)
|
||||
of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, false)
|
||||
of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, false)
|
||||
of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, false)
|
||||
of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, false)
|
||||
of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, false)
|
||||
of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, false)
|
||||
of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, false)
|
||||
of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, false)
|
||||
of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, false)
|
||||
of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, false)
|
||||
of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, false)
|
||||
of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, false)
|
||||
else:
|
||||
case blendMode
|
||||
of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, true, true)
|
||||
of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, true, true)
|
||||
of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, true, true)
|
||||
of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, true, true)
|
||||
of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, true, true)
|
||||
of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, true, true)
|
||||
of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, true, true)
|
||||
of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, true, true)
|
||||
of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, true, true)
|
||||
of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, true, true)
|
||||
of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, true, true)
|
||||
of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, true, true)
|
||||
of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, true, true)
|
||||
of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, true, true)
|
||||
of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, true, true)
|
||||
of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, true, true)
|
||||
of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, true, true)
|
||||
of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, true, true)
|
||||
of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, true, true)
|
||||
of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, true, true)
|
||||
of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, true, true)
|
||||
of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, true, true)
|
||||
of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, true, true)
|
||||
of bmNormal: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmNormal, true)
|
||||
of bmDarken: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDarken, true)
|
||||
of bmMultiply: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMultiply, true)
|
||||
of bmLinearBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearBurn, true)
|
||||
of bmColorBurn: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorBurn, true)
|
||||
of bmLighten: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLighten, true)
|
||||
of bmScreen: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmScreen, true)
|
||||
of bmLinearDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLinearDodge, true)
|
||||
of bmColorDodge: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColorDodge, true)
|
||||
of bmOverlay: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverlay, true)
|
||||
of bmSoftLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSoftLight, true)
|
||||
of bmHardLight: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHardLight, true)
|
||||
of bmDifference: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmDifference, true)
|
||||
of bmExclusion: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExclusion, true)
|
||||
of bmHue: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmHue, true)
|
||||
of bmSaturation: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSaturation, true)
|
||||
of bmColor: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmColor, true)
|
||||
of bmLuminosity: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmLuminosity, true)
|
||||
of bmMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmMask, true)
|
||||
of bmOverwrite: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmOverwrite, true)
|
||||
of bmSubtractMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmSubtractMask, true)
|
||||
of bmIntersectMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmIntersectMask, true)
|
||||
of bmExcludeMask: drawUberStatic(a, b, c, start, stepX, stepY, lines, bmExcludeMask, true)
|
||||
|
||||
proc draw*(
|
||||
a, b: Image, pos = vec2(0, 0), blendMode = bmNormal
|
||||
|
|
79
tests/benchmark_images.nim
Normal file
79
tests/benchmark_images.nim
Normal file
|
@ -0,0 +1,79 @@
|
|||
import chroma, pixie, fidget/opengl/perf
|
||||
|
||||
const iterations = 100
|
||||
|
||||
proc fillOriginal(a: Image, rgba: ColorRGBA) =
|
||||
for y in 0 ..< a.height:
|
||||
for x in 0 ..< a.width:
|
||||
a.setRgbaUnsafe(x, y, rgba)
|
||||
|
||||
proc invertOriginal(a: Image) =
|
||||
for y in 0 ..< a.height:
|
||||
for x in 0 ..< a.width:
|
||||
var rgba = a.getRgbaUnsafe(x, y)
|
||||
rgba.r = 255 - rgba.r
|
||||
rgba.g = 255 - rgba.g
|
||||
rgba.b = 255 - rgba.b
|
||||
rgba.a = 255 - rgba.a
|
||||
a.setRgbaUnsafe(x, y, rgba)
|
||||
|
||||
proc applyOpacityOriginal(a: Image, opacity: float32): Image =
|
||||
result = newImage(a.width, a.height)
|
||||
let op = (255 * opacity).uint32
|
||||
for y in 0 ..< a.height:
|
||||
for x in 0 ..< a.width:
|
||||
var rgba = a.getRgbaUnsafe(x, y)
|
||||
rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
|
||||
result.setRgbaUnsafe(x, y, rgba)
|
||||
|
||||
proc sharpOpacityOriginal(a: Image): Image =
|
||||
result = newImage(a.width, a.height)
|
||||
for y in 0 ..< a.height:
|
||||
for x in 0 ..< a.width:
|
||||
var rgba = a.getRgbaUnsafe(x, y)
|
||||
if rgba.a == 0:
|
||||
result.setRgbaUnsafe(x, y, rgba(0, 0, 0, 0))
|
||||
else:
|
||||
result.setRgbaUnsafe(x, y, rgba(255, 255, 255, 255))
|
||||
|
||||
timeIt "fillOriginal":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a.fillOriginal(rgba(255, 255, 255, 255))
|
||||
doAssert a[0, 0] == rgba(255, 255, 255, 255)
|
||||
|
||||
timeIt "fill":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a.fill(rgba(255, 255, 255, 255))
|
||||
doAssert a[0, 0] == rgba(255, 255, 255, 255)
|
||||
|
||||
timeIt "invertOriginal":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a.invertOriginal()
|
||||
|
||||
timeIt "invert":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a.invert()
|
||||
|
||||
timeIt "applyOpacityOriginal":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a = a.applyOpacityOriginal(0.5)
|
||||
|
||||
timeIt "applyOpacity":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a.applyOpacity(0.5)
|
||||
|
||||
timeIt "sharpOpacityOriginal":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a = a.sharpOpacityOriginal()
|
||||
|
||||
timeIt "sharpOpacity":
|
||||
var a = newImage(2560, 1440)
|
||||
for i in 0 ..< iterations:
|
||||
a.sharpOpacity()
|
|
@ -4,13 +4,15 @@ timeIt "spread":
|
|||
var tmp = 0
|
||||
var spread: Image
|
||||
for i in 0 ..< 100:
|
||||
var a = newImageFill(100, 100, rgba(0, 0, 0, 0))
|
||||
var b = newImageFill(50, 50, rgba(0, 0, 0, 255))
|
||||
var a = newImage(100, 100)
|
||||
var b = newImage(50, 50)
|
||||
b.fill(rgba(0, 0, 0, 255))
|
||||
a.draw(b, vec2(25, 25))
|
||||
|
||||
spread = a.spread(spread = 10)
|
||||
|
||||
b = newImageFill(50, 50, rgba(255, 255, 255, 255))
|
||||
b = newImage(50, 50)
|
||||
b.fill(rgba(255, 255, 255, 255))
|
||||
spread.draw(b, vec2(25, 25))
|
||||
|
||||
tmp += spread.width * spread.height
|
||||
|
@ -21,13 +23,15 @@ timeIt "blur":
|
|||
var tmp = 0
|
||||
var blur: Image
|
||||
for i in 0 ..< 100:
|
||||
var a = newImageFill(100, 100, rgba(0, 0, 0, 0))
|
||||
var b = newImageFill(50, 50, rgba(255, 255, 255, 255))
|
||||
var a = newImage(100, 100)
|
||||
var b = newImage(50, 50)
|
||||
b.fill(rgba(255, 255, 255, 255))
|
||||
a.draw(b, vec2(25, 25))
|
||||
|
||||
blur = a.blur(radius = 10)
|
||||
|
||||
b = newImageFill(50, 50, rgba(255, 255, 255, 255))
|
||||
b = newImage(50, 50)
|
||||
b.fill(rgba(255, 255, 255, 255))
|
||||
blur.draw(b, vec2(25, 25))
|
||||
|
||||
tmp += blur.width * blur.height
|
||||
|
@ -38,14 +42,16 @@ timeIt "shadow":
|
|||
var tmp = 0
|
||||
var shadow: Image
|
||||
for i in 0 ..< 100:
|
||||
var a = newImageFill(100, 100, rgba(0, 0, 0, 0))
|
||||
var b = newImageFill(50, 50, rgba(0, 0, 0, 255))
|
||||
var a = newImage(100, 100)
|
||||
var b = newImage(50, 50)
|
||||
b.fill(rgba(0, 0, 0, 255))
|
||||
a.draw(b, vec2(25, 25))
|
||||
|
||||
shadow = a.shadow(
|
||||
offset = vec2(0, 0), spread = 10, blur = 10, color = rgba(0, 0, 0, 255))
|
||||
|
||||
b = newImageFill(50, 50, rgba(255, 255, 255, 255))
|
||||
b = newImage(50, 50)
|
||||
b.fill(rgba(255, 255, 255, 255))
|
||||
shadow.draw(b, vec2(25, 25))
|
||||
|
||||
tmp += shadow.width * shadow.height
|
||||
|
@ -57,8 +63,9 @@ timeIt "shadow":
|
|||
# var tmp = 0
|
||||
# var shadow: Image
|
||||
# for i in 0 ..< 1:
|
||||
# var a = newImageFill(10, 200, rgba(0, 0, 0, 0))
|
||||
# var b = newImageFill(50, 50, rgba(0, 0, 0, 255))
|
||||
# var a = newImage(10, 200)
|
||||
# var b = newImage(50, 50)
|
||||
# b.fill(rgba(0, 0, 0, 255))
|
||||
# a.draw(b, vec2(-25, -25))
|
||||
|
||||
# for spread in 0 .. 0:
|
||||
|
@ -73,7 +80,8 @@ timeIt "shadow":
|
|||
# for y in 25 ..< (25 + spread + blur).int:
|
||||
# echo y - 25, ":", shadow[5, y].a
|
||||
|
||||
# b = newImageFill(50, 50, rgba(255, 255, 255, 255))
|
||||
# b = newImage(50, 50)
|
||||
# b.fill(rgba(255, 255, 255, 255))
|
||||
# shadow.draw(b, vec2(-25, -25))
|
||||
|
||||
# tmp += shadow.width * shadow.height
|
|
@ -1,209 +0,0 @@
|
|||
import pixie, chroma, vmath, fidget/opengl/perf, pixie/fileformats/bmp
|
||||
|
||||
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:
|
||||
let srcPos = mat * vec2(x.float32, y.float32)
|
||||
let destRgba = destImage.getRgbaUnsafe(x, y)
|
||||
var rgba = destRgba
|
||||
var srcRgba = rgba(0, 0, 0, 0)
|
||||
if srcImage.inside(srcPos.x.floor.int, srcPos.y.floor.int):
|
||||
srcRgba = srcImage.getRgbaSmooth(srcPos.x - 0.5, srcPos.y - 0.5)
|
||||
if blendMode.hasEffect(srcRgba):
|
||||
rgba = blendMode.mix(destRgba, srcRgba)
|
||||
destImage.setRgbaUnsafe(x, y, rgba)
|
||||
|
||||
proc inPlaceDraw*(destImage: Image, srcImage: Image, pos = vec2(0, 0), blendMode = bmNormal) =
|
||||
destImage.inPlaceDraw(srcImage, translate(-pos), blendMode)
|
||||
|
||||
proc drawStepperInPlace*(a: Image, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||
## Draws one image onto another using matrix with color blending.
|
||||
|
||||
type Segment = object
|
||||
## A math segment from point "at" to point "to"
|
||||
at*: Vec2
|
||||
to*: Vec2
|
||||
|
||||
proc segment(at, to: Vec2): Segment =
|
||||
result.at = at
|
||||
result.to = to
|
||||
|
||||
proc intersects(a, b: Segment, at: var Vec2): bool =
|
||||
## Checks if the a segment intersects b segment.
|
||||
## If it returns true, at will have point of intersection
|
||||
var s1x, s1y, s2x, s2y: float32
|
||||
s1x = a.to.x - a.at.x
|
||||
s1y = a.to.y - a.at.y
|
||||
s2x = b.to.x - b.at.x
|
||||
s2y = b.to.y - b.at.y
|
||||
|
||||
var s, t: float32
|
||||
s = (-s1y * (a.at.x - b.at.x) + s1x * (a.at.y - b.at.y)) /
|
||||
(-s2x * s1y + s1x * s2y)
|
||||
t = (s2x * (a.at.y - b.at.y) - s2y * (a.at.x - b.at.x)) /
|
||||
(-s2x * s1y + s1x * s2y)
|
||||
|
||||
if s >= 0 and s < 1 and t >= 0 and t < 1:
|
||||
at.x = a.at.x + (t * s1x)
|
||||
at.y = a.at.y + (t * s1y)
|
||||
return true
|
||||
return false
|
||||
|
||||
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
|
||||
|
||||
template forBlend(
|
||||
mixer: proc(a, b: ColorRGBA): ColorRGBA,
|
||||
getRgba: proc(a: Image, x, y: float32): ColorRGBA {.inline.},
|
||||
) =
|
||||
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(a.getAddr(0, y), a.getAddr(0, y), 4*xMin)
|
||||
|
||||
for x in xMin ..< xMax:
|
||||
let srcV = start + stepX * float32(x) + stepY * float32(y)
|
||||
var rgba = a.getRgbaUnsafe(x, y)
|
||||
if b.inside((srcV.x - h).int, (srcV.y - h).int):
|
||||
let rgba2 = b.getRgba(srcV.x - h, srcV.y - h)
|
||||
rgba = mixer(rgba, rgba2)
|
||||
a.setRgbaUnsafe(x, y, rgba)
|
||||
|
||||
#for x in xMax ..< a.width:
|
||||
# result.setRgbaUnsafe(x, y, a.getRgbaUnsafe(x, y))
|
||||
# if a.width - xMax > 0:
|
||||
# copyMem(result.getAddr(xMax, y), a.getAddr(xMax, y), 4*(a.width - xMax))
|
||||
|
||||
proc getRgba(a: Image, x, y: float32): ColorRGBA {.inline.} =
|
||||
a.getRgbaUnsafe(x.int, y.int)
|
||||
|
||||
if stepX.length == 1.0 and stepY.length == 1.0:
|
||||
case blendMode
|
||||
of bmNormal: forBlend(blendNormal, getRgba)
|
||||
of bmDarken: forBlend(blendDarken, getRgba)
|
||||
of bmMultiply: forBlend(blendMultiply, getRgba)
|
||||
of bmLinearBurn: forBlend(blendLinearBurn, getRgba)
|
||||
of bmColorBurn: forBlend(blendColorBurn, getRgba)
|
||||
of bmLighten: forBlend(blendLighten, getRgba)
|
||||
of bmScreen: forBlend(blendScreen, getRgba)
|
||||
of bmLinearDodge: forBlend(blendLinearDodge, getRgba)
|
||||
of bmColorDodge: forBlend(blendColorDodge, getRgba)
|
||||
of bmOverlay: forBlend(blendOverlay, getRgba)
|
||||
of bmSoftLight: forBlend(blendSoftLight, getRgba)
|
||||
of bmHardLight: forBlend(blendHardLight, getRgba)
|
||||
of bmDifference: forBlend(blendDifference, getRgba)
|
||||
of bmExclusion: forBlend(blendExclusion, getRgba)
|
||||
of bmHue: forBlend(blendHue, getRgba)
|
||||
of bmSaturation: forBlend(blendSaturation, getRgba)
|
||||
of bmColor: forBlend(blendColor, getRgba)
|
||||
of bmLuminosity: forBlend(blendLuminosity, getRgba)
|
||||
of bmMask: forBlend(blendMask, getRgba)
|
||||
of bmOverwrite: forBlend(blendOverwrite, getRgba)
|
||||
of bmSubtractMask: forBlend(blendSubtractMask, getRgba)
|
||||
of bmIntersectMask: forBlend(blendIntersectMask, getRgba)
|
||||
of bmExcludeMask: forBlend(blendExcludeMask, getRgba)
|
||||
else:
|
||||
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)
|
||||
|
||||
timeIt "inPlaceDraw":
|
||||
var tmp = 0
|
||||
for i in 0 ..< 1000:
|
||||
var a = newImageFill(1000, 1000, rgba(0, 255, 0, 255))
|
||||
var b = newImageFill(100, 100, rgba(0, 255, 0, 255))
|
||||
a.inPlaceDraw(b, pos=vec2(25, 25))
|
||||
tmp += a.width * a.height
|
||||
echo tmp
|
||||
|
||||
timeIt "drawStepper":
|
||||
var tmp = 0
|
||||
for i in 0 ..< 1000:
|
||||
var a = newImageFill(1000, 1000, rgba(255, 0, 0, 255))
|
||||
var b = newImageFill(100, 100, rgba(0, 255, 0, 255))
|
||||
var c = a.drawStepper(b, translate(vec2(25, 25)), bmNormal)
|
||||
tmp += c.width * c.height
|
||||
echo tmp
|
||||
|
||||
timeIt "drawStepperInPlace":
|
||||
var tmp = 0
|
||||
for i in 0 ..< 1000:
|
||||
var a = newImageFill(1000, 1000, rgba(0, 255, 0, 255))
|
||||
var b = newImageFill(100, 100, rgba(0, 255, 0, 255))
|
||||
drawStepperInPlace(a, b, translate(vec2(25, 25)), bmNormal)
|
||||
tmp += a.width * a.height
|
||||
echo tmp
|
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 382 B |
Loading…
Reference in a new issue