memononen/nanovg

Failed to fill self-crossing polygon

Opened this issue · 3 comments

I rendered a sandglass-like shape with following code:

    nvgBeginPath(nvg);
    nvgMoveTo(nvg, 0, 0);
    nvgLineTo(nvg, 100, 75);
    nvgLineTo(nvg, 100, 25);
    nvgLineTo(nvg, 0, 100);
    
    nvgFillColor( nvg, nvgRGB(255, 0, 0) );
    nvgFill(nvg);

It filled the area of whole square bounding box.

In addition, if I render such kind of thing with non-full alpha, it would also show a very dim stroked path of that shape.

Does nanovg allow to draw polygons like that? Or I have to manually separate it into more "healthy" polygons?

I made some more tests on different computers, and it looks like a platform-specific issue.

Incorrect filling:

  • AMD R9 390, Windows 10, newest driver.
  • Integrated Intel HD 4000, Windows 10.
    Correct filling:
  • Integrated Intel HD 3000, Debian Stretch.

Using GL2 or GL3 backend seems unrelated.

I made a more straightforward test. It also failed to fill non-convex shapes. The whole code is pasted below, it could be compiled with nanovg, SDL2 and glew:

#include <GL/glew.h>

#define SDL_MAIN_HANDLED
#include <SDL.h>

#include <nanovg.h>

#define NANOVG_GL3_IMPLEMENTATION
#include <nanovg_gl.h>

#ifdef _WIN32
int WinMain()
#else
int main()
#endif
{

    SDL_Init( SDL_INIT_EVERYTHING );

    auto win = SDL_CreateWindow( "nanovg sdl test", 100, 100, 600, 400, SDL_WINDOW_OPENGL );
    auto gl = SDL_GL_CreateContext( win );

    glewInit();

    auto nvg = nvgCreateGL3( NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG );

    while ( true )
    {
        int w, h;
        SDL_GetWindowSize(win, &w, &h);
        glClearColor( 1, 1, 1, 1 );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT );

        nvgBeginFrame(nvg, w, h, 1);

        // a timeglass-shape fill
        nvgBeginPath( nvg );
        nvgMoveTo( nvg, 50, 50 );
        nvgLineTo( nvg, 200, 200 );
        nvgLineTo( nvg, 200, 50 );
        nvgLineTo( nvg, 50, 200 );
        nvgFillColor( nvg, nvgRGBA( 255, 0, 0, 64 ) );
        nvgFill( nvg );

        // a non-convex fill
        nvgBeginPath(nvg);
        nvgMoveTo(nvg, 220, 50);
        nvgLineTo(nvg, 230, 40);
        nvgLineTo(nvg, 240, 45);
        nvgLineTo(nvg, 250, 70);
        nvgLineTo(nvg, 260, 20);
        nvgLineTo(nvg, 270, 100);
        nvgLineTo(nvg, 280, 80);
        nvgLineTo(nvg, 290, 30);
        nvgLineTo(nvg, 300, 60);
        nvgLineTo(nvg, 270, 250);
        nvgLineTo(nvg, 230, 250);
        nvgFillColor( nvg, nvgRGBA( 255, 0, 255, 64 ) );
        nvgFill( nvg );
        
        // simple triangle
        nvgBeginPath(nvg);
        nvgMoveTo(nvg, 330, 150);
        nvgLineTo(nvg, 450, 200);
        nvgLineTo(nvg, 320, 350);
        nvgFillColor( nvg, nvgRGBA( 0, 0, 255, 64 ) );
        nvgFill(nvg);

        nvgEndFrame(nvg);

        SDL_GL_SwapWindow( win );

        SDL_Event e;
        bool should_break = false;
        while ( SDL_PollEvent( &e ) )
        {
            if (e.type == SDL_WINDOWEVENT)
            {
                if (e.window.event == SDL_WINDOWEVENT_CLOSE)
                    should_break = true;
            }
        }

        if (should_break)
            break;
    }

    nvgDeleteGL3( nvg );
    SDL_GL_DeleteContext( gl );
    SDL_DestroyWindow( win );
}

Ok I've found the problem. Stencil buffer is not turned on by default, in both SDL and the actual environment I use (JUCE).