Merge pull request #330 from treeform/sweeps2
Sweeps: Fix jugged outline and streaking.
This commit is contained in:
commit
bc631f649c
5 changed files with 240 additions and 70 deletions
123
experiments/rounded_rect.nim
Normal file
123
experiments/rounded_rect.nim
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import benchy, chroma, pixie, pixie/internal, strformat
|
||||||
|
import benchy, chroma, pixie
|
||||||
|
|
||||||
|
proc newRoundedRectImage1(w, h, r: int, color: Color): Image =
|
||||||
|
result = newImage(w, h)
|
||||||
|
let ctx = newContext(result)
|
||||||
|
ctx.fillStyle = color(0, 1, 0, 1)
|
||||||
|
let
|
||||||
|
pos = vec2(0, 0)
|
||||||
|
wh = vec2(w.float32, h.float32)
|
||||||
|
r = r.float32
|
||||||
|
ctx.fillRoundedRect(rect(pos, wh), r)
|
||||||
|
|
||||||
|
proc newRoundedRectImage15(w, h, r: int, color: Color): Image =
|
||||||
|
let path = newPath()
|
||||||
|
let
|
||||||
|
pos = vec2(0, 0)
|
||||||
|
wh = vec2(w.float32, h.float32)
|
||||||
|
r = r.float32
|
||||||
|
path.roundedRect(rect(pos, wh), r, r, r, r)
|
||||||
|
result = path.fillImage(w, h, color(0, 1, 0, 1))
|
||||||
|
|
||||||
|
proc newRoundedRectImage2(w, h, r: int, color: Color): Image =
|
||||||
|
result = newImage(w, h)
|
||||||
|
result.fill(color)
|
||||||
|
|
||||||
|
let
|
||||||
|
w1 = w - 1
|
||||||
|
h1 = h - 1
|
||||||
|
for y in 0 ..< r:
|
||||||
|
for x in 0 ..< r:
|
||||||
|
var a: float32 = 0
|
||||||
|
for s in 0 ..< 5:
|
||||||
|
let
|
||||||
|
yc = y.float32 + s.float32 / 5 + (1 / 5 / 2)
|
||||||
|
xc = r.float32 - sqrt(r.float32*r.float32 - (yc - r.float32) ^ 2)
|
||||||
|
let mid = (x.float32 - xc + 1).clamp(0, 1)
|
||||||
|
a += 1/5 * mid
|
||||||
|
|
||||||
|
if a < 1:
|
||||||
|
var c = color
|
||||||
|
c.a = a
|
||||||
|
let cx = c.rgbx
|
||||||
|
result.setRgbaUnsafe(x, y, cx)
|
||||||
|
result.setRgbaUnsafe(w1 - x, y, cx)
|
||||||
|
result.setRgbaUnsafe(w1 - x, h1 - y, cx)
|
||||||
|
result.setRgbaUnsafe(x, h1 - y, cx)
|
||||||
|
|
||||||
|
proc newRoundedRectImage3(w, h, r: int, color: Color): Image =
|
||||||
|
result = newImage(w, h)
|
||||||
|
result.fill(color)
|
||||||
|
|
||||||
|
if r == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
const
|
||||||
|
q = 5
|
||||||
|
qf = q.float32
|
||||||
|
qoffset: float32 = (1 / qf / 2)
|
||||||
|
|
||||||
|
let
|
||||||
|
r = r.clamp(0, min(w, h) div 2)
|
||||||
|
rf = r.float32
|
||||||
|
w1 = w - 1
|
||||||
|
h1 = h - 1
|
||||||
|
rgbx = color.rgbx
|
||||||
|
channels = [rgbx.r.uint32, rgbx.g.uint32, rgbx.b.uint32, rgbx.a.uint32]
|
||||||
|
|
||||||
|
var coverage = newSeq[uint8](r)
|
||||||
|
|
||||||
|
for y in 0 ..< r:
|
||||||
|
zeroMem(coverage[0].addr, coverage.len)
|
||||||
|
var yf: float32 = y.float32 + qoffset
|
||||||
|
for m in 0 ..< q:
|
||||||
|
let hit = sqrt(rf^2 - yf^2)
|
||||||
|
coverage[hit.int] += max((1 - (hit - hit.trunc)) * 255 / qf, 0).uint8
|
||||||
|
for x in hit.int + 1 ..< r:
|
||||||
|
coverage[x] += (255 div q).uint8
|
||||||
|
yf += 1 / qf
|
||||||
|
|
||||||
|
for x in 0 ..< r:
|
||||||
|
let coverage = 255 - coverage[x]
|
||||||
|
if coverage != 255:
|
||||||
|
var cx: ColorRGBX
|
||||||
|
cx.r = ((channels[0] * coverage) div 255).uint8
|
||||||
|
cx.g = ((channels[1] * coverage) div 255).uint8
|
||||||
|
cx.b = ((channels[2] * coverage) div 255).uint8
|
||||||
|
cx.a = ((channels[3] * coverage) div 255).uint8
|
||||||
|
|
||||||
|
let
|
||||||
|
xn = r - x - 1
|
||||||
|
yn = r - y - 1
|
||||||
|
result.setRgbaUnsafe(xn, yn, cx)
|
||||||
|
result.setRgbaUnsafe(w1 - xn, yn, cx)
|
||||||
|
result.setRgbaUnsafe(w1 - xn, h1 - yn, cx)
|
||||||
|
result.setRgbaUnsafe(xn, h1 - yn, cx)
|
||||||
|
|
||||||
|
const r = 16
|
||||||
|
|
||||||
|
let img1 = newRoundedRectImage1(200, 200, r, color(0, 1, 0, 1))
|
||||||
|
img1.writeFile("rrect_current.png")
|
||||||
|
let img2 = newRoundedRectImage3(200, 200, r, color(0, 1, 0, 1))
|
||||||
|
img2.writeFile("rrect_new.png")
|
||||||
|
|
||||||
|
let (diffScore, diffImage) = diff(img1, img2)
|
||||||
|
echo &"score: {diffScore}"
|
||||||
|
diffImage.writeFile("rrect_diff.png")
|
||||||
|
|
||||||
|
timeIt "fill rounded rect via path 1":
|
||||||
|
for i in 0 ..< 10:
|
||||||
|
discard newRoundedRectImage1(200, 200, r, color(0, 1, 0, 1))
|
||||||
|
|
||||||
|
timeIt "fill rounded rect via path 1.5":
|
||||||
|
for i in 0 ..< 10:
|
||||||
|
discard newRoundedRectImage15(200, 200, r, color(0, 1, 0, 1))
|
||||||
|
|
||||||
|
timeIt "fill rounded rect via math 2":
|
||||||
|
for i in 0 ..< 10:
|
||||||
|
discard newRoundedRectImage2(200, 200, 50, color(0, 1, 0, 1))
|
||||||
|
|
||||||
|
timeIt "fill rounded rect via math 3":
|
||||||
|
for i in 0 ..< 10:
|
||||||
|
discard newRoundedRectImage3(200, 200, r, color(0, 1, 0, 1))
|
|
@ -64,6 +64,10 @@ var hourGlass = parsePath("""
|
||||||
M 20 20 L 180 20 L 20 180 L 180 180 z
|
M 20 20 L 180 20 L 20 180 L 180 180 z
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
var hourGlass2 = parsePath("""
|
||||||
|
M 20 20 L 180 20 L 20 180 L 180 180 z M 62 24 L 132 24 L 50 173 L 156 173 z
|
||||||
|
""")
|
||||||
|
|
||||||
# Hole
|
# Hole
|
||||||
var hole = parsePath("""
|
var hole = parsePath("""
|
||||||
M 40 40 L 40 160 L 160 160 L 160 40 z
|
M 40 40 L 40 160 L 160 160 L 160 40 z
|
||||||
|
@ -88,6 +92,8 @@ when defined(bench):
|
||||||
test("cricle", cricle, 100)
|
test("cricle", cricle, 100)
|
||||||
test("halfAarc", halfAarc, 100)
|
test("halfAarc", halfAarc, 100)
|
||||||
test("hourGlass", hourGlass, 100)
|
test("hourGlass", hourGlass, 100)
|
||||||
|
test("hourGlass2", hourGlass2, wr=wrNonZero)
|
||||||
|
test("hourGlass2", hourGlass2, wr=wrEvenOdd)
|
||||||
test("hole", hole, 100)
|
test("hole", hole, 100)
|
||||||
test("holeEvenOdd", holeEvenOdd, 100, wr=wrNonZero)
|
test("holeEvenOdd", holeEvenOdd, 100, wr=wrNonZero)
|
||||||
test("holeEvenOdd", holeEvenOdd, 100, wr=wrEvenOdd)
|
test("holeEvenOdd", holeEvenOdd, 100, wr=wrEvenOdd)
|
||||||
|
@ -99,7 +105,8 @@ else:
|
||||||
# test("cricle", cricle)
|
# test("cricle", cricle)
|
||||||
# test("halfAarc", halfAarc)
|
# test("halfAarc", halfAarc)
|
||||||
# test("hourGlass", hourGlass)
|
# test("hourGlass", hourGlass)
|
||||||
#test("hole", hole, wr=wrEvenOdd)
|
test("hourGlass2", hourGlass2, wr=wrEvenOdd)
|
||||||
test("holeEvenOdd", holeEvenOdd, wr=wrNonZero)
|
# test("hole", hole, wr=wrEvenOdd)
|
||||||
test("holeEvenOdd", holeEvenOdd, wr=wrEvenOdd)
|
# test("holeEvenOdd", holeEvenOdd, wr=wrNonZero)
|
||||||
|
# test("holeEvenOdd", holeEvenOdd, wr=wrEvenOdd)
|
||||||
# test("letterG", letterG)
|
# test("letterG", letterG)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 4.4 KiB |
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import chroma, pixie/common, pixie/images, pixie/internal, pixie/paints,
|
import chroma, pixie/common, pixie/images, pixie/internal, pixie/paints,
|
||||||
pixie/paths, strutils, tables, vmath, xmlparser, xmltree
|
pixie/paths, strutils, tables, vmath, xmlparser, xmltree
|
||||||
|
|
||||||
when defined(pixieDebugSvg):
|
when defined(pixieDebugSvg):
|
||||||
import strtabs
|
import strtabs
|
||||||
|
|
||||||
|
|
|
@ -2103,6 +2103,17 @@ when defined(pixieSweeps):
|
||||||
line.winding = s[1]
|
line.winding = s[1]
|
||||||
return line
|
return line
|
||||||
|
|
||||||
|
proc intersectsYLine(y: float32, s: Segment, atx: var float32): bool {.inline.} =
|
||||||
|
let
|
||||||
|
s2y = s.to.y - s.at.y
|
||||||
|
denominator = -s2y
|
||||||
|
numerator = s.at.y - y
|
||||||
|
u = numerator / denominator
|
||||||
|
if u >= 0 and u <= 1:
|
||||||
|
let at = s.at + (u * vec2(s.to.x - s.at.x, s2y))
|
||||||
|
atx = at.x
|
||||||
|
return true
|
||||||
|
|
||||||
proc binaryInsert(arr: var seq[float32], v: float32) =
|
proc binaryInsert(arr: var seq[float32], v: float32) =
|
||||||
if arr.len == 0:
|
if arr.len == 0:
|
||||||
arr.add(v)
|
arr.add(v)
|
||||||
|
@ -2195,16 +2206,23 @@ when defined(pixieSweeps):
|
||||||
windingRule: WindingRule,
|
windingRule: WindingRule,
|
||||||
blendMode: BlendMode
|
blendMode: BlendMode
|
||||||
) =
|
) =
|
||||||
const q = 1/256.0
|
|
||||||
let rgbx = color.rgbx
|
let rgbx = color.rgbx
|
||||||
var segments = shapes.shapesToSegments()
|
var segments = shapes.shapesToSegments()
|
||||||
let
|
let
|
||||||
bounds = computeBounds(segments).snapToPixels()
|
bounds = computeBounds(segments).snapToPixels()
|
||||||
startX = max(0, bounds.x.int)
|
startX = max(0, bounds.x.int)
|
||||||
|
|
||||||
if segments.len == 0:
|
if segments.len == 0 or bounds.w.int == 0 or bounds.h.int == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# const q = 1/10
|
||||||
|
# for i in 0 ..< segments.len:
|
||||||
|
# segments[i][0].at.x = quantize(segments[i][0].at.x, q)
|
||||||
|
# segments[i][0].at.y = quantize(segments[i][0].at.y, q)
|
||||||
|
# segments[i][0].to.x = quantize(segments[i][0].to.x, q)
|
||||||
|
# segments[i][0].to.y = quantize(segments[i][0].to.y, q)
|
||||||
|
|
||||||
# Create sorted segments.
|
# Create sorted segments.
|
||||||
segments.sortSegments(0, segments.high)
|
segments.sortSegments(0, segments.high)
|
||||||
|
|
||||||
|
@ -2227,14 +2245,13 @@ when defined(pixieSweeps):
|
||||||
let s = segments[lastSeg]
|
let s = segments[lastSeg]
|
||||||
|
|
||||||
if s[0].to.y != cutLines[i + 1]:
|
if s[0].to.y != cutLines[i + 1]:
|
||||||
var at: Vec2
|
var atx: float32
|
||||||
var seg = s[0]
|
var seg = s[0]
|
||||||
for j in i ..< sweeps.len:
|
for j in i ..< sweeps.len:
|
||||||
let y = cutLines[j + 1]
|
let y = cutLines[j + 1]
|
||||||
#TODO: speed up with horizintal line intersect
|
if intersectsYLine(y, seg, atx):
|
||||||
if intersects(line(vec2(0, y), vec2(1, y)), seg, at):
|
sweeps[j].add(toLine((segment(seg.at, vec2(atx, y)), s[1])))
|
||||||
sweeps[j].add(toLine((segment(seg.at, at), s[1])))
|
seg = segment(vec2(atx, y), seg.to)
|
||||||
seg = segment(at, seg.to)
|
|
||||||
else:
|
else:
|
||||||
if seg.at.y != seg.to.y:
|
if seg.at.y != seg.to.y:
|
||||||
sweeps[j].add(toLine(s))
|
sweeps[j].add(toLine(s))
|
||||||
|
@ -2247,40 +2264,49 @@ when defined(pixieSweeps):
|
||||||
break
|
break
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
i = 0
|
# i = 0
|
||||||
while i < sweeps.len:
|
# while i < sweeps.len:
|
||||||
# TODO: Maybe finds all cuts first, add them to array, cut all lines at once.
|
# # TODO: Maybe finds all cuts first, add them to array, cut all lines at once.
|
||||||
for t in 0 ..< 10: # TODO: maybe while true:
|
# var crossCuts: seq[float32]
|
||||||
# keep cutting sweep
|
|
||||||
var needsCut = false
|
# # echo i, " cut?"
|
||||||
var cutterLine: float32 = 0
|
|
||||||
block doubleFor:
|
# for aIndex in 0 ..< sweeps[i].len:
|
||||||
for a in sweeps[i]:
|
# let a = sweeps[i][aIndex]
|
||||||
let aSeg = segment(vec2(a.atx, cutLines[i]), vec2(a.tox, cutLines[i+1]))
|
# # echo i, ":", sweeps.len, ":", cutLines.len
|
||||||
for b in sweeps[i]:
|
# let aSeg = segment(vec2(a.atx, cutLines[i]), vec2(a.tox, cutLines[i+1]))
|
||||||
let bSeg = segment(vec2(b.atx, cutLines[i]), vec2(b.tox, cutLines[i+1]))
|
# for bIndex in aIndex + 1 ..< sweeps[i].len:
|
||||||
var at: Vec2
|
# let b = sweeps[i][bIndex]
|
||||||
if intersectsInner(aSeg, bSeg, at):
|
# let bSeg = segment(vec2(b.atx, cutLines[i]), vec2(b.tox, cutLines[i+1]))
|
||||||
needsCut = true
|
# var at: Vec2
|
||||||
cutterLine = at.y
|
# if intersectsInner(aSeg, bSeg, at):
|
||||||
break doubleFor
|
# crossCuts.binaryInsert(at.y)
|
||||||
# TODO enable?
|
|
||||||
if false and needsCut:
|
# if crossCuts.len > 0:
|
||||||
# Doing a cut.
|
# var
|
||||||
var
|
# thisSweep = sweeps[i]
|
||||||
thisSweep = sweeps[i]
|
# yTop = cutLines[i]
|
||||||
sweeps[i].setLen(0)
|
# yBottom = cutLines[i + 1]
|
||||||
sweeps.insert(newSeq[SweepLine](), i + 1)
|
# sweeps[i].setLen(0)
|
||||||
for a in thisSweep:
|
|
||||||
let seg = segment(vec2(a.atx, cutLines[i]), vec2(a.tox, cutLines[i+1]))
|
# for k in crossCuts:
|
||||||
var at: Vec2
|
# let prevLen = cutLines.len
|
||||||
if intersects(line(vec2(0, cutterLine), vec2(1, cutterLine)), seg, at):
|
# cutLines.binaryInsert(k)
|
||||||
sweeps[i+0].add(toLine((segment(seg.at, at), a.winding)))
|
# if prevLen != cutLines.len:
|
||||||
sweeps[i+1].add(toLine((segment(at, seg.to), a.winding)))
|
# sweeps.insert(newSeq[SweepLine](), i + 1)
|
||||||
cutLines.binaryInsert(cutterLine)
|
|
||||||
else:
|
# for a in thisSweep:
|
||||||
break
|
# var seg = segment(vec2(a.atx, yTop), vec2(a.tox, yBottom))
|
||||||
inc i
|
# var at: Vec2
|
||||||
|
# for j, cutterLine in crossCuts:
|
||||||
|
# if intersects(line(vec2(0, cutterLine), vec2(1, cutterLine)), seg, at):
|
||||||
|
# sweeps[i+j].add(toLine((segment(seg.at, at), a.winding)))
|
||||||
|
# seg = segment(at, seg.to)
|
||||||
|
# sweeps[i+crossCuts.len].add(toLine((seg, a.winding)))
|
||||||
|
|
||||||
|
# i += crossCuts.len
|
||||||
|
|
||||||
|
# inc i
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < sweeps.len:
|
while i < sweeps.len:
|
||||||
|
@ -2320,13 +2346,18 @@ when defined(pixieSweeps):
|
||||||
# echo "L ", sw.x, " ", sw.y
|
# echo "L ", sw.x, " ", sw.y
|
||||||
|
|
||||||
proc computeCoverage(
|
proc computeCoverage(
|
||||||
coverages: var seq[uint8],
|
coverages: var seq[uint16],
|
||||||
y: int,
|
y: int,
|
||||||
startX: int,
|
startX: int,
|
||||||
cutLines: seq[float32],
|
cutLines: seq[float32],
|
||||||
currCutLine: int,
|
currCutLine: int,
|
||||||
sweep: seq[SweepLine]
|
sweep: seq[SweepLine]
|
||||||
) =
|
) =
|
||||||
|
|
||||||
|
if cutLines[currCutLine + 1] - cutLines[currCutLine] < 1/256:
|
||||||
|
# TODO some thing about micro sweeps
|
||||||
|
return
|
||||||
|
|
||||||
let
|
let
|
||||||
sweepHeight = cutLines[currCutLine + 1] - cutLines[currCutLine]
|
sweepHeight = cutLines[currCutLine + 1] - cutLines[currCutLine]
|
||||||
yFracTop = ((y.float32 - cutLines[currCutLine]) / sweepHeight).clamp(0, 1)
|
yFracTop = ((y.float32 - cutLines[currCutLine]) / sweepHeight).clamp(0, 1)
|
||||||
|
@ -2341,59 +2372,67 @@ when defined(pixieSweeps):
|
||||||
swX = mix(sweep[i+0].atx, sweep[i+0].tox, yFracBottom)
|
swX = mix(sweep[i+0].atx, sweep[i+0].tox, yFracBottom)
|
||||||
seX = mix(sweep[i+1].atx, sweep[i+1].tox, yFracBottom)
|
seX = mix(sweep[i+1].atx, sweep[i+1].tox, yFracBottom)
|
||||||
|
|
||||||
minWi = min(nwX, swX).int
|
minWi = min(nwX, swX).int#.clamp(startX, coverages.len + startX)
|
||||||
maxWi = max(nwX, swX).ceil.int
|
maxWi = max(nwX, swX).ceil.int#.clamp(startX, coverages.len + startX)
|
||||||
|
|
||||||
minEi = min(neX, seX).int
|
minEi = min(neX, seX).int#.clamp(startX, coverages.len + startX)
|
||||||
maxEi = max(neX, seX).ceil.int
|
maxEi = max(neX, seX).ceil.int#.clamp(startX, coverages.len + startX)
|
||||||
|
|
||||||
# TODO: Add case when trapezoids both starts and stops on same pixle.
|
|
||||||
|
|
||||||
let
|
let
|
||||||
nw = vec2(sweep[i+0].atx, cutLines[currCutLine])
|
nw = vec2(sweep[i+0].atx, cutLines[currCutLine])
|
||||||
sw = vec2(sweep[i+0].tox, cutLines[currCutLine + 1])
|
sw = vec2(sweep[i+0].tox, cutLines[currCutLine + 1])
|
||||||
|
f16 = (256 * 256 - 1).float32
|
||||||
for x in minWi ..< maxWi:
|
for x in minWi ..< maxWi:
|
||||||
var area = pixelCover(nw - vec2(x.float32, y.float32), sw - vec2(
|
var area = pixelCover(
|
||||||
x.float32, y.float32))
|
nw - vec2(x.float32, y.float32),
|
||||||
coverages[x - startX] += (area * 255).uint8
|
sw - vec2(x.float32, y.float32)
|
||||||
|
)
|
||||||
|
coverages[x - startX] += (area * f16).uint16
|
||||||
|
|
||||||
let x = maxWi
|
let x = maxWi
|
||||||
var midArea = pixelCover(nw - vec2(x.float32, y.float32), sw - vec2(
|
var midArea = pixelCover(
|
||||||
x.float32, y.float32))
|
nw - vec2(x.float32, y.float32),
|
||||||
var midArea8 = (midArea * 255).uint8
|
sw - vec2(x.float32, y.float32)
|
||||||
for x in maxWi ..< minEi:
|
)
|
||||||
# TODO: Maybe try coverages of uint16 to prevent streeks in solid white fill?
|
for x in maxWi ..< maxEi:
|
||||||
coverages[x - startX] += midArea8
|
coverages[x - startX] += (midArea * f16).uint16
|
||||||
|
|
||||||
let
|
let
|
||||||
ne = vec2(sweep[i+1].atx, cutLines[currCutLine])
|
ne = vec2(sweep[i+1].atx, cutLines[currCutLine])
|
||||||
se = vec2(sweep[i+1].tox, cutLines[currCutLine + 1])
|
se = vec2(sweep[i+1].tox, cutLines[currCutLine + 1])
|
||||||
for x in minEi ..< maxEi:
|
for x in minEi ..< maxEi:
|
||||||
var area = midArea - pixelCover(ne - vec2(x.float32, y.float32), se -
|
var area = pixelCover(
|
||||||
vec2(x.float32, y.float32))
|
ne - vec2(x.float32, y.float32),
|
||||||
coverages[x - startX] += (area * 255).uint8
|
se - vec2(x.float32, y.float32)
|
||||||
|
)
|
||||||
|
coverages[x - startX] -= (area * f16).uint16
|
||||||
|
|
||||||
i += 2
|
i += 2
|
||||||
|
|
||||||
var
|
var
|
||||||
currCutLine = 0
|
currCutLine = 0
|
||||||
coverages = newSeq[uint8](bounds.w.int)
|
coverages16 = newSeq[uint16](bounds.w.int)
|
||||||
for scanLine in cutLines[0].int ..< cutLines[^1].ceil.int:
|
coverages8 = newSeq[uint8](bounds.w.int)
|
||||||
zeroMem(coverages[0].addr, coverages.len)
|
for scanLine in max(cutLines[0].int, 0) ..< min(cutLines[^1].ceil.int, image.height):
|
||||||
|
|
||||||
coverages.computeCoverage(scanLine, startX, cutLines, currCutLine, sweeps[currCutLine])
|
zeroMem(coverages16[0].addr, coverages16.len * 2)
|
||||||
|
|
||||||
|
coverages16.computeCoverage(
|
||||||
|
scanLine, startX, cutLines, currCutLine, sweeps[currCutLine])
|
||||||
while cutLines[currCutLine + 1] < scanLine.float + 1.0:
|
while cutLines[currCutLine + 1] < scanLine.float + 1.0:
|
||||||
inc currCutLine
|
inc currCutLine
|
||||||
if currCutLine == sweeps.len:
|
if currCutLine == sweeps.len:
|
||||||
break
|
break
|
||||||
coverages.computeCoverage(scanLine, startX, cutLines, currCutLine,
|
coverages16.computeCoverage(
|
||||||
sweeps[currCutLine])
|
scanLine, startX, cutLines, currCutLine, sweeps[currCutLine])
|
||||||
|
|
||||||
|
for i in 0 ..< coverages16.len:
|
||||||
|
coverages8[i] = (coverages16[i] shr 8).uint8
|
||||||
image.fillCoverage(
|
image.fillCoverage(
|
||||||
rgbx,
|
rgbx,
|
||||||
startX = startX,
|
startX = startX,
|
||||||
y = scanLine,
|
y = scanLine,
|
||||||
coverages,
|
coverages8,
|
||||||
blendMode
|
blendMode
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue