Add winding rule, make float blends public (for shaders)

This commit is contained in:
treeform 2020-12-11 21:08:06 -08:00
parent 8d3784790b
commit db5b1f4cb4
2 changed files with 65 additions and 43 deletions

View file

@ -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 =

View file

@ -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.