commit
cdb6b3c6fe
4 changed files with 111 additions and 123 deletions
|
@ -10,5 +10,5 @@ requires "vmath >= 0.4.0"
|
||||||
requires "chroma >= 0.2.1"
|
requires "chroma >= 0.2.1"
|
||||||
requires "zippy >= 0.3.5"
|
requires "zippy >= 0.3.5"
|
||||||
requires "flatty >= 0.1.3"
|
requires "flatty >= 0.1.3"
|
||||||
requires "nimsimd >= 0.4.8"
|
requires "nimsimd >= 1.0.0"
|
||||||
requires "bumpy >= 1.0.1"
|
requires "bumpy >= 1.0.1"
|
||||||
|
|
|
@ -44,7 +44,7 @@ proc writeFile*(image: Image, filePath: string) =
|
||||||
let fileFormat = case splitFile(filePath).ext:
|
let fileFormat = case splitFile(filePath).ext:
|
||||||
of ".png": ffPng
|
of ".png": ffPng
|
||||||
of ".bmp": ffBmp
|
of ".bmp": ffBmp
|
||||||
of ".jpg",".jpeg": ffJpg
|
of ".jpg", ".jpeg": ffJpg
|
||||||
else:
|
else:
|
||||||
raise newException(PixieError, "Unsupported image file extension")
|
raise newException(PixieError, "Unsupported image file extension")
|
||||||
image.writeFile(filePath, fileformat)
|
image.writeFile(filePath, fileformat)
|
||||||
|
|
|
@ -227,9 +227,6 @@ proc toStraightAlpha*(image: Image) =
|
||||||
when defined(release):
|
when defined(release):
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
proc draw*(a, b: Image, mat: Mat3, blendMode = bmNormal)
|
|
||||||
proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.}
|
|
||||||
|
|
||||||
proc invert*(image: Image) =
|
proc invert*(image: Image) =
|
||||||
## Inverts all of the colors and alpha.
|
## Inverts all of the colors and alpha.
|
||||||
var i: int
|
var i: int
|
||||||
|
@ -266,15 +263,19 @@ proc getRgbaSmooth*(image: Image, x, y: float32): ColorRGBA {.inline.} =
|
||||||
|
|
||||||
finalMix.toStraightAlpha()
|
finalMix.toStraightAlpha()
|
||||||
|
|
||||||
proc resize*(srcImage: Image, width, height: int): Image =
|
proc gaussianLookup(radius: int): seq[float32] =
|
||||||
result = newImage(width, height)
|
## Compute lookup table for 1d Gaussian kernel.
|
||||||
result.draw(
|
result.setLen(radius * 2 + 1)
|
||||||
srcImage,
|
var total = 0.0
|
||||||
scale(vec2(
|
for xb in -radius .. radius:
|
||||||
(width + 1).float / srcImage.width.float,
|
let
|
||||||
(height + 1).float / srcImage.height.float
|
s = radius.float32 / 2.2 # 2.2 matches Figma.
|
||||||
))
|
x = xb.float32
|
||||||
)
|
a = 1 / sqrt(2 * PI * s^2) * exp(-1 * x^2 / (2 * s^2))
|
||||||
|
result[xb + radius] = a
|
||||||
|
total += a
|
||||||
|
for xb in -radius .. radius:
|
||||||
|
result[xb + radius] = result[xb + radius] / total
|
||||||
|
|
||||||
proc blur*(image: Image, radius: float32) =
|
proc blur*(image: Image, radius: float32) =
|
||||||
## Applies Gaussian blur to the image given a radius.
|
## Applies Gaussian blur to the image given a radius.
|
||||||
|
@ -282,18 +283,7 @@ proc blur*(image: Image, radius: float32) =
|
||||||
if radius == 0:
|
if radius == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Compute lookup table for 1d Gaussian kernel.
|
let lookup = gaussianLookup(radius)
|
||||||
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))
|
|
||||||
lookup[xb + radius] = a
|
|
||||||
total += a
|
|
||||||
for xb in -radius .. radius:
|
|
||||||
lookup[xb + radius] /= total
|
|
||||||
|
|
||||||
# Blur in the X direction.
|
# Blur in the X direction.
|
||||||
var blurX = newImage(image.width, image.height)
|
var blurX = newImage(image.width, image.height)
|
||||||
|
@ -340,18 +330,7 @@ proc blurAlpha*(image: Image, radius: float32) =
|
||||||
if radius == 0:
|
if radius == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Compute lookup table for 1d Gaussian kernel.
|
let lookup = gaussianLookup(radius)
|
||||||
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))
|
|
||||||
lookup[xb + radius] = a
|
|
||||||
total += a
|
|
||||||
for xb in -radius .. radius:
|
|
||||||
lookup[xb + radius] /= total
|
|
||||||
|
|
||||||
# Blur in the X direction.
|
# Blur in the X direction.
|
||||||
var blurX = newImage(image.width, image.height)
|
var blurX = newImage(image.width, image.height)
|
||||||
|
@ -374,64 +353,20 @@ proc blurAlpha*(image: Image, radius: float32) =
|
||||||
alpha += c2.a.float32 * a
|
alpha += c2.a.float32 * a
|
||||||
image.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
|
image.setRgbaUnsafe(x, y, rgba(0, 0, 0, alpha.uint8))
|
||||||
|
|
||||||
proc shift*(image: Image, offset: Vec2) =
|
|
||||||
## Shifts the image by offset.
|
|
||||||
if offset != vec2(0, 0):
|
|
||||||
let copy = image.copy() # Copy to read from.
|
|
||||||
image.fill(rgba(0, 0, 0, 0)) # Reset this for being drawn to.
|
|
||||||
image.draw(copy, offset) # Draw copy into image.
|
|
||||||
|
|
||||||
proc spread*(image: Image, spread: float32) =
|
|
||||||
## Grows the image as a mask by spread.
|
|
||||||
let
|
|
||||||
copy = image.copy()
|
|
||||||
spread = round(spread).int
|
|
||||||
assert spread > 0
|
|
||||||
for y in 0 ..< image.height:
|
|
||||||
for x in 0 ..< image.width:
|
|
||||||
var maxAlpha = 0.uint8
|
|
||||||
block blurBox:
|
|
||||||
for bx in -spread .. spread:
|
|
||||||
for by in -spread .. spread:
|
|
||||||
let alpha = copy[x + bx, y + by].a
|
|
||||||
if alpha > maxAlpha:
|
|
||||||
maxAlpha = alpha
|
|
||||||
if maxAlpha == 255:
|
|
||||||
break blurBox
|
|
||||||
image[x, y] = rgba(0, 0, 0, maxAlpha)
|
|
||||||
|
|
||||||
proc shadow*(
|
|
||||||
mask: Image, offset: Vec2, spread, blur: float32, color: ColorRGBA
|
|
||||||
): Image =
|
|
||||||
## Create a shadow of the image with the offset, spread and blur.
|
|
||||||
var shadow = mask
|
|
||||||
if offset != vec2(0, 0):
|
|
||||||
shadow.shift(offset)
|
|
||||||
if spread > 0:
|
|
||||||
shadow.spread(spread)
|
|
||||||
if blur > 0:
|
|
||||||
shadow.blurAlpha(blur)
|
|
||||||
result = newImage(mask.width, mask.height)
|
|
||||||
result.fill(color)
|
|
||||||
result.draw(shadow, blendMode = bmMask)
|
|
||||||
|
|
||||||
proc applyOpacity*(image: Image, opacity: float32) =
|
proc applyOpacity*(image: Image, opacity: float32) =
|
||||||
## Multiplies alpha of the image by opacity.
|
## Multiplies alpha of the image by opacity.
|
||||||
let op = (255 * opacity).uint32
|
let op = (255 * opacity).uint32
|
||||||
for i in 0 ..< image.data.len:
|
for rgba in image.data.mitems:
|
||||||
var rgba = image.data[i]
|
|
||||||
rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
|
rgba.a = ((rgba.a.uint32 * op) div 255).clamp(0, 255).uint8
|
||||||
image.data[i] = rgba
|
|
||||||
|
|
||||||
proc sharpOpacity*(image: Image) =
|
proc sharpOpacity*(image: Image) =
|
||||||
## Sharpens the opacity to extreme.
|
## Sharpens the opacity to extreme.
|
||||||
## A = 0 stays 0. Anything else turns into 255.
|
## A = 0 stays 0. Anything else turns into 255.
|
||||||
for i in 0 ..< image.data.len:
|
for rgba in image.data.mitems:
|
||||||
var rgba = image.data[i]
|
|
||||||
if rgba.a == 0:
|
if rgba.a == 0:
|
||||||
image.data[i] = rgba(0, 0, 0, 0)
|
rgba = rgba(0, 0, 0, 0)
|
||||||
else:
|
else:
|
||||||
image.data[i] = rgba(255, 255, 255, 255)
|
rgba = rgba(255, 255, 255, 255)
|
||||||
|
|
||||||
proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
|
@ -466,7 +401,7 @@ proc drawCorrect*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
proc drawUber(
|
proc drawUber(
|
||||||
a, b: Image,
|
a, b: Image,
|
||||||
p, dx, dy: Vec2,
|
p, dx, dy: Vec2,
|
||||||
segments: array[0..3, Segment],
|
perimeter: array[0..3, Segment],
|
||||||
blendMode: BlendMode,
|
blendMode: BlendMode,
|
||||||
smooth: bool
|
smooth: bool
|
||||||
) =
|
) =
|
||||||
|
@ -480,7 +415,7 @@ proc drawUber(
|
||||||
a: vec2(-1000, y.float32 + yOffset),
|
a: vec2(-1000, y.float32 + yOffset),
|
||||||
b: vec2(1000, y.float32 + yOffset)
|
b: vec2(1000, y.float32 + yOffset)
|
||||||
)
|
)
|
||||||
for segment in segments:
|
for segment in perimeter:
|
||||||
var at: Vec2
|
var at: Vec2
|
||||||
if scanline.intersects(segment, at) and segment.to != at:
|
if scanline.intersects(segment, at) and segment.to != at:
|
||||||
xMin = min(xMin, at.x.floor.int)
|
xMin = min(xMin, at.x.floor.int)
|
||||||
|
@ -510,7 +445,7 @@ proc drawUber(
|
||||||
if a.width - xMax > 0:
|
if a.width - xMax > 0:
|
||||||
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
|
zeroMem(a.data[a.dataIndex(xMax, y)].addr, 4 * (a.width - xMax))
|
||||||
|
|
||||||
proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
proc draw*(a, b: Image, mat: Mat3, blendMode = bmNormal) =
|
||||||
## Draws one image onto another using matrix with color blending.
|
## Draws one image onto another using matrix with color blending.
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -520,7 +455,7 @@ proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
mat * vec2(b.width.float32, b.height.float32),
|
mat * vec2(b.width.float32, b.height.float32),
|
||||||
mat * vec2(0, b.height.float32)
|
mat * vec2(0, b.height.float32)
|
||||||
]
|
]
|
||||||
segments = [
|
perimeter = [
|
||||||
segment(corners[0], corners[1]),
|
segment(corners[0], corners[1]),
|
||||||
segment(corners[1], corners[2]),
|
segment(corners[1], corners[2]),
|
||||||
segment(corners[2], corners[3]),
|
segment(corners[2], corners[3]),
|
||||||
|
@ -551,7 +486,62 @@ proc draw*(a, b: Image, mat: Mat3, blendMode: BlendMode) =
|
||||||
mat[2, 1].fractional == 0.0
|
mat[2, 1].fractional == 0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
a.drawUber(b, p, dx, dy, segments, blendMode, smooth)
|
a.drawUber(b, p, dx, dy, perimeter, blendMode, smooth)
|
||||||
|
|
||||||
proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} =
|
proc draw*(a, b: Image, pos = vec2(0, 0), blendMode = bmNormal) {.inline.} =
|
||||||
a.draw(b, translate(pos), blendMode)
|
a.draw(b, translate(pos), blendMode)
|
||||||
|
|
||||||
|
proc resize*(srcImage: Image, width, height: int): Image =
|
||||||
|
result = newImage(width, height)
|
||||||
|
result.draw(
|
||||||
|
srcImage,
|
||||||
|
scale(vec2(
|
||||||
|
(width + 1).float / srcImage.width.float,
|
||||||
|
(height + 1).float / srcImage.height.float
|
||||||
|
)),
|
||||||
|
bmOverwrite
|
||||||
|
)
|
||||||
|
|
||||||
|
proc shift*(image: Image, offset: Vec2) =
|
||||||
|
## Shifts the image by offset.
|
||||||
|
if offset != vec2(0, 0):
|
||||||
|
let copy = image.copy() # Copy to read from.
|
||||||
|
image.fill(rgba(0, 0, 0, 0)) # Reset this for being drawn to.
|
||||||
|
image.draw(copy, offset, bmOverwrite) # Draw copy into image.
|
||||||
|
|
||||||
|
proc spread*(image: Image, spread: float32) =
|
||||||
|
## Grows the image as a mask by spread.
|
||||||
|
if spread == 0:
|
||||||
|
return
|
||||||
|
if spread < 0:
|
||||||
|
raise newException(PixieError, "Cannot apply negative spread")
|
||||||
|
|
||||||
|
let
|
||||||
|
copy = image.copy()
|
||||||
|
spread = round(spread).int
|
||||||
|
for y in 0 ..< image.height:
|
||||||
|
for x in 0 ..< image.width:
|
||||||
|
var maxAlpha = 0.uint8
|
||||||
|
block blurBox:
|
||||||
|
for bx in -spread .. spread:
|
||||||
|
for by in -spread .. spread:
|
||||||
|
let alpha = copy[x + bx, y + by].a
|
||||||
|
if alpha > maxAlpha:
|
||||||
|
maxAlpha = alpha
|
||||||
|
if maxAlpha == 255:
|
||||||
|
break blurBox
|
||||||
|
image.setRgbaUnsafe(x, y, rgba(0, 0, 0, maxAlpha))
|
||||||
|
|
||||||
|
proc shadow*(
|
||||||
|
mask: Image, offset: Vec2, spread, blur: float32, color: ColorRGBA
|
||||||
|
): Image =
|
||||||
|
## Create a shadow of the image with the offset, spread and blur.
|
||||||
|
if offset != vec2(0, 0):
|
||||||
|
mask.shift(offset)
|
||||||
|
if spread > 0:
|
||||||
|
mask.spread(spread)
|
||||||
|
if blur > 0:
|
||||||
|
mask.blurAlpha(blur)
|
||||||
|
result = newImage(mask.width, mask.height)
|
||||||
|
result.fill(color)
|
||||||
|
result.draw(mask, blendMode = bmMask)
|
||||||
|
|
|
@ -724,7 +724,7 @@ iterator segments*(s: seq[Vec2]): Segment =
|
||||||
for i in 0 ..< s.len - 1:
|
for i in 0 ..< s.len - 1:
|
||||||
yield(segment(s[i], s[i + 1]))
|
yield(segment(s[i], s[i + 1]))
|
||||||
|
|
||||||
proc quickSort(a: var seq[(float32, bool)], inl, inr: int) =
|
proc quickSort(a: var seq[(float32, int16)], inl, inr: int) =
|
||||||
var
|
var
|
||||||
r = inr
|
r = inr
|
||||||
l = inl
|
l = inl
|
||||||
|
@ -744,18 +744,17 @@ proc quickSort(a: var seq[(float32, bool)], inl, inr: int) =
|
||||||
quickSort(a, inl, r)
|
quickSort(a, inl, r)
|
||||||
quickSort(a, l, inr)
|
quickSort(a, l, inr)
|
||||||
|
|
||||||
proc computeBounds(shapes: seq[seq[(Segment, bool)]]): Rect =
|
proc computeBounds(segments: seq[(Segment, int16)]): Rect =
|
||||||
var
|
var
|
||||||
xMin = float32.high
|
xMin = float32.high
|
||||||
xMax = float32.low
|
xMax = float32.low
|
||||||
yMin = float32.high
|
yMin = float32.high
|
||||||
yMax = float32.low
|
yMax = float32.low
|
||||||
for shape in shapes:
|
for (segment, _) in segments:
|
||||||
for (segment, _) in shape:
|
xMin = min(xMin, min(segment.at.x, segment.to.x))
|
||||||
xMin = min(xMin, min(segment.at.x, segment.to.x))
|
xMax = max(xMax, max(segment.at.x, segment.to.x))
|
||||||
xMax = max(xMax, max(segment.at.x, segment.to.x))
|
yMin = min(yMin, min(segment.at.y, segment.to.y))
|
||||||
yMin = min(yMin, min(segment.at.y, segment.to.y))
|
yMax = max(yMax, max(segment.at.y, segment.to.y))
|
||||||
yMax = max(yMax, max(segment.at.y, segment.to.y))
|
|
||||||
|
|
||||||
xMin = floor(xMin)
|
xMin = floor(xMin)
|
||||||
xMax = ceil(xMax)
|
xMax = ceil(xMax)
|
||||||
|
@ -773,23 +772,22 @@ proc fillShapes(
|
||||||
color: ColorRGBA,
|
color: ColorRGBA,
|
||||||
windingRule: WindingRule
|
windingRule: WindingRule
|
||||||
) =
|
) =
|
||||||
var sortedShapes = newSeq[seq[(Segment, bool)]](shapes.len)
|
var sortedSegments: seq[(Segment, int16)]
|
||||||
for i, sorted in sortedShapes.mpairs:
|
for shape in shapes:
|
||||||
for segment in shapes[i].segments:
|
for segment in shape.segments:
|
||||||
if segment.at.y == segment.to.y: # Skip horizontal
|
if segment.at.y == segment.to.y: # Skip horizontal
|
||||||
continue
|
continue
|
||||||
let winding = segment.at.y > segment.to.y
|
if segment.at.y > segment.to.y:
|
||||||
if winding:
|
|
||||||
var segment = segment
|
var segment = segment
|
||||||
swap(segment.at, segment.to)
|
swap(segment.at, segment.to)
|
||||||
sorted.add((segment, winding))
|
sortedSegments.add((segment, -1.int16))
|
||||||
else:
|
else:
|
||||||
sorted.add((segment, winding))
|
sortedSegments.add((segment, 1.int16))
|
||||||
|
|
||||||
# Figure out the total bounds of all the shapes,
|
# Figure out the total bounds of all the shapes,
|
||||||
# rasterize only within the total bounds
|
# rasterize only within the total bounds
|
||||||
let
|
let
|
||||||
bounds = computeBounds(sortedShapes)
|
bounds = computeBounds(sortedSegments)
|
||||||
startX = max(0, bounds.x.int)
|
startX = max(0, bounds.x.int)
|
||||||
startY = max(0, bounds.y.int)
|
startY = max(0, bounds.y.int)
|
||||||
stopY = min(image.height, (bounds.y + bounds.h).int)
|
stopY = min(image.height, (bounds.y + bounds.h).int)
|
||||||
|
@ -802,7 +800,7 @@ proc fillShapes(
|
||||||
initialOffset = offset / 2
|
initialOffset = offset / 2
|
||||||
|
|
||||||
var
|
var
|
||||||
hits = newSeq[(float32, bool)](4)
|
hits = newSeq[(float32, int16)](4)
|
||||||
coverages = newSeq[uint8](image.width)
|
coverages = newSeq[uint8](image.width)
|
||||||
numHits: int
|
numHits: int
|
||||||
|
|
||||||
|
@ -816,16 +814,15 @@ proc fillShapes(
|
||||||
yLine = y.float32 + initialOffset + offset * m.float32 + ep
|
yLine = y.float32 + initialOffset + offset * m.float32 + ep
|
||||||
scanline = Line(a: vec2(0, yLine), b: vec2(1000, yLine))
|
scanline = Line(a: vec2(0, yLine), b: vec2(1000, yLine))
|
||||||
numHits = 0
|
numHits = 0
|
||||||
for i, shape in sortedShapes:
|
for (segment, winding) in sortedSegments:
|
||||||
for (segment, winding) in shape:
|
if segment.at.y > yLine or segment.to.y < y.float32:
|
||||||
if segment.at.y > yLine or segment.to.y < y.float32:
|
continue
|
||||||
continue
|
var at: Vec2
|
||||||
var at: Vec2
|
if scanline.intersects(segment, at):# and segment.to != at:
|
||||||
if scanline.intersects(segment, at):# and segment.to != at:
|
if numHits == hits.len:
|
||||||
if numHits == hits.len:
|
hits.setLen(hits.len * 2)
|
||||||
hits.setLen(hits.len * 2)
|
hits[numHits] = (at.x.clamp(0, image.width.float32), winding)
|
||||||
hits[numHits] = (at.x.clamp(0, image.width.float32), winding)
|
inc numHits
|
||||||
inc numHits
|
|
||||||
|
|
||||||
quickSort(hits, 0, numHits - 1)
|
quickSort(hits, 0, numHits - 1)
|
||||||
|
|
||||||
|
@ -870,7 +867,7 @@ proc fillShapes(
|
||||||
for j in i ..< fillStart + fillLen:
|
for j in i ..< fillStart + fillLen:
|
||||||
coverages[j] += sampleCoverage
|
coverages[j] += sampleCoverage
|
||||||
|
|
||||||
count += (if winding: -1 else: 1)
|
count += winding
|
||||||
x = at
|
x = at
|
||||||
|
|
||||||
# Apply the coverage and blend
|
# Apply the coverage and blend
|
||||||
|
@ -880,10 +877,9 @@ proc fillShapes(
|
||||||
|
|
||||||
let
|
let
|
||||||
coverageMask1 = cast[M128i]([0xffffffff, 0, 0, 0]) # First 32 bits
|
coverageMask1 = cast[M128i]([0xffffffff, 0, 0, 0]) # First 32 bits
|
||||||
coverageMask3 = mm_set1_epi32(cast[int32](0x000000ff)) # Only `r`
|
coverageMask2 = mm_set1_epi32(cast[int32](0x000000ff)) # Only `r`
|
||||||
oddMask = mm_set1_epi16(cast[int16](0xff00))
|
oddMask = mm_set1_epi16(cast[int16](0xff00))
|
||||||
div255 = mm_set1_epi16(cast[int16](0x8081))
|
div255 = mm_set1_epi16(cast[int16](0x8081))
|
||||||
zero = mm_set1_epi32(0)
|
|
||||||
v255 = mm_set1_epi32(255)
|
v255 = mm_set1_epi32(255)
|
||||||
vColor = mm_set1_epi32(cast[int32](color))
|
vColor = mm_set1_epi32(cast[int32](color))
|
||||||
|
|
||||||
|
@ -891,9 +887,11 @@ proc fillShapes(
|
||||||
var coverage = mm_loadu_si128(coverages[x].addr)
|
var coverage = mm_loadu_si128(coverages[x].addr)
|
||||||
coverage = mm_and_si128(coverage, coverageMask1)
|
coverage = mm_and_si128(coverage, coverageMask1)
|
||||||
|
|
||||||
if mm_movemask_epi8(mm_cmpeq_epi16(coverage, zero)) != 0xffff:
|
let eqZero = mm_cmpeq_epi16(coverage, mm_setzero_si128())
|
||||||
|
if mm_movemask_epi8(eqZero) != 0xffff:
|
||||||
# If the coverages are not all zero
|
# If the coverages are not all zero
|
||||||
var source = vColor
|
var source = vColor
|
||||||
|
|
||||||
coverage = mm_slli_si128(coverage, 2)
|
coverage = mm_slli_si128(coverage, 2)
|
||||||
coverage = mm_shuffle_epi32(coverage, MM_SHUFFLE(1, 1, 0, 0))
|
coverage = mm_shuffle_epi32(coverage, MM_SHUFFLE(1, 1, 0, 0))
|
||||||
|
|
||||||
|
@ -910,7 +908,7 @@ proc fillShapes(
|
||||||
|
|
||||||
coverage = mm_and_si128(
|
coverage = mm_and_si128(
|
||||||
mm_or_si128(mm_or_si128(a, b), mm_or_si128(c, d)),
|
mm_or_si128(mm_or_si128(a, b), mm_or_si128(c, d)),
|
||||||
coverageMask3
|
coverageMask2
|
||||||
)
|
)
|
||||||
|
|
||||||
if mm_movemask_epi8(mm_cmpeq_epi32(coverage, v255)) != 0xffff:
|
if mm_movemask_epi8(mm_cmpeq_epi32(coverage, v255)) != 0xffff:
|
||||||
|
|
Loading…
Reference in a new issue