Add toAlphy and fromAlphy.
This commit is contained in:
parent
b86d914dd0
commit
41edec4711
3 changed files with 48 additions and 160 deletions
|
@ -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)
|
|
|
@ -155,22 +155,37 @@ proc magnifyBy2*(image: Image, scale2x: int): Image =
|
||||||
proc magnifyBy2*(image: Image): Image =
|
proc magnifyBy2*(image: Image): Image =
|
||||||
image.magnifyBy2(2)
|
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.} =
|
func lerp(a, b: Color, v: float32): Color {.inline.} =
|
||||||
result.r = lerp(a.r, b.r, v)
|
result.r = lerp(a.r, b.r, v)
|
||||||
result.g = lerp(a.g, b.g, v)
|
result.g = lerp(a.g, b.g, v)
|
||||||
result.b = lerp(a.b, b.b, v)
|
result.b = lerp(a.b, b.b, v)
|
||||||
result.a = lerp(a.a, b.a, v)
|
result.a = lerp(a.a, b.a, v)
|
||||||
|
|
||||||
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
proc toAlphy*(c: Color): Color =
|
||||||
## Gets a pixel as (x, y) floats.
|
## Converts a color to premultiplied alpha from straight.
|
||||||
|
|
||||||
proc toAlphy(c: Color): Color =
|
|
||||||
result.r = c.r * c.a
|
result.r = c.r * c.a
|
||||||
result.g = c.g * c.a
|
result.g = c.g * c.a
|
||||||
result.b = c.b * c.a
|
result.b = c.b * c.a
|
||||||
result.a = c.a
|
result.a = c.a
|
||||||
|
|
||||||
proc fromAlphy(c: Color): Color =
|
proc fromAlphy*(c: Color): Color =
|
||||||
|
## Converts a color to from premultiplied alpha to straight.
|
||||||
if c.a == 0:
|
if c.a == 0:
|
||||||
return
|
return
|
||||||
result.r = c.r / c.a
|
result.r = c.r / c.a
|
||||||
|
@ -178,6 +193,24 @@ proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
||||||
result.b = c.b / c.a
|
result.b = c.b / c.a
|
||||||
result.a = 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.
|
||||||
var
|
var
|
||||||
x = x # TODO: look at maybe +0.5
|
x = x # TODO: look at maybe +0.5
|
||||||
y = y # TODO: look at maybe +0.5
|
y = y # TODO: look at maybe +0.5
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Loading…
Reference in a new issue