Dlaczego kwadrat jest nadal wyświetlany?

0

Witam, czytam sobie bibliotekę Dear ImGui i się z niej uczę troszeczkę ją zmieniając.

Zatrzymałem się przy zamykaniu okna. Okno teoretycznie jest zamknięte, nie można korzystać z buttonów, itp. ale grafika nadal jest zrenderowana.

Każde okno gui - Window - ma klasę o nazwie RenderData. Jest to klasa, która posiada takie zmienne, obiekty jak tablicę vector wierzchołków oraz tablicę vector elementów do renderowania indeksowego, tablicę vector DrawCmd, która odpowiada za dane per draw call. Ta klasa posiada również metody, które są odpowiedzialne za dodawanie w odpowiedni sposób danych, które dostarczył nam użytkownik. Na przykład FillRect(Vector2 pos, Vector2 size, Color color); dodaje do tablicy vector wierzchołków dane w taki sposób, aby po podaniu tablicy wierzchołków do vbo i wywołaniu komendy rysowania, na ekranie pokazał się prostokąt.

Posiada też metodę, która czyści zasoby

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

Za dostarczenie tych danych do buffera odpowiada klasa GUIRenderer.
Posiada ona tablicę vector wzkaźnika na RenderData, vbo, ebo oraz vao.
Metody to:

  • Create(); - tworzy vbo, ebo, vao i shadery
  • AddRenderData(RenderData* render); - to tablicy push_backuje render, który jest właśnie tym z okna gui
    `RenderPresent(); - ustawia kamerę, obsługuje blending, dodaje atrybuty do vbo, idzie przez renderData.size() i w tej pętli dodaje dane z aktualnej renderdaty do vbo, ebo, idzie przez ilość drawCmd i obsługuje polecenia rysowania, wygląda tak:
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();
                //To są moje funkcje, które odblokowują i dodają atrybuty
        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()

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

Jeśli zgłębimy się trochę w Dear ImGui możemy zobaczyć, że klasa context posiada w tej sprawie 3 najważniejsze objekty

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

CurrentWindowStack jest co głównę pętle resetowany do size = 0
WindowsById jest to rodzaj magazynu na okna pod względem nazwy/id(hashu)
a do Windows dodawana jest następna klasa tylko wtedy gdy nie ma jeszcze w WindowsById - nowe okno dodawane jest też do WindowsById, żeby w następnym przejściu przez pętle można było stwierdzić, że okno o podanej nazwie(hashu) już istnieje i nie trzeba go tworzyć od nowa.

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

void GUI::New()
{
    currentWindowStack.resize(0);
}
void GUI::Begin(const std::string& name)
    {
        Window* window = context->FindWindowByName(name);
        if (!window) {
                        // Jeśli jeszcze nie znaleziono okna o takiej nazwie, stwórz go
            window = context->CreateGUIWindow(name);
        }

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

        window->active = true;

        RenderData* winRenderer = window->renderer;
        winRenderer->Free();
                //Add draw call dodaje początkowe wartości do tablicy drawCmd, czyli po prostu dodaje jedno polecenie rysowania
        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()
{
     //... tworzenie okna sdl
     //... tworzenie kontekstu opengl
    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("Testowy");
            gui.Button("TestButton");
            gui.End();
        }
        gui.RenderPresent();
    }
    return 0;
}

gdy openWindow jest na true, button powinien działać i wszystko powinno się ładnie renderować - i tak się dzieje.
Jendka gdy openWindow jest na false, wtedy button nie powinien działać i nic nie powinno być renderowane - button nie działa (czyli tak jak powinno być) ale nadal jest renderowany obraz.

Dlaczego nadal jest renderowany obraz? Co powinienem poprawić aby obraz znikał? Dlaczego znika w Dear ImGui?

1

Szukaj metody Window::close() albo Window::hide().
Najlepiej chyba jednak wyjdziesz na wywaleniu tego nieudokumentowanego tworu na rzecz rozwiązań od lat sprawdzających się w praktyce, i z kompletną dokumentacją oraz bogactwem przykładów - czyli Qt albo (ponoć) WxWidgets.

0

Szukaj metody Window::close() albo Window::hide().

Nie ma takiej metody. Zamknięcie powinno działać po prostu robiąc całe okno i widgety, które działają w tym oknie w ifie np.

bool openWindow = false
int time = 0;
while(!quit) {
    ++time;
    if(time > 3000) {
        openWindow = !openWindow;
        time = 0;
    }
    if(openWindow) {
        gui.Begin("Nazwa");
        gui.Button("JakisButon");
        gui.End();
    }
}

I w momencie gdy openWindow = false wtedy zrenderowane rzeczy znikają, gdy openWindow = true, wtedy są znów renderowane.

Najlepiej chyba jednak wyjdziesz na wywaleniu tego nieudokumentowanego tworu na rzecz rozwiązań od lat sprawdzających się w praktyce, i z kompletną dokumentacją oraz bogactwem przykładów - czyli Qt albo (ponoć) WxWidgets.

Z tego co czytałem to Dear Imgui nie jest złą biblioteką, a Qt nie jest immediate mode gui.

0

A gdzie to pieruństwo ma jakąkolwiek dokumentację? Tylko githuba z tą biblioteką znalazłem, a w nim nic - nic przynajmniej w folderze doc.

0

w imgui_demo.cp jest funkcja ImGui::ShowDemoWindow();, która pokazuje w jaki sposób można korzystać z tej biblioteki i jakie opcje oferuje.

0

Hmm coś tam jest:

 if (ImGui::MenuItem("Close")) { test_window = false; }
1506                     ImGui::EndPopup();
oraz
ImGui::CloseCurrentPopup();

ale jak tak oglądam ten kod, to naprawdę jest to poroniony pomysł to całe ImGui. Weź się Bracie lepiej poucz Qt - co masz przeciwko tej bibliotece poza "immediate mode gui"?(co to w ogóle znaczy)

0

"immediate mode gui"?(co to w ogóle znaczy)

https://en.wikipedia.org/wiki/Immediate_Mode_GUI
https://gist.github.com/bkara[...]fd21a15542e0ec96f7268150f1b62

Hmm coś tam jest:

if (ImGui::MenuItem("Close")) { test_window = false; }
1506                     ImGui::EndPopup();
oraz
ImGui::CloseCurrentPopup();

To nie jest to.

ale jak tak oglądam ten kod, to naprawdę jest to poroniony pomysł to całe ImGui. Weź się Bracie lepiej poucz Qt - co masz przeciwko tej bibliotece

Bardziej mi się podoba ten styl, są zalety i wady tego trybu.

0

Znalazłem błąd. W metodzie New powinienem iść przez wszystkie window i ustawiac window->active na false, a w RenderPresent sprawdzać czy window->active jest na true i wtedy dopiero dodawać do vectora z klasy GUIRenderer

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0