Why graphics is rendered even if it should not? Trying to close gui windows like Dear Im gui does

-1

I am reading Dear Imgui library and I learn by changing it a bit. I am stuck with window closing. My window theoretically is closed, widgets do not work, but graphics still render.

Every gui window - Window - has a class named RenderData. It is a class which has variables, objects like vector array of vertices, vector array of elements, vector array of DrawCmd (DrawCmd is a struct which has data per draw call - One DrawCmd = one opengl draw call). Window class also has methods that are responsible for adding data in proper way that user gave us. For example FillRect(Vector2 pos, Vector2 size, Color color); adds to the vector of vertices, data in way that after giving it to the vbo and call draw call it can render rectangle.

It also has the method that clears resources

void RenderData::Free()
{
    vtxData.clear();     
    drawCmd.clear();
    vtxBuffer.clear();
    elemBuffer.clear();
    currVtxIndex = 0;
}

The GUIRenderer class is responsible for providing this data to the buffer It has vector of pointers on RenderData, vbo, ebo and vao. Methods are: - Create() - creates vbo, ebo, vao and shaders - AddRenderData(RenderData* render)' - it push_back render which is in our gui window - RenderPresent(); - sets up camera, blends, adds vbo attrtibutes, goes through renderData.size() and adds data from current renderData to the vbo and ebo, goes through drawCmd and call draw call. It looks like this:

void GUIRenderer::RenderPresent()
{
    windowSize = window.getWindowSize();
    setRenderViewport(0, 0, static_cast<uint>(windowSize.w), static_cast<uint>(windowSize.h));

    camera.Projection(0.0f, windowSize.w, windowSize.h, 0.0f);
    camera.Update();

    shader->UseProgram();
    shader->UniformMatrix4fv(0, camera.getCameraMatrix());

    EnableBlendFunc(Blend_Source_Alpha, Blend_One_Minus_Source_Alpha);
    vao = vao->Create();

    BindBuffer();
            //These are my functions that adds and enables vbo attributes
    AddAttribute(0, 3, FLOAT, alse, sizeof(Vertex), (const void*)offsetof(Vertex, position));
    AddAttribute(1, 4, UNSIGNED_BYTE, true, sizeof(Vertex), (const void*)offsetof(Vertex, color));

    for (uint i = 0; i < renderData.size(); ++i) {
        const RenderData* currentRender = renderData[i];
        const uint* elemBufferOffset = nullptr;

        vbo->BindBuffer();
        vbo->AddData(currentRender->vtxBuffer.size() * sizeof(Vertex), currentRender->vtxBuffer.data());

        ebo->BindBuffer();
        ebo->AddData(currentRender->elemBuffer.size() * sizeof(uint), currentRender->elemBuffer.data());

        for (uint j = 0; j < currentRender->drawCmd.size(); ++j) {
            const DrawCmd drawCmd = currentRender->drawCmd[j];

            if(drawCmd.shader) drawCmd .shader->UseProgram();

            DrawElements(drawCall.elemCount, elemBufferOffset);

            if(drawCmd.shader) drawCmd .shader->UnuseProgram();

            elemBufferOffset += drawCmd .elemCount;
        }
    }

    DisableBlendFunc();
}

klasa GUI posiada metodę, która obsługuje tą klasę, to znaczy dodaje renderData, które są w oknach do tablicy, która jest w GUIRenderer. Ta metoda nazywa się GUI::RenderPresent()

GUI class has a method that adds renderDatas which are in our gui windows to vector of render data pointers in GUIRenderer. It is called GUI::RenderPresent()

void GUI::RenderPresent()
{
    for(const auto& window : context->window) {
        guiRenderer.AddRenderData(window->renderer);
    }
    guiRenderer.RenderPresent();
}

Problem jak już na początku wspomniałem polega na tym, że po "zamknięciu" okna grafika tego okna nadal jest renderowana

The problem as I mentioned at the beginning is that, after "closing" the window, graphics of this window still renders If we go deeper in to the Dear ImGui we can see that context Class has 3 the most importants objects

ImVector<ImGuiWindow*>  Windows;
ImVector<ImGuiWindow*>  CurrentWindowStack;
ImGuiStorage            WindowsById;

CurrentWindowStack the size of this is restarted to 0 every iteration through main loop, it is push_back in Begin(...); and pop in End() WindowsById it is a some kind of storage for windows based on name/id(hash) if we want to create a new window (so it is not in WindowsById yet) we have to create it and push it back to Windows and also to the storage(WindowsById). Before we do this, we have to check if WindowById does not have our window. If it has, we do not need to create it, we just need to use it again.

moja metoda wygląda bardzo podobnie z pewnymi zmianami (dla uproszczenia będzie wyglądać prawie dokładnie identycznie)

my method is very simillar but it has some changes (for simplicity it will look the same, without bullshits)

void GUI::New()
{
    currentWindowStack.resize(0);
}


void GUI::Begin(const std::string& name)
{
    Window* window = context->FindWindowByName(name);
    if (!window) {
        // if there is no window with this name/id(hash) - create it and at to the storage (`WindowById`)
        window = context->CreateGUIWindow(name);
    }

    context->currentWindowStack.push_back(window);
    context->currentWindow = window;

    window->active = true;

    RenderData* winRenderer = window->renderer;
    winRenderer->Free();

    //it adds default values to the drawCmd vector array, it just adds one draw call
    winRenderer->AddDrawCall();

            uint backgroundColor = 0x80000000;
    winRenderer->FillRect(Rect(window->position, window->size), backgroundColor);
}

void GUI::End()
{                                                                                
    Window* window = context->currentWindow;

    context->currentWindowStack.pop_back();
    context->currentWindow = context->currentWindowStack.empty() ? nullptr : context->currentWindowStack.back();
}

int main()
{
    //... sdl window
    //... opengl context
    GUI gui;
    bool openWindow = true;
    while(!quit) {
        bool pressed = false;
        if(keyDown(KEY_b) && !pressed) {
            openWindow = !open;
            pressed = true;
        } 
        gui.New();
        if(openWindow ) {
            gui.Begin("Test");
            gui.Button("TestButton");
            gui.End();
        }
        gui.RenderPresent();
    }
    return 0;
}

when openWindow is true, button should work and also everything should render - and it is o but when openWindow is false, button should not work (and it does not, so it is ok) and nothing should be rendered - but it is rendered - window background, window's widgets.

Why the graphics is rendered even if it should not? Why does it work in Dear imGui and not in my application? What should I change to fix it?

c++
user-interface
opengl
graphics
2d
asked on Stack Overflow Dec 11, 2018 by JarekBisnesu

1 Answer

2

Begin sets widnow->active to be true, but you never reset it to false and never use it.

You have to read closely. Dear Imgui's NewFrame() method sets all windows' active to false and Render checks if window is active, and if it is, it adds to the vector of drawlist.

So, New() should look like this:

void GUI::New()
{
    currentWindowStack.resize(0);
    for(const auto& window : context.window) {
        window->active = false;
    }
}

and RenderPresent() should look like this:

void GUI::RenderPresent()
{
    for(const auto& window : context->window) {
        if(window->active) {
             guiRenderer.AddRenderData(window->renderer);
        }
    }
    guiRenderer.RenderPresent();
}
answered on Stack Overflow Dec 13, 2018 by Shout

User contributions licensed under CC BY-SA 3.0