commit
ebae5e79f2
3 changed files with 47 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
||||||
import bitops, flatty/binny, math, pixie/common, pixie/paths, sets, tables,
|
import flatty/binny, math, pixie/common, pixie/paths, sets, tables,
|
||||||
unicode, vmath
|
unicode, vmath
|
||||||
|
|
||||||
## See https://docs.microsoft.com/en-us/typography/opentype/spec/
|
## See https://docs.microsoft.com/en-us/typography/opentype/spec/
|
||||||
|
@ -867,8 +867,15 @@ proc parseCoverage(buf: string, offset: int): Coverage =
|
||||||
else:
|
else:
|
||||||
failUnsupported()
|
failUnsupported()
|
||||||
|
|
||||||
proc valueFormatSize(valueFormat: uint16): int {.inline.} =
|
proc valueFormatSize(valueFormat: uint16): int =
|
||||||
countSetBits(valueFormat) * 2
|
# countSetBits(valueFormat) * 2
|
||||||
|
var
|
||||||
|
n = valueFormat
|
||||||
|
bitsSet: int
|
||||||
|
while n > 0:
|
||||||
|
n = (n and (n - 1))
|
||||||
|
inc bitsSet
|
||||||
|
bitsSet * 2
|
||||||
|
|
||||||
proc parseValueRecord(
|
proc parseValueRecord(
|
||||||
buf: string, offset: int, valueFormat: uint16
|
buf: string, offset: int, valueFormat: uint16
|
||||||
|
|
|
@ -413,7 +413,7 @@ proc parseOtf*(buf: string): Font =
|
||||||
result.typeface.opentype = parseOpenType(buf)
|
result.typeface.opentype = parseOpenType(buf)
|
||||||
result.size = 12
|
result.size = 12
|
||||||
result.lineHeight = AutoLineHeight
|
result.lineHeight = AutoLineHeight
|
||||||
result.paint = Paint(kind: pkSolid, color: rgbx(0, 0, 0, 255))
|
result.paint = rgbx(0, 0, 0, 255)
|
||||||
|
|
||||||
proc parseTtf*(buf: string): Font =
|
proc parseTtf*(buf: string): Font =
|
||||||
parseOtf(buf)
|
parseOtf(buf)
|
||||||
|
|
|
@ -500,6 +500,11 @@ proc roundedRect*(
|
||||||
## Adds a rounded rectangle.
|
## Adds a rounded rectangle.
|
||||||
## Clockwise param can be used to subtract a rect from a path when using
|
## Clockwise param can be used to subtract a rect from a path when using
|
||||||
## even-odd winding rule.
|
## even-odd winding rule.
|
||||||
|
|
||||||
|
if nw == 0 and ne == 0 and se == 0 and sw == 0:
|
||||||
|
path.rect(x, y, w, h, clockwise)
|
||||||
|
return
|
||||||
|
|
||||||
let
|
let
|
||||||
s = splineCircleK
|
s = splineCircleK
|
||||||
|
|
||||||
|
@ -992,7 +997,8 @@ proc computePixelBounds(segments: seq[(Segment, int16)]): Rect =
|
||||||
xMax = float32.low
|
xMax = float32.low
|
||||||
yMin = float32.high
|
yMin = float32.high
|
||||||
yMax = float32.low
|
yMax = float32.low
|
||||||
for (segment, _) in segments:
|
for i in 0 ..< segments.len: # For arc
|
||||||
|
let segment = segments[i][0]
|
||||||
xMin = min(xMin, min(segment.at.x, segment.to.x))
|
xMin = min(xMin, min(segment.at.x, segment.to.x))
|
||||||
xMax = max(xMax, max(segment.at.x, segment.to.x))
|
xMax = max(xMax, max(segment.at.x, segment.to.x))
|
||||||
yMin = min(yMin, segment.at.y)
|
yMin = min(yMin, segment.at.y)
|
||||||
|
@ -1089,14 +1095,14 @@ proc shouldFill(windingRule: WindingRule, count: int): bool {.inline.} =
|
||||||
of wrEvenOdd:
|
of wrEvenOdd:
|
||||||
count mod 2 != 0
|
count mod 2 != 0
|
||||||
|
|
||||||
template computeCoverages(
|
proc computeCoverages(
|
||||||
coverages: var seq[uint8],
|
coverages: var seq[uint8],
|
||||||
hits: var seq[(float32, int16)],
|
hits: var seq[(float32, int16)],
|
||||||
size: Vec2,
|
size: Vec2,
|
||||||
y: int,
|
y: int,
|
||||||
partitioning: Partitioning,
|
partitioning: Partitioning,
|
||||||
windingRule: WindingRule
|
windingRule: WindingRule
|
||||||
) =
|
) {.inline.} =
|
||||||
const
|
const
|
||||||
quality = 5 # Must divide 255 cleanly (1, 3, 5, 15, 17, 51, 85)
|
quality = 5 # Must divide 255 cleanly (1, 3, 5, 15, 17, 51, 85)
|
||||||
sampleCoverage = (255 div quality).uint8
|
sampleCoverage = (255 div quality).uint8
|
||||||
|
@ -1106,15 +1112,20 @@ template computeCoverages(
|
||||||
zeroMem(coverages[0].addr, coverages.len)
|
zeroMem(coverages[0].addr, coverages.len)
|
||||||
|
|
||||||
# Do scanlines for this row
|
# Do scanlines for this row
|
||||||
let partition = getIndexForY(partitioning, y)
|
let partitionIndex = partitioning.getIndexForY(y)
|
||||||
var
|
var
|
||||||
yLine = y.float32 + initialOffset - offset
|
yLine = y.float32 + initialOffset - offset
|
||||||
|
scanline = line(vec2(0, yLine), vec2(size.x, yLine))
|
||||||
numHits: int
|
numHits: int
|
||||||
for m in 0 ..< quality:
|
for m in 0 ..< quality:
|
||||||
yLine += offset
|
yLine += offset
|
||||||
let scanline = line(vec2(0, yLine), vec2(size.x, yLine))
|
scanline.a.y = yLine
|
||||||
|
scanline.b.y = yLine
|
||||||
numHits = 0
|
numHits = 0
|
||||||
for (segment, winding) in partitioning.partitions[partition]:
|
for i in 0 ..< partitioning.partitions[partitionIndex].len: # For arc
|
||||||
|
let
|
||||||
|
segment = partitioning.partitions[partitionIndex][i][0]
|
||||||
|
winding = partitioning.partitions[partitionIndex][i][1]
|
||||||
if segment.at.y <= scanline.a.y and segment.to.y >= scanline.a.y:
|
if segment.at.y <= scanline.a.y and segment.to.y >= scanline.a.y:
|
||||||
var at: Vec2
|
var at: Vec2
|
||||||
if scanline.intersects(segment, at) and segment.to != at:
|
if scanline.intersects(segment, at) and segment.to != at:
|
||||||
|
@ -1198,7 +1209,7 @@ proc fillShapes(
|
||||||
startX = max(0, bounds.x.int)
|
startX = max(0, bounds.x.int)
|
||||||
startY = max(0, bounds.y.int)
|
startY = max(0, bounds.y.int)
|
||||||
pathHeight = min(image.height, (bounds.y + bounds.h).int)
|
pathHeight = min(image.height, (bounds.y + bounds.h).int)
|
||||||
partitions = partitionSegments(segments, startY, pathHeight - startY)
|
partitioning = partitionSegments(segments, startY, pathHeight - startY)
|
||||||
|
|
||||||
var
|
var
|
||||||
coverages = newSeq[uint8](image.width)
|
coverages = newSeq[uint8](image.width)
|
||||||
|
@ -1210,7 +1221,7 @@ proc fillShapes(
|
||||||
hits,
|
hits,
|
||||||
image.wh,
|
image.wh,
|
||||||
y,
|
y,
|
||||||
partitions,
|
partitioning,
|
||||||
windingRule
|
windingRule
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1308,7 +1319,7 @@ proc fillShapes(
|
||||||
startY = max(0, bounds.y.int)
|
startY = max(0, bounds.y.int)
|
||||||
stopY = min(mask.height, (bounds.y + bounds.h).int)
|
stopY = min(mask.height, (bounds.y + bounds.h).int)
|
||||||
pathHeight = stopY - startY
|
pathHeight = stopY - startY
|
||||||
partitions = partitionSegments(segments, startY, pathHeight)
|
partitioning = partitionSegments(segments, startY, pathHeight)
|
||||||
|
|
||||||
when defined(amd64) and not defined(pixieNoSimd):
|
when defined(amd64) and not defined(pixieNoSimd):
|
||||||
let maskerSimd = bmNormal.maskerSimd()
|
let maskerSimd = bmNormal.maskerSimd()
|
||||||
|
@ -1323,7 +1334,7 @@ proc fillShapes(
|
||||||
hits,
|
hits,
|
||||||
mask.wh,
|
mask.wh,
|
||||||
y,
|
y,
|
||||||
partitions,
|
partitioning,
|
||||||
windingRule
|
windingRule
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1551,6 +1562,7 @@ proc fillPath*(
|
||||||
) =
|
) =
|
||||||
## Fills a path.
|
## Fills a path.
|
||||||
if paint.kind == pkSolid:
|
if paint.kind == pkSolid:
|
||||||
|
if paint.color.a > 0:
|
||||||
var shapes = parseSomePath(path, transform.pixelScale())
|
var shapes = parseSomePath(path, transform.pixelScale())
|
||||||
shapes.transform(transform)
|
shapes.transform(transform)
|
||||||
image.fillShapes(shapes, paint.color, windingRule, paint.blendMode)
|
image.fillShapes(shapes, paint.color, windingRule, paint.blendMode)
|
||||||
|
@ -1614,6 +1626,7 @@ proc strokePath*(
|
||||||
) =
|
) =
|
||||||
## Strokes a path.
|
## Strokes a path.
|
||||||
if paint.kind == pkSolid:
|
if paint.kind == pkSolid:
|
||||||
|
if paint.color.a > 0:
|
||||||
var strokeShapes = strokeShapes(
|
var strokeShapes = strokeShapes(
|
||||||
parseSomePath(path, transform.pixelScale()),
|
parseSomePath(path, transform.pixelScale()),
|
||||||
strokeWidth,
|
strokeWidth,
|
||||||
|
|
Loading…
Reference in a new issue