This commit is contained in:
Ryan Oldenburg 2022-06-28 20:05:43 -05:00
parent 0affa5284b
commit f41f895e24

View file

@ -1919,155 +1919,147 @@ proc fillShapes(
break break
if allEntriesInScanlineSpanIt and tmp == 2: if allEntriesInScanlineSpanIt and tmp == 2:
var at: Vec2 var
if not intersectsInside( left = partitions[partitionIndex].entries[entryIndices[0]]
partitions[partitionIndex].entries[entryIndices[0]].segment, right = partitions[partitionIndex].entries[entryIndices[1]]
partitions[partitionIndex].entries[entryIndices[1]].segment, block:
at # Ensure left is actually on the left
): let
# We have 2 non-intersecting lines maybeLeftMaxX = max(left.segment.at.x, left.segment.to.x)
var maybeRightMaxX = max(right.segment.at.x, right.segment.to.x)
left = partitions[partitionIndex].entries[entryIndices[0]] if maybeLeftMaxX > maybeRightMaxX:
right = partitions[partitionIndex].entries[entryIndices[1]] swap left, right
block:
# Ensure left is actually on the left # Use trapezoid coverage at the edges and fill in the middle
when allowSimd and defined(amd64):
let vecRgbx = mm_set_ps(
rgbx.a.float32,
rgbx.b.float32,
rgbx.g.float32,
rgbx.r.float32
)
proc solveX(entry: PartitionEntry, y: float32): float32 =
if entry.m == 0:
entry.b
else:
(y - entry.b) / entry.m
proc solveY(entry: PartitionEntry, x: float32): float32 =
entry.m * x + entry.b
var
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
rightTop = vec2(0, y.float32)
rightBottom = vec2(0, (y + 1).float32)
rightTop.x = right.solveX(rightTop.y)
rightBottom.x = right.solveX(rightBottom.y)
let
leftMaxX = max(leftTop.x, leftBottom.x)
rightMinX = min(rightTop.x, rightBottom.x)
leftCoverEnd = leftMaxX.ceil.int
rightCoverBegin = rightMinX.trunc.int
if leftCoverEnd < rightCoverBegin:
# 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 let
maybeLeftMaxX = max(left.segment.at.x, left.segment.to.x) inverted = leftTop.x < leftBottom.x
maybeRightMaxX = max(right.segment.at.x, right.segment.to.x) sliverStart = min(leftTop.x, leftBottom.x)
if maybeLeftMaxX > maybeRightMaxX: rectStart = max(leftTop.x, leftBottom.x)
swap left, right 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)
# We have 2 non-intersecting lines that require anti-aliasing block: # Right-side partial coverage
# Use trapezoid coverage at the edges and fill in the middle let
inverted = rightTop.x > rightBottom.x
when allowSimd and defined(amd64): rectEnd = min(rightTop.x, rightBottom.x)
let vecRgbx = mm_set_ps( sliverEnd = max(rightTop.x, rightBottom.x)
rgbx.a.float32, var
rgbx.b.float32, pen = rectEnd
rgbx.g.float32, prevPen = pen
rgbx.r.float32 penY = if inverted: (y + 1).float32 else: y.float32
) prevPenY = penY
for x in rectEnd.int ..< sliverEnd.ceil.int:
proc solveX(entry: PartitionEntry, y: float32): float32 = prevPen = pen
if entry.m == 0: pen = (x + 1).float32
entry.b let leftRectArea = prevPen.fractional
else: if pen > sliverEnd:
(y - entry.b) / entry.m pen = sliverEnd
prevPenY = penY
proc solveY(entry: PartitionEntry, x: float32): float32 = penY = right.solveY(pen)
entry.m * x + entry.b if x < 0 or x >= image.width:
continue
var let
leftTop = vec2(0, y.float32) run = pen - prevPen
leftBottom = vec2(0, (y + 1).float32) triangleArea = 0.5.float32 * run * abs(penY - prevPenY)
leftTop.x = left.solveX(leftTop.y.float32) rectArea =
leftBottom.x = left.solveX(leftBottom.y) if inverted:
(penY - y.float32) * run
var else:
rightTop = vec2(0, y.float32) ((y + 1).float32 - penY) * run
rightBottom = vec2(0, (y + 1).float32) area = leftRectArea + triangleArea + rectArea
rightTop.x = right.solveX(rightTop.y) dataIndex = image.dataIndex(x, y)
rightBottom.x = right.solveX(rightBottom.y) backdrop = image.data[dataIndex]
source =
when allowSimd and defined(amd64):
applyOpacity(vecRgbx, area)
else:
rgbx * area
image.data[dataIndex] = blender(backdrop, source)
let let
leftMaxX = max(leftTop.x, leftBottom.x) fillBegin = leftCoverEnd.clamp(0, image.width)
rightMinX = min(rightTop.x, rightBottom.x) fillEnd = rightCoverBegin.clamp(0, image.width)
leftCoverEnd = leftMaxX.ceil.int if fillEnd - fillBegin > 0:
rightCoverBegin = rightMinX.trunc.int hits[0] = (fixed32(fillBegin.float32), 1.int16)
hits[1] = (fixed32(fillEnd.float32), -1.int16)
image.fillHits(rgbx, 0, y, hits, 2, NonZero, blendMode)
if leftCoverEnd < rightCoverBegin: inc y
# Only take this shortcut if the partial coverage areas on the continue
# 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)
let
fillBegin = leftCoverEnd.clamp(0, image.width)
fillEnd = rightCoverBegin.clamp(0, image.width)
if fillEnd - fillBegin > 0:
hits[0] = (fixed32(fillBegin.float32), 1.int16)
hits[1] = (fixed32(fillEnd.float32), -1.int16)
image.fillHits(rgbx, 0, y, hits, 2, NonZero, blendMode)
inc y
continue
computeCoverage( computeCoverage(
cast[ptr UncheckedArray[uint8]](coverages[0].addr), cast[ptr UncheckedArray[uint8]](coverages[0].addr),