memononen / nanovg

Antialiased 2D vector drawing library on top of OpenGL for UI and visualizations.
zlib License
5.15k stars 771 forks source link

Confusion about the filling rule. #598

Open unvestigate opened 3 years ago

unvestigate commented 3 years ago

The documentation for NVG claims that "NanoVG uses even-odd filling rule and by default the paths are wound in counter clockwise order." It then goes on to describe how shapes should be wound CCW and holes CW. I am doing a little bit of research on how to render SVG images using NVG and all documentation I have found on the subject suggests that the Even-Odd filling rule does not care about the winding, while the Non-Zero rule does. Eg:

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule https://www.w3.org/TR/SVG2/painting.html#WindingRule https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule

Also I am a bit confused what it means that "NanoVG uses even-odd filling rule" in the first place. It would seem to me that whether or not a shape is filled is determined by (and only by) the winding order of the shape points. Am I right, or does the NVG library actually perform any filling rule tests at runtime? (Ie. fire a ray in any direction and counting intersections etc.)

unvestigate commented 3 years ago

Actually, it seems I misunderstood the NVG docs a little. In nvg__flattenPaths() there is a piece of code labeled "Enforce winding" which makes sure the winding is what the path->winding variable specifies. Because of this it seems like the winding for shapes fed into NVG doesn't really matter, only the winding set with nvgPathWinding().

The docs make it seem like you can create holes by feeding shapes with CW winding into NVG: "In order to wind one of the predefined shapes as a hole, you should call nvgPathWinding(vg, NVG_HOLE)". (Emphasis on predefined by me).

Anyway, my original question remains. Does NVG perform any kind of even-odd filling rule logic, or is the solidness of a shape determined by the winding only?

leddoo commented 3 years ago

Hey, I've also stumbled across this today. From my testing, it seems that nanovg actually uses the non-zero fill rule: nvg-non-zero

(The documentation for nvgArc is wrong too: It does not start a new path. You have to nvgMoveTo manually.)

leddoo commented 3 years ago

Oh, by the way: NVG_SOLID == NVG_CCW and NVG_HOLE == NVG_CW.