fixed point hits
This commit is contained in:
parent
550bec6117
commit
7a2fb9949b
1 changed files with 56 additions and 49 deletions
|
@ -49,6 +49,8 @@ type
|
||||||
partitions: seq[Partition]
|
partitions: seq[Partition]
|
||||||
startY, partitionHeight: uint32
|
startY, partitionHeight: uint32
|
||||||
|
|
||||||
|
FixedPoint = int32 ## 24.8 fixed point
|
||||||
|
|
||||||
const
|
const
|
||||||
epsilon: float32 = 0.0001 * PI ## Tiny value used for some computations.
|
epsilon: float32 = 0.0001 * PI ## Tiny value used for some computations.
|
||||||
pixelErrorMargin: float32 = 0.2
|
pixelErrorMargin: float32 = 0.2
|
||||||
|
@ -1149,20 +1151,20 @@ proc partitionSegments(
|
||||||
partition.requiresAntiAliasing =
|
partition.requiresAntiAliasing =
|
||||||
requiresAntiAliasing(partition.entries)
|
requiresAntiAliasing(partition.entries)
|
||||||
|
|
||||||
proc getIndexForY(partitioning: var Partitioning, y: int): uint32 {.inline.} =
|
|
||||||
if partitioning.partitions.len == 1:
|
|
||||||
0.uint32
|
|
||||||
else:
|
|
||||||
min(
|
|
||||||
(y.uint32 - partitioning.startY) div partitioning.partitionHeight,
|
|
||||||
partitioning.partitions.high.uint32
|
|
||||||
)
|
|
||||||
|
|
||||||
proc maxEntryCount(partitioning: var Partitioning): int =
|
proc maxEntryCount(partitioning: var Partitioning): int =
|
||||||
for i in 0 ..< partitioning.partitions.len:
|
for i in 0 ..< partitioning.partitions.len:
|
||||||
result = max(result, partitioning.partitions[i].entries.len)
|
result = max(result, partitioning.partitions[i].entries.len)
|
||||||
|
|
||||||
proc sortHits(hits: var seq[(float32, int16)], inl, inr: int) =
|
proc fixedPoint(f: float32): FixedPoint {.inline.} =
|
||||||
|
FixedPoint(f * 256)
|
||||||
|
|
||||||
|
proc pixel(p: FixedPoint): int {.inline.} =
|
||||||
|
p div 256
|
||||||
|
|
||||||
|
proc trunc(p: FixedPoint): FixedPoint {.inline.} =
|
||||||
|
(p div 256) * 256
|
||||||
|
|
||||||
|
proc sortHits(hits: var seq[(FixedPoint, int16)], inl, inr: int) =
|
||||||
## Quicksort + insertion sort, in-place and faster than standard lib sort.
|
## Quicksort + insertion sort, in-place and faster than standard lib sort.
|
||||||
let n = inr - inl + 1
|
let n = inr - inl + 1
|
||||||
if n < 32: # Use insertion sort for the rest
|
if n < 32: # Use insertion sort for the rest
|
||||||
|
@ -1202,15 +1204,15 @@ proc shouldFill(
|
||||||
count mod 2 != 0
|
count mod 2 != 0
|
||||||
|
|
||||||
iterator walk(
|
iterator walk(
|
||||||
hits: seq[(float32, int16)],
|
hits: seq[(FixedPoint, int16)],
|
||||||
numHits: int,
|
numHits: int,
|
||||||
windingRule: WindingRule,
|
windingRule: WindingRule,
|
||||||
y: int,
|
y: int,
|
||||||
width: float32
|
width: int
|
||||||
): (float32, float32, int) =
|
): (FixedPoint, FixedPoint, int) =
|
||||||
var
|
var
|
||||||
i, count: int
|
i, count: int
|
||||||
prevAt: float32
|
prevAt: FixedPoint
|
||||||
while i < numHits:
|
while i < numHits:
|
||||||
let (at, winding) = hits[i]
|
let (at, winding) = hits[i]
|
||||||
if at > 0:
|
if at > 0:
|
||||||
|
@ -1236,20 +1238,27 @@ iterator walk(
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
when defined(pixieLeakCheck):
|
when defined(pixieLeakCheck):
|
||||||
if prevAt != width and count != 0:
|
if prevAt != fixedPoint(width.float32) and count != 0:
|
||||||
echo "Leak detected: ", count, " @ (", prevAt, ", ", y, ")"
|
echo "Leak detected: ", count, " @ (", prevAt, ", ", y, ")"
|
||||||
|
|
||||||
proc computeCoverage(
|
proc computeCoverage(
|
||||||
coverages: ptr UncheckedArray[uint8],
|
coverages: ptr UncheckedArray[uint8],
|
||||||
hits: var seq[(float32, int16)],
|
hits: var seq[(FixedPoint, int16)],
|
||||||
numHits: var int,
|
numHits: var int,
|
||||||
aa: var bool,
|
aa: var bool,
|
||||||
width: float32,
|
width: int,
|
||||||
y, startX: int,
|
y, startX: int,
|
||||||
partitioning: var Partitioning,
|
partitioning: var Partitioning,
|
||||||
windingRule: WindingRule
|
windingRule: WindingRule
|
||||||
) {.inline.} =
|
) {.inline.} =
|
||||||
let partitionIndex = partitioning.getIndexForY(y)
|
let partitionIndex =
|
||||||
|
if partitioning.partitions.len == 1:
|
||||||
|
0.uint32
|
||||||
|
else:
|
||||||
|
min(
|
||||||
|
(y.uint32 - partitioning.startY) div partitioning.partitionHeight,
|
||||||
|
partitioning.partitions.high.uint32
|
||||||
|
)
|
||||||
|
|
||||||
aa = partitioning.partitions[partitionIndex].requiresAntiAliasing
|
aa = partitioning.partitions[partitionIndex].requiresAntiAliasing
|
||||||
|
|
||||||
|
@ -1271,7 +1280,7 @@ proc computeCoverage(
|
||||||
else:
|
else:
|
||||||
(yLine - entry.b) / entry.m
|
(yLine - entry.b) / entry.m
|
||||||
|
|
||||||
hits[numHits] = (min(x, width), entry.winding)
|
hits[numHits] = (fixedPoint(min(x, width.float32)), entry.winding)
|
||||||
inc numHits
|
inc numHits
|
||||||
|
|
||||||
if numHits > 0:
|
if numHits > 0:
|
||||||
|
@ -1279,27 +1288,27 @@ proc computeCoverage(
|
||||||
|
|
||||||
if aa:
|
if aa:
|
||||||
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, width):
|
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, width):
|
||||||
var fillStart = prevAt.int
|
var fillStart = prevAt.pixel
|
||||||
|
|
||||||
let
|
let
|
||||||
pixelCrossed = at.int - prevAt.int > 0
|
pixelCrossed = at.pixel != prevAt.pixel
|
||||||
leftCover =
|
leftCover =
|
||||||
if pixelCrossed:
|
if pixelCrossed:
|
||||||
trunc(prevAt) + 1 - prevAt
|
prevAt.trunc + fixedPoint(1.0) - prevAt
|
||||||
else:
|
else:
|
||||||
at - prevAt
|
at - prevAt
|
||||||
if leftCover != 0:
|
if leftCover != 0:
|
||||||
inc fillStart
|
inc fillStart
|
||||||
coverages[prevAt.int - startX] +=
|
coverages[prevAt.pixel - startX] +=
|
||||||
(leftCover * sampleCoverage.float32).uint8
|
(leftCover * sampleCoverage.int32).pixel.uint8
|
||||||
|
|
||||||
if pixelCrossed:
|
if pixelCrossed:
|
||||||
let rightCover = at - trunc(at)
|
let rightCover = at - at.trunc
|
||||||
if rightCover > 0:
|
if rightCover > 0:
|
||||||
coverages[at.int - startX] +=
|
coverages[at.pixel - startX] +=
|
||||||
(rightCover * sampleCoverage.float32).uint8
|
(rightCover * sampleCoverage.int32).pixel.uint8
|
||||||
|
|
||||||
let fillLen = at.int - fillStart
|
let fillLen = at.pixel - fillStart
|
||||||
if fillLen > 0:
|
if fillLen > 0:
|
||||||
var i = fillStart
|
var i = fillStart
|
||||||
when defined(amd64) and allowSimd:
|
when defined(amd64) and allowSimd:
|
||||||
|
@ -1494,19 +1503,17 @@ proc fillHits(
|
||||||
image: Image,
|
image: Image,
|
||||||
rgbx: ColorRGBX,
|
rgbx: ColorRGBX,
|
||||||
startX, y: int,
|
startX, y: int,
|
||||||
hits: seq[(float32, int16)],
|
hits: seq[(FixedPoint, int16)],
|
||||||
numHits: int,
|
numHits: int,
|
||||||
windingRule: WindingRule,
|
windingRule: WindingRule,
|
||||||
blendMode: BlendMode
|
blendMode: BlendMode
|
||||||
) =
|
) =
|
||||||
let
|
let blender = blendMode.blender()
|
||||||
blender = blendMode.blender()
|
|
||||||
width = image.width.float32
|
|
||||||
var filledTo: int
|
var filledTo: int
|
||||||
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, width):
|
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, image.width):
|
||||||
let
|
let
|
||||||
fillStart = prevAt.int
|
fillStart = prevAt.pixel
|
||||||
fillLen = at.int - fillStart
|
fillLen = at.pixel - fillStart
|
||||||
if fillLen <= 0:
|
if fillLen <= 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1556,19 +1563,17 @@ proc fillHits(
|
||||||
proc fillHits(
|
proc fillHits(
|
||||||
mask: Mask,
|
mask: Mask,
|
||||||
startX, y: int,
|
startX, y: int,
|
||||||
hits: seq[(float32, int16)],
|
hits: seq[(FixedPoint, int16)],
|
||||||
numHits: int,
|
numHits: int,
|
||||||
windingRule: WindingRule,
|
windingRule: WindingRule,
|
||||||
blendMode: BlendMode
|
blendMode: BlendMode
|
||||||
) =
|
) =
|
||||||
let
|
let masker = blendMode.masker()
|
||||||
masker = blendMode.masker()
|
|
||||||
width = mask.width.float32
|
|
||||||
var filledTo: int
|
var filledTo: int
|
||||||
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, width):
|
for (prevAt, at, count) in hits.walk(numHits, windingRule, y, mask.width):
|
||||||
let
|
let
|
||||||
fillStart = prevAt.int
|
fillStart = prevAt.pixel
|
||||||
fillLen = at.int - fillStart
|
fillLen = at.pixel - fillStart
|
||||||
if fillLen <= 0:
|
if fillLen <= 0:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -1633,7 +1638,7 @@ proc fillShapes(
|
||||||
var
|
var
|
||||||
partitioning = partitionSegments(segments, startY, pathHeight - startY)
|
partitioning = partitionSegments(segments, startY, pathHeight - startY)
|
||||||
coverages = newSeq[uint8](pathWidth)
|
coverages = newSeq[uint8](pathWidth)
|
||||||
hits = newSeq[(float32, int16)](partitioning.maxEntryCount)
|
hits = newSeq[(FixedPoint, int16)](partitioning.maxEntryCount)
|
||||||
numHits: int
|
numHits: int
|
||||||
aa: bool
|
aa: bool
|
||||||
|
|
||||||
|
@ -1643,7 +1648,7 @@ proc fillShapes(
|
||||||
hits,
|
hits,
|
||||||
numHits,
|
numHits,
|
||||||
aa,
|
aa,
|
||||||
image.width.float32,
|
image.width,
|
||||||
y,
|
y,
|
||||||
startX,
|
startX,
|
||||||
partitioning,
|
partitioning,
|
||||||
|
@ -1702,7 +1707,7 @@ proc fillShapes(
|
||||||
var
|
var
|
||||||
partitioning = partitionSegments(segments, startY, pathHeight)
|
partitioning = partitionSegments(segments, startY, pathHeight)
|
||||||
coverages = newSeq[uint8](pathWidth)
|
coverages = newSeq[uint8](pathWidth)
|
||||||
hits = newSeq[(float32, int16)](partitioning.maxEntryCount)
|
hits = newSeq[(FixedPoint, int16)](partitioning.maxEntryCount)
|
||||||
numHits: int
|
numHits: int
|
||||||
aa: bool
|
aa: bool
|
||||||
|
|
||||||
|
@ -1712,7 +1717,7 @@ proc fillShapes(
|
||||||
hits,
|
hits,
|
||||||
numHits,
|
numHits,
|
||||||
aa,
|
aa,
|
||||||
mask.width.float32,
|
mask.width,
|
||||||
y,
|
y,
|
||||||
startX,
|
startX,
|
||||||
partitioning,
|
partitioning,
|
||||||
|
@ -2071,7 +2076,7 @@ proc overlaps(
|
||||||
test: Vec2,
|
test: Vec2,
|
||||||
windingRule: WindingRule
|
windingRule: WindingRule
|
||||||
): bool =
|
): bool =
|
||||||
var hits: seq[(float32, int16)]
|
var hits: seq[(FixedPoint, int16)]
|
||||||
|
|
||||||
let
|
let
|
||||||
scanline = line(vec2(0, test.y), vec2(1000, test.y))
|
scanline = line(vec2(0, test.y), vec2(1000, test.y))
|
||||||
|
@ -2081,13 +2086,15 @@ proc overlaps(
|
||||||
var at: Vec2
|
var at: Vec2
|
||||||
if scanline.intersects(segment, at):
|
if scanline.intersects(segment, at):
|
||||||
if segment.to != at:
|
if segment.to != at:
|
||||||
hits.add((at.x, winding))
|
hits.add((fixedPoint(at.x), winding))
|
||||||
|
|
||||||
sortHits(hits, 0, hits.high)
|
sortHits(hits, 0, hits.high)
|
||||||
|
|
||||||
|
let testX = fixedPoint(test.x)
|
||||||
|
|
||||||
var count: int
|
var count: int
|
||||||
for (at, winding) in hits:
|
for (at, winding) in hits:
|
||||||
if at > test.x:
|
if at > testX:
|
||||||
return shouldFill(windingRule, count)
|
return shouldFill(windingRule, count)
|
||||||
count += winding
|
count += winding
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue