From 3997e8b555ebb2b263dde7dce0d626d9a08fca29 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 22:46:42 +0100 Subject: [PATCH 01/12] Fixed animated window titles from being updated when displayed in the CTRL+Tab list. + Adding overkill helpers for reusing buffers. (#787) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 39 ++++++++++++++++++++++++++++++++++----- imgui_internal.h | 2 ++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 42cccf76..053c8ea2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -66,6 +66,7 @@ Other Changes: - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) - Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary keep the focus on the parent window, which could steal it from newly appearing windows. (#787) +- Nav: Fixed animated window titles from being updated when displayed in the CTRL+Tab list. (#787) - Error recovery: Extraneous/undesired calls to End() are now being caught by an assert in the End() function closer to the user call site (instead of being reported in EndFrame). Past the assert, they don't lead to crashes any more. (#1651) Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. diff --git a/imgui.cpp b/imgui.cpp index a1c64193..3f9ce8be 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1259,11 +1259,25 @@ void ImStrncpy(char* dst, const char* src, size_t count) dst[count-1] = 0; } -char* ImStrdup(const char *str) +char* ImStrdup(const char* str) { - size_t len = strlen(str) + 1; - void* buf = ImGui::MemAlloc(len); - return (char*)memcpy(buf, (const void*)str, len); + size_t len = strlen(str); + void* buf = ImGui::MemAlloc(len + 1); + return (char*)memcpy(buf, (const void*)str, len + 1); +} + +char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) +{ + size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1; + size_t src_size = strlen(src) + 1; + if (dst_buf_size < src_size) + { + ImGui::MemFree(dst); + dst = (char*)ImGui::MemAlloc(src_size); + if (p_dst_size) + *p_dst_size = src_size; + } + return (char*)memcpy(dst, (const void*)src, src_size); } const char* ImStrchrRange(const char* str, const char* str_end, char c) @@ -1367,7 +1381,9 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) } #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS -// Pass data_size==0 for zero-terminated strings +// Pass data_size == 0 for zero-terminated strings, data_size > 0 for non-string data. +// Pay attention that data_size==0 will yield different results than passing strlen(data) because the zero-terminated codepath handles ###. +// This should technically be split into two distinct functions (ImHashData/ImHashStr), perhaps once we remove the silly static variable. // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. ImU32 ImHash(const void* data, int data_size, ImU32 seed) { @@ -2391,6 +2407,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) WindowPadding = ImVec2(0.0f, 0.0f); WindowRounding = 0.0f; WindowBorderSize = 0.0f; + NameBufLen = (int)strlen(name) + 1; MoveId = GetID("#MOVE"); ChildId = 0; Scroll = ImVec2(0.0f, 0.0f); @@ -4802,6 +4819,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->LastFrameActive = current_frame; window->IDStack.resize(1); + // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged). + // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere. + bool window_title_visible_elsewhere = false; + if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) + { + size_t buf_len = (size_t)window->NameBufLen; + window->Name = ImStrdupcpy(window->Name, &buf_len, name); + window->NameBufLen = (int)buf_len; + } + // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS // Update contents size from last frame for auto-fitting (or use explicit size) diff --git a/imgui_internal.h b/imgui_internal.h index f035854a..213ef3dc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -143,6 +143,7 @@ IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); IMGUI_API char* ImStrdup(const char* str); +IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); IMGUI_API int ImStrlenW(const ImWchar* str); IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line @@ -1071,6 +1072,7 @@ struct IMGUI_API ImGuiWindow ImVec2 WindowPadding; // Window padding at the time of begin. float WindowRounding; // Window rounding at the time of begin. float WindowBorderSize; // Window border size at the time of begin. + int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! ImGuiID MoveId; // == window->GetID("#MOVE") ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window) ImVec2 Scroll; From c2db7f63bd7d07812ef73b441448fc54ab2ea084 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 23:45:07 +0100 Subject: [PATCH 02/12] Selectable() should have an ID even though they are disabled, to be consistent with other widgets. Not sure of the reasoning ~1.41 which made this turn to 0. --- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 213ef3dc..7429c34c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -331,8 +331,8 @@ enum ImGuiItemStatusFlags_ // FIXME: this is in development, not exposed/functional as a generic feature yet. enum ImGuiLayoutType_ { - ImGuiLayoutType_Vertical, - ImGuiLayoutType_Horizontal + ImGuiLayoutType_Vertical = 0, + ImGuiLayoutType_Horizontal = 1, }; enum ImGuiAxis diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bdf4991e..dd1c2eb4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -282,10 +282,12 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set - if (need_wrap) PushTextWrapPos(0.0f); + bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + if (need_backup) + PushTextWrapPos(0.0f); TextV(fmt, args); - if (need_wrap) PopTextWrapPos(); + if (need_backup) + PopTextWrapPos(); } void ImGui::LabelText(const char* label, const char* fmt, ...) @@ -5030,7 +5032,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl bb.Min.y -= spacing_U; bb.Max.x += spacing_R; bb.Max.y += spacing_D; - if (!ItemAdd(bb, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id)) + if (!ItemAdd(bb, id)) { if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) PushColumnClipRect(); From b33977bc15d7edeccbbd6a05dd7a5099c835f33f Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 Jan 2019 23:59:05 +0100 Subject: [PATCH 03/12] Tests: Reworking hook prototypes for imgui-test to be faster and multi-context friendly. --- imgui.cpp | 7 ++++--- imgui_internal.h | 10 +++++----- imgui_widgets.cpp | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3f9ce8be..bcd4daf7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2697,7 +2697,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg) window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_ItemAdd(bb, id); + if (id != 0) + ImGuiTestEngineHook_ItemAdd(&g, bb, id); #endif // Clipping test @@ -3251,7 +3252,7 @@ void ImGui::NewFrame() ImGuiContext& g = *GImGui; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_PreNewFrame(); + ImGuiTestEngineHook_PreNewFrame(&g); #endif // Check user data @@ -3427,7 +3428,7 @@ void ImGui::NewFrame() g.FrameScopePushedImplicitWindow = true; #ifdef IMGUI_ENABLE_TEST_ENGINE - ImGuiTestEngineHook_PostNewFrame(); + ImGuiTestEngineHook_PostNewFrame(&g); #endif } diff --git a/imgui_internal.h b/imgui_internal.h index 7429c34c..97520ce3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1429,11 +1429,11 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch // Test engine hooks (imgui-test) //#define IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE -extern void ImGuiTestEngineHook_PreNewFrame(); -extern void ImGuiTestEngineHook_PostNewFrame(); -extern void ImGuiTestEngineHook_ItemAdd(const ImRect& bb, ImGuiID id); -extern void ImGuiTestEngineHook_ItemInfo(ImGuiID id, const char* label, int flags); -#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(_ID, _LABEL, _FLAGS) // Register status flags +extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx); +extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id); +extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, int flags); +#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags #else #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0) #endif diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dd1c2eb4..2edc5d3c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -282,7 +282,7 @@ void ImGui::TextWrapped(const char* fmt, ...) void ImGui::TextWrappedV(const char* fmt, va_list args) { - bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set + bool need_backup = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set if (need_backup) PushTextWrapPos(0.0f); TextV(fmt, args); @@ -399,8 +399,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = window; #ifdef IMGUI_ENABLE_TEST_ENGINE - if (window->DC.LastItemId != id) - ImGuiTestEngineHook_ItemAdd(bb, id); + if (id != 0 && window->DC.LastItemId != id) + ImGuiTestEngineHook_ItemAdd(&g, bb, id); #endif bool pressed = false; From 57b1622afcf5a1afef3da0664845118f1da942fa Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 15:28:33 +0100 Subject: [PATCH 04/12] Added IMGUI_USE_STB_SPRINTF (undocumented) (#1038) --- imgui.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index bcd4daf7..2e7ceb6d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1351,6 +1351,11 @@ void ImStrTrimBlanks(char* buf) // B) When buf==NULL vsnprintf() will return the output size. #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +#ifdef IMGUI_USE_STB_SPRINTF +#define STB_SPRINTF_IMPLEMENTATION +#include "imstb_sprintf.h" +#endif + #if defined(_MSC_VER) && !defined(vsnprintf) #define vsnprintf _vsnprintf #endif @@ -1359,7 +1364,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) { va_list args; va_start(args, fmt); +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else int w = vsnprintf(buf, buf_size, fmt, args); +#endif va_end(args); if (buf == NULL) return w; @@ -1371,7 +1380,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) { +#ifdef IMGUI_USE_STB_SPRINTF + int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args); +#else int w = vsnprintf(buf, buf_size, fmt, args); +#endif if (buf == NULL) return w; if (w == -1 || w >= (int)buf_size) From f53cd3ee0f5a08e3115420d98d3d89118a0fcf57 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 16:26:45 +0100 Subject: [PATCH 05/12] Internals: LowerBound: Use raw pointer typedefs, we never use iterator anywhere else in the codebase. Demo: Typo. C98 fix. --- imgui.cpp | 26 +++++++++++++------------- imgui_demo.cpp | 2 +- imgui_internal.h | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e7ceb6d..e8194f87 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1795,15 +1795,15 @@ ImU32 ImGui::GetColorU32(ImU32 col) //----------------------------------------------------------------------------- // std::lower_bound but without the bullshit -static ImVector::iterator LowerBound(ImVector& data, ImGuiID key) +static ImGuiStorage::Pair* LowerBound(ImVector& data, ImGuiID key) { - ImVector::iterator first = data.begin(); - ImVector::iterator last = data.end(); + ImGuiStorage::Pair* first = data.Data; + ImGuiStorage::Pair* last = data.Data + data.Size; size_t count = (size_t)(last - first); while (count > 0) { size_t count2 = count >> 1; - ImVector::iterator mid = first + count2; + ImGuiStorage::Pair* mid = first + count2; if (mid->key < key) { first = ++mid; @@ -1836,7 +1836,7 @@ void ImGuiStorage::BuildSortByKey() int ImGuiStorage::GetInt(ImGuiID key, int default_val) const { - ImVector::iterator it = LowerBound(const_cast&>(Data), key); + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) return default_val; return it->val_i; @@ -1849,7 +1849,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const { - ImVector::iterator it = LowerBound(const_cast&>(Data), key); + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) return default_val; return it->val_f; @@ -1857,7 +1857,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const void* ImGuiStorage::GetVoidPtr(ImGuiID key) const { - ImVector::iterator it = LowerBound(const_cast&>(Data), key); + ImGuiStorage::Pair* it = LowerBound(const_cast&>(Data), key); if (it == Data.end() || it->key != key) return NULL; return it->val_p; @@ -1866,7 +1866,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const // References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer. int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) it = Data.insert(it, Pair(key, default_val)); return &it->val_i; @@ -1879,7 +1879,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val) float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) it = Data.insert(it, Pair(key, default_val)); return &it->val_f; @@ -1887,7 +1887,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val) void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) it = Data.insert(it, Pair(key, default_val)); return &it->val_p; @@ -1896,7 +1896,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val) // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame) void ImGuiStorage::SetInt(ImGuiID key, int val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) { Data.insert(it, Pair(key, val)); @@ -1912,7 +1912,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val) void ImGuiStorage::SetFloat(ImGuiID key, float val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) { Data.insert(it, Pair(key, val)); @@ -1923,7 +1923,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val) void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val) { - ImVector::iterator it = LowerBound(Data, key); + ImGuiStorage::Pair* it = LowerBound(Data, key); if (it == Data.end() || it->key != key) { Data.insert(it, Pair(key, val)); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 856531b9..dcaa3660 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4027,7 +4027,7 @@ void ShowExampleAppDocuments(bool* p_open) { static ExampleAppDocuments app; - if (!ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar)) + if (!ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar)) { ImGui::End(); return; diff --git a/imgui_internal.h b/imgui_internal.h index 97520ce3..538759ce 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -332,7 +332,7 @@ enum ImGuiItemStatusFlags_ enum ImGuiLayoutType_ { ImGuiLayoutType_Vertical = 0, - ImGuiLayoutType_Horizontal = 1, + ImGuiLayoutType_Horizontal = 1 }; enum ImGuiAxis From 9ad341902da34e462b73e8bca85e39179f210e6c Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 17:37:22 +0100 Subject: [PATCH 06/12] ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible. --- docs/CHANGELOG.txt | 2 + imgui.h | 8 ++-- imgui_draw.cpp | 116 +++++++++++++++++++++++++-------------------- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 053c8ea2..66ed9545 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other Changes: Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen. Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected into e.g. an error log and stopping the script execution. +- ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible. + (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.) - IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends. - IO: Renamed InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead! - IO: AddInputCharacter() goes into a queue which can receive as many characters as needed during the frame. This is useful diff --git a/imgui.h b/imgui.h index 82c0a62e..4298b3b8 100644 --- a/imgui.h +++ b/imgui.h @@ -1847,11 +1847,11 @@ struct ImDrawList IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0); // Stateful path API, add points then finish with PathFillConvex() or PathStroke() - inline void PathClear() { _Path.resize(0); } + inline void PathClear() { _Path.Size = 0; } inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); } - inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } - inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); } // Note: Anti-aliased filling requires points to be in clockwise order. - inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); PathClear(); } + inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); } + inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. + inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10); IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6853ce0a..9833590f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -656,7 +656,13 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c _IdxWritePtr += 6; } +// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superflous function calls to optimize debug/non-inlined builds. +// Those macros expects l-values. +#define IM_NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } +#define IM_NORMALIZE2F_OVER_EPSILON_CLAMP(VX,VY,EPS,INVLENMAX) { float d2 = VX*VX + VY*VY; if (d2 > EPS) { float inv_len = 1.0f / ImSqrt(d2); if (inv_len > INVLENMAX) inv_len = INVLENMAX; VX *= inv_len; VY *= inv_len; } } + // TODO: Thickness anti-aliased lines cap are missing their AA fringe. +// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds. void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness) { if (points_count < 2) @@ -686,10 +692,11 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 for (int i1 = 0; i1 < count; i1++) { const int i2 = (i1+1) == points_count ? 0 : i1+1; - ImVec2 diff = points[i2] - points[i1]; - diff *= ImInvLength(diff, 1.0f); - temp_normals[i1].x = diff.y; - temp_normals[i1].y = -diff.x; + float dx = points[i2].x - points[i1].x; + float dy = points[i2].y - points[i1].y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i1].x = dy; + temp_normals[i1].y = -dx; } if (!closed) temp_normals[points_count-1] = temp_normals[points_count-2]; @@ -712,17 +719,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+3; // Average normals - ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) - { - float scale = 1.0f / dmr2; - if (scale > 100.0f) scale = 100.0f; - dm *= scale; - } - dm *= AA_SIZE; - temp_points[i2*2+0] = points[i2] + dm; - temp_points[i2*2+1] = points[i2] - dm; + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f) + dm_x *= AA_SIZE; + dm_y *= AA_SIZE; + + // Add temporary vertexes + ImVec2* out_vtx = &temp_points[i2*2]; + out_vtx[0].x = points[i2].x + dm_x; + out_vtx[0].y = points[i2].y + dm_y; + out_vtx[1].x = points[i2].x - dm_x; + out_vtx[1].y = points[i2].y - dm_y; // Add indexes _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); @@ -766,20 +774,24 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 unsigned int idx2 = (i1+1) == points_count ? _VtxCurrentIdx : idx1+4; // Average normals - ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f; - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) - { - float scale = 1.0f / dmr2; - if (scale > 100.0f) scale = 100.0f; - dm *= scale; - } - ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE); - ImVec2 dm_in = dm * half_inner_thickness; - temp_points[i2*4+0] = points[i2] + dm_out; - temp_points[i2*4+1] = points[i2] + dm_in; - temp_points[i2*4+2] = points[i2] - dm_in; - temp_points[i2*4+3] = points[i2] - dm_out; + float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f; + float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f); + float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE); + float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE); + float dm_in_x = dm_x * half_inner_thickness; + float dm_in_y = dm_y * half_inner_thickness; + + // Add temporary vertexes + ImVec2* out_vtx = &temp_points[i2*4]; + out_vtx[0].x = points[i2].x + dm_out_x; + out_vtx[0].y = points[i2].y + dm_out_y; + out_vtx[1].x = points[i2].x + dm_in_x; + out_vtx[1].y = points[i2].y + dm_in_y; + out_vtx[2].x = points[i2].x - dm_in_x; + out_vtx[2].y = points[i2].y - dm_in_y; + out_vtx[3].x = points[i2].x - dm_out_x; + out_vtx[3].y = points[i2].y - dm_out_y; // Add indexes _IdxWritePtr[0] = (ImDrawIdx)(idx2+1); _IdxWritePtr[1] = (ImDrawIdx)(idx1+1); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2); @@ -817,11 +829,13 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 const int i2 = (i1+1) == points_count ? 0 : i1+1; const ImVec2& p1 = points[i1]; const ImVec2& p2 = points[i2]; - ImVec2 diff = p2 - p1; - diff *= ImInvLength(diff, 1.0f); - const float dx = diff.x * (thickness * 0.5f); - const float dy = diff.y * (thickness * 0.5f); + float dx = p2.x - p1.x; + float dy = p2.y - p1.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + dx *= (thickness * 0.5f); + dy *= (thickness * 0.5f); + _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col; _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col; @@ -836,6 +850,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 } } +// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds. void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col) { if (points_count < 3) @@ -867,10 +882,11 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun { const ImVec2& p0 = points[i0]; const ImVec2& p1 = points[i1]; - ImVec2 diff = p1 - p0; - diff *= ImInvLength(diff, 1.0f); - temp_normals[i0].x = diff.y; - temp_normals[i0].y = -diff.x; + float dx = p1.x - p0.x; + float dy = p1.y - p0.y; + IM_NORMALIZE2F_OVER_ZERO(dx, dy); + temp_normals[i0].x = dy; + temp_normals[i0].y = -dx; } for (int i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) @@ -878,19 +894,15 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun // Average normals const ImVec2& n0 = temp_normals[i0]; const ImVec2& n1 = temp_normals[i1]; - ImVec2 dm = (n0 + n1) * 0.5f; - float dmr2 = dm.x*dm.x + dm.y*dm.y; - if (dmr2 > 0.000001f) - { - float scale = 1.0f / dmr2; - if (scale > 100.0f) scale = 100.0f; - dm *= scale; - } - dm *= AA_SIZE * 0.5f; + float dm_x = (n0.x + n1.x) * 0.5f; + float dm_y = (n0.y + n1.y) * 0.5f; + IM_NORMALIZE2F_OVER_EPSILON_CLAMP(dm_x, dm_y, 0.000001f, 100.0f); + dm_x *= AA_SIZE * 0.5f; + dm_y *= AA_SIZE * 0.5f; // Add vertices - _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner - _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer + _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col; // Inner + _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans; // Outer _VtxWritePtr += 2; // Add indexes for fringes @@ -2422,7 +2434,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const { if (c >= IndexLookup.Size) return FallbackGlyph; - const ImWchar i = IndexLookup[c]; + const ImWchar i = IndexLookup.Data[c]; if (i == (ImWchar)-1) return FallbackGlyph; return &Glyphs.Data[i]; @@ -2432,7 +2444,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const { if (c >= IndexLookup.Size) return NULL; - const ImWchar i = IndexLookup[c]; + const ImWchar i = IndexLookup.Data[c]; if (i == (ImWchar)-1) return NULL; return &Glyphs.Data[i]; @@ -2492,7 +2504,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } } - const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX); + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); if (ImCharIsBlankW(c)) { if (inside_word) @@ -2609,7 +2621,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale; + const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; if (line_width + char_width >= max_width) { s = prev_s; From 61a99f994e7127b1b3e8bba53fba2037841a60dc Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 Jan 2019 18:23:28 +0100 Subject: [PATCH 07/12] Minot internal tweaks, comments --- imgui.cpp | 4 +++- imgui_widgets.cpp | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e8194f87..12a10b0b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1351,6 +1351,7 @@ void ImStrTrimBlanks(char* buf) // B) When buf==NULL vsnprintf() will return the output size. #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS +//#define IMGUI_USE_STB_SPRINTF #ifdef IMGUI_USE_STB_SPRINTF #define STB_SPRINTF_IMPLEMENTATION #include "imstb_sprintf.h" @@ -2664,7 +2665,8 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y) const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y); //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG] window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); - window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y)); + window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); + window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x); window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y); //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2edc5d3c..1fbee11c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -204,7 +204,7 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) } ImRect bb(text_pos, text_pos + text_size); - ItemSize(bb); + ItemSize(text_size); ItemAdd(bb, 0); } else @@ -548,7 +548,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f); const ImRect bb(pos, pos + size); - ItemSize(bb, style.FramePadding.y); + ItemSize(size, style.FramePadding.y); if (!ItemAdd(bb, id)) return false; @@ -602,7 +602,7 @@ bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg) const ImGuiID id = window->GetID(str_id); ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); - ItemSize(bb); + ItemSize(size); if (!ItemAdd(bb, id)) return false; From 289569ef278a1beff0987a6d128227d33ce15115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 10 Jan 2019 14:58:59 +0100 Subject: [PATCH 08/12] Update link to Magnum bindings. (#2269) The various community projects that integrated Dear ImGui into Magnum were merged together and are now an official part of the engine. --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index c40aaf54..5f9a188c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -147,7 +147,7 @@ Frameworks: - OpenSceneGraph/OSG: [gist](https://gist.github.com/fulezi/d2442ca7626bf270226014501357042c) - ORX: [pr #1843](https://github.com/ocornut/imgui/pull/1843) - LÖVE+Lua: [love-imgui](https://github.com/slages/love-imgui) -- Magnum: [magnum-imgui](https://github.com/lecopivo/magnum-imgui), [MagnumImguiPort](https://github.com/lecopivo/MagnumImguiPort) +- Magnum: [ImGuiIntegration](https://doc.magnum.graphics/magnum/namespaceMagnum_1_1ImGuiIntegration.html) ([example](https://doc.magnum.graphics/magnum/examples-imgui.html)) - NanoRT: [syoyo/imgui](https://github.com/syoyo/imgui/tree/nanort) - Qt3d: [imgui-qt3d](https://github.com/alpqr/imgui-qt3d), QOpenGLWindow [qtimgui](https://github.com/ocornut/imgui/issues/1910) - SFML: [imgui-sfml](https://github.com/EliasD/imgui-sfml) From 81eaa497732d72c569604ff1d3cb73da677c5a85 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:14:51 +0100 Subject: [PATCH 09/12] Internals: Added comment index in imgui_internal.h --- imgui_internal.h | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 538759ce..ee266441 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -6,8 +6,27 @@ // #define IMGUI_DEFINE_MATH_OPERATORS // To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators) +/* + +Index of this file: +// Header mess +// Forward declarations +// STB libraries includes +// Context pointer +// Generic helpers +// Misc data structures +// Main imgui context +// Tab bar, tab item +// Internal API + +*/ + #pragma once +//----------------------------------------------------------------------------- +// Header mess +//----------------------------------------------------------------------------- + #ifndef IMGUI_VERSION #error Must include imgui.h before imgui_internal.h #endif @@ -30,7 +49,7 @@ #endif //----------------------------------------------------------------------------- -// Forward Declarations +// Forward declarations //----------------------------------------------------------------------------- struct ImRect; // An axis-aligned rectangle (2 points) @@ -68,7 +87,7 @@ typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior() //------------------------------------------------------------------------- -// STB libraries +// STB libraries includes //------------------------------------------------------------------------- namespace ImGuiStb @@ -84,7 +103,7 @@ namespace ImGuiStb } // namespace ImGuiStb //----------------------------------------------------------------------------- -// Context +// Context pointer //----------------------------------------------------------------------------- #ifndef GImGui @@ -92,7 +111,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe #endif //----------------------------------------------------------------------------- -// Helpers +// Generic helpers //----------------------------------------------------------------------------- #define IM_PI 3.14159265358979323846f @@ -242,7 +261,7 @@ struct IMGUI_API ImPool }; //----------------------------------------------------------------------------- -// Types +// Misc data structures //----------------------------------------------------------------------------- // 1D vector (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches) @@ -1172,7 +1191,7 @@ struct ImGuiItemHoveredDataBackup }; //----------------------------------------------------------------------------- -// Tab Bar, Tab Item +// Tab bar, tab item //----------------------------------------------------------------------------- enum ImGuiTabBarFlagsPrivate_ From 1f6e0b2f9818f4475d119d587352c83e90786618 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 9 Jan 2019 14:11:31 +0100 Subject: [PATCH 10/12] ImVector: Made a struct. Using T/T* in the code instead of value_type/iterator. Renamed index_from_pointer() to index_from_ptr() (was not documented, added in 1.63, users not supposed to use ImVector, hopefully not a big deal). --- imgui.cpp | 4 +-- imgui.h | 78 ++++++++++++++++++++++++----------------------- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 12a10b0b..c9b4188b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4384,7 +4384,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) { // Retrieve settings from .ini file - window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings); + window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); window->Pos = ImFloor(settings->Pos); window->Collapsed = settings->Collapsed; @@ -8940,7 +8940,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting if (!settings) { settings = ImGui::CreateNewWindowSettings(window->Name); - window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings); + window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); } IM_ASSERT(settings->ID == window->ID); settings->Pos = window->Pos; diff --git a/imgui.h b/imgui.h index 4298b3b8..d790b6f4 100644 --- a/imgui.h +++ b/imgui.h @@ -1157,55 +1157,57 @@ enum ImGuiCond_ // Helper: ImVector<> // Lightweight std::vector<>-like class to avoid dragging dependencies (also: some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. +// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. // Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, // do NOT use this class as a std::vector replacement in your own code! //----------------------------------------------------------------------------- template -class ImVector +struct ImVector { -public: - int Size; - int Capacity; - T* Data; + int Size; + int Capacity; + T* Data; + // Provide standard typedefs but we don't use them ourselves. typedef T value_type; typedef value_type* iterator; typedef const value_type* const_iterator; - inline ImVector() { Size = Capacity = 0; Data = NULL; } - inline ~ImVector() { if (Data) ImGui::MemFree(Data); } - inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } - inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; } + // Constructors, destructor + inline ImVector() { Size = Capacity = 0; Data = NULL; } + inline ImVector(const ImVector& src) { Size = Capacity = 0; Data = NULL; operator=(src); } + inline ImVector& operator=(const ImVector& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } + inline ~ImVector() { if (Data) ImGui::MemFree(Data); } - inline bool empty() const { return Size == 0; } - inline int size() const { return Size; } - inline int capacity() const { return Capacity; } - inline value_type& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } - inline const value_type& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } + inline bool empty() const { return Size == 0; } + inline int size() const { return Size; } + inline int capacity() const { return Capacity; } + inline T& operator[](int i) { IM_ASSERT(i < Size); return Data[i]; } + inline const T& operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; } - inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } - inline iterator begin() { return Data; } - inline const_iterator begin() const { return Data; } - inline iterator end() { return Data + Size; } - inline const_iterator end() const { return Data + Size; } - inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; } - inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; } - inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } - inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } + inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } } + inline T* begin() { return Data; } + inline const T* begin() const { return Data; } + inline T* end() { return Data + Size; } + inline const T* end() const { return Data + Size; } + inline T& front() { IM_ASSERT(Size > 0); return Data[0]; } + inline const T& front() const { IM_ASSERT(Size > 0); return Data[0]; } + inline T& back() { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline const T& back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; } + inline void swap(ImVector& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; } - inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } - inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } - inline void resize(int new_size,const value_type& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } + inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } + inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } + inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; - value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type)); + T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { - memcpy(new_data, Data, (size_t)Size * sizeof(value_type)); + memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; @@ -1213,15 +1215,15 @@ public: } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. - inline void push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } - inline void pop_back() { IM_ASSERT(Size > 0); Size--; } - inline void push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); } - inline iterator erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; } - inline iterator erase(const_iterator it, const_iterator it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(value_type)); Size -= (int)count; return Data + off; } - inline iterator erase_unsorted(const_iterator it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(value_type)); Size--; return Data + off; } - inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } - inline bool contains(const value_type& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } - inline int index_from_pointer(const_iterator it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } + inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } + inline void pop_back() { IM_ASSERT(Size > 0); Size--; } + inline void push_front(const T& v) { if (Size == 0) push_back(v); else insert(Data, v); } + inline T* erase(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; } + inline T* erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data+Size && it_last > it && it_last <= Data+Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; } + inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; } + inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; } + inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; } + inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; } }; //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index ee266441..51f3a3f7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1240,7 +1240,7 @@ struct ImGuiTabBar short LastTabItemIdx; // For BeginTabItem()/EndTabItem() ImGuiTabBar(); - int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_pointer(tab); } + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } }; //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1fbee11c..d65a420b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6286,7 +6286,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, tab->Width = size.x; tab_is_new = true; } - tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_pointer(tab); + tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); tab->WidthContents = size.x; const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); From 7ffbcfe46725985e62665d637add60e091a5e64c Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 9 Jan 2019 15:56:37 +0100 Subject: [PATCH 11/12] ImVector: Made reserve() another silly one-liner. It's not longer than other functions and our weird obsessions deserve to be carried with stringent consistence. + Comments --- imgui.h | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index d790b6f4..3cac4336 100644 --- a/imgui.h +++ b/imgui.h @@ -1200,19 +1200,7 @@ struct ImVector inline int _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; } inline void resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; } inline void resize(int new_size, const T& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; } - inline void reserve(int new_capacity) - { - if (new_capacity <= Capacity) - return; - T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); - if (Data) - { - memcpy(new_data, Data, (size_t)Size * sizeof(T)); - ImGui::MemFree(Data); - } - Data = new_data; - Capacity = new_capacity; - } + inline void reserve(int new_capacity) { if (new_capacity <= Capacity) return; T* new_data = (T*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); ImGui::MemFree(Data); } Data = new_data; Capacity = new_capacity; } // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden. inline void push_back(const T& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; } From e4c19f5af18f167f52cb67810235c8125b0a8340 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 10 Jan 2019 13:15:29 +0100 Subject: [PATCH 12/12] ImFontGlyphRangesBuilder: Using 32-bits fields for storage instead of 8-bit ones, comments, todo. --- docs/TODO.txt | 1 + imgui.h | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 8b60c057..5e3f73ff 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -319,6 +319,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - optimization: replace vsnprintf with stb_printf? or enable the defines/infrastructure to allow it (#1038) - optimization: add clipping for multi-component widgets (SliderFloatX, ColorEditX, etc.). one problem is that nav branch can't easily clip parent group when there is a move request. - optimization: add a flag to disable most of rendering, for the case where the user expect to skip it (#335) + - optimization: fully covered window (covered by another with non-translucent bg + WindowRounding worth of padding) may want to clip rendering. - optimization: use another hash function than crc32, e.g. FNV1a - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)? - optimization: turn some the various stack vectors into statically-sized arrays diff --git a/imgui.h b/imgui.h index 3cac4336..dad97c6f 100644 --- a/imgui.h +++ b/imgui.h @@ -13,14 +13,14 @@ Index of this file: // Forward declarations and basic types // ImGui API (Dear ImGui end-user API) // Flags & Enumerations -// ImVector +// ImVector<> // ImGuiStyle // ImGuiIO // Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload) // Obsolete functions // Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor) // Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData) -// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFont) +// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) */ @@ -1155,11 +1155,11 @@ enum ImGuiCond_ //----------------------------------------------------------------------------- // Helper: ImVector<> -// Lightweight std::vector<>-like class to avoid dragging dependencies (also: some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). +// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. // Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. // Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, -// do NOT use this class as a std::vector replacement in your own code! +// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. //----------------------------------------------------------------------------- template @@ -1933,12 +1933,14 @@ struct ImFontGlyph }; // Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). +// This is essentially a tightly packed of vector of 64k booleans = 8KB storage. struct ImFontGlyphRangesBuilder { - ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) - ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); } - bool GetBit(int n) const { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; } - void SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); } // Set bit 'c' in the array + ImVector UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used) + + ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / 32); memset(UsedChars.Data, 0, 0x10000 / 32); } + bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array + void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array void AddChar(ImWchar c) { SetBit(c); } // Add character IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added) IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext