c++openglsfmlmaskingstencil-buffer

Stencil Test doesn't seem to do anything


It seems that no matter what I do the stencil buffer has no effect on what I'm drawing. I'm drawing two rectangles, one is drawn over top of the other and slightly off of it. The part where they intersect is the only thing I want to be displayed. This would achieve what I want for my scrollable areas for my UI.

Here is my draw call:

void drawGL(sf::Window& i_Window)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
    glStencilFunc(GL_ALWAYS, 1, 0xFF);
    glStencilMask(0xFF);
    glUtil::DrawQuad(0.0f, 0.0f, 300, 300, 1.0f, 1.0f, 1.0f);

    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glStencilFunc(GL_EQUAL, 1, 0xFF);
    glStencilMask(0x00);
    glUtil::DrawQuad(200.0f, 200.0f, 200.0f, 200.0f, 0.0f, 1.0f, 0.0f);
}

Here is how I initialize OpenGL

void initGL(sf::Window& i_Window)
{
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glEnable(GL_STENCIL_TEST);
    glDisable(GL_DEPTH_TEST);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnableClientState(GL_VERTEX_ARRAY);
    //glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glLoadIdentity();
    glOrtho(0, i_Window.getSize().x, i_Window.getSize().y, 0, 0, 10);
    glClearColor(0.0245f, 0.1294f, 0.27255f, 1.0f);
}

My DrawQuad() implementation

    void DrawQuad(GLfloat i_fX, GLfloat i_fY, GLfloat i_fWidth, GLfloat i_fHeight, GLfloat i_fR, GLfloat i_fG, GLfloat i_fB, GLfloat i_fA = 1.0f)
    {
        GLfloat Vertices[18] = {};
        Vertices[0] = 0;            Vertices[1] = 0;            Vertices[2] = 0.0f;
        Vertices[3] = 0;            Vertices[4] = i_fHeight;    Vertices[5] = 0.0f;
        Vertices[6] = i_fWidth;     Vertices[7] = i_fHeight;    Vertices[8] = 0.0f;

        Vertices[9] = 0;            Vertices[10] = 0;           Vertices[11] = 0.0f;
        Vertices[12] = i_fWidth;    Vertices[13] = i_fHeight;   Vertices[14] = 0.0f;
        Vertices[15] = i_fWidth;    Vertices[16] = 0;           Vertices[17] = 0.0f;

        glPushMatrix();
        glTranslatef(i_fX, i_fY, 0.0f);
        glColor4f(i_fR, i_fG, i_fB, i_fA);
        glVertexPointer(3, GL_FLOAT, 0, Vertices);
        glDrawArrays(GL_TRIANGLES, 0, 6);
        glPopMatrix();
    }

And my main() function, in case it's useful for diagnosing...

int main()
{
    sf::Window window(sf::VideoMode(1200, 720), "My window");
    initGL(window);

    sf::Event event;
    int nNumFrames = 0;
    while (window.isOpen())
    {
        while (window.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
            case sf::Event::KeyPressed:
                window.close();
                break;
            case sf::Event::Resized:
                glViewport(0, 0, window.getSize().x, window.getSize().y);
                glLoadIdentity();
                glOrtho(0, window.getSize().x, window.getSize().y, 0, 0, 10);
                break;
            }
        }

        drawGL(window);
        window.display();

        ++nNumFrames;
    }

    return 0;
}

Here is a screenshot of what I get, regardless of how I set up the stencil buffer functions. What I want to see is just a small green box where the white and green box intersect. The result


Solution

  • Your window (default framebuffer) doesn't have a stencil buffer at all. You have to setup a OpenGL window with a stencil buffer by using the sf::ContextSettings class.

    See Using OpenGL in a SFML window:

    sf::ContextSettings settings;
    settings.depthBits = 24;
    settings.stencilBits = 8;
    settings.antialiasingLevel = 4;
    settings.majorVersion = 4;
    settings.minorVersion = 6;
    
    sf::Window window(sf::VideoMode(1200, 720), "My window", sf::Style::Default, settings);