Why glScissor s cut too much?

0

I want my render class to support clipping. I would like to set different clip rect to different objects.

struct Rect
{
    int x = 0, y = 0, w = 0, h = 0;
};

struct Vertex
{
    int x = 0, y = 0;
    uint color = 0xffffffff;
};

struct DrawCall
{
    Rect clipRect = Rect(0);
    uint elemCount = 0;
};

class Renderer
{
   public:
        Renderer() = deafault;

        void Init();        

        void Prepare();
        void DrawText(std::string text, int x, int y, uint color);
        void PresentScene();

        void UpdateClipRect();
        void PushClipRect(const Rect& rect);
        void PopClipRect();        

        std::vector<Vertex> vtxBuff;
        std::vector<uint> elemBuff;
        std::vector<Rect> clipRects;
        std::vector<DrawCall> drawCalls;

        uint vao = 0, vbo = 0, ebo = 0;
};

void Renderer::Init()
{
    CreateVao();
    BindVao();

    CreateVbo();
    BindVbo();
    AddVboAttribs(...);
    AddVboAttribs(...);

    CreateEbo();
}

void Renderer::Prepare()
{
    vtxBuff.clear();
    elemBuff.clear();
    clipRects.clear();
    drawCalls.clear();
}

void Renderer::DrawText(std::string text, int x, int y, uint color)
{ 
    int i = vtxBuff.size();
    for(int i = 0; i < text.size(); ++i) 
    {
        //example values
        vtxBuff.push_back({x, y, color}); 
        vtxBuff.push_back({x, y, color});
        vtxBuff.push_back({x, y, color}); 
        vtxBuff.push_back({x, y, color});

        elemBuff.push_back(i);
        elemBuff.push_back(i + 1);
        elemBuff.push_back(i + 2);
        elemBuff.push_back(i + 2);
        elemBuff.push_back(i + 3);
        elemBuff.push_back(i);

        DrawCall& currentDraw = drawCalls[drawCall.size() - 1];
        currentDraw.elemCount += 6;
    }
}

void Renderer::PresentScene()
{
    EnableScissorTest();
    EnableBlendFunc(...);

    BindVbo();
    AddVboData(vtxBuff.size() * sizeof(Vertex), vtxBuff.data();

    BindEbo();
    AddEboData(elemBuff.size() * sizeof(uint), elemBuff.data();

    for(const auto& drawCall : drawCalls)
    {
        Rect clipRect = drawCall.clipRect;
        if (clipRect.x < windowSizeW && clipRect.y < windowSizeH && clipRect.w >= 0.0f && clipRect.h >= 0.0f) 
        {
            glScissor(clipRect.x, clipRect.y, clipRect.w, clipRect.h);
            bindTexture(); //if needed
            DrawElements(drawCall.elemCount, 0);
        }
    }
}

void Renderer::UpdateClipRect()
{
    const Rect currentClip = clipRects.size() ? clipRects[clipRects.size() - 1] : Rect(0.0f, 0.0f, windowSizeW, windowSizeH);
    DrawCall* currentDraw = drawCalls.size() > 0 ? &drawCalls[drawCalls.size() - 1] : nullptr;
    if (!currentDraw || currentDraw->elemCount != 0) 
    {
        DrawCall drawCall;
        drawCall.clipRect = currentClip;
        drawCalls.push_back(drawCall);
        return;
    }

    if(currentDraw->elementCount == 0)
    {
        //if we have nothing to draw, we do not need to have draw call
        drawCalls.pop_back();
    } 
    else 
    {
        currentDraw->clipRect = currentClip;
    }
}

void Renderer::PushClipRect(const Rect& rect)
{
    clipRects.push_back(rect);
    UpdateClipRect();
}

void Renderer::PopClipRect()
{
    clipRects.pop_back();
    UpdateClipRect();
}

int main()
{
    OpenWindow();
    InitOpenGL();

    Renderer renderer;
    Renderer.Init();

    InitShaders(vtx, frag);
    AddOrtho(0.0f, 1280.0f, 0.0f, 720.0f);  

    while(running) 
    {
         glDisable(GL_SCISSOR_TEST);
         glClear(GL_COLOR_BUFFER_BIT);

         renderer.Prepare();

         renderer.PushClipRect(Rect(0, 0, 1280, 720);
         renderer.DrawText("SomeText", 0, 250, 0xffffffff);
         renderer.DrawText("SomeText2", 0, 200, 0xffffffff);
         //renderer.PopClipRect();

         renderer.PushClipRect(Rect(500, 0, 120, 720);
         renderer.DrawText("Clipped text display", 504, 510, 0xffffffff);
         //renderer.PopClipRect();

         renderer.PresentScene();

         SwapWindows();
    }
}

It renders only "SomeText" and "SomeText2". "Clipped text display" is totally invisible. It gets visible when I remove renderer.PushClipRect(Rect(500, 0, 120, 720); or set it to be again renderer.PushClipRect(Rect(0, 0, 1280, 720); (because second draw call is removed and it uses the first one, as it should).

it works when I set renderer.PushClipRect(Rect(500, 0, 120, 720); above the "SomeText", but then "SomeText" and "SomeText2" are invisible.

Poping does not change anything.

Why does it work like this? How to fix it?

c++
opengl
2d
renderer
clipping
asked on Stack Overflow Aug 25, 2018 by Lolexio • edited Aug 25, 2018 by Lolexio

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0