Merge pull request #451 from guzba/master

2 pixel-aligned vertical lines shortcut
This commit is contained in:
Andre von Houck 2022-06-24 17:54:00 -07:00 committed by GitHub
commit 461d713fc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -43,8 +43,8 @@ type
Partition = object
entries: seq[PartitionEntry]
requiresAntiAliasing: bool
bottom: int
requiresAntiAliasing, twoNonintersectingSpanningSegments: bool
top, bottom: int
Fixed32 = int32 ## 24.8 fixed point
@ -1131,6 +1131,18 @@ proc partitionSegments(
startY = top.uint32
partitionHeight = height.uint32 div numPartitions
# Set the bottom values for the partitions (y value where this partition ends)
result[0].top = top
result[0].bottom = top + partitionHeight.int
for i in 1 ..< result.len:
result[i].top = result[i - 1].bottom
result[i].bottom = result[i - 1].bottom + partitionHeight.int
# Ensure the final partition goes to the actual bottom
# This is needed since the final partition includes
# height - (height div numPartitions) * numPartitions
result[^1].bottom = top + height
var entries = newSeq[PartitionEntry](segments.len)
for i, (segment, winding) in segments:
entries[i] = initPartitionEntry(segment, winding)
@ -1166,18 +1178,33 @@ proc partitionSegments(
result[partitionIndex].entries[indexes[partitionIndex]] = entries[i]
inc indexes[partitionIndex]
# Set the bottom values for the partitions (y value where this partition ends)
var partitionBottom = top + partitionHeight.int
for partition in result.mitems:
partition.bottom = partitionBottom
partition.requiresAntiAliasing =
requiresAntiAliasing(partition.entries)
partitionBottom += partitionHeight.int
partition.requiresAntiAliasing = requiresAntiAliasing(partition.entries)
if partition.entries.len == 2:
# Clip the entries to the parition bounds
let
top = partition.top.float32
bottom = partition.bottom.float32
topLine = line(vec2(0, top), vec2(1000, top))
bottomLine = line(vec2(0, bottom), vec2(1000, bottom))
for entry in partition.entries.mitems:
if entry.segment.at.y <= top and entry.segment.to.y >= bottom:
var at: Vec2
discard intersects(entry.segment, topLine, at)
entry.segment.at = at
discard intersects(entry.segment, bottomLine, at)
entry.segment.to = at
# Ensure the final partition goes to the actual bottom
# This is needed since the final partition includes
# height - (height div numPartitions) * numPartitions
result[^1].bottom = top + height
let
entry0 = partition.entries[0].segment
entry1 = partition.entries[1].segment
var at: Vec2
if not intersects(entry0, entry1, at):
# These two segments do not intersect, enable shortcut
partition.twoNonintersectingSpanningSegments = true
# Ensure entry[0] is on the left
if entry1.at.x < entry0.at.x:
swap partition.entries[1], partition.entries[0]
proc maxEntryCount(partitions: var seq[Partition]): int =
for i in 0 ..< partitions.len:
@ -1273,12 +1300,9 @@ proc computeCoverage(
width: int,
y, startX: int,
partitions: var seq[Partition],
partitionIndex: var int,
partitionIndex: int,
windingRule: WindingRule
) {.inline.} =
if y >= partitions[partitionIndex].bottom:
inc partitionIndex
aa = partitions[partitionIndex].requiresAntiAliasing
let
@ -1823,7 +1847,45 @@ proc fillShapes(
numHits: int
aa: bool
for y in startY ..< pathHeight:
var y = startY
while y < pathHeight:
if y >= partitions[partitionIndex].bottom:
inc partitionIndex
let
partitionTop = partitions[partitionIndex].top
partitionBottom = partitions[partitionIndex].bottom
partitionHeight = partitionBottom - partitionTop
if partitionHeight == 0:
continue
if partitions[partitionIndex].twoNonintersectingSpanningSegments:
if partitions[partitionIndex].requiresAntiAliasing:
discard
else: # No AA required, must be 2 vertical pixel-aligned lines
let
left = partitions[partitionIndex].entries[0].segment.at.x.int
right = partitions[partitionIndex].entries[1].segment.at.x.int
minX = left.clamp(0, image.width)
maxX = right.clamp(0, image.width)
skipBlending =
blendMode == OverwriteBlend or
(blendMode == NormalBlend and rgbx.a == 255)
if skipBlending and minX == 0 and maxX == image.width:
# We can be greedy, just do one big mult-row fill
let
start = image.dataIndex(0, y)
len = image.dataIndex(0, y + partitionHeight) - start
fillUnsafe(image.data, rgbx, start, len)
else:
for r in 0 ..< partitionHeight:
hits[0] = (cast[Fixed32](minX * 256), 1.int16)
hits[1] = (cast[Fixed32](maxX * 256), -1.int16)
image.fillHits(rgbx, 0, y + r, hits, 2, NonZero, blendMode)
y += partitionHeight
continue
computeCoverage(
cast[ptr UncheckedArray[uint8]](coverages[0].addr),
hits,
@ -1836,6 +1898,7 @@ proc fillShapes(
partitionIndex,
windingRule
)
if aa:
image.fillCoverage(
rgbx,
@ -1856,6 +1919,8 @@ proc fillShapes(
blendMode
)
inc y
if blendMode == MaskBlend:
image.clearUnsafe(0, 0, 0, startY)
image.clearUnsafe(0, pathHeight, 0, image.height)
@ -1895,6 +1960,9 @@ proc fillShapes(
aa: bool
for y in startY ..< pathHeight:
if y >= partitions[partitionIndex].bottom:
inc partitionIndex
computeCoverage(
cast[ptr UncheckedArray[uint8]](coverages[0].addr),
hits,