memononen / nanovg

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

nvgArc draws an unexpected line #173

Open SmilyOrg opened 10 years ago

SmilyOrg commented 10 years ago

Since nvgArc is a "shape" API call, I wouldn't expect it to draw a line from the current position to the beginning of the arc, which is what I'm seeing right now. I can encounter this behavior when drawing some lines with moveTo and lineTo and then calling drawArc. I suspect this is not intentional and I've tracked it down to this line:

    int move = ctx->ncommands > 0 ? NVG_LINETO : NVG_MOVETO; 

The problem goes away if I hardcode that to just NVG_MOVETO, but I think that will break arcTo behavior.

The solution should be adding some knowledge to the conditional so it knows if the function was called by itself or from arcTo somehow. Adding an argument would come out as odd to external users of the API, so I suppose something like a global state flag would have to be employed, unless I'm missing a cleaner way? (Edit: I suppose creating an "internal" nvgArc and calling that from both the actual nvgArc and nvgArcTo would be one possible solution too)

An example demonstrating the problem:

Current behavior: before

Expected behavior: after

SmilyOrg commented 10 years ago

I fixed this in our internal fork by renaming the current nvgArc function to a non-exposed nvg__Arc function:

void nvg__Arc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir, NVGcommands firstCommand)

With this, firstCommand replaces the move var inside.

nvgArc now just calls nvg__Arc like so:

void nvgArc(struct NVGcontext* ctx, float cx, float cy, float r, float a0, float a1, int dir)
{
    nvg__Arc(ctx, cx, cy, r, a0, a1, dir, NVG_MOVETO);
}

nvgArcTo now calls nvg__Arc with the previous logic for firstCommand:

nvg__Arc(ctx, cx, cy, radius, a0, a1, dir, ctx->ncommands > 0 ? NVG_LINETO : NVG_MOVETO);

I believe something along those lines would be the best way to avoid this problem.

GPrimola commented 1 year ago

Hi @SmilyOrg where is this internal fork? I'm working with nanovg's arcs and I'm having a hard time with that too!

Thanks!

mulle-nat commented 1 year ago

First up I don't think nvgArc is supposed to be a standalone call. You can make it one, by issueing a nvgMoveTo call before calling it though. As far as I know nanovg tries to mirror HTML5 canvas for better and for worse. Therefore the Mozilla documentation for arcTo and arc can be very helpful to understand how both functions are supposed to work. arcTo is considered sort of broken even in HTML5 and seems to be merely useful for drawing rounded rectangles and not much more.

SmilyOrg commented 1 year ago

My OP was 9 years ago! 🤯

@mulle-nat I think you may be right and this is actually expected behavior, but it wasn't that expected to me back then 😅

@GPrimola the above points considered, if you're still interested in the fork (well, it's more like a vendored copy), it's actually public and still online, here you go: https://github.com/LoomSDK/LoomSDK/blame/c6ff83f99b313f402326948c57661908933dabdd/loom/vendor/nanovg/src/nanovg.c#L1942-L1996