From db5b1f4cb461b3669bd57831711401cf8dd3863f Mon Sep 17 00:00:00 2001 From: treeform Date: Fri, 11 Dec 2020 21:08:06 -0800 Subject: [PATCH] Add winding rule, make float blends public (for shaders) --- src/pixie/blends.nim | 46 ++++++++++++++++---------------- src/pixie/paths.nim | 62 ++++++++++++++++++++++++++++++-------------- 2 files changed, 65 insertions(+), 43 deletions(-) diff --git a/src/pixie/blends.nim b/src/pixie/blends.nim index f71660f..21ab748 100644 --- a/src/pixie/blends.nim +++ b/src/pixie/blends.nim @@ -128,29 +128,29 @@ proc alphaFix(backdrop, source, mixed: Color): Color = result.g /= result.a result.b /= result.a -proc blendNormalFloats(backdrop, source: Color): Color {.inline.} = +proc blendNormalFloats*(backdrop, source: Color): Color {.inline.} = result = source result = alphaFix(backdrop, source, result) -proc blendDarkenFloats(backdrop, source: Color): Color {.inline.} = +proc blendDarkenFloats*(backdrop, source: Color): Color {.inline.} = result.r = min(backdrop.r, source.r) result.g = min(backdrop.g, source.g) result.b = min(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendMultiplyFloats(backdrop, source: Color): Color {.inline.} = +proc blendMultiplyFloats*(backdrop, source: Color): Color {.inline.} = result.r = backdrop.r * source.r result.g = backdrop.g * source.g result.b = backdrop.b * source.b result = alphaFix(backdrop, source, result) -proc blendLinearBurnFloats(backdrop, source: Color): Color {.inline.} = +proc blendLinearBurnFloats*(backdrop, source: Color): Color {.inline.} = result.r = backdrop.r + source.r - 1 result.g = backdrop.g + source.g - 1 result.b = backdrop.b + source.b - 1 result = alphaFix(backdrop, source, result) -proc blendColorBurnFloats(backdrop, source: Color): Color {.inline.} = +proc blendColorBurnFloats*(backdrop, source: Color): Color {.inline.} = proc blend(backdrop, source: float32): float32 {.inline.} = if backdrop == 1: 1.0 @@ -163,25 +163,25 @@ proc blendColorBurnFloats(backdrop, source: Color): Color {.inline.} = result.b = blend(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendLightenFloats(backdrop, source: Color): Color {.inline.} = +proc blendLightenFloats*(backdrop, source: Color): Color {.inline.} = result.r = max(backdrop.r, source.r) result.g = max(backdrop.g, source.g) result.b = max(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendScreenFloats(backdrop, source: Color): Color {.inline.} = +proc blendScreenFloats*(backdrop, source: Color): Color {.inline.} = result.r = screen(backdrop.r, source.r) result.g = screen(backdrop.g, source.g) result.b = screen(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendLinearDodgeFloats(backdrop, source: Color): Color {.inline.} = +proc blendLinearDodgeFloats*(backdrop, source: Color): Color {.inline.} = result.r = backdrop.r + source.r result.g = backdrop.g + source.g result.b = backdrop.b + source.b result = alphaFix(backdrop, source, result) -proc blendColorDodgeFloats(backdrop, source: Color): Color {.inline.} = +proc blendColorDodgeFloats*(backdrop, source: Color): Color {.inline.} = proc blend(backdrop, source: float32): float32 {.inline.} = if backdrop == 0: 0.0 @@ -194,31 +194,31 @@ proc blendColorDodgeFloats(backdrop, source: Color): Color {.inline.} = result.b = blend(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendOverlayFloats(backdrop, source: Color): Color {.inline.} = +proc blendOverlayFloats*(backdrop, source: Color): Color {.inline.} = result.r = hardLight(source.r, backdrop.r) result.g = hardLight(source.g, backdrop.g) result.b = hardLight(source.b, backdrop.b) result = alphaFix(backdrop, source, result) -proc blendHardLightFloats(backdrop, source: Color): Color {.inline.} = +proc blendHardLightFloats*(backdrop, source: Color): Color {.inline.} = result.r = hardLight(backdrop.r, source.r) result.g = hardLight(backdrop.g, source.g) result.b = hardLight(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendSoftLightFloats(backdrop, source: Color): Color {.inline.} = +proc blendSoftLightFloats*(backdrop, source: Color): Color {.inline.} = result.r = softLight(backdrop.r, source.r) result.g = softLight(backdrop.g, source.g) result.b = softLight(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendDifferenceFloats(backdrop, source: Color): Color {.inline.} = +proc blendDifferenceFloats*(backdrop, source: Color): Color {.inline.} = result.r = abs(backdrop.r - source.r) result.g = abs(backdrop.g - source.g) result.b = abs(backdrop.b - source.b) result = alphaFix(backdrop, source, result) -proc blendExclusionFloats(backdrop, source: Color): Color {.inline.} = +proc blendExclusionFloats*(backdrop, source: Color): Color {.inline.} = proc blend(backdrop, source: float32): float32 {.inline.} = backdrop + source - 2 * backdrop * source result.r = blend(backdrop.r, source.r) @@ -226,39 +226,39 @@ proc blendExclusionFloats(backdrop, source: Color): Color {.inline.} = result.b = blend(backdrop.b, source.b) result = alphaFix(backdrop, source, result) -proc blendColorFloats(backdrop, source: Color): Color {.inline.} = +proc blendColorFloats*(backdrop, source: Color): Color {.inline.} = result = SetLum(source, Lum(backdrop)) result = alphaFix(backdrop, source, result) -proc blendLuminosityFloats(backdrop, source: Color): Color {.inline.} = +proc blendLuminosityFloats*(backdrop, source: Color): Color {.inline.} = result = SetLum(backdrop, Lum(source)) result = alphaFix(backdrop, source, result) -proc blendHueFloats(backdrop, source: Color): Color {.inline.} = +proc blendHueFloats*(backdrop, source: Color): Color {.inline.} = result = SetLum(SetSat(source, Sat(backdrop)), Lum(backdrop)) result = alphaFix(backdrop, source, result) -proc blendSaturationFloats(backdrop, source: Color): Color {.inline.} = +proc blendSaturationFloats*(backdrop, source: Color): Color {.inline.} = result = SetLum(SetSat(backdrop, Sat(source)), Lum(backdrop)) result = alphaFix(backdrop, source, result) -proc blendMaskFloats(backdrop, source: Color): Color {.inline.} = +proc blendMaskFloats*(backdrop, source: Color): Color {.inline.} = result = backdrop result.a = min(backdrop.a, source.a) -proc blendSubtractMaskFloats(backdrop, source: Color): Color {.inline.} = +proc blendSubtractMaskFloats*(backdrop, source: Color): Color {.inline.} = result = backdrop result.a = backdrop.a * (1 - source.a) -proc blendIntersectMaskFloats(backdrop, source: Color): Color {.inline.} = +proc blendIntersectMaskFloats*(backdrop, source: Color): Color {.inline.} = result = backdrop result.a = backdrop.a * source.a -proc blendExcludeMaskFloats(backdrop, source: Color): Color {.inline.} = +proc blendExcludeMaskFloats*(backdrop, source: Color): Color {.inline.} = result = backdrop result.a = abs(backdrop.a - source.a) -proc blendOverwriteFloats(backdrop, source: Color): Color {.inline.} = +proc blendOverwriteFloats*(backdrop, source: Color): Color {.inline.} = source proc alphaFix(backdrop, source: ColorRGBA, vb, vs, vm: M128): ColorRGBA = diff --git a/src/pixie/paths.nim b/src/pixie/paths.nim index aa00731..7fd35d3 100644 --- a/src/pixie/paths.nim +++ b/src/pixie/paths.nim @@ -1,6 +1,9 @@ import vmath, images, chroma, strutils, algorithm, common, bumpy type + WindingRule* = enum + wrNonZero + wrEvenOdd PathCommandKind* = enum ## Type of path commands @@ -590,6 +593,7 @@ proc fillPolygons*( size: Vec2, polys: seq[seq[Vec2]], color: ColorRGBA, + windingRule: WindingRule, quality = 4, ): Image = const ep = 0.0001 * PI @@ -633,10 +637,19 @@ proc fillPolygons*( if hits.len == 0: continue var - penFill = 0.0 + penFill = 0 curHit = 0 for x in 0 ..< result.width: - var penEdge = penFill + var penEdge: float32 + case windingRule + of wrNonZero: + penEdge = penFill.float32 + of wrEvenOdd: + if penFill mod 2 == 0: + penEdge = 0.0 + else: + penEdge = 1.0 + while true: if curHit >= hits.len or x != hits[curHit][0].int: break @@ -644,10 +657,10 @@ proc fillPolygons*( cover = hits[curHit][0] - x.float32 winding = hits[curHit][1] if winding == false: - penFill += 1.0 + penFill += 1 penEdge += 1.0 - cover else: - penFill -= 1.0 + penFill -= 1 penEdge -= 1.0 - cover inc curHit alphas[x] += penEdge @@ -676,43 +689,47 @@ proc parseSomePath(path: SomePath): seq[seq[Vec2]] = proc fillPath*( image: Image, path: SomePath, - color: ColorRGBA + color: ColorRGBA, + windingRule = wrNonZero ) = let polys = parseSomePath(path) - tmp = fillPolygons(image.wh, polys, color) + tmp = fillPolygons(image.wh, polys, color, windingRule) image.draw(tmp) proc fillPath*( image: Image, path: SomePath, color: ColorRGBA, - pos: Vec2 + pos: Vec2, + windingRule = wrNonZero ) = var polys = parseSomePath(path) for poly in polys.mitems: for i, p in poly.mpairs: poly[i] = p + pos - let tmp = fillPolygons(image.wh, polys, color) + let tmp = fillPolygons(image.wh, polys, color, windingRule) image.draw(tmp) proc fillPath*( image: Image, path: SomePath, color: ColorRGBA, - mat: Mat3 + mat: Mat3, + windingRule = wrNonZero ) = var polys = parseSomePath(path) for poly in polys.mitems: for i, p in poly.mpairs: poly[i] = mat * p - let tmp = fillPolygons(image.wh, polys, color) + let tmp = fillPolygons(image.wh, polys, color, windingRule) image.draw(tmp) proc fillPathBounds*( path: SomePath, color: ColorRGBA, - mat: Mat3 + mat: Mat3, + windingRule = wrNonZero ): (Rect, Image) = var polys = parseSomePath(path) for poly in polys.mitems: @@ -722,7 +739,7 @@ proc fillPathBounds*( for poly in polys.mitems: for i, p in poly.mpairs: poly[i] = p - bounds.xy - var image = fillPolygons(bounds.wh, polys, color) + var image = fillPolygons(bounds.wh, polys, color, windingRule) return (bounds, image) proc strokePath*( @@ -730,6 +747,7 @@ proc strokePath*( path: Path, color: ColorRGBA, strokeWidth: float32 = 1.0, + windingRule = wrNonZero # TODO: Add more params: # strokeLocation: StrokeLocation, # strokeCap: StorkeCap, @@ -739,14 +757,15 @@ proc strokePath*( polys = parseSomePath(path) (strokeL, strokeR) = (strokeWidth/2, strokeWidth/2) polys2 = strokePolygons(polys, strokeL, strokeR) - tmp = fillPolygons(image.wh, polys2, color) + tmp = fillPolygons(image.wh, polys2, color, windingRule) image.draw(tmp) proc strokePath*( image: Image, path: SomePath, color: ColorRGBA, - strokeWidth: float32 + strokeWidth: float32, + windingRule = wrNonZero ) = image.strokePath(parsePath(path), color, strokeWidth) @@ -755,7 +774,8 @@ proc strokePath*( path: SomePath, color: ColorRGBA, strokeWidth: float32, - pos: Vec2 + pos: Vec2, + windingRule = wrNonZero ) = var polys = parseSomePath(path) let (strokeL, strokeR) = (strokeWidth/2, strokeWidth/2) @@ -763,7 +783,7 @@ proc strokePath*( for poly in polys2.mitems: for i, p in poly.mpairs: poly[i] = p + pos - let tmp = fillPolygons(image.wh, polys2, color) + let tmp = fillPolygons(image.wh, polys2, color, windingRule) image.draw(tmp) proc strokePath*( @@ -771,7 +791,8 @@ proc strokePath*( path: SomePath, color: ColorRGBA, strokeWidth: float32, - mat: Mat3 + mat: Mat3, + windingRule = wrNonZero ) = var polys = parseSomePath(path) let (strokeL, strokeR) = (strokeWidth/2, strokeWidth/2) @@ -779,19 +800,20 @@ proc strokePath*( for poly in polys2.mitems: for i, p in poly.mpairs: poly[i] = mat * p - let tmp = fillPolygons(image.wh, polys2, color) + let tmp = fillPolygons(image.wh, polys2, color, windingRule) image.draw(tmp) proc strokePathBounds*( path: SomePath, color: ColorRGBA, strokeWidth: float32, - mat: Mat3 + mat: Mat3, + windingRule = wrNonZero ): (Rect, Image) = var polys = parseSomePath(path) let (strokeL, strokeR) = (strokeWidth/2, strokeWidth/2) var polys2 = strokePolygons(polys, strokeL, strokeR) - fillPathBounds(polys2, color, mat) + fillPathBounds(polys2, color, mat, windingRule) proc addPath*(path: Path, other: Path) = ## Adds a path to the current path.