From 117d57df5bdddeaea8a286de8879879f5436a067 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 18:21:10 +0200 Subject: [PATCH] ImDrawList: Additional comments and extracted bits into ImDrawList::PopUnusedDrawCmd() --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 12 +++--------- imgui.h | 1 + imgui_draw.cpp | 19 ++++++++++++++++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5f9f7b165..6ab1019d6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,8 @@ Other Changes: [@thedmd, @Shironekoben, @sergeyn, @ocornut] - ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split when current VtxOffset was not zero would lead to draw commands with wrong VtxOffset. (#2591) +- ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split right after + a callback draw command would incorrectly override the callback draw command. - Misc, Freetype: Fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails. - CI: Added CI test to verify we're never accidentally dragging libstdc++ (on some compiler setups, static constructors for non-pod data seems to drag in libstdc++ due to thread-safety concerns). diff --git a/imgui.cpp b/imgui.cpp index 95dc22a65..1b190a6e6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4077,18 +4077,12 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) { + // Remove trailing command if unused. + // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well. + draw_list->PopUnusedDrawCmd(); if (draw_list->CmdBuffer.Size == 0) return; - // Remove trailing command if unused - ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.back(); - if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) - { - draw_list->CmdBuffer.pop_back(); - if (draw_list->CmdBuffer.Size == 0) - return; - } - // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. // May trigger for you if you are using PrimXXX functions incorrectly. IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); diff --git a/imgui.h b/imgui.h index 45f3aa7c4..de4faf281 100644 --- a/imgui.h +++ b/imgui.h @@ -2061,6 +2061,7 @@ struct ImDrawList // NB: all primitives needs to be reserved via PrimReserve() beforehand! IMGUI_API void ResetForNewFrame(); IMGUI_API void ClearFreeMemory(); + IMGUI_API void PopUnusedDrawCmd(); IMGUI_API void PrimReserve(int idx_count, int vtx_count); IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 43daede2d..fb25fecba 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -437,6 +437,17 @@ void ImDrawList::AddDrawCmd() CmdBuffer.push_back(draw_cmd); } +// Pop trailing draw command (used before merging or presenting to user) +// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL +void ImDrawList::PopUnusedDrawCmd() +{ + if (CmdBuffer.Size == 0) + return; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); +} + void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) { ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -1362,13 +1373,12 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) void ImDrawListSplitter::Merge(ImDrawList* draw_list) { - // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. if (_Count <= 1) return; SetCurrentChannel(draw_list, 0); - if (draw_list->CmdBuffer.Size != 0 && draw_list->CmdBuffer.back().ElemCount == 0) - draw_list->CmdBuffer.pop_back(); + draw_list->PopUnusedDrawCmd(); // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. int new_cmd_buffer_count = 0; @@ -1378,8 +1388,11 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) for (int i = 1; i < _Count; i++) { ImDrawChannel& ch = _Channels[i]; + + // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback. if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) ch._CmdBuffer.pop_back(); + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) { ImDrawCmd* next_cmd = &ch._CmdBuffer[0];