Browse Source

Viewport: per-viewport overlay draw list created on demand. With this pattern it'll be easier to consider adding more (e.g. background draw list). (#545)

omar 7 years ago
parent
commit
8be6f40ae1
2 changed files with 40 additions and 33 deletions
  1. 35 30
      imgui.cpp
  2. 5 3
      imgui_internal.h

+ 35 - 30
imgui.cpp

@@ -2717,17 +2717,32 @@ int ImGui::GetFrameCount()
     return GImGui->FrameCount;
 }
 
-ImDrawList* ImGui::GetOverlayDrawList(ImGuiWindow* window)
+ImDrawList* ImGui::GetOverlayDrawList(ImGuiViewportP* viewport)
 {
-    IM_ASSERT(window && window->Viewport);
-    return window->Viewport->OverlayDrawList;
+    // Create the draw list on demand, because it is not frequently used for all viewports
+    ImGuiContext& g = *GImGui;
+    if (viewport->OverlayDrawList == NULL)
+    {
+        viewport->OverlayDrawList = IM_NEW(ImDrawList)(&g.DrawListSharedData);
+        viewport->OverlayDrawList->_OwnerName = "##Overlay";
+    }
+
+    // Our ImDrawList system requires that there is always a command
+    if (viewport->LastFrameOverlayDrawList != g.FrameCount)
+    {
+        viewport->OverlayDrawList->Clear();
+        viewport->OverlayDrawList->PushTextureID(g.IO.Fonts->TexID);
+        viewport->OverlayDrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
+        viewport->OverlayDrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
+        viewport->LastFrameOverlayDrawList = g.FrameCount;
+    }
+    return viewport->OverlayDrawList;
 }
 
 ImDrawList* ImGui::GetOverlayDrawList()
 {
     ImGuiWindow* window = GImGui->CurrentWindow;
-    IM_ASSERT(window && window->Viewport);
-    return window->Viewport->OverlayDrawList;
+    return GetOverlayDrawList(window->Viewport);
 }
 
 ImDrawListSharedData* ImGui::GetDrawListSharedData()
@@ -3633,15 +3648,6 @@ void ImGui::RenderPlatformWindowsDefault(void* platform_render_arg, void* render
     }
 }
 
-static void SetupOverlayDrawList(ImDrawList* draw_list, ImGuiViewport* viewport)
-{
-    ImGuiContext& g = *GImGui;
-    draw_list->Clear();
-    draw_list->PushTextureID(g.IO.Fonts->TexID);
-    draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
-    draw_list->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
-}
-
 static void NewFrameUpdateMouseInputs()
 {
     ImGuiContext& g = *GImGui;
@@ -3832,7 +3838,6 @@ void ImGui::NewFrame()
         ImGuiViewportP* viewport = g.Viewports[n];
         viewport->DrawData = NULL;
         viewport->DrawDataP.Clear();
-        SetupOverlayDrawList(viewport->OverlayDrawList, viewport);
     }
 
     // Clear reference to active widget if the widget isn't alive anymore
@@ -4051,7 +4056,7 @@ void ImGui::Initialize(ImGuiContext* context)
     g.SettingsHandlers.push_front(ini_handler);
 
     // Create default viewport
-    ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(&g.DrawListSharedData);
+    ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
     viewport->ID = IMGUI_VIEWPORT_DEFAULT_ID;
     viewport->Idx = 0;
     g.Viewports.push_back(viewport);
@@ -4563,7 +4568,7 @@ void ImGui::Render()
             ImVec2 pos = (g.MousePosViewport == viewport) ? main_pos : ConvertPlatformPosToViewportPos(ConvertViewportPosToPlatformPos(main_pos, g.MousePosViewport), viewport);
             if (viewport->GetRect().Overlaps(ImRect(pos, pos + ImVec2(2,2)*sc + size * sc)))
             {
-                ImDrawList* draw_list = viewport->OverlayDrawList;
+                ImDrawList* draw_list = GetOverlayDrawList(viewport);
                 draw_list->PushTextureID(tex_id);
                 draw_list->AddImage(tex_id, pos+ImVec2(1,0)*sc, pos+ImVec2(1,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48));        // Shadow
                 draw_list->AddImage(tex_id, pos+ImVec2(2,0)*sc, pos+ImVec2(2,0)*sc + size*sc, uv[2], uv[3], IM_COL32(0,0,0,48));        // Shadow
@@ -4580,7 +4585,8 @@ void ImGui::Render()
     {
         ImGuiViewportP* viewport = g.Viewports[n];
         viewport->DrawDataBuilder.FlattenIntoSingleLayer();
-        AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], viewport->OverlayDrawList);
+        if (viewport->OverlayDrawList != NULL)
+            AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetOverlayDrawList(viewport));
         SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]);
         g.IO.MetricsRenderVertices += viewport->DrawData->TotalVtxCount;
         g.IO.MetricsRenderIndices += viewport->DrawData->TotalIdxCount;
@@ -4683,7 +4689,7 @@ ImGuiViewportP* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFl
     else
     {
         // New viewport
-        viewport = IM_NEW(ImGuiViewportP)(&g.DrawListSharedData);
+        viewport = IM_NEW(ImGuiViewportP)();
         viewport->ID = id;
         viewport->Idx = g.Viewports.Size;
         viewport->Pos = ImVec2(g.Viewports.back()->GetNextX(), 0.0f);
@@ -4691,11 +4697,9 @@ ImGuiViewportP* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFl
         g.Viewports.push_back(viewport);
         
         // We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport.
-        // 1. We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame
-        // 2. Our ImDrawList system requires that there is always a command, SetupOverlayDrawList() effectively does that by setting up texture and clip rect
+        // We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame
         g.DrawListSharedData.ClipRectFullscreen.z = ImMax(g.DrawListSharedData.ClipRectFullscreen.z, viewport->Pos.x + viewport->Size.x);
         g.DrawListSharedData.ClipRectFullscreen.w = ImMax(g.DrawListSharedData.ClipRectFullscreen.w, viewport->Pos.y + viewport->Size.y);
-        SetupOverlayDrawList(viewport->OverlayDrawList, viewport);
     }
 
     IM_ASSERT(viewport->Pos.y == 0.0f);
@@ -6699,12 +6703,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
 
         // Draw modal window background (darkens what is behind them, all viewports)
         if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow() && window->HiddenFrames <= 0)
-        {
-            window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
             for (int viewport_n = 0; viewport_n < g.Viewports.Size; viewport_n++)
-                if (g.Viewports[viewport_n] != window->Viewport)
-                    g.Viewports[viewport_n]->OverlayDrawList->AddRectFilled(g.Viewports[viewport_n]->Pos, g.Viewports[viewport_n]->Pos + g.Viewports[viewport_n]->Size, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
-        }
+            {
+                ImGuiViewportP* viewport = g.Viewports[viewport_n];
+                ImDrawList* draw_list = (viewport == window->Viewport) ? window->DrawList : GetOverlayDrawList(viewport);
+                draw_list->AddRectFilled(viewport->Pos, viewport->Pos + viewport->Size, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
+            }
 
         // Draw navigation selection/windowing rectangle background
         if (g.NavWindowingTarget == window)
@@ -14060,7 +14064,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
                     return;
                 }
 
-                ImDrawList* overlay_draw_list = viewport->OverlayDrawList; // Render additional visuals into the top-most draw list
+                ImDrawList* overlay_draw_list = GetOverlayDrawList(viewport); // Render additional visuals into the top-most draw list
                 if (window && ImGui::IsItemHovered())
                     overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
                 if (!node_open)
@@ -14245,8 +14249,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
                 char buf[32];
                 ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
                 float font_size = ImGui::GetFontSize() * 2;
-                window->Viewport->OverlayDrawList->AddRectFilled(window->PosFloat, window->PosFloat + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
-                window->Viewport->OverlayDrawList->AddText(NULL, font_size, window->PosFloat, IM_COL32(255, 255, 255, 255), buf);
+                ImDrawList* overlay_draw_list = GetOverlayDrawList(window->Viewport);
+                overlay_draw_list->AddRectFilled(window->PosFloat, window->PosFloat + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
+                overlay_draw_list->AddText(NULL, font_size, window->PosFloat, IM_COL32(255, 255, 255, 255), buf);
             }
         }
     }

+ 5 - 3
imgui_internal.h

@@ -516,6 +516,7 @@ struct ImGuiViewportP : public ImGuiViewport
     int                 Idx;
     int                 LastFrameActive;          // Last frame number this viewport was activated by a window
     int                 LastFrameAsRefViewport;   // Last frame number this viewport was io.MouseViewportRef
+    int                 LastFrameOverlayDrawList;
     ImGuiID             LastNameHash;
     float               Alpha;                    // Window opacity (when dragging dockable windows/viewports we make them transparent)
     float               LastAlpha;
@@ -525,8 +526,8 @@ struct ImGuiViewportP : public ImGuiViewport
     ImDrawDataBuilder   DrawDataBuilder;
     ImVec2              RendererLastSize;
 
-    ImGuiViewportP(ImDrawListSharedData* draw_list_shared_data) { Idx = 1; LastFrameActive = LastFrameAsRefViewport = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; Window = NULL; OverlayDrawList = IM_NEW(ImDrawList)(draw_list_shared_data); OverlayDrawList->_OwnerName = "##Overlay"; RendererLastSize = ImVec2(-1.0f,-1.0f); }
-    ~ImGuiViewportP()        { IM_DELETE(OverlayDrawList); }
+    ImGuiViewportP()         { Idx = 1; LastFrameActive = LastFrameAsRefViewport = LastFrameOverlayDrawList = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; Window = NULL; OverlayDrawList = NULL; RendererLastSize = ImVec2(-1.0f,-1.0f); }
+    ~ImGuiViewportP()        { if (OverlayDrawList) IM_DELETE(OverlayDrawList); }
     ImRect  GetRect() const  { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
     float   GetNextX() const { const float SPACING = 4.0f; return Pos.x + Size.x + SPACING; }
 };
@@ -1099,7 +1100,8 @@ namespace ImGui
     IMGUI_API void          PopItemFlag();
 
     IMGUI_API void          SetCurrentFont(ImFont* font);
-    IMGUI_API ImDrawList*   GetOverlayDrawList(ImGuiWindow* window);
+    IMGUI_API ImDrawList*   GetOverlayDrawList(ImGuiViewportP* viewport);
+    inline ImDrawList*      GetOverlayDrawList(ImGuiWindow* window) { return GetOverlayDrawList(window->Viewport); }
 
     IMGUI_API void          OpenPopupEx(ImGuiID id);
     IMGUI_API void          ClosePopup(ImGuiID id);