mask.unsafe[x, y]

This commit is contained in:
Ryan Oldenburg 2021-12-11 18:04:01 -06:00
parent ff1e6bd12d
commit 18a81b3d0e
3 changed files with 38 additions and 40 deletions

View file

@ -689,7 +689,7 @@ proc drawCorrect(
blended = blender(backdrop, rgbx(0, 0, 0, sample)) blended = blender(backdrop, rgbx(0, 0, 0, sample))
a.unsafe[x, y] = blended a.unsafe[x, y] = blended
else: # a is a Mask else: # a is a Mask
let backdrop = a.getValueUnsafe(x, y) let backdrop = a.unsafe[x, y]
when type(b) is Image: when type(b) is Image:
let sample = b.getRgbaSmooth(xFloat, yFloat, tiled).a let sample = b.getRgbaSmooth(xFloat, yFloat, tiled).a
else: # b is a Mask else: # b is a Mask
@ -803,12 +803,12 @@ proc drawUber(
blended = blender(backdrop, rgbx(0, 0, 0, sample)) blended = blender(backdrop, rgbx(0, 0, 0, sample))
a.unsafe[x, y] = blended a.unsafe[x, y] = blended
else: # a is a Mask else: # a is a Mask
let backdrop = a.getValueUnsafe(x, y) let backdrop = a.unsafe[x, y]
when type(b) is Image: when type(b) is Image:
let sample = b.getRgbaSmooth(srcPos.x, srcPos.y).a let sample = b.getRgbaSmooth(srcPos.x, srcPos.y).a
else: # b is a Mask else: # b is a Mask
let sample = b.getValueSmooth(srcPos.x, srcPos.y) let sample = b.getValueSmooth(srcPos.x, srcPos.y)
a.setValueUnsafe(x, y, masker(backdrop, sample)) a.unsafe[x, y] = masker(backdrop, sample)
srcPos += dx srcPos += dx
@ -900,16 +900,16 @@ proc drawUber(
blended = blender(backdrop, sample) blended = blender(backdrop, sample)
else: # b is a Mask else: # b is a Mask
let let
sample = b.getValueUnsafe(samplePos.x, samplePos.y) sample = b.unsafe[samplePos.x, samplePos.y]
blended = blender(backdrop, rgbx(0, 0, 0, sample)) blended = blender(backdrop, rgbx(0, 0, 0, sample))
a.unsafe[x, y] = blended a.unsafe[x, y] = blended
else: # a is a Mask else: # a is a Mask
let backdrop = a.getValueUnsafe(x, y) let backdrop = a.unsafe[x, y]
when type(b) is Image: when type(b) is Image:
let sample = b.unsafe[samplePos.x, samplePos.y].a let sample = b.unsafe[samplePos.x, samplePos.y].a
else: # b is a Mask else: # b is a Mask
let sample = b.getValueUnsafe(samplePos.x, samplePos.y) let sample = b.unsafe[samplePos.x, samplePos.y]
a.setValueUnsafe(x, y, masker(backdrop, sample)) a.unsafe[x, y] = masker(backdrop, sample)
srcPos += dx srcPos += dx

View file

@ -9,6 +9,9 @@ type
width*, height*: int width*, height*: int
data*: seq[uint8] data*: seq[uint8]
UnsafeMask = object
mask: Mask
when defined(release): when defined(release):
{.push checks: off.} {.push checks: off.}
@ -38,29 +41,24 @@ proc inside*(mask: Mask, x, y: int): bool {.inline, raises: [].} =
proc dataIndex*(mask: Mask, x, y: int): int {.inline, raises: [].} = proc dataIndex*(mask: Mask, x, y: int): int {.inline, raises: [].} =
mask.width * y + x mask.width * y + x
proc getValueUnsafe*(mask: Mask, x, y: int): uint8 {.inline, raises: [].} = template unsafe*(src: Mask): UnsafeMask =
## Gets a value from (x, y) coordinates. UnsafeMask(mask: src)
## * No bounds checking *
## Make sure that x, y are in bounds.
## Failure in the assumptions will case unsafe memory reads.
result = mask.data[mask.dataIndex(x, y)]
proc setValueUnsafe*(mask: Mask, x, y: int, value: uint8) {.inline, raises: [].} = template `[]`*(view: UnsafeMask, x, y: int): uint8 =
## Sets a value from (x, y) coordinates. view.mask.data[view.mask.dataIndex(x, y)]
## * No bounds checking *
## Make sure that x, y are in bounds. template `[]=`*(view: UnsafeMask, x, y: int, color: uint8) =
## Failure in the assumptions will case unsafe memory writes. view.mask.data[view.mask.dataIndex(x, y)] = color
mask.data[mask.dataIndex(x, y)] = value
proc `[]`*(mask: Mask, x, y: int): uint8 {.inline, raises: [].} = proc `[]`*(mask: Mask, x, y: int): uint8 {.inline, raises: [].} =
## Gets a value at (x, y) or returns transparent black if outside of bounds. ## Gets a value at (x, y) or returns transparent black if outside of bounds.
if mask.inside(x, y): if mask.inside(x, y):
return mask.getValueUnsafe(x, y) return mask.unsafe[x, y]
proc `[]=`*(mask: Mask, x, y: int, value: uint8) {.inline, raises: [].} = proc `[]=`*(mask: Mask, x, y: int, value: uint8) {.inline, raises: [].} =
## Sets a value at (x, y) or does nothing if outside of bounds. ## Sets a value at (x, y) or does nothing if outside of bounds.
if mask.inside(x, y): if mask.inside(x, y):
mask.setValueUnsafe(x, y, value) mask.unsafe[x, y] = value
proc getValue*(mask: Mask, x, y: int): uint8 {.inline, raises: [].} = proc getValue*(mask: Mask, x, y: int): uint8 {.inline, raises: [].} =
## Gets a value at (x, y) or returns transparent black if outside of bounds. ## Gets a value at (x, y) or returns transparent black if outside of bounds.
@ -144,11 +142,11 @@ proc minifyBy2*(mask: Mask, power = 1): Mask {.raises: [PixieError].} =
for x in x ..< result.width: for x in x ..< result.width:
let value = let value =
src.getValueUnsafe(x * 2 + 0, y * 2 + 0).uint32 + src.unsafe[x * 2 + 0, y * 2 + 0].uint32 +
src.getValueUnsafe(x * 2 + 1, y * 2 + 0) + src.unsafe[x * 2 + 1, y * 2 + 0] +
src.getValueUnsafe(x * 2 + 1, y * 2 + 1) + src.unsafe[x * 2 + 1, y * 2 + 1] +
src.getValueUnsafe(x * 2 + 0, y * 2 + 1) src.unsafe[x * 2 + 0, y * 2 + 1]
result.setValueUnsafe(x, y, (value div 4).uint8) result.unsafe[x, y] = (value div 4).uint8
# Set src as this result for if we do another power # Set src as this result for if we do another power
src = result src = result
@ -163,7 +161,7 @@ proc magnifyBy2*(mask: Mask, power = 1): Mask {.raises: [PixieError].} =
for y in 0 ..< result.height: for y in 0 ..< result.height:
for x in 0 ..< mask.width: for x in 0 ..< mask.width:
let let
value = mask.getValueUnsafe(x, y div scale) value = mask.unsafe[x, y div scale]
scaledX = x * scale scaledX = x * scale
idx = result.dataIndex(scaledX, y) idx = result.dataIndex(scaledX, y)
for i in 0 ..< scale: for i in 0 ..< scale:
@ -222,24 +220,24 @@ proc spread*(mask: Mask, spread: float32) {.raises: [PixieError].} =
for x in 0 ..< mask.width: for x in 0 ..< mask.width:
var maxValue: uint8 var maxValue: uint8
for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1): for xx in max(x - spread, 0) .. min(x + spread, mask.width - 1):
let value = mask.getValueUnsafe(xx, y) let value = mask.unsafe[xx, y]
if value > maxValue: if value > maxValue:
maxValue = value maxValue = value
if maxValue == 255: if maxValue == 255:
break break
spreadX.setValueUnsafe(y, x, maxValue) spreadX.unsafe[y, x] = maxValue
# Spread in the Y direction and modify mask. # Spread in the Y direction and modify mask.
for y in 0 ..< mask.height: for y in 0 ..< mask.height:
for x in 0 ..< mask.width: for x in 0 ..< mask.width:
var maxValue: uint8 var maxValue: uint8
for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1): for yy in max(y - spread, 0) .. min(y + spread, mask.height - 1):
let value = spreadX.getValueUnsafe(yy, x) let value = spreadX.unsafe[yy, x]
if value > maxValue: if value > maxValue:
maxValue = value maxValue = value
if maxValue == 255: if maxValue == 255:
break break
mask.setValueUnsafe(x, y, maxValue) mask.unsafe[x, y] = maxValue
proc ceil*(mask: Mask) {.raises: [].} = proc ceil*(mask: Mask) {.raises: [].} =
## A value of 0 stays 0. Anything else turns into 255. ## A value of 0 stays 0. Anything else turns into 255.
@ -277,10 +275,10 @@ proc blur*(mask: Mask, radius: float32, outOfBounds: uint8 = 0) {.raises: [Pixie
for xx in x - radius ..< min(x + radius, 0): for xx in x - radius ..< min(x + radius, 0):
value += outOfBounds * kernel[xx - x + radius].uint32 value += outOfBounds * kernel[xx - x + radius].uint32
for xx in max(x - radius, 0) .. min(x + radius, mask.width - 1): for xx in max(x - radius, 0) .. min(x + radius, mask.width - 1):
value += mask.getValueUnsafe(xx, y) * kernel[xx - x + radius].uint32 value += mask.unsafe[xx, y] * kernel[xx - x + radius].uint32
for xx in max(x - radius, mask.width) .. x + radius: for xx in max(x - radius, mask.width) .. x + radius:
value += outOfBounds * kernel[xx - x + radius].uint32 value += outOfBounds * kernel[xx - x + radius].uint32
blurX.setValueUnsafe(y, x, (value div 256 div 255).uint8) blurX.unsafe[y, x] = (value div 256 div 255).uint8
# Blur in the Y direction and modify image. # Blur in the Y direction and modify image.
for y in 0 ..< mask.height: for y in 0 ..< mask.height:
@ -289,10 +287,10 @@ proc blur*(mask: Mask, radius: float32, outOfBounds: uint8 = 0) {.raises: [Pixie
for yy in y - radius ..< min(y + radius, 0): for yy in y - radius ..< min(y + radius, 0):
value += outOfBounds * kernel[yy - y + radius].uint32 value += outOfBounds * kernel[yy - y + radius].uint32
for yy in max(y - radius, 0) .. min(y + radius, mask.height - 1): for yy in max(y - radius, 0) .. min(y + radius, mask.height - 1):
value += blurX.getValueUnsafe(yy, x) * kernel[yy - y + radius].uint32 value += blurX.unsafe[yy, x] * kernel[yy - y + radius].uint32
for yy in max(y - radius, mask.height) .. y + radius: for yy in max(y - radius, mask.height) .. y + radius:
value += outOfBounds * kernel[yy - y + radius].uint32 value += outOfBounds * kernel[yy - y + radius].uint32
mask.setValueUnsafe(x, y, (value div 256 div 255).uint8) mask.unsafe[x, y] = (value div 256 div 255).uint8
when defined(release): when defined(release):
{.pop.} {.pop.}

View file

@ -1449,10 +1449,10 @@ proc fillCoverage(
while x < startX + coverages.len: while x < startX + coverages.len:
let coverage = coverages[x - startX] let coverage = coverages[x - startX]
if coverage != 0 or blendMode == bmExcludeMask: if coverage != 0 or blendMode == bmExcludeMask:
let backdrop = mask.getValueUnsafe(x, y) let backdrop = mask.unsafe[x, y]
mask.setValueUnsafe(x, y, masker(backdrop, coverage)) mask.unsafe[x, y] = masker(backdrop, coverage)
elif blendMode == bmMask: elif blendMode == bmMask:
mask.setValueUnsafe(x, y, 0) mask.unsafe[x, y] = 0
inc x inc x
if blendMode == bmMask: if blendMode == bmMask:
@ -1564,8 +1564,8 @@ proc fillHits(
x += 16 x += 16
for x in x ..< fillStart + fillLen: for x in x ..< fillStart + fillLen:
let backdrop = mask.getValueUnsafe(x, y) let backdrop = mask.unsafe[x, y]
mask.setValueUnsafe(x, y, masker(backdrop, 255)) mask.unsafe[x, y] = masker(backdrop, 255)
if blendMode == bmMask: if blendMode == bmMask:
mask.clearUnsafe(0, y, startX, y) mask.clearUnsafe(0, y, startX, y)