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_backujerender
, który jest właśnie tym z okna gui
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?