This commit is contained in:
Ryan Oldenburg 2022-06-28 19:53:12 -05:00
parent fe488708cd
commit 0affa5284b

View file

@ -1937,150 +1937,134 @@ proc fillShapes(
if maybeLeftMaxX > maybeRightMaxX: if maybeLeftMaxX > maybeRightMaxX:
swap left, right swap left, right
let requiresAntiAliasing = # We have 2 non-intersecting lines that require anti-aliasing
left.segment.requiresAntiAliasing or # Use trapezoid coverage at the edges and fill in the middle
right.segment.requiresAntiAliasing
if requiresAntiAliasing: when allowSimd and defined(amd64):
# We have 2 non-intersecting lines that require anti-aliasing let vecRgbx = mm_set_ps(
# Use trapezoid coverage at the edges and fill in the middle rgbx.a.float32,
rgbx.b.float32,
rgbx.g.float32,
rgbx.r.float32
)
when allowSimd and defined(amd64): proc solveX(entry: PartitionEntry, y: float32): float32 =
let vecRgbx = mm_set_ps( if entry.m == 0:
rgbx.a.float32, entry.b
rgbx.b.float32, else:
rgbx.g.float32, (y - entry.b) / entry.m
rgbx.r.float32
)
proc solveX(entry: PartitionEntry, y: float32): float32 = proc solveY(entry: PartitionEntry, x: float32): float32 =
if entry.m == 0: entry.m * x + entry.b
entry.b
else:
(y - entry.b) / entry.m
proc solveY(entry: PartitionEntry, x: float32): float32 = var
entry.m * x + entry.b leftTop = vec2(0, y.float32)
leftBottom = vec2(0, (y + 1).float32)
leftTop.x = left.solveX(leftTop.y.float32)
leftBottom.x = left.solveX(leftBottom.y)
var var
leftTop = vec2(0, y.float32) rightTop = vec2(0, y.float32)
leftBottom = vec2(0, (y + 1).float32) rightBottom = vec2(0, (y + 1).float32)
leftTop.x = left.solveX(leftTop.y.float32) rightTop.x = right.solveX(rightTop.y)
leftBottom.x = left.solveX(leftBottom.y) rightBottom.x = right.solveX(rightBottom.y)
var let
rightTop = vec2(0, y.float32) leftMaxX = max(leftTop.x, leftBottom.x)
rightBottom = vec2(0, (y + 1).float32) rightMinX = min(rightTop.x, rightBottom.x)
rightTop.x = right.solveX(rightTop.y) leftCoverEnd = leftMaxX.ceil.int
rightBottom.x = right.solveX(rightBottom.y) rightCoverBegin = rightMinX.trunc.int
let if leftCoverEnd < rightCoverBegin:
leftMaxX = max(leftTop.x, leftBottom.x) # Only take this shortcut if the partial coverage areas on the
rightMinX = min(rightTop.x, rightBottom.x) # left and the right do not overlap
leftCoverEnd = leftMaxX.ceil.int
rightCoverBegin = rightMinX.trunc.int
if leftCoverEnd < rightCoverBegin: let blender = blendMode.blender()
# Only take this shortcut if the partial coverage areas on the
# left and the right do not overlap
let blender = blendMode.blender()
block: # Left-side partial coverage
let
inverted = leftTop.x < leftBottom.x
sliverStart = min(leftTop.x, leftBottom.x)
rectStart = max(leftTop.x, leftBottom.x)
var
pen = sliverStart
prevPen = pen
penY = if inverted: y.float32 else: (y + 1).float32
prevPenY = penY
for x in sliverStart.int ..< rectStart.ceil.int:
prevPen = pen
pen = (x + 1).float32
var rightRectArea = 0.float32
if pen > rectStart:
rightRectArea = pen - rectStart
pen = rectStart
prevPenY = penY
penY = left.solveY(pen)
if x < 0 or x >= image.width:
continue
let
run = pen - prevPen
triangleArea = 0.5.float32 * run * abs(penY - prevPenY)
rectArea =
if inverted:
(prevPenY - y.float32) * run
else:
((y + 1).float32 - prevPenY) * run
area = triangleArea + rectArea + rightRectArea
dataIndex = image.dataIndex(x, y)
backdrop = image.data[dataIndex]
source =
when allowSimd and defined(amd64):
applyOpacity(vecRgbx, area)
else:
rgbx * area
image.data[dataIndex] = blender(backdrop, source)
block: # Right-side partial coverage
let
inverted = rightTop.x > rightBottom.x
rectEnd = min(rightTop.x, rightBottom.x)
sliverEnd = max(rightTop.x, rightBottom.x)
var
pen = rectEnd
prevPen = pen
penY = if inverted: (y + 1).float32 else: y.float32
prevPenY = penY
for x in rectEnd.int ..< sliverEnd.ceil.int:
prevPen = pen
pen = (x + 1).float32
let leftRectArea = prevPen.fractional
if pen > sliverEnd:
pen = sliverEnd
prevPenY = penY
penY = right.solveY(pen)
if x < 0 or x >= image.width:
continue
let
run = pen - prevPen
triangleArea = 0.5.float32 * run * abs(penY - prevPenY)
rectArea =
if inverted:
(penY - y.float32) * run
else:
((y + 1).float32 - penY) * run
area = leftRectArea + triangleArea + rectArea
dataIndex = image.dataIndex(x, y)
backdrop = image.data[dataIndex]
source =
when allowSimd and defined(amd64):
applyOpacity(vecRgbx, area)
else:
rgbx * area
image.data[dataIndex] = blender(backdrop, source)
block: # Left-side partial coverage
let let
fillBegin = leftCoverEnd.clamp(0, image.width) inverted = leftTop.x < leftBottom.x
fillEnd = rightCoverBegin.clamp(0, image.width) sliverStart = min(leftTop.x, leftBottom.x)
if fillEnd - fillBegin > 0: rectStart = max(leftTop.x, leftBottom.x)
hits[0] = (fixed32(fillBegin.float32), 1.int16) var
hits[1] = (fixed32(fillEnd.float32), -1.int16) pen = sliverStart
image.fillHits(rgbx, 0, y, hits, 2, NonZero, blendMode) prevPen = pen
penY = if inverted: y.float32 else: (y + 1).float32
prevPenY = penY
for x in sliverStart.int ..< rectStart.ceil.int:
prevPen = pen
pen = (x + 1).float32
var rightRectArea = 0.float32
if pen > rectStart:
rightRectArea = pen - rectStart
pen = rectStart
prevPenY = penY
penY = left.solveY(pen)
if x < 0 or x >= image.width:
continue
let
run = pen - prevPen
triangleArea = 0.5.float32 * run * abs(penY - prevPenY)
rectArea =
if inverted:
(prevPenY - y.float32) * run
else:
((y + 1).float32 - prevPenY) * run
area = triangleArea + rectArea + rightRectArea
dataIndex = image.dataIndex(x, y)
backdrop = image.data[dataIndex]
source =
when allowSimd and defined(amd64):
applyOpacity(vecRgbx, area)
else:
rgbx * area
image.data[dataIndex] = blender(backdrop, source)
inc y block: # Right-side partial coverage
continue let
inverted = rightTop.x > rightBottom.x
rectEnd = min(rightTop.x, rightBottom.x)
sliverEnd = max(rightTop.x, rightBottom.x)
var
pen = rectEnd
prevPen = pen
penY = if inverted: (y + 1).float32 else: y.float32
prevPenY = penY
for x in rectEnd.int ..< sliverEnd.ceil.int:
prevPen = pen
pen = (x + 1).float32
let leftRectArea = prevPen.fractional
if pen > sliverEnd:
pen = sliverEnd
prevPenY = penY
penY = right.solveY(pen)
if x < 0 or x >= image.width:
continue
let
run = pen - prevPen
triangleArea = 0.5.float32 * run * abs(penY - prevPenY)
rectArea =
if inverted:
(penY - y.float32) * run
else:
((y + 1).float32 - penY) * run
area = leftRectArea + triangleArea + rectArea
dataIndex = image.dataIndex(x, y)
backdrop = image.data[dataIndex]
source =
when allowSimd and defined(amd64):
applyOpacity(vecRgbx, area)
else:
rgbx * area
image.data[dataIndex] = blender(backdrop, source)
else:
let let
minX = left.segment.at.x.int.clamp(0, image.width) fillBegin = leftCoverEnd.clamp(0, image.width)
maxX = right.segment.at.x.int.clamp(0, image.width) fillEnd = rightCoverBegin.clamp(0, image.width)
hits[0] = (cast[Fixed32](minX * 256), 1.int16) if fillEnd - fillBegin > 0:
hits[1] = (cast[Fixed32](maxX * 256), -1.int16) hits[0] = (fixed32(fillBegin.float32), 1.int16)
image.fillHits(rgbx, 0, y, hits, 2, NonZero, blendMode) hits[1] = (fixed32(fillEnd.float32), -1.int16)
image.fillHits(rgbx, 0, y, hits, 2, NonZero, blendMode)
inc y inc y
continue continue