c++imgui

Invalid ImGuiContext when it should be valid


I have 2 layers with the same base type. These two layers override a virtual void on_imgui_render() {}. Both layers are added to the same vector, and are iterated on one after the other. In imgui_layer, the following code returns a valid context, but in sandbox_layer, this code returns null. Why is one scope able to acquire a valid context, but the other doesn't?

ImGuiContext& g = *GImGui;
fl::b8 within_frame_scope = g.WithinFrameScope;

In full:

class FL_API layer
{
public:
    explicit layer(const std::string& name = "Layer");
    virtual ~layer() = default;

    layer(const layer& other)                = delete;
    layer(layer&& other) noexcept            = delete;
    layer& operator=(const layer& other)     = delete;
    layer& operator=(layer&& other) noexcept = delete;

    virtual void on_attach() {}
    virtual void on_detach() {}
    virtual void on_update() {}
    virtual void on_render() {}
    virtual void on_imgui_render() {}
    virtual void on_event(event& event) {}

protected:
    std::string m_debug_name;
};
void imgui_layer::on_imgui_render()
{
    ImGuiContext& g = *GImGui;
    fl::b8 within_frame_scope = g.WithinFrameScope;
    (void) within_frame_scope;
}
void sandbox_layer::on_imgui_render()
{
    ImGuiContext& g = *GImGui;
    fl::b8 within_frame_scope = g.WithinFrameScope;
    (void) within_frame_scope;
}
m_imgui_layer->begin();
std::ranges::for_each(m_layerstack, [](layer* layer) { layer->on_imgui_render(); });
m_imgui_layer->end();
void imgui_layer::begin()
{
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();
}

void imgui_layer::end()
{
    ImGuiIO& io    = ImGui::GetIO();
    io.DisplaySize = ImVec2(static_cast<f32>(application::instance()->get_window().get_width()), static_cast<f32>(application::instance()->get_window().get_height()));

    ImGui::Render();
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
    {
        GLFWwindow* backup_current_context = glfwGetCurrentContext();
        ImGui::UpdatePlatformWindows();
        ImGui::RenderPlatformWindowsDefault();
        glfwMakeContextCurrent(backup_current_context);
    }
}

Solution

  • ImGui uses globals, which are not shared across DLL boundaries. The imgui.h and imgui.cpp contain solid answers to this problem. In short:

    ImGui::SetCurrentContext(fl::imgui_layer::get_context());
    
    ImGuiMemAllocFunc alloc_func = nullptr;
    ImGuiMemFreeFunc free_func   = nullptr;
    void* user_data              = nullptr;
    
    fl::imgui_layer::get_allocator_callbacks(&alloc_func, &free_func, &user_data);
    ImGui::SetAllocatorFunctions(alloc_func, free_func, user_data);