集成IMGUI,类似unity布局方式分享

首先感谢前人的分享


我们设置几个集成的规则:

  • 不能污染游戏的环境
  • 能够访问游戏的内存
  • 游戏画面作为子节点(类似unity布局)
  • 可切换成纯win32窗口显示

总结一下前人的分享,游戏界面都是主界面,全部覆盖win32窗口,并不能作为子节点。(至少没有示例)
所以,这篇分享主要解决的问题是怎么能够把游戏界面在IMGUI子窗口中渲染。

思路:
做引擎编辑器,最常用的做法是framebuffer,来显示游戏画面。
那我们用framebuffer做离线渲染,作为图片放入到IMGUI子窗口中即可。

以下都是以windows平台opengl为例

  1. 创建两个窗口window1,window2.
  2. window1 作为游戏窗口,创建framebuffer。
  3. window2 作为编辑器窗口。
  4. window1 的context共享到window2。window2就可以访问window1的内存了。
  5. 隐藏window1窗口。
  6. 先切换context到window1,拿到framebuffer,再切换context到window2,渲染IMGUI。
  7. 渲染IMGUI,拿到window1的framebuffer,作为Image渲染到IMGUI子窗口即可。

FAQ:

  1. opengl 2 在IMGUI中,上述方案,渲染有问题。升级至opengl 3即可。
  2. 最新glfw3.3.8用cocos创建窗口的方式,启动崩溃。降至cocos当前使用版本3.3.3即可。
  3. IMGUI dock分支,可以把子窗口拖出 win32窗口,但是会创建一个独立的进程。
    是因为windows平台下,没有描述窗口之间的关系。
static ImGuiViewport* ImGui_ImplGlfw_GetParentViewport(ImGuiViewport const& viewport)
{
    return viewport.ParentViewportId ? ImGui::FindViewportByID(viewport.ParentViewportId) : nullptr;
}

static void ImGui_ImplGlfw_AddParentToView(ImGuiViewport const& viewport, ImGuiViewport const& parent_viewport)
{
#ifdef _WIN32
    ::SetWindowLongPtr((HWND)viewport.PlatformHandleRaw, GWLP_HWNDPARENT, (LONG_PTR)parent_viewport.PlatformHandleRaw);
#endif
}

static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
{
    ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
    ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
    viewport->PlatformUserData = vd;

    // GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
    // With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
    glfwWindowHint(GLFW_VISIBLE, false);
    glfwWindowHint(GLFW_FOCUSED, false);
#if GLFW_HAS_FOCUS_ON_SHOW
    glfwWindowHint(GLFW_FOCUS_ON_SHOW, false);
 #endif
    glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true);
#if GLFW_HAS_WINDOW_TOPMOST
    glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false);
#endif
    GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : nullptr;
    vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", nullptr, share_window);
    vd->WindowOwned = true;
    viewport->PlatformHandle = (void*)vd->Window;
#ifdef _WIN32
    viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window);
#elif defined(__APPLE__)
    viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window);
#endif
    glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);

    if (ImGuiViewport* parent_viewport = ImGui_ImplGlfw_GetParentViewport(*viewport))
        ImGui_ImplGlfw_AddParentToView(*viewport, *parent_viewport);

    // Install GLFW callbacks for secondary viewports
    glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback);
    glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback);
    glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback);
    glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback);
    glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback);
    glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback);
    glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback);
    glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback);
    glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback);
    glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback);
    if (bd->ClientApi == GlfwClientApi_OpenGL)
    {
        glfwMakeContextCurrent(vd->Window);
        glfwSwapInterval(0);
    }
}

对比修改就可以了。

放个最后效果

imgui 牛逼, 开源游戏引擎都用这个

楼主有例子可以分享一下吗,最近想搞个节点树查看器,方便动态调试,现在代码量太大,编译速度巨慢

这种随便写写就有https://wujiayish.github.io/cocos2d-x-examples/index.html?5

上面就是关键代码

怎么使用呢

不好意思,没有直接能使用的。嵌入在公司项目里了,有时间我提出来一份。