integer lerp, integer premultiply and straighten alpha
This commit is contained in:
parent
f6864b109e
commit
45fe8bd9ea
|
@ -9,20 +9,43 @@ proc fractional*(v: float32): float32 {.inline.} =
|
||||||
result = abs(v)
|
result = abs(v)
|
||||||
result = result - floor(result)
|
result = result - floor(result)
|
||||||
|
|
||||||
|
proc lerp*(a, b: ColorRGBA, t: float32): ColorRGBA {.inline.} =
|
||||||
|
let x = round(t * 255).uint32
|
||||||
|
result.r = ((a.r.uint32 * (255 - x) + b.r.uint32 * x) div 255).uint8
|
||||||
|
result.g = ((a.g.uint32 * (255 - x) + b.g.uint32 * x) div 255).uint8
|
||||||
|
result.b = ((a.b.uint32 * (255 - x) + b.b.uint32 * x) div 255).uint8
|
||||||
|
result.a = ((a.a.uint32 * (255 - x) + b.a.uint32 * x) div 255).uint8
|
||||||
|
|
||||||
|
proc premultiplyAlpha*(c: ColorRGBA): ColorRGBA {.inline.} =
|
||||||
|
## Converts a color to premultiplied alpha from straight alpha.
|
||||||
|
result.r = ((c.r.uint16 * c.a.uint16) div 255).uint8
|
||||||
|
result.g = ((c.g.uint16 * c.a.uint16) div 255).uint8
|
||||||
|
result.b = ((c.b.uint16 * c.a.uint16) div 255).uint8
|
||||||
|
result.a = c.a
|
||||||
|
|
||||||
|
proc straightenAlpha*(c: ColorRGBA): ColorRGBA {.inline.} =
|
||||||
|
## Converts a color to from premultiplied alpha to straight alpha.
|
||||||
|
result = c
|
||||||
|
if result.a != 0 and result.a != 255:
|
||||||
|
let multiplier = ((255 / c.a.float32) * 255).uint32
|
||||||
|
result.r = ((result.r.uint32 * multiplier) div 255).uint8
|
||||||
|
result.g = ((result.g.uint32 * multiplier) div 255).uint8
|
||||||
|
result.b = ((result.b.uint32 * multiplier) div 255).uint8
|
||||||
|
|
||||||
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 toAlphy*(c: Color): Color =
|
proc toAlphy*(c: Color): Color {.inline.} =
|
||||||
## Converts a color to premultiplied alpha from straight.
|
## Converts a color to premultiplied alpha from straight.
|
||||||
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 {.inline.} =
|
||||||
## Converts a color to from premultiplied alpha to straight.
|
## Converts a color to from premultiplied alpha to straight.
|
||||||
if c.a == 0:
|
if c.a == 0:
|
||||||
return
|
return
|
||||||
|
|
|
@ -250,23 +250,22 @@ proc invert*(image: Image) =
|
||||||
image.data[j] = rgba
|
image.data[j] = rgba
|
||||||
|
|
||||||
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
||||||
## Gets a pixel as (x, y) floats.
|
|
||||||
let
|
let
|
||||||
minX = x.floor.int
|
minX = x.floor.int
|
||||||
difX = x - x.floor
|
difX = x - x.floor
|
||||||
minY = y.floor.int
|
minY = y.floor.int
|
||||||
difY = y - y.floor
|
difY = y - y.floor
|
||||||
|
|
||||||
vX0Y0 = image[minX, minY].color().toAlphy()
|
vX0Y0 = image[minX, minY].premultiplyAlpha()
|
||||||
vX1Y0 = image[minX + 1, minY].color().toAlphy()
|
vX1Y0 = image[minX + 1, minY].premultiplyAlpha()
|
||||||
vX0Y1 = image[minX, minY + 1].color().toAlphy()
|
vX0Y1 = image[minX, minY + 1].premultiplyAlpha()
|
||||||
vX1Y1 = image[minX + 1, minY + 1].color().toAlphy()
|
vX1Y1 = image[minX + 1, minY + 1].premultiplyAlpha()
|
||||||
|
|
||||||
bottomMix = lerp(vX0Y0, vX1Y0, difX)
|
bottomMix = lerp(vX0Y0, vX1Y0, difX)
|
||||||
topMix = lerp(vX0Y1, vX1Y1, difX)
|
topMix = lerp(vX0Y1, vX1Y1, difX)
|
||||||
finalMix = lerp(bottomMix, topMix, difY)
|
finalMix = lerp(bottomMix, topMix, difY)
|
||||||
|
|
||||||
return finalMix.fromAlphy().rgba()
|
finalMix.straightenAlpha()
|
||||||
|
|
||||||
proc resize*(srcImage: Image, width, height: int): Image =
|
proc resize*(srcImage: Image, width, height: int): Image =
|
||||||
result = newImage(width, height)
|
result = newImage(width, height)
|
||||||
|
|
|
@ -5,12 +5,10 @@ let a = newImage(2560, 1440)
|
||||||
timeIt "fill":
|
timeIt "fill":
|
||||||
a.fill(rgba(255, 255, 255, 255))
|
a.fill(rgba(255, 255, 255, 255))
|
||||||
doAssert a[0, 0] == rgba(255, 255, 255, 255)
|
doAssert a[0, 0] == rgba(255, 255, 255, 255)
|
||||||
keep(a)
|
|
||||||
|
|
||||||
timeIt "fill_rgba":
|
timeIt "fill_rgba":
|
||||||
a.fill(rgba(63, 127, 191, 191))
|
a.fill(rgba(63, 127, 191, 191))
|
||||||
doAssert a[0, 0] == rgba(63, 127, 191, 191)
|
doAssert a[0, 0] == rgba(63, 127, 191, 191)
|
||||||
keep(a)
|
|
||||||
|
|
||||||
timeIt "subImage":
|
timeIt "subImage":
|
||||||
keep a.subImage(0, 0, 256, 256)
|
keep a.subImage(0, 0, 256, 256)
|
||||||
|
@ -34,3 +32,19 @@ timeIt "toAlphy":
|
||||||
|
|
||||||
timeIt "fromAlphy":
|
timeIt "fromAlphy":
|
||||||
a.fromAlphy()
|
a.fromAlphy()
|
||||||
|
|
||||||
|
timeIt "lerp integers":
|
||||||
|
for i in 0 ..< 100000:
|
||||||
|
let c = a[0, 0]
|
||||||
|
var z: int
|
||||||
|
for t in 0 .. 100:
|
||||||
|
z += lerp(c, c, t.float32 / 100).a.int
|
||||||
|
doAssert z > 0
|
||||||
|
|
||||||
|
timeIt "lerp floats":
|
||||||
|
for i in 0 ..< 100000:
|
||||||
|
let c = a[0, 0]
|
||||||
|
var z: int
|
||||||
|
for t in 0 .. 100:
|
||||||
|
z += lerp(c.color, c.color, t.float32 / 100).rgba().a.int
|
||||||
|
doAssert z > 0
|
||||||
|
|
Loading…
Reference in a new issue