From 531c11d5c72890f324c9734ef5c860408b8a7f3d Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 21 Dec 2017 18:50:27 +0100 Subject: [PATCH] ImDrawList: Small refactor toward removing dependency on GImGui + PushClipRectFullscreen now correctly uses data provided by imgui which can takes account of DisplaySize + Removed static variable in PathArcToFast() which caused linking issues to some. --- imgui.cpp | 25 +++++++++++++------- imgui.h | 7 ++++-- imgui_draw.cpp | 59 ++++++++++++++++++++++++------------------------ imgui_internal.h | 23 +++++++++++++++---- 4 files changed, 71 insertions(+), 43 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5fcd9ee5f..dbed5341c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1818,7 +1818,7 @@ bool ImGuiListClipper::Step() // ImGuiWindow //----------------------------------------------------------------------------- -ImGuiWindow::ImGuiWindow(const char* name) +ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) { Name = ImStrdup(name); ID = ImHash(name, 0); @@ -1859,7 +1859,7 @@ ImGuiWindow::ImGuiWindow(const char* name) FontWindowScale = 1.0f; DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList)); - IM_PLACEMENT_NEW(DrawList) ImDrawList(); + IM_PLACEMENT_NEW(DrawList) ImDrawList(&context->DrawListSharedData); DrawList->_OwnerName = Name; ParentWindow = NULL; RootWindow = NULL; @@ -2254,6 +2254,11 @@ ImDrawList* ImGui::GetOverlayDrawList() return &GImGui->OverlayDrawList; } +ImDrawListSharedData* ImGui::GetDrawListSharedData() +{ + return &GImGui->DrawListSharedData; +} + void ImGui::NewFrame() { ImGuiContext& g = *GImGui; @@ -2274,6 +2279,8 @@ void ImGui::NewFrame() SetCurrentFont(GetDefaultFont()); IM_ASSERT(g.Font->IsLoaded()); + g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y); + g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; g.Time += g.IO.DeltaTime; g.FrameCount += 1; @@ -4145,7 +4152,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl // Create window the first time ImGuiWindow* window = (ImGuiWindow*)ImGui::MemAlloc(sizeof(ImGuiWindow)); - IM_PLACEMENT_NEW(window) ImGuiWindow(name); + IM_PLACEMENT_NEW(window) ImGuiWindow(&g, name); window->Flags = flags; g.WindowsById.SetVoidPtr(window->ID, window); @@ -5243,7 +5250,11 @@ static void SetCurrentFont(ImFont* font) g.Font = font; g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; - g.FontTexUvWhitePixel = g.Font->ContainerAtlas->TexUvWhitePixel; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; } void ImGui::PushFont(ImFont* font) @@ -5820,7 +5831,7 @@ float ImGui::GetFontSize() ImVec2 ImGui::GetFontTexUvWhitePixel() { - return GImGui->FontTexUvWhitePixel; + return GImGui->DrawListSharedData.TexUvWhitePixel; } void ImGui::SetWindowFontScale(float scale) @@ -10489,7 +10500,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle); ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle); ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle); - ImVec2 uv_white = g.FontTexUvWhitePixel; + ImVec2 uv_white = GetFontTexUvWhitePixel(); draw_list->PrimReserve(6, 6); draw_list->PrimVtx(tra, uv_white, hue_color32); draw_list->PrimVtx(trb, uv_white, hue_color32); @@ -11609,7 +11620,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) return; ImDrawList* overlay_draw_list = &GImGui->OverlayDrawList; // Render additional visuals into the top-most draw list - overlay_draw_list->PushClipRectFullScreen(); int elem_offset = 0; for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++) { @@ -11652,7 +11662,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) } ImGui::TreePop(); } - overlay_draw_list->PopClipRect(); ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 55ac7b208..c24a86035 100644 --- a/imgui.h +++ b/imgui.h @@ -50,6 +50,7 @@ struct ImDrawChannel; // Temporary storage for outputting drawing struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call) struct ImDrawData; // All draw command lists required to render the frame struct ImDrawList; // A single draw command list (generally one per window) +struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself) struct ImDrawVert; // A single vertex (20 bytes by default, override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT) struct ImFont; // Runtime data for a single font within a parent ImFontAtlas struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader @@ -466,6 +467,7 @@ namespace ImGui IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); IMGUI_API ImDrawList* GetOverlayDrawList(); // this draw list will be the last rendered one, useful to quickly draw overlays shapes/text + IMGUI_API ImDrawListSharedData* GetDrawListSharedData(); IMGUI_API const char* GetStyleColorName(ImGuiCol idx); IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); @@ -1325,7 +1327,7 @@ struct ImDrawCmd ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. void* UserCallbackData; // The draw callback code can access this. - ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = -8192.0f; ClipRect.z = ClipRect.w = +8192.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; } + ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; } }; // Vertex index (override with '#define ImDrawIdx unsigned int' inside in imconfig.h) @@ -1384,6 +1386,7 @@ struct ImDrawList ImVector VtxBuffer; // Vertex buffer. // [Internal, used while building lists] + const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) const char* _OwnerName; // Pointer to owner window's name for debugging unsigned int _VtxCurrentIdx; // [Internal] == VtxBuffer.Size ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) @@ -1395,7 +1398,7 @@ struct ImDrawList int _ChannelsCount; // [Internal] number of active channels (1+) ImVector _Channels; // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size) - ImDrawList() { _OwnerName = NULL; Clear(); } + ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); } ~ImDrawList() { ClearFreeMemory(); } IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) IMGUI_API void PushClipRectFullScreen(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 69e93689f..03ff863c3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -277,10 +277,27 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) } //----------------------------------------------------------------------------- -// ImDrawList +// ImDrawListData //----------------------------------------------------------------------------- -static const ImVec4 GNullClipRect(-8192.0f, -8192.0f, +8192.0f, +8192.0f); // Large values that are easy to encode in a few bits+shift +ImDrawListSharedData::ImDrawListSharedData() +{ + Font = NULL; + FontSize = 0.0f; + CurveTessellationTol = 0.0f; + ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f); + + // Const data + for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++) + { + const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12); + CircleVtx12[i] = ImVec2(cosf(a), sinf(a)); + } +} + +//----------------------------------------------------------------------------- +// ImDrawList +//----------------------------------------------------------------------------- void ImDrawList::Clear() { @@ -321,7 +338,7 @@ void ImDrawList::ClearFreeMemory() } // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds -#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : GNullClipRect) +#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen) #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL) void ImDrawList::AddDrawCmd() @@ -412,8 +429,7 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_ void ImDrawList::PushClipRectFullScreen() { - PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w)); - //PushClipRect(GetVisibleRect()); // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiContext from here? + PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w)); } void ImDrawList::PopClipRect() @@ -533,7 +549,7 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count) // Fully unrolled with inline call to keep our debug builds decently fast. void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col) { - ImVec2 b(c.x, a.y), d(a.x, c.y), uv(GImGui->FontTexUvWhitePixel); + ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel); ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx; _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2); _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3); @@ -581,7 +597,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 if (points_count < 2) return; - const ImVec2 uv = GImGui->FontTexUvWhitePixel; + const ImVec2 uv = _Data->TexUvWhitePixel; anti_aliased &= GImGui->Style.AntiAliasedLines; //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug @@ -759,7 +775,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col, bool anti_aliased) { - const ImVec2 uv = GImGui->FontTexUvWhitePixel; + const ImVec2 uv = _Data->TexUvWhitePixel; anti_aliased &= GImGui->Style.AntiAliasedShapes; //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug @@ -842,20 +858,6 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12) { - static ImVec2 circle_vtx[12]; - static bool circle_vtx_builds = false; - const int circle_vtx_count = IM_ARRAYSIZE(circle_vtx); - if (!circle_vtx_builds) - { - for (int i = 0; i < circle_vtx_count; i++) - { - const float a = ((float)i / (float)circle_vtx_count) * 2*IM_PI; - circle_vtx[i].x = cosf(a); - circle_vtx[i].y = sinf(a); - } - circle_vtx_builds = true; - } - if (radius == 0.0f || a_min_of_12 > a_max_of_12) { _Path.push_back(centre); @@ -864,7 +866,7 @@ void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_ _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1)); for (int a = a_min_of_12; a <= a_max_of_12; a++) { - const ImVec2& c = circle_vtx[a % circle_vtx_count]; + const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)]; _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius)); } } @@ -916,7 +918,7 @@ void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImV if (num_segments == 0) { // Auto-tessellated - PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, GImGui->Style.CurveTessellationTol, 0); + PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); } else { @@ -998,7 +1000,7 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0) return; - const ImVec2 uv = GImGui->FontTexUvWhitePixel; + const ImVec2 uv = _Data->TexUvWhitePixel; PrimReserve(6, 4); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3)); @@ -1094,12 +1096,11 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, if (text_begin == text_end) return; - // IMPORTANT: This is one of the few instance of breaking the encapsulation of ImDrawList, as we pull this from ImGui state, but it is just SO useful. - // Might just move Font/FontSize to ImDrawList? + // Pull default font/size from the shared ImDrawListSharedData instance if (font == NULL) - font = GImGui->Font; + font = _Data->Font; if (font_size == 0.0f) - font_size = GImGui->FontSize; + font_size = _Data->FontSize; IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. diff --git a/imgui_internal.h b/imgui_internal.h index ed19ba664..ca1563671 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -453,6 +453,21 @@ struct ImGuiColumnsSet } }; +struct ImDrawListSharedData +{ + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + ImFont* Font; // Current/default font (optional, for simplified AddText overload) + float FontSize; // Current/default font size (optional, for simplified AddText overload) + float CurveTessellationTol; + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + + // Const data + // FIXME: Bake rounded corners fill/borders in atlas + ImVec2 CircleVtx12[12]; + + ImDrawListSharedData(); +}; + // Main state for ImGui struct ImGuiContext { @@ -462,7 +477,7 @@ struct ImGuiContext ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back() float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. - ImVec2 FontTexUvWhitePixel; // (Shortcut) == Font->TexUvWhitePixel + ImDrawListSharedData DrawListSharedData; float Time; int FrameCount; @@ -574,12 +589,11 @@ struct ImGuiContext int WantTextInputNextFrame; char TempBuffer[1024*3+1]; // temporary text buffer - ImGuiContext() + ImGuiContext() : OverlayDrawList(NULL) { Initialized = false; Font = NULL; FontSize = FontBaseSize = 0.0f; - FontTexUvWhitePixel = ImVec2(0.0f, 0.0f); Time = 0.0f; FrameCount = 0; @@ -639,6 +653,7 @@ struct ImGuiContext OsImePosRequest = OsImePosSet = ImVec2(-1.0f, -1.0f); ModalWindowDarkeningRatio = 0.0f; + OverlayDrawList._Data = &DrawListSharedData; OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging MouseCursor = ImGuiMouseCursor_Arrow; memset(MouseCursorData, 0, sizeof(MouseCursorData)); @@ -805,7 +820,7 @@ struct IMGUI_API ImGuiWindow int FocusIdxTabRequestNext; // " public: - ImGuiWindow(const char* name); + ImGuiWindow(ImGuiContext* context, const char* name); ~ImGuiWindow(); ImGuiID GetID(const char* str, const char* str_end = NULL);