From 81cfe09657891236fe45839842f67119e6d2eef1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Oct 2024 15:44:44 +0100 Subject: [PATCH 001/716] Selectable, Style: selected Selectable() use _Header color instead of an arbitrary lerp between _Header and _HeaderHovered. (#8106, #1861) --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 2 +- imgui_widgets.cpp | 8 ++------ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 194803ac6de1..4e987c00379e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- Selectable: selected Selectables use ImGuiCol_Header instead of an arbitrary lerp + between _Header and _HeaderHovered which was introduced v1.91 (#8106, #1861) - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. - Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f24254e2ea40..c6c06a58cd16 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10220,7 +10220,7 @@ struct ExampleAssetsBrowser // Rendering parameters const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) }; - const ImU32 icon_bg_color = ImGui::GetColorU32(ImGuiCol_MenuBarBg); + const ImU32 icon_bg_color = ImGui::GetColorU32(IM_COL32(35, 35, 35, 220)); const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f); const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 757eb8ab68d7..ee15e990ac66 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7017,12 +7017,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl const bool highlighted = hovered || (flags & ImGuiSelectableFlags_Highlight); if (highlighted || selected) { - // FIXME-MULTISELECT: Styling: Color for 'selected' elements? ImGuiCol_HeaderSelected - ImU32 col; - if (selected && !highlighted) - col = GetColorU32(ImLerp(GetStyleColorVec4(ImGuiCol_Header), GetStyleColorVec4(ImGuiCol_HeaderHovered), 0.5f)); - else - col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header); + // Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106) + ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(bb.Min, bb.Max, col, false, 0.0f); } if (g.NavId == id) From 81b689b9693df736386026916b598eeedf43a9bb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Oct 2024 15:52:37 +0100 Subject: [PATCH 002/716] Backends: OpenGL3: added additional debug GL_CALL enclosure for glCreateShader() calls. (#8104) --- backends/imgui_impl_opengl3.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index f5235096faff..c03156a7e174 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -895,13 +895,15 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() // Create shaders const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader }; - GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER); + GLuint vert_handle; + GL_CALL(vert_handle = glCreateShader(GL_VERTEX_SHADER)); glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr); glCompileShader(vert_handle); CheckShader(vert_handle, "vertex shader"); const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader }; - GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER); + GLuint frag_handle; + GL_CALL(frag_handle = glCreateShader(GL_FRAGMENT_SHADER)); glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr); glCompileShader(frag_handle); CheckShader(frag_handle, "fragment shader"); From d67e2eea1a0775066bb966ac8bbb9ecd6b5c48ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Oct 2024 16:43:41 +0100 Subject: [PATCH 003/716] Backends: Win32: internal rename. --- backends/imgui_impl_win32.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 477d54abe97e..97735ae33fe9 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -559,22 +559,10 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) #define DBT_DEVNODES_CHANGED 0x0007 #endif -// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) -// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. -// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. -// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. -// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. -// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. -// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. -// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. -#if 0 -// Copy this line into your .cpp file to forward declare the function. -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); -#endif - +// Helper to obtain the source of mouse messages. // See https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages // Prefer to call this at the top of the message handler to avoid the possibility of other Win32 calls interfering with this. -static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() +static ImGuiMouseSource ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo() { LPARAM extra_info = ::GetMessageExtraInfo(); if ((extra_info & 0xFFFFFF80) == 0xFF515700) @@ -584,6 +572,18 @@ static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() return ImGuiMouseSource_Mouse; } +// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) +// Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. +// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. +// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. + +// Copy this line into your .cpp file to forward declare the function: +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). @@ -599,7 +599,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA case WM_NCMOUSEMOVE: { // We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events - ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); + ImGuiMouseSource mouse_source = ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo(); const int area = (msg == WM_MOUSEMOVE) ? 1 : 2; bd->MouseHwnd = hwnd; if (bd->MouseTrackedArea != area) @@ -646,7 +646,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: { - ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); + ImGuiMouseSource mouse_source = ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo(); int button = 0; if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) { button = 0; } if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } @@ -664,7 +664,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA case WM_MBUTTONUP: case WM_XBUTTONUP: { - ImGuiMouseSource mouse_source = GetMouseSourceFromMessageExtraInfo(); + ImGuiMouseSource mouse_source = ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo(); int button = 0; if (msg == WM_LBUTTONUP) { button = 0; } if (msg == WM_RBUTTONUP) { button = 1; } From 3b8c7d0326d307598edce07e53f03614f972b757 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Oct 2024 16:58:07 +0100 Subject: [PATCH 004/716] Backends: Win32: rework to add ImGui_ImplWin32_WndProcHandlerEx() not using current context (experimental). (#8069, #6293, #5856, #586) + GetIOEx(). Amend fedf45c + cba656a. Amend 416cfdb9. --- backends/imgui_impl_win32.cpp | 94 +++++++++++++++++++---------------- imgui.cpp | 7 +++ imgui.h | 2 +- imgui_internal.h | 1 + 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 97735ae33fe9..c213f8158011 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -133,12 +133,16 @@ static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplWin32_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } +static ImGui_ImplWin32_Data* ImGui_ImplWin32_GetBackendData(ImGuiIO& io) +{ + return (ImGui_ImplWin32_Data*)io.BackendPlatformUserData; +} // Functions -static void ImGui_ImplWin32_UpdateKeyboardCodePage() +static void ImGui_ImplWin32_UpdateKeyboardCodePage(ImGuiIO& io) { // Retrieve keyboard code page, required for handling of non-Unicode Windows. - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); HKL keyboard_layout = ::GetKeyboardLayout(0); LCID keyboard_lcid = MAKELCID(HIWORD(keyboard_layout), SORT_DEFAULT); if (::GetLocaleInfoA(keyboard_lcid, (LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE), (LPSTR)&bd->KeyboardCodePage, sizeof(bd->KeyboardCodePage)) == 0) @@ -168,7 +172,7 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) bd->TicksPerSecond = perf_frequency; bd->Time = perf_counter; bd->LastMouseCursor = ImGuiMouseCursor_COUNT; - ImGui_ImplWin32_UpdateKeyboardCodePage(); + ImGui_ImplWin32_UpdateKeyboardCodePage(io); // Set platform dependent data in viewport ImGuiViewport* main_viewport = ImGui::GetMainViewport(); @@ -228,13 +232,11 @@ void ImGui_ImplWin32_Shutdown() IM_DELETE(bd); } -static bool ImGui_ImplWin32_UpdateMouseCursor() +static bool ImGui_ImplWin32_UpdateMouseCursor(ImGuiIO& io, ImGuiMouseCursor imgui_cursor) { - ImGuiIO& io = ImGui::GetIO(); if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) return false; - ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) { // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor @@ -266,42 +268,39 @@ static bool IsVkDown(int vk) return (::GetKeyState(vk) & 0x8000) != 0; } -static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) +static void ImGui_ImplWin32_AddKeyEvent(ImGuiIO& io, ImGuiKey key, bool down, int native_keycode, int native_scancode = -1) { - ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(key, down); io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code) IM_UNUSED(native_scancode); } -static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds() +static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds(ImGuiIO& io) { // Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one. if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftShift, false, VK_LSHIFT); if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightShift, false, VK_RSHIFT); // Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW). if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftSuper, false, VK_LWIN); if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN)) - ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN); + ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightSuper, false, VK_RWIN); } -static void ImGui_ImplWin32_UpdateKeyModifiers() +static void ImGui_ImplWin32_UpdateKeyModifiers(ImGuiIO& io) { - ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(ImGuiMod_Ctrl, IsVkDown(VK_CONTROL)); io.AddKeyEvent(ImGuiMod_Shift, IsVkDown(VK_SHIFT)); io.AddKeyEvent(ImGuiMod_Alt, IsVkDown(VK_MENU)); io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN)); } -static void ImGui_ImplWin32_UpdateMouseData() +static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io) { - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); IM_ASSERT(bd->hWnd != 0); HWND focused_window = ::GetForegroundWindow(); @@ -328,11 +327,10 @@ static void ImGui_ImplWin32_UpdateMouseData() } // Gamepad navigation mapping -static void ImGui_ImplWin32_UpdateGamepads() +static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) { #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. // return; @@ -381,7 +379,9 @@ static void ImGui_ImplWin32_UpdateGamepads() MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768); #undef MAP_BUTTON #undef MAP_ANALOG -#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +#else // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD + IM_UNUSED(io); +#endif } void ImGui_ImplWin32_NewFrame() @@ -402,21 +402,21 @@ void ImGui_ImplWin32_NewFrame() bd->Time = current_time; // Update OS mouse position - ImGui_ImplWin32_UpdateMouseData(); + ImGui_ImplWin32_UpdateMouseData(io); // Process workarounds for known Windows key handling issues - ImGui_ImplWin32_ProcessKeyEventsWorkarounds(); + ImGui_ImplWin32_ProcessKeyEventsWorkarounds(io); // Update OS mouse cursor with the cursor requested by imgui ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); if (bd->LastMouseCursor != mouse_cursor) { bd->LastMouseCursor = mouse_cursor; - ImGui_ImplWin32_UpdateMouseCursor(); + ImGui_ImplWin32_UpdateMouseCursor(io, mouse_cursor); } // Update game controllers (if enabled and available) - ImGui_ImplWin32_UpdateGamepads(); + ImGui_ImplWin32_UpdateGamepads(io); } // Map VK_xxx to ImGuiKey_xxx. @@ -578,21 +578,27 @@ static ImGuiMouseSource ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo() // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. -// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds. // PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. -// Copy this line into your .cpp file to forward declare the function: -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +// Copy either line into your .cpp file to forward declare the function: +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Use ImGui::GetCurrentContext() +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io); // Doesn't use ImGui::GetCurrentContext() IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). // We silently allow both context or just only backend data to be nullptr. - ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); - if (bd == nullptr) + if (ImGui::GetCurrentContext() == NULL) return 0; - ImGuiIO& io = ImGui::GetIO(); + return ImGui_ImplWin32_WndProcHandlerEx(hwnd, msg, wParam, lParam, ImGui::GetIO()); +} +// This version is in theory thread-safe in the sense that no path should access ImGui::GetCurrentContext(). +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io) +{ + ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); + if (bd == NULL) + return 0; switch (msg) { case WM_MOUSEMOVE: @@ -653,7 +659,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } if (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr) - ::SetCapture(hwnd); + ::SetCapture(hwnd); // Allow us to read mouse coordinates when dragging mouse outside of our window bounds. bd->MouseButtonsDown |= 1 << button; io.AddMouseSourceEvent(mouse_source); io.AddMouseButtonEvent(button, true); @@ -692,7 +698,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA if (wParam < 256) { // Submit modifiers - ImGui_ImplWin32_UpdateKeyModifiers(); + ImGui_ImplWin32_UpdateKeyModifiers(io); // Obtain virtual key code and convert to ImGuiKey const ImGuiKey key = ImGui_ImplWin32_KeyEventToImGuiKey(wParam, lParam); @@ -701,28 +707,28 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA // Special behavior for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit the key down event. if (key == ImGuiKey_PrintScreen && !is_key_down) - ImGui_ImplWin32_AddKeyEvent(key, true, vk, scancode); + ImGui_ImplWin32_AddKeyEvent(io, key, true, vk, scancode); // Submit key event if (key != ImGuiKey_None) - ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode); + ImGui_ImplWin32_AddKeyEvent(io, key, is_key_down, vk, scancode); // Submit individual left/right modifier events if (vk == VK_SHIFT) { // Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds() - if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } - if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } + if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); } + if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); } } else if (vk == VK_CONTROL) { - if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } - if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } + if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); } + if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); } } else if (vk == VK_MENU) { - if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } - if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } + if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); } + if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(io, ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); } } } return 0; @@ -732,7 +738,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA io.AddFocusEvent(msg == WM_SETFOCUS); return 0; case WM_INPUTLANGCHANGE: - ImGui_ImplWin32_UpdateKeyboardCodePage(); + ImGui_ImplWin32_UpdateKeyboardCodePage(io); return 0; case WM_CHAR: if (::IsWindowUnicode(hwnd)) @@ -750,7 +756,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA return 0; case WM_SETCURSOR: // This is required to restore cursor when transitioning from e.g resize borders to client area. - if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor(io, bd->LastMouseCursor)) return 1; return 0; case WM_DEVICECHANGE: diff --git a/imgui.cpp b/imgui.cpp index 81f872f7ba61..25089e0fd962 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4748,6 +4748,13 @@ ImGuiIO& ImGui::GetIO() return GImGui->IO; } +// This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856) +ImGuiIO& ImGui::GetIOEx(ImGuiContext* ctx) +{ + IM_ASSERT(ctx != NULL); + return ctx->IO; +} + ImGuiPlatformIO& ImGui::GetPlatformIO() { IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?"); diff --git a/imgui.h b/imgui.h index 04f958eec69b..eb3991d972d1 100644 --- a/imgui.h +++ b/imgui.h @@ -2248,7 +2248,7 @@ struct ImGuiIO // Keyboard/Gamepad Navigation options bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. - bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. + bool ConfigNavMoveSetMousePos; // = false // Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true. bool ConfigNavCaptureKeyboard; // = true // Sets io.WantCaptureKeyboard when io.NavActive is set. bool ConfigNavEscapeClearFocusItem; // = true // Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on. bool ConfigNavEscapeClearFocusWindow;// = false // Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem). diff --git a/imgui_internal.h b/imgui_internal.h index 0c441a260b9c..fab1573031d2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2936,6 +2936,7 @@ namespace ImGui // If this ever crashes because g.CurrentWindow is NULL, it means that either: // - ImGui::NewFrame() has never been called, which is illegal. // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. + IMGUI_API ImGuiIO& GetIOEx(ImGuiContext* ctx); inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); From 0bde57c25a90ee1b99e511385611db6185d318f8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Oct 2024 11:47:03 +0100 Subject: [PATCH 005/716] Font, Misc: remove qualifier from most font functions. Fixed ClearOutputData() not clearing Used4kPagesMap (mostly harmless). --- backends/imgui_impl_dx10.h | 2 +- backends/imgui_impl_dx11.cpp | 2 +- backends/imgui_impl_dx11.h | 2 +- backends/imgui_impl_dx12.h | 2 +- backends/imgui_impl_wgpu.h | 2 +- docs/CHANGELOG.txt | 1 + imgui.cpp | 2 +- imgui.h | 16 ++++++++-------- imgui_draw.cpp | 15 ++++++++------- 9 files changed, 23 insertions(+), 21 deletions(-) diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 95759737b590..667f296f17bd 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -26,7 +26,7 @@ IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 16d480e0867b..b928bb86fbc0 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -23,7 +23,7 @@ // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer. // 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled). -// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. +// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX11_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. // 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 57b19bc037ee..c3b8379b14b7 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -29,8 +29,8 @@ IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX11_RenderDrawData() call. diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 5da528573429..1e36d730f77b 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -37,8 +37,8 @@ IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX12_RenderDrawData() call. diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index e4398575c11d..f9fb037764f6 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -52,8 +52,8 @@ IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame(); IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder); // Use if you want to reset your rendering device without losing Dear ImGui state. -IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects(); IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects(); // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplWGPU_RenderDrawData() call. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4e987c00379e..7443976155d5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,7 @@ Other changes: - Selectable: selected Selectables use ImGuiCol_Header instead of an arbitrary lerp between _Header and _HeaderHovered which was introduced v1.91 (#8106, #1861) +- Fonts: removed const qualifiers from most font functions. - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. - Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the diff --git a/imgui.cpp b/imgui.cpp index 25089e0fd962..94358e41714b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3637,7 +3637,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con // min max ellipsis_max // <-> this is generally some padding value - const ImFont* font = draw_list->_Data->Font; + ImFont* font = draw_list->_Data->Font; const float font_size = draw_list->_Data->FontSize; const float font_scale = draw_list->_Data->FontScale; const char* text_end_ellipsis = NULL; diff --git a/imgui.h b/imgui.h index eb3991d972d1..7aec7b0e254e 100644 --- a/imgui.h +++ b/imgui.h @@ -3122,7 +3122,7 @@ struct ImDrawList IMGUI_API void AddEllipse(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f); IMGUI_API void AddEllipseFilled(const ImVec2& center, const ImVec2& radius, ImU32 col, float rot = 0.0f, int num_segments = 0); IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL); - IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); + IMGUI_API void AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL); IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points) IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points) @@ -3471,18 +3471,18 @@ struct ImFont // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const; - IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const; - float GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c); + IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c); + float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } bool IsLoaded() const { return ContainerAtlas != NULL; } const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. - IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8 - IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const; - IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const; - IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const; + IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 + IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width); + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c); + IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); // [Internal] Don't use! IMGUI_API void BuildLookupTable(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 01723b35c97d..d54c96babcbb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1646,7 +1646,7 @@ void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const Im PathStroke(col, 0, thickness); } -void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) +void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -3638,6 +3638,7 @@ void ImFont::ClearOutputData() DirtyLookupTables = true; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; + memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); } static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) @@ -3822,7 +3823,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; } -const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const +const ImFontGlyph* ImFont::FindGlyph(ImWchar c) { if (c >= (size_t)IndexLookup.Size) return FallbackGlyph; @@ -3832,7 +3833,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const return &Glyphs.Data[i]; } -const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const +const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) { if (c >= (size_t)IndexLookup.Size) return NULL; @@ -3855,7 +3856,7 @@ static inline const char* CalcWordWrapNextLineStartA(const char* text, const cha // Simple word-wrapping for English, not full-featured. Please submit failing cases! // This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) -const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const +const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { // For references, possible wrap point marked with ^ // "aaa bbb, ccc,ddd. eee fff. ggg!" @@ -3953,7 +3954,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c return s; } -ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const +ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) { if (!text_end) text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. @@ -4032,7 +4033,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) const +void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) { const ImFontGlyph* glyph = FindGlyph(c); if (!glyph || !glyph->Visible) @@ -4047,7 +4048,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const +void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) { if (!text_end) text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. From 9a0dff1bc56bff17269ec922f78b03ca838e3ea2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 29 Oct 2024 14:26:02 +0100 Subject: [PATCH 006/716] Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use PressedOnClick instead of PressedOnClickRelease when unspecified. --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_widgets.cpp | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7443976155d5..82c6b226638a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - Selectable: selected Selectables use ImGuiCol_Header instead of an arbitrary lerp between _Header and _HeaderHovered which was introduced v1.91 (#8106, #1861) +- Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use + PressedOnClick instead of PressedOnClickRelease when unspecified. - Fonts: removed const qualifiers from most font functions. - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. diff --git a/imgui.h b/imgui.h index 7aec7b0e254e..6f6779abf054 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.5 WIP" -#define IMGUI_VERSION_NUM 19141 +#define IMGUI_VERSION_NUM 19142 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ee15e990ac66..1ee9a962437c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -495,19 +495,19 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); + // Default behavior inherited from item flags + // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.ItemFlags : g.CurrentItemFlags); + if (flags & ImGuiButtonFlags_AllowOverlap) + item_flags |= ImGuiItemFlags_AllowOverlap; + // Default only reacts to left mouse button if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) flags |= ImGuiButtonFlags_MouseButtonLeft; // Default behavior requires click + release inside bounding box if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0) - flags |= ImGuiButtonFlags_PressedOnDefault_; - - // Default behavior inherited from item flags - // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. - ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.ItemFlags : g.CurrentItemFlags); - if (flags & ImGuiButtonFlags_AllowOverlap) - item_flags |= ImGuiItemFlags_AllowOverlap; + flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_; ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; From a4fcc93f4af38e567de0a09e40b67134158be5de Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Oct 2024 15:07:26 +0100 Subject: [PATCH 007/716] Log/Capture: renaming ImGuiLogType to ImGuiLogFlags --- imgui.cpp | 33 +++++++++++++++++---------------- imgui_internal.h | 20 ++++++++++++-------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 94358e41714b..44a17508ff52 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4007,7 +4007,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) memset(LocalizationTable, 0, sizeof(LocalizationTable)); LogEnabled = false; - LogType = ImGuiLogType_None; + LogFlags = ImGuiLogFlags_None; LogNextPrefix = LogNextSuffix = NULL; LogFile = NULL; LogLinePosY = FLT_MAX; @@ -14324,15 +14324,16 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* } // Start logging/capturing text output -void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) +void ImGui::LogBegin(ImGuiLogFlags flags, int auto_open_depth) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(g.LogEnabled == false); - IM_ASSERT(g.LogFile == NULL); - IM_ASSERT(g.LogBuffer.empty()); + IM_ASSERT(g.LogFile == NULL && g.LogBuffer.empty()); + IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiLogFlags_OutputMask_)); // Check that only 1 type flag is used + g.LogEnabled = g.ItemUnclipByLog = true; - g.LogType = type; + g.LogFlags = flags; g.LogNextPrefix = g.LogNextSuffix = NULL; g.LogDepthRef = window->DC.TreeDepth; g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); @@ -14355,7 +14356,7 @@ void ImGui::LogToTTY(int auto_open_depth) return; IM_UNUSED(auto_open_depth); #ifndef IMGUI_DISABLE_TTY_FUNCTIONS - LogBegin(ImGuiLogType_TTY, auto_open_depth); + LogBegin(ImGuiLogFlags_OutputTTY, auto_open_depth); g.LogFile = stdout; #endif } @@ -14381,7 +14382,7 @@ void ImGui::LogToFile(int auto_open_depth, const char* filename) return; } - LogBegin(ImGuiLogType_File, auto_open_depth); + LogBegin(ImGuiLogFlags_OutputFile, auto_open_depth); g.LogFile = f; } @@ -14391,7 +14392,7 @@ void ImGui::LogToClipboard(int auto_open_depth) ImGuiContext& g = *GImGui; if (g.LogEnabled) return; - LogBegin(ImGuiLogType_Clipboard, auto_open_depth); + LogBegin(ImGuiLogFlags_OutputClipboard, auto_open_depth); } void ImGui::LogToBuffer(int auto_open_depth) @@ -14399,7 +14400,7 @@ void ImGui::LogToBuffer(int auto_open_depth) ImGuiContext& g = *GImGui; if (g.LogEnabled) return; - LogBegin(ImGuiLogType_Buffer, auto_open_depth); + LogBegin(ImGuiLogFlags_OutputBuffer, auto_open_depth); } void ImGui::LogFinish() @@ -14409,29 +14410,29 @@ void ImGui::LogFinish() return; LogText(IM_NEWLINE); - switch (g.LogType) + switch (g.LogFlags & ImGuiLogFlags_OutputMask_) { - case ImGuiLogType_TTY: + case ImGuiLogFlags_OutputTTY: #ifndef IMGUI_DISABLE_TTY_FUNCTIONS fflush(g.LogFile); #endif break; - case ImGuiLogType_File: + case ImGuiLogFlags_OutputFile: ImFileClose(g.LogFile); break; - case ImGuiLogType_Buffer: + case ImGuiLogFlags_OutputBuffer: break; - case ImGuiLogType_Clipboard: + case ImGuiLogFlags_OutputClipboard: if (!g.LogBuffer.empty()) SetClipboardText(g.LogBuffer.begin()); break; - case ImGuiLogType_None: + default: IM_ASSERT(0); break; } g.LogEnabled = g.ItemUnclipByLog = false; - g.LogType = ImGuiLogType_None; + g.LogFlags = ImGuiLogFlags_None; g.LogFile = NULL; g.LogBuffer.clear(); } diff --git a/imgui_internal.h b/imgui_internal.h index fab1573031d2..af7270be8c7a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -177,6 +177,7 @@ typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // F typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow() typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns() +typedef int ImGuiLogFlags; // -> enum ImGuiLogFlags_ // Flags: for LogBegin() text capturing function typedef int ImGuiNavRenderCursorFlags; // -> enum ImGuiNavRenderCursorFlags_//Flags: for RenderNavCursor() typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions @@ -989,13 +990,16 @@ enum ImGuiLayoutType_ ImGuiLayoutType_Vertical = 1 }; -enum ImGuiLogType +// Flags for LogBegin() text capturing function +enum ImGuiLogFlags_ { - ImGuiLogType_None = 0, - ImGuiLogType_TTY, - ImGuiLogType_File, - ImGuiLogType_Buffer, - ImGuiLogType_Clipboard, + ImGuiLogFlags_None = 0, + + ImGuiLogFlags_OutputTTY = 1 << 0, + ImGuiLogFlags_OutputFile = 1 << 1, + ImGuiLogFlags_OutputBuffer = 1 << 2, + ImGuiLogFlags_OutputClipboard = 1 << 3, + ImGuiLogFlags_OutputMask_ = ImGuiLogFlags_OutputTTY | ImGuiLogFlags_OutputFile | ImGuiLogFlags_OutputBuffer | ImGuiLogFlags_OutputClipboard, }; // X/Y enums are fixed to 0/1 so they may be used to index ImVec2 @@ -2316,7 +2320,7 @@ struct ImGuiContext // Capture/Logging bool LogEnabled; // Currently capturing - ImGuiLogType LogType; // Capture target + ImGuiLogFlags LogFlags; // Capture flags/type ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. const char* LogNextPrefix; @@ -3067,7 +3071,7 @@ namespace ImGui IMGUI_API void EndDisabledOverrideReenable(); // Logging/Capture - IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. + IMGUI_API void LogBegin(ImGuiLogFlags flags, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); From f37a9a27e582ad5316186f017e66b662efd9ca6b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Oct 2024 15:10:35 +0100 Subject: [PATCH 008/716] Log/Capture: reworked scope + decorating menus, tabs. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 4 +++- imgui_internal.h | 1 + imgui_widgets.cpp | 4 ++++ 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 82c6b226638a..c20f0f04794d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Other changes: - Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use PressedOnClick instead of PressedOnClickRelease when unspecified. - Fonts: removed const qualifiers from most font functions. +- Log/Capture: better decorating of BeginMenu() and TabItem() output. +- Log/Capture: a non terminated log ends automatically in the window which called it. - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. - Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the diff --git a/imgui.cpp b/imgui.cpp index 44a17508ff52..5d079f4aea54 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4008,6 +4008,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) LogEnabled = false; LogFlags = ImGuiLogFlags_None; + LogWindow = NULL; LogNextPrefix = LogNextSuffix = NULL; LogFile = NULL; LogLinePosY = FLT_MAX; @@ -7748,7 +7749,7 @@ void ImGui::End() } // Stop logging - if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging + if (g.LogWindow == window) // FIXME: add more options for scope of logging LogFinish(); if (window->DC.IsSetPos) @@ -14334,6 +14335,7 @@ void ImGui::LogBegin(ImGuiLogFlags flags, int auto_open_depth) g.LogEnabled = g.ItemUnclipByLog = true; g.LogFlags = flags; + g.LogWindow = window; g.LogNextPrefix = g.LogNextSuffix = NULL; g.LogDepthRef = window->DC.TreeDepth; g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); diff --git a/imgui_internal.h b/imgui_internal.h index af7270be8c7a..932a0484ca86 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2321,6 +2321,7 @@ struct ImGuiContext // Capture/Logging bool LogEnabled; // Currently capturing ImGuiLogFlags LogFlags; // Capture flags/type + ImGuiWindow* LogWindow; ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. const char* LogNextPrefix; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1ee9a962437c..def3f5870a4c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8811,6 +8811,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) float w = label_size.x; ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y)); + LogSetNextTextDecoration("[", "]"); RenderText(text_pos, label); PopStyleVar(); window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar(). @@ -8827,6 +8828,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y)); + LogSetNextTextDecoration("", ">"); RenderText(text_pos, label); if (icon_w > 0.0f) RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon); @@ -9040,6 +9042,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut if (shortcut_w > 0.0f) { PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); + LogSetNextTextDecoration("(", ")"); RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL, false); PopStyleColor(); } @@ -10288,6 +10291,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; ellipsis_max_x = text_pixel_clip_bb.Max.x; } + LogSetNextTextDecoration("/", "\\"); RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); #if 0 From 772ca9e9a9d9c8f7c90730b751279490fa427f7d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Oct 2024 15:14:02 +0100 Subject: [PATCH 009/716] Log/Capture: added experimental io.ConfigWindowsCopyContentsWithCtrlC config option. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 18 ++++++++---------- imgui.h | 5 +++-- imgui_demo.cpp | 4 +++- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c20f0f04794d..026448b767bd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,10 @@ Other changes: - Fonts: removed const qualifiers from most font functions. - Log/Capture: better decorating of BeginMenu() and TabItem() output. - Log/Capture: a non terminated log ends automatically in the window which called it. +- Log/Capture: added experimental io.ConfigWindowsCopyContentsWithCtrlC option to + automatically copy window contents into clipboard using CTRL+C. This is experimental + because (1) it currently breaks on nested Begin/End, (2) text output quality varies, + and (3) text output comes in submission order rather than spatial order. - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. - Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the diff --git a/imgui.cpp b/imgui.cpp index 5d079f4aea54..b24f75068666 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1422,6 +1422,7 @@ ImGuiIO::ImGuiIO() ConfigDragClickToInputText = false; ConfigWindowsResizeFromEdges = true; ConfigWindowsMoveFromTitleBarOnly = false; + ConfigWindowsCopyContentsWithCtrlC = false; ConfigScrollbarScrollByPage = true; ConfigMemoryCompactTimer = 60.0f; ConfigDebugIsDebuggerPresent = false; @@ -7587,6 +7588,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (want_focus && window == g.NavWindow) NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls + // Pressing CTRL+C copy window content into the clipboard + // [EXPERIMENTAL] Breaks on nested Begin/End pairs. We need to work that out and add better logging scope. + // [EXPERIMENTAL] Text outputs has many issues. + if (g.IO.ConfigWindowsCopyContentsWithCtrlC) + if (g.NavWindow && g.NavWindow->RootWindow == window && g.ActiveId == 0 && Shortcut(ImGuiMod_Ctrl | ImGuiKey_C)) + LogToClipboard(0); + // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open); @@ -7597,16 +7605,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) if (flags & ImGuiWindowFlags_Tooltip) g.TooltipPreviousWindow = window; - // Pressing CTRL+C while holding on a window copy its content to the clipboard - // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope. - // Maybe we can support CTRL+C on every element? - /* - //if (g.NavWindow == window && g.ActiveId == 0) - if (g.ActiveId == window->MoveId) - if (g.IO.KeyCtrl && IsKeyPressed(ImGuiKey_C)) - LogToClipboard(); - */ - // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. SetLastItemDataForWindow(window, title_bar_rect); diff --git a/imgui.h b/imgui.h index 6f6779abf054..726c97f7366b 100644 --- a/imgui.h +++ b/imgui.h @@ -2242,7 +2242,7 @@ struct ImGuiIO // Font system ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. float FontGlobalScale; // = 1.0f // Global scale all fonts - bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. + bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with CTRL+Wheel. ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. @@ -2263,8 +2263,9 @@ struct ImGuiIO bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting). bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only). bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard. - bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) + bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag) bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar. + bool ConfigWindowsCopyContentsWithCtrlC; // = false // [EXPERIMENTAL] CTRL+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order. bool ConfigScrollbarScrollByPage; // = true // Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location. float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c6c06a58cd16..1a52b0ed2a7c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -549,8 +549,10 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); - ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback."); + ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); + ImGui::Checkbox("io.ConfigWindowsCopyContentsWithCtrlC", &io.ConfigWindowsCopyContentsWithCtrlC); // [EXPERIMENTAL] + ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* CTRL+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order."); ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage); ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location."); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); From 71c77c081ac36841e682498229088e7678207112 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Oct 2024 15:41:45 +0100 Subject: [PATCH 010/716] Demo: added a "Windows" section. --- imgui_demo.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1a52b0ed2a7c..f44aedc6e4c7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -541,13 +541,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.ConfigNavCursorVisibleAlways", &io.ConfigNavCursorVisibleAlways); ImGui::SameLine(); HelpMarker("Navigation cursor is always visible."); - ImGui::SeparatorText("Widgets"); - ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); - ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); - ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); - ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); - ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); - ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); + ImGui::SeparatorText("Windows"); ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges); ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires ImGuiBackendFlags_HasMouseCursors for better mouse cursor feedback."); ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly); @@ -555,6 +549,14 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::SameLine(); HelpMarker("*EXPERIMENTAL* CTRL+C copy the contents of focused window into the clipboard.\n\nExperimental because:\n- (1) has known issues with nested Begin/End pairs.\n- (2) text output quality varies.\n- (3) text output is in submission order rather than spatial order."); ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage); ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location."); + + ImGui::SeparatorText("Widgets"); + ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink); + ImGui::SameLine(); HelpMarker("Enable blinking cursor (optional as some users consider it to be distracting)."); + ImGui::Checkbox("io.ConfigInputTextEnterKeepActive", &io.ConfigInputTextEnterKeepActive); + ImGui::SameLine(); HelpMarker("Pressing Enter will keep item active and select contents (single-line only)."); + ImGui::Checkbox("io.ConfigDragClickToInputText", &io.ConfigDragClickToInputText); + ImGui::SameLine(); HelpMarker("Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving)."); ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors); ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors."); ImGui::Text("Also see Style->Rendering for rendering options."); From f77d22837c0d2e8d0582cd1e8f077a88fa6ebd9b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Nov 2024 14:24:54 +0100 Subject: [PATCH 011/716] Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll(). (#8013) --- docs/CHANGELOG.txt | 4 +++- examples/example_android_opengl3/main.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 026448b767bd..02297a64bdf9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,7 +60,9 @@ Other changes: actual include. (#8095, #7967, #3190) [@sev-] - Backends: SDL2, SDL3: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten target. (#4019, #6096, #1463) -- Examples: Added SDL3+Vulkan example. (#8084, #8085) +- Examples: SDL3+Vulkan: Added example. (#8084, #8085) +- Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll() + which has been deprecated. (#8013) [@feather179] ----------------------------------------------------------------------- VERSION 1.91.4 (Released 2024-10-18) diff --git a/examples/example_android_opengl3/main.cpp b/examples/example_android_opengl3/main.cpp index e0ad5f9360c8..42aa622f762f 100644 --- a/examples/example_android_opengl3/main.cpp +++ b/examples/example_android_opengl3/main.cpp @@ -68,7 +68,7 @@ void android_main(struct android_app* app) struct android_poll_source* out_data; // Poll all events. If the app is not visible, this loop blocks until g_Initialized == true. - while (ALooper_pollAll(g_Initialized ? 0 : -1, nullptr, &out_events, (void**)&out_data) >= 0) + while (ALooper_pollOnce(g_Initialized ? 0 : -1, nullptr, &out_events, (void**)&out_data) >= 0) { // Process one event if (out_data != nullptr) From 75f83de52abe2b419eacbcbbee5d62c99f65b85b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Nov 2024 19:48:40 +0100 Subject: [PATCH 012/716] InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within a callback would sometimes prevents further appending to the buffer. (#7925) There's a confusion between TextA.Size and CurLenA we should be merging them. Amend 19accb14a --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_internal.h | 2 +- imgui_widgets.cpp | 6 ++++-- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 02297a64bdf9..7bb626478e4b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Other changes: - Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use PressedOnClick instead of PressedOnClickRelease when unspecified. - Fonts: removed const qualifiers from most font functions. +- InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within + a callback would sometimes prevents further appending to the buffer. - Log/Capture: better decorating of BeginMenu() and TabItem() output. - Log/Capture: a non terminated log ends automatically in the window which called it. - Log/Capture: added experimental io.ConfigWindowsCopyContentsWithCtrlC option to diff --git a/imgui.h b/imgui.h index 726c97f7366b..9fd077379422 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.5 WIP" -#define IMGUI_VERSION_NUM 19142 +#define IMGUI_VERSION_NUM 19143 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 932a0484ca86..18b1467778be 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1111,7 +1111,7 @@ struct IMGUI_API ImGuiInputTextState ImStbTexteditState* Stb; // State for stb_textedit.h ImGuiID ID; // widget id owning the text state int CurLenA; // UTF-8 length of the string in TextA (in bytes) - ImVector TextA; // main UTF8 buffer. + ImVector TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1). ImVector InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) ImVector CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack int BufCapacityA; // end-user buffer capacity diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index def3f5870a4c..40e482d45205 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4200,6 +4200,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (new_text == new_text_end) return; + // Grow internal buffer if needed const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); if (new_text_len + BufTextLen >= BufSize) @@ -4213,7 +4214,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); IM_ASSERT(Buf == edit_state->TextA.Data); int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; - edit_state->TextA.reserve(new_buf_size + 1); + edit_state->TextA.resize(new_buf_size + 1); Buf = edit_state->TextA.Data; BufSize = edit_state->BufCapacityA = new_buf_size; } @@ -5034,7 +5035,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() - state->TextA.Size = state->CurLenA + 1; state->CursorAnimReset(); } } @@ -5342,6 +5342,8 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); + Text("TextA.Size: %d, Capacity: %d", state->TextA.Size, state->TextA.Capacity); + Text("BufCapacityA: %d", state->BufCapacityA); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state From 82d0584e7bbefdd5de1d181f8bcf6eb6d656d525 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 4 Nov 2024 20:24:36 +0100 Subject: [PATCH 013/716] InputText: using CurLenA instead of TextA.Size for correctness. (#7925) Was harmless because TextA is always zero-terminated, and TextA.Size >= CurLenA + 1. --- imgui_widgets.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 40e482d45205..01828c5e8310 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3930,7 +3930,7 @@ namespace ImStb { static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenA; } static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->CurLenA); return obj->TextA[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->TextA.Size); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->CurLenA); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } static char STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { @@ -3953,7 +3953,7 @@ static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int id if (idx >= obj->CurLenA) return obj->CurLenA + 1; unsigned int c; - return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->TextA.Size); + return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->CurLenA); } static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) @@ -3986,8 +3986,8 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) const char* curr_p = obj->TextA.Data + idx; const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextA.Data + obj->TextA.Size); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextA.Data + obj->TextA.Size); + unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextA.Data + obj->CurLenA); + unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextA.Data + obj->CurLenA); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4002,8 +4002,8 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) const char* curr_p = obj->TextA.Data + idx; const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextA.Data + obj->TextA.Size); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextA.Data + obj->TextA.Size); + unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextA.Data + obj->CurLenA); + unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextA.Data + obj->CurLenA); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -5342,8 +5342,8 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); - Text("TextA.Size: %d, Capacity: %d", state->TextA.Size, state->TextA.Capacity); Text("BufCapacityA: %d", state->BufCapacityA); + Text("(Internal Buffer: TextA Size: %d, Capacity: %d)", state->TextA.Size, state->TextA.Capacity); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); if (BeginChild("undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY)) // Visualize undo state From d4791f1bbef15fa407c853bf845ee1adefb0b940 Mon Sep 17 00:00:00 2001 From: Brotcrunsher Date: Tue, 5 Nov 2024 10:12:52 +0100 Subject: [PATCH 014/716] Fixed a comment typo. (#8128) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 9fd077379422..27e3bda5e706 100644 --- a/imgui.h +++ b/imgui.h @@ -3065,7 +3065,7 @@ enum ImDrawListFlags_ // access the current window draw list and draw custom primitives. // You can interleave normal ImGui:: calls and adding primitives to the current draw list. // In single viewport mode, top-left is == GetMainViewport()->Pos (generally 0,0), bottom-right is == GetMainViewport()->Pos+Size (generally io.DisplaySize). -// You are totally free to apply whatever transformation matrix to want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) +// You are totally free to apply whatever transformation matrix you want to the data (depending on the use of the transformation you may want to apply it to ClipRect as well!) // Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects. struct ImDrawList { From 88e232739bc9da4c4070a9c912b7ebee0acc84f6 Mon Sep 17 00:00:00 2001 From: Maya Warrier <34803055+mayawarrier@users.noreply.github.com> Date: Tue, 5 Nov 2024 04:44:39 -0500 Subject: [PATCH 015/716] Ignore clang warning Wnontrivial-memaccess (#8129) Produced when memset(this, ..) is used on a non-trivially copyable type --- backends/imgui_impl_metal.mm | 7 +++++++ backends/imgui_impl_osx.mm | 7 +++++++ imgui_draw.cpp | 1 + imgui_internal.h | 1 + 4 files changed, 16 insertions(+) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index b8f82a65ded5..102f6982afd8 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -38,6 +38,13 @@ #import #import +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#endif +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#endif + #pragma mark - Support classes // A wrapper around a MTLBuffer object that knows the last time it was reused diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index de9b57408a06..6ff4f19a42c5 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -27,6 +27,13 @@ #import #import +#if defined(__clang__) +#if __has_warning("-Wunknown-warning-option") +#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' +#endif +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#endif + // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d54c96babcbb..2385d2ed8c1b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -66,6 +66,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used diff --git a/imgui_internal.h b/imgui_internal.h index 18b1467778be..ad90e0309c2f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -91,6 +91,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn' #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind From be2d006e2e7e9f029e893ff358d9acc87c250411 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 5 Nov 2024 10:50:49 +0100 Subject: [PATCH 016/716] Align warning blocks. Removed -Wunused-function, -Wmissing-prototypes from imgui_internal.h As supposedly they were for stb_textedit.h which is now moved to imgui_draw.cpp --- imgui.cpp | 18 +++++++++--------- imgui.h | 8 ++++---- imgui_demo.cpp | 12 ++++++------ imgui_draw.cpp | 14 +++++++------- imgui_internal.h | 12 +++++------- 5 files changed, 31 insertions(+), 33 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b24f75068666..01a72c6b7b3c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1126,15 +1126,15 @@ CODE #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #elif defined(__GNUC__) // We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association. -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif // Debug options diff --git a/imgui.h b/imgui.h index 27e3bda5e706..973a52f53468 100644 --- a/imgui.h +++ b/imgui.h @@ -130,15 +130,15 @@ Index of this file: #pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' #endif #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' -#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #elif defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif //----------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f44aedc6e4c7..f5e16f06c161 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -145,12 +145,12 @@ Index of this file: #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. #endif // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2385d2ed8c1b..ac6d0228196e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -68,12 +68,12 @@ Index of this file: #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used -#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function -#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value -#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value +#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif //------------------------------------------------------------------------- @@ -102,7 +102,7 @@ namespace IMGUI_STB_NAMESPACE #if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma clang diagnostic ignored "-Wmissing-prototypes" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" #pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier diff --git a/imgui_internal.h b/imgui_internal.h index ad90e0309c2f..a35ab64e2e12 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -82,11 +82,9 @@ Index of this file: #endif #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok, for ImFloor() -#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h -#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h -#pragma clang diagnostic ignored "-Wold-style-cast" -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -#pragma clang diagnostic ignored "-Wdouble-promotion" +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant +#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wmissing-noreturn" // warning: function 'xxx' could be declared with attribute 'noreturn' #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated @@ -94,8 +92,8 @@ Index of this file: #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #endif From 63234f8dd0a2acf5fa48184798382ea1e045ab3a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 5 Nov 2024 11:32:02 +0100 Subject: [PATCH 017/716] InputText: Internals: rename CurLenA->TextLen, InitialTextA->TextToRevertTo. Follow the refactors in #7925. --- imgui_internal.h | 10 ++--- imgui_widgets.cpp | 96 +++++++++++++++++++++++------------------------ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index a35ab64e2e12..6d84f1027aca 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1109,11 +1109,11 @@ struct IMGUI_API ImGuiInputTextState ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). ImStbTexteditState* Stb; // State for stb_textedit.h ImGuiID ID; // widget id owning the text state - int CurLenA; // UTF-8 length of the string in TextA (in bytes) + int TextLen; // UTF-8 length of the string in TextA (in bytes) ImVector TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1). - ImVector InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) + ImVector TextToRevertTo; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) ImVector CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack - int BufCapacityA; // end-user buffer capacity + int BufCapacity; // end-user buffer capacity (include zero terminator) ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y) float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) @@ -1126,8 +1126,8 @@ struct IMGUI_API ImGuiInputTextState ImGuiInputTextState(); ~ImGuiInputTextState(); - void ClearText() { CurLenA = 0; TextA[0] = 0; CursorClamp(); } - void ClearFreeMemory() { TextA.clear(); InitialTextA.clear(); } + void ClearText() { TextLen = 0; TextA[0] = 0; CursorClamp(); } + void ClearFreeMemory() { TextA.clear(); TextToRevertTo.clear(); } void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation void OnCharPressed(unsigned int c); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 01828c5e8310..9d572422283f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3928,15 +3928,15 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c // - ...but we don't use that feature. namespace ImStb { -static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenA; } -static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->CurLenA); return obj->TextA[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->CurLenA); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } +static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->TextLen; } +static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextA[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } static char STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { const char* text = obj->TextA.Data; const char* text_remaining = NULL; - const ImVec2 size = InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->CurLenA, &text_remaining, NULL, true); + const ImVec2 size = InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->TextLen, &text_remaining, NULL, true); r->x0 = 0.0f; r->x1 = size.x; r->baseline_y_delta = size.y; @@ -3950,10 +3950,10 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) { - if (idx >= obj->CurLenA) - return obj->CurLenA + 1; + if (idx >= obj->TextLen) + return obj->TextLen + 1; unsigned int c; - return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->CurLenA); + return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->TextLen); } static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) @@ -3986,8 +3986,8 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) const char* curr_p = obj->TextA.Data + idx; const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextA.Data + obj->CurLenA); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextA.Data + obj->CurLenA); + unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextA.Data + obj->TextLen); + unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextA.Data + obj->TextLen); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4002,8 +4002,8 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) const char* curr_p = obj->TextA.Data + idx; const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextA.Data + obj->CurLenA); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextA.Data + obj->CurLenA); + unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextA.Data + obj->TextLen); + unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextA.Data + obj->TextLen); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4020,7 +4020,7 @@ static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) } static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { - int len = obj->CurLenA; + int len = obj->TextLen; idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); while (idx < len && !is_word_boundary_from_left(obj, idx)) idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); @@ -4029,7 +4029,7 @@ static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); - int len = obj->CurLenA; + int len = obj->TextLen; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx); return idx > len ? len : idx; @@ -4043,7 +4043,7 @@ static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) char* dst = obj->TextA.Data + pos; obj->Edited = true; - obj->CurLenA -= n; + obj->TextLen -= n; // Offset remaining text (FIXME-OPT: Use memmove) const char* src = obj->TextA.Data + pos + n; @@ -4055,10 +4055,10 @@ static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const char* new_text, int new_text_len) { const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; - const int text_len = obj->CurLenA; + const int text_len = obj->TextLen; IM_ASSERT(pos <= text_len); - if (!is_resizable && (new_text_len + obj->CurLenA + 1 > obj->BufCapacityA)) + if (!is_resizable && (new_text_len + obj->TextLen + 1 > obj->BufCapacity)) return false; // Grow internal buffer if needed @@ -4075,8 +4075,8 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ch memcpy(text + pos, new_text, (size_t)new_text_len); obj->Edited = true; - obj->CurLenA += new_text_len; - obj->TextA[obj->CurLenA] = '\0'; + obj->TextLen += new_text_len; + obj->TextA[obj->TextLen] = '\0'; return true; } @@ -4108,8 +4108,8 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ch // the stb_textedit_paste() function creates two separate records, so we perform it manually. (FIXME: Report to nothings/stb?) static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len) { - stb_text_makeundo_replace(str, state, 0, str->CurLenA, text_len); - ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenA); + stb_text_makeundo_replace(str, state, 0, str->TextLen, text_len); + ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->TextLen); state->cursor = state->select_start = state->select_end = 0; if (text_len <= 0) return; @@ -4157,13 +4157,13 @@ void ImGuiInputTextState::OnCharPressed(unsigned int c) // Those functions are not inlined in imgui_internal.h, allowing us to hide ImStbTexteditState from that header. void ImGuiInputTextState::CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking -void ImGuiInputTextState::CursorClamp() { Stb->cursor = ImMin(Stb->cursor, CurLenA); Stb->select_start = ImMin(Stb->select_start, CurLenA); Stb->select_end = ImMin(Stb->select_end, CurLenA); } +void ImGuiInputTextState::CursorClamp() { Stb->cursor = ImMin(Stb->cursor, TextLen); Stb->select_start = ImMin(Stb->select_start, TextLen); Stb->select_end = ImMin(Stb->select_end, TextLen); } bool ImGuiInputTextState::HasSelection() const { return Stb->select_start != Stb->select_end; } void ImGuiInputTextState::ClearSelection() { Stb->select_start = Stb->select_end = Stb->cursor; } int ImGuiInputTextState::GetCursorPos() const { return Stb->cursor; } int ImGuiInputTextState::GetSelectionStart() const { return Stb->select_start; } int ImGuiInputTextState::GetSelectionEnd() const { return Stb->select_end; } -void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = CurLenA; Stb->has_preferred_x = 0; } +void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = TextLen; Stb->has_preferred_x = 0; } void ImGuiInputTextState::ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } void ImGuiInputTextState::ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } @@ -4216,7 +4216,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; edit_state->TextA.resize(new_buf_size + 1); Buf = edit_state->TextA.Data; - BufSize = edit_state->BufCapacityA = new_buf_size; + BufSize = edit_state->BufCapacity = new_buf_size; } if (BufTextLen != pos) @@ -4380,8 +4380,8 @@ void ImGui::InputTextDeactivateHook(ImGuiID id) else { IM_ASSERT(state->TextA.Data != 0); - g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1); - memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1); + g.InputTextDeactivatedState.TextA.resize(state->TextLen + 1); + memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->TextLen + 1); } } @@ -4521,21 +4521,21 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!init_reload_from_user_buf) { // Take a copy of the initial buffer value. - state->InitialTextA.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. - memcpy(state->InitialTextA.Data, buf, buf_len + 1); + state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); } // Preserve cursor position and undo/redo stack if we come back to same widget // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? bool recycle_state = (state->ID == id && !init_changed_specs && !init_reload_from_user_buf); - if (recycle_state && (state->CurLenA != buf_len || (strncmp(state->TextA.Data, buf, buf_len) != 0))) + if (recycle_state && (state->TextLen != buf_len || (strncmp(state->TextA.Data, buf, buf_len) != 0))) recycle_state = false; // Start edition state->ID = id; state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. - state->CurLenA = (int)strlen(buf); - memcpy(state->TextA.Data, buf, state->CurLenA + 1); + state->TextLen = (int)strlen(buf); + memcpy(state->TextA.Data, buf, state->TextLen + 1); if (recycle_state) { @@ -4646,7 +4646,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { IM_ASSERT(state != NULL); state->Edited = false; - state->BufCapacityA = buf_size; + state->BufCapacity = buf_size; state->Flags = flags; // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. @@ -4871,7 +4871,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) { const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0; - const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->CurLenA; + const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->TextLen; char backup = state->TextA.Data[ie]; state->TextA.Data[ie] = 0; // A bit of a hack since SetClipboardText only takes null terminated strings @@ -4936,15 +4936,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IMSTB_TEXTEDIT_CHARTYPE empty_string; stb_textedit_replace(state, state->Stb, &empty_string, 0); } - else if (strcmp(buf, state->InitialTextA.Data) != 0) + else if (strcmp(buf, state->TextToRevertTo.Data) != 0) { - apply_new_text = state->InitialTextA.Data; - apply_new_text_length = state->InitialTextA.Size - 1; + apply_new_text = state->TextToRevertTo.Data; + apply_new_text_length = state->TextToRevertTo.Size - 1; // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents. // Push records into the undo stack so we can CTRL+Z the revert operation itself value_changed = true; - stb_textedit_replace(state, state->Stb, state->InitialTextA.Data, state->InitialTextA.Size - 1); + stb_textedit_replace(state, state->Stb, state->TextToRevertTo.Data, state->TextToRevertTo.Size - 1); } } @@ -5003,14 +5003,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.UserData = callback_user_data; // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 - state->CallbackTextBackup.resize(state->CurLenA + 1); - memcpy(state->CallbackTextBackup.Data, state->TextA.Data, state->CurLenA + 1); + state->CallbackTextBackup.resize(state->TextLen + 1); + memcpy(state->CallbackTextBackup.Data, state->TextA.Data, state->TextLen + 1); char* callback_buf = is_readonly ? buf : state->TextA.Data; callback_data.EventKey = event_key; callback_data.Buf = callback_buf; - callback_data.BufTextLen = state->CurLenA; - callback_data.BufSize = state->BufCapacityA; + callback_data.BufTextLen = state->TextLen; + callback_data.BufSize = state->BufCapacity; callback_data.BufDirty = false; const int utf8_cursor_pos = callback_data.CursorPos = state->Stb->cursor; @@ -5023,7 +5023,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Read back what user may have modified callback_buf = is_readonly ? buf : state->TextA.Data; // Pointer may have been invalidated by a resize callback IM_ASSERT(callback_data.Buf == callback_buf); // Invalid to modify those fields - IM_ASSERT(callback_data.BufSize == state->BufCapacityA); + IM_ASSERT(callback_data.BufSize == state->BufCapacity); IM_ASSERT(callback_data.Flags == flags); const bool buf_dirty = callback_data.BufDirty; if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb->cursor = callback_data.CursorPos; state->CursorFollow = true; } @@ -5034,7 +5034,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Callback may update buffer and thus set buf_dirty even in read-only mode. IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? - state->CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() + state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() state->CursorAnimReset(); } } @@ -5044,7 +5044,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) { apply_new_text = state->TextA.Data; - apply_new_text_length = state->CurLenA; + apply_new_text_length = state->TextLen; value_changed = true; } } @@ -5128,7 +5128,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { IM_ASSERT(state != NULL); if (!is_displaying_hint) - buf_display_end = buf_display + state->CurLenA; + buf_display_end = buf_display + state->TextLen; // Render text (with cursor and selection) // This is going to be messy. We need to: @@ -5138,7 +5138,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. const char* text_begin = state->TextA.Data; - const char* text_end = text_begin + state->CurLenA; + const char* text_end = text_begin + state->TextLen; ImVec2 cursor_offset, select_start_offset; { @@ -5280,7 +5280,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) * g.FontSize); // We don't need width else if (!is_displaying_hint && g.ActiveId == id) - buf_display_end = buf_display + state->CurLenA; + buf_display_end = buf_display + state->TextLen; else if (!is_displaying_hint) buf_display_end = buf_display + strlen(buf_display); @@ -5341,8 +5341,8 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) ImStb::StbUndoState* undo_state = &stb_state->undostate; Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); - Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end); - Text("BufCapacityA: %d", state->BufCapacityA); + Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->TextLen, stb_state->cursor, stb_state->select_start, stb_state->select_end); + Text("BufCapacityA: %d", state->BufCapacity); Text("(Internal Buffer: TextA Size: %d, Capacity: %d)", state->TextA.Size, state->TextA.Capacity); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); From ec2f1d69c8d8d6373d64ee0ffb29b51b78925d65 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 5 Nov 2024 13:18:16 +0100 Subject: [PATCH 018/716] Docs: word-wrap some the older changelogs. --- docs/CHANGELOG.txt | 765 +++++++++++++++++++++++++++++++-------------- 1 file changed, 523 insertions(+), 242 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7bb626478e4b..9e43a56a1faa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -4597,20 +4597,27 @@ Other Changes: - See https://github.com/ocornut/imgui/issues/1599 for recommended gamepad mapping or download PNG/PSD at http://goo.gl/9LgVZW - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. Read imgui.cpp for more details. - To use Keyboard Navigation: - - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, Escape to cancel/close, Ctrl-Tab to focus windows, etc. - - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set. - For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. + - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically + fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. + - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, + Escape to cancel/close, Ctrl-Tab to focus windows, etc. + - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), + the io.WantCaptureKeyboard flag will be set. + - For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. - Navigation: SetItemDefaultFocus() sets the navigation position in addition to scrolling. (#787) - Navigation: Added IsItemFocused(), added IsAnyItemFocused(). (#787) - Navigation: Added window flags: ImGuiWindowFlags_NoNav (== ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus). - Navigation: Style: Added ImGuiCol_NavHighlight, ImGuiCol_NavWindowingHighlight colors. (#787) - Navigation: TreeNode: Added ImGuiTreeNodeFlags_NavLeftJumpsBackHere flag to allow Nav Left direction to jump back to parent tree node from any of its child. (#1079) - Navigation: IO: Added io.ConfigFlags (input), io.NavActive (output), io.NavVisible (output). (#787) -- Context: Removed the default global context and font atlas instances, which caused various problems to users of multiple contexts and DLL users. (#1565, #1599) - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. Existing apps will assert/crash without it. -- Context: Added SetAllocatorFunctions() to rewire memory allocators (as a replacement to previous parameters to CreateContext()). Allocators are shared by all contexts and imgui helpers. (#1565, #586, #992, #1007, #1558) -- Context: You may pass a ImFontAtlas to CreateContext() to specify a font atlas to share. Shared font atlas are not owned by the context and not destroyed along with it. (#1599) +- Context: Removed the default global context and font atlas instances, which caused various + problems to users of multiple contexts and DLL users. (#1565, #1599) YOU NOW NEED TO CALL + ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. + Existing apps will assert/crash without it. +- Context: Added SetAllocatorFunctions() to rewire memory allocators (as a replacement to previous + parameters to CreateContext()). Allocators are shared by all contexts and imgui helpers. (#1565, #586, #992, #1007, #1558) +- Context: You may pass a ImFontAtlas to CreateContext() to specify a font atlas to share. + Shared font atlas are not owned by the context and not destroyed along with it. (#1599) - Context: Added IMGUI_DISABLE_DEFAULT_ALLOCATORS to disable linking with malloc/free. (#1565, #586, #992, #1007, #1558) - IO: Added io.ConfigFlags for user application to store settings for imgui and for the backend: - ImGuiConfigFlags_NavEnableKeyboard: Enable keyboard navigation. @@ -4619,61 +4626,85 @@ Other Changes: - ImGuiConfigFlags_NoMouseCursorChange: Instruct backend to not alter mouse cursor shape and visibility (by default the example backend use mouse cursor API of the platform when available) - ImGuiConfigFlags_NoMouse: Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information passed by the backend. - ImGuiConfigFlags_IsSRGB, ImGuiConfigFlags_IsTouchScreen: Flags for general application use. -- IO: Added io.BackendFlags for backend to store its capabilities (currently: _HasGamepad, _HasMouseCursors, _HasSetMousePos). This will be used more in the next version. +- IO: Added io.BackendFlags for backend to store its capabilities (currently: _HasGamepad, + _HasMouseCursors, _HasSetMousePos). This will be used more in the next version. - IO: Added ImGuiKey_Insert, ImGuiKey_Space keys. Setup in all example backends. (#1541) - IO: Added Horizontal Mouse Wheel support for horizontal scrolling. (#1463) [@tseeker] - IO: Added IsAnyMouseDown() helper which is helpful for backends to handle mouse capturing. -- Window: Clicking on a window with the ImGuiWIndowFlags_NoMove flags takes an ActiveId so we can't hover something else when dragging afterwards. (#1381, #1337) -- Window: IsWindowHovered(): Added ImGuiHoveredFlags_AnyWindow, ImGuiFocusedFlags_AnyWindow flags (See Breaking Changes). Added to demo. (#1382) -- Window: Added SetNextWindowBgAlpha() helper. Particularly helpful since the legacy 5-parameters version of Begin() has been marked as obsolete in 1.53. (#1567) -- Window: Fixed SetNextWindowContentSize() with 0.0f on Y axis (or SetNextWindowContentWidth()) overwriting the contents size. Got broken on Dec 10 (1.53). (#1363) +- Window: Clicking on a window with the ImGuiWIndowFlags_NoMove flags takes an ActiveId so + we can't hover something else when dragging afterwards. (#1381, #1337) +- Window: IsWindowHovered(): Added ImGuiHoveredFlags_AnyWindow, ImGuiFocusedFlags_AnyWindow flags + (See Breaking Changes). Added to demo. (#1382) +- Window: Added SetNextWindowBgAlpha() helper. Particularly helpful since the legacy 5-parameters + version of Begin() has been marked as obsolete in 1.53. (#1567) +- Window: Fixed SetNextWindowContentSize() with 0.0f on Y axis (or SetNextWindowContentWidth()) + overwriting the contents size. Got broken on Dec 10 (1.53). (#1363) - ArrowButton: Added ArrowButton() given a cardinal direction (e.g. ImGuiDir_Left). - InputText: Added alternative clipboard shortcuts: Shift+Delete (cut), CTRL+Insert (copy), Shift+Insert (paste). (#1541) -- InputText: Fixed losing Cursor X position when clicking outside on an item that's submitted after the InputText(). It was only noticeable when restoring focus programmatically. (#1418, #1554) -- InputText: Added ImGuiInputTextFlags_CharsScientific flag to also allow 'e'/'E' for input of values using scientific notation. Automatically used by InputFloat. +- InputText: Fixed losing Cursor X position when clicking outside on an item that's submitted + after the InputText(). It was only noticeable when restoring focus programmatically. (#1418, #1554) +- InputText: Added ImGuiInputTextFlags_CharsScientific flag to also allow 'e'/'E' for input of values + using scientific notation. Automatically used by InputFloat. - Style: Default style is now StyleColorsDark(), instead of the old StyleColorsClassic(). (#707) - Style: Enable window border by default. (#707) -- Style: Exposed ImGuiStyleVar_WindowTitleAlign, ImGuiStyleVar_ScrollbarSize, ImGuiStyleVar_ScrollbarRounding, ImGuiStyleVar_GrabRounding + added an assert to reduce accidental breakage. (#1181) +- Style: Exposed ImGuiStyleVar_WindowTitleAlign, ImGuiStyleVar_ScrollbarSize, ImGuiStyleVar_ScrollbarRounding, + ImGuiStyleVar_GrabRounding + added an assert to reduce accidental breakage. (#1181) - Style: Added style.MouseCursorScale help when using the software mouse cursor facility. (#939). - Style: Close button nows display a cross before hovering. Fixed cross positioning being a little off. Uses button colors for highlight when hovering. (#707) - Popup: OpenPopup() Always reopen existing pop-ups. (Removed imgui_internal.h's OpenPopupEx() which was used for this.) (#1497, #1533). - Popup: BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick() all react on mouse release instead of mouse press. (~#439) -- Popup: Better handling of user mistakenly calling OpenPopup() every frame (with reopen_existing option). The error will now be more visible and easier to understand. (#1497) +- Popup: Better handling of user mistakenly calling OpenPopup() every frame (with the 'reopen_existing' option). + The error will now be more visible and easier to understand. (#1497) - Popup: BeginPopup(): Exposed extra_flags parameter that are passed through to Begin(). (#1533) -- Popup: BeginPopupModal: fixed the conditional test for SetNextWindowPos() which was polling the wrong window, which in practice made the test succeed all the time. +- Popup: BeginPopupModal: fixed the conditional test for SetNextWindowPos() which was polling + the wrong window, which in practice made the test succeed all the time. - Tooltip: BeginTooltip() sets ImGuiWindowFlags_NoInputs flag. -- Scrollbar: Fixed ScrollbarY enable test after ScrollbarX has been enabled being a little off (small regression from Nov 2017). (#1574) -- Scrollbar: Fixed ScrollbarX enable test subtracting WindowPadding.x (this has been there since the addition of horizontal scroll bar!). +- Scrollbar: Fixed ScrollbarY enable test after ScrollbarX has been enabled being a little + off (small regression from Nov 2017). (#1574) +- Scrollbar: Fixed ScrollbarX enable test subtracting WindowPadding.x (this has been there + since the addition of horizontal scroll bar!). - Columns: Clear offsets data when columns count changed. (#1525) - Columns: Fixed a memory leak of ImGuiColumnsSet's Columns vector. (#1529) [@unprompted] - Columns: Fixed resizing a window very small breaking some columns positioning (broken in 1.53). -- Columns: The available column extent takes consideration of the right-most clipped pixel, so the right-most column may look a little wider but will contain the same amount of visible contents. +- Columns: The available column extent takes consideration of the right-most clipped pixel, + so the right-most column may look a little wider but will contain the same amount of visible contents. - MenuBar: Fixed menu bar pushing a clipping rect outside of its allocated bound (usually unnoticeable). - TreeNode: nodes with the ImGuiTreeNodeFlags_Leaf flag correctly disable highlight when DragDrop is active. (#143, #581) - Drag and Drop: Increased payload type string to 32 characters instead of 8. (#143) - Drag and Drop: TreeNode as drop target displays rectangle over full frame. (#1597, #143) - DragFloat: Fix/workaround for backends which do not preserve a valid mouse position when dragged out of bounds. (#1559) - InputFloat: Allow inputing value using scientific notation e.g. "1e+10". -- InputDouble: Added InputDouble() function. We use a format string instead of a decimal_precision parameter to also for "%e" and variants. (#1011) +- InputDouble: Added InputDouble() function. We use a format string instead of a 'decimal_precision' + parameter to also for "%e" and variants. (#1011) - Slider, Combo: Use ImGuiCol_FrameBgHovered color when hovered. (#1456) [@stfx] -- Combo: BeginCombo(): Added ImGuiComboFlags_NoArrowButton to disable the arrow button and only display the wide value preview box. -- Combo: BeginCombo(): Added ImGuiComboFlags_NoPreview to disable the preview and only display a square arrow button. +- Combo: BeginCombo(): Added ImGuiComboFlags_NoArrowButton to disable the arrow button and + only display the wide value preview box. +- Combo: BeginCombo(): Added ImGuiComboFlags_NoPreview to disable the preview and only + display a square arrow button. - Combo: Arrow button isn't displayed over frame background so its blended color matches other buttons. Left side of the button isn't rounded. - PlotLines: plot a flat line if scale_min==scale_max. (#1621) -- Fonts: Changed DisplayOffset.y to defaults to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. - If you were adding or subtracting (not assigning) to ImFont::DisplayOffset check if your fonts are correctly aligned vertically. (#1619) +- Fonts: Changed DisplayOffset.y to defaults to 0 instead of +1. Fixed rounding of Ascent/Descent + to match TrueType renderer. If you were adding or subtracting (not assigning) to ImFont::DisplayOffset + check if your fonts are correctly aligned vertically. (#1619) - Fonts: Updated stb_truetype from 1.14 to stb_truetype 1.19. (w/ include fix from some platforms #1622) - Fonts: Added optional FreeType rasterizer in misc/freetype. Moved from imgui_club repo. (#618) [@Vuhdo, @mikesart, @ocornut] - Fonts: Moved extra_fonts/ to misc/fonts/. - ImFontAtlas: Fixed cfg.MergeMode not reusing existing glyphs if available (always overwrote). -- ImFontAtlas: Handle stb_truetype stbtt_InitFont() and stbtt_PackBegin() possible failures more gracefully, GetTexDataAsRGBA32() won't crash during conversion. (#1527) -- ImFontAtlas: Moved mouse cursor data out of ImGuiContext, fix drawing them with multiple contexts. Also remove the last remaining undesirable dependency on ImGui in imgui_draw.cpp. (#939) -- ImFontAtlas: Added ImFontAtlasFlags_NoPowerOfTwoHeight flag to disable padding font height to nearest power of two. (#1613) -- ImFontAtlas: Added ImFontAtlasFlags_NoMouseCursors flag to disable baking software mouse cursors, mostly to save texture memory on very low end hardware. (#1613) -- ImDrawList: Fixed AddRect() with anti-aliasing disabled (lower-right corner pixel was often missing, rounding looks a little better.) (#1646) +- ImFontAtlas: Handle stb_truetype stbtt_InitFont() and stbtt_PackBegin() possible failures + more gracefully, GetTexDataAsRGBA32() won't crash during conversion. (#1527) +- ImFontAtlas: Moved mouse cursor data out of ImGuiContext, fix drawing them with multiple contexts. + Also remove the last remaining undesirable dependency on ImGui in imgui_draw.cpp. (#939) +- ImFontAtlas: Added ImFontAtlasFlags_NoPowerOfTwoHeight flag to disable padding font height + to nearest power of two. (#1613) +- ImFontAtlas: Added ImFontAtlasFlags_NoMouseCursors flag to disable baking software mouse cursors, + mostly to save texture memory on very low end hardware. (#1613) +- ImDrawList: Fixed AddRect() with anti-aliasing disabled (lower-right corner pixel was often + missing, rounding looks a little better.) (#1646) - ImDrawList: Added CloneOutput() helper to facilitate the cloning of ImDrawData or ImDrawList for multi-threaded rendering. -- Misc: Functions passed to libc qsort are explicitly marked cdecl to support compiling with vectorcall as the default calling convention. (#1230, #1611) [@RandyGaul] -- Misc: ImVec2: added [] operator. This is becoming desirable for some code working of either axes independently. Better adding it sooner than later. +- Misc: Functions passed to libc qsort are explicitly marked cdecl to support compiling with + vectorcall as the default calling convention. (#1230, #1611) [@RandyGaul] +- Misc: ImVec2: added [] operator. This is becoming desirable for some code working of either + axes independently. Better adding it sooner than later. - Misc: NewFrame(): Added an assert to detect incorrect filling of the io.KeyMap[] array earlier. (#1555) - Misc: Added IM_OFFSETOF() helper in imgui.h (previously was in imgui_internal.h) - Misc: Added IM_NEW(), IM_DELETE() helpers in imgui.h (previously were in imgui_internal.h) @@ -4692,7 +4723,8 @@ Other Changes: - Examples: Using Dark theme by default. (#707). Tweaked demo code. - Examples: Added support for horizontal mouse wheel for API that allows it. (#1463) [@tseeker] - Examples: All examples now setup the io.BackendFlags to signify they can honor mouse cursors, gamepad, etc. -- Examples: DirectX10: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) in every other backends. (#1733) +- Examples: DirectX10: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that + was left in DX10 example but removed in 1.47 (Nov 2015) in every other backends. (#1733) - Examples: DirectX12: Added DirectX 12 example. (#301) [@jdm3] - Examples: OpenGL3+GLFW,SDL: Changed GLSL shader version from 330 to 150. (#1466, #1504) - Examples: OpenGL3+GLFW,SDL: Added a way to override the GLSL version string in the Init function. (#1466, #1504). @@ -4706,11 +4738,13 @@ Other Changes: - Examples: GLFW: Added support for mouse cursor shapes (the diagonal resize cursors are unfortunately not supported by GLFW at the moment. (#1495) - Examples: GLFW: Don't attempt to change the mouse cursor input mode if it is set to GLFW_CURSOR_DISABLED by the application. (#1202) [@PhilCK] - Examples: SDL: Added support for mouse cursor shapes. (#1626) [@olls] -- Examples: SDL: Using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging (SDL 2.0.4+ only, otherwise using SDL_WINDOW_INPUT_FOCUS instead of previously SDL_WINDOW_MOUSE_FOCUS). (#1559) +- Examples: SDL: Using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging + (SDL 2.0.4+ only, otherwise using SDL_WINDOW_INPUT_FOCUS instead of previously SDL_WINDOW_MOUSE_FOCUS). (#1559) - Examples: SDL: Enabled vsync by default so people don't come at us when the examples are running at 2000 FPS and burning a CPU core. - Examples: SDL: Using SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency() to handle frame-rate over 1000 FPS properly. (#996) - Examples: SDL: Using scan-code exclusively instead of a confusing mixture of scan-codes and key-codes. -- Examples: SDL: Visual Studio: Added .vcxproj file. Using %SDL2_DIR% in the default .vcxproj and build files instead of %SDL_DIR%, the earlier being more standard. +- Examples: SDL: Visual Studio: Added .vcxproj file. Using %SDL2_DIR% in the default .vcxproj + and build files instead of %SDL_DIR%, the earlier being more standard. - Examples: Vulkan: Visual Studio: Added .vcxproj file. - Examples: Apple: Fixed filenames in OSX xcode project. Various other Mac friendly fixes. [@gerryhernandez etc.] - Examples: Visual Studio: Disabled extraneous function-level check in Release build. @@ -4756,41 +4790,63 @@ Other Changes: - See ImGuiDragDropFlags for various options. - The ColorEdit4() and ColorButton() widgets now support Drag and Drop. - The API is tagged as Beta as it still may be subject to small changes. -- Drag and Drop: When drag and drop is active, tree nodes and collapsing header can be opened by hovering on them for 0.7 seconds. -- Renamed io.OSXBehaviors to io.OptMacOSXBehaviors. Should not affect users as the compile-time default is usually enough. (#473, #650) +- Drag and Drop: When drag and drop is active, tree nodes and collapsing header can be opened + by hovering on them for 0.7 seconds. +- Renamed io.OSXBehaviors to io.OptMacOSXBehaviors. Should not affect users as the compile-time + default is usually enough. (#473, #650) - Style: Added StyleColorsDark() style. (#707) [@dougbinks] - Style: Added StyleColorsLight() style. Best used with frame borders + thicker font than the default font. (#707) - Style: Added style.PopupRounding setting. (#1112) -- Style: Added style.FrameBorderSize, style.WindowBorderSize, style.PopupBorderSize. Removed ImGuiWindowFlags_ShowBorders window flag! +- Style: Added style.FrameBorderSize, style.WindowBorderSize, style.PopupBorderSize. + Removed ImGuiWindowFlags_ShowBorders window flag! Borders are now fully set up in the ImGuiStyle structure. Use ImGui::ShowStyleEditor() to look them up. (#707, fix #819, #1031) - Style: Various small changes to the classic style (most noticeably, buttons are now using blue shades). (#707) - Style: Renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg. - Style: Renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding. - Style: Removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency. (#707) - Style: Made the ScaleAllSizes() helper rounds down every values so they are aligned on integers. -- Focus: Added SetItemDefaultFocus(), which in the current (master) branch behave the same as doing `if (IsWindowAppearing()) SetScrollHere()`. - In the navigation branch this will also set the default focus. Prefer using this when creating combo boxes with `BeginCombo()` so your code will be forward-compatible with gamepad/keyboard navigation features. (#787) -- Combo: Pop-up grows horizontally to accommodate for contents that is larger then the parent combo button. -- Combo: Added BeginCombo()/EndCombo() API which allows use to submit content of any form and manage your selection state without relying on indices. -- Combo: Added ImGuiComboFlags_PopupAlignLeft flag to BeginCombo() to prioritize keeping the pop-up on the left side (for small-button-looking combos). -- Combo: Added ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLargest to easily provide desired pop-up height. -- Combo: You can use SetNextWindowSizeConstraints() before BeginCombo() to specify specific pop-up width/height constraints. +- Focus: Added SetItemDefaultFocus(), which in the current (master) branch behave the same + as doing `if (IsWindowAppearing()) SetScrollHere()`. In the navigation branch this will also + set the default focus. Prefer using this when creating combo boxes with `BeginCombo()` so your + code will be forward-compatible with gamepad/keyboard navigation features. (#787) +- Combo: Pop-up grows horizontally to accommodate for contents that is larger then the parent + combo button. +- Combo: Added BeginCombo()/EndCombo() API which allows use to submit content of any form and + manage your selection state without relying on indices. +- Combo: Added ImGuiComboFlags_PopupAlignLeft flag to BeginCombo() to prioritize keeping the + pop-up on the left side (for small-button-looking combos). +- Combo: Added ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLargest + to easily provide desired pop-up height. +- Combo: You can use SetNextWindowSizeConstraints() before BeginCombo() to specify specific + pop-up width/height constraints. - Combo: Offset popup position by border size so that a double border isn't so visible. (#707) - Combo: Recycling windows by using a stack number instead of a unique id, wasting less memory (like menus do). - InputText: Added ImGuiInputTextFlags_NoUndoRedo flag. (#1506, #1508) [@ibachar] -- Window: Fixed auto-resize allocating too much space for scrollbar when SizeContents is bigger than maximum window size (fixes c0547d3). (#1417) -- Window: Child windows with MenuBar use regular WindowPadding.y so layout look consistent as child or as a regular window. -- Window: Begin(): Fixed appending into a child window with a second Begin() from a different window stack querying the wrong window for the window->Collapsed test. -- Window: Calling IsItemActive(), IsItemHovered() etc. after a call to Begin() provides item data for the title bar, so you can easily test if the title bar is being hovered, etc. (#823) +- Window: Fixed auto-resize allocating too much space for scrollbar when SizeContents is + bigger than maximum window size (fixes c0547d3). (#1417) +- Window: Child windows with MenuBar use regular WindowPadding.y so layout look consistent as + child or as a regular window. +- Window: Begin(): Fixed appending into a child window with a second Begin() from a different + window stack querying the wrong window for the window->Collapsed test. +- Window: Calling IsItemActive(), IsItemHovered() etc. after a call to Begin() provides item + data for the title bar, so you can easily test if the title bar is being hovered, etc. (#823) - Window: Made it possible to use SetNextWindowPos() on a child window. -- Window: Fixed a one frame glitch. When an appearing window claimed the focus themselves, the title bar wouldn't use the focused color for one frame. -- Window: Added ImGuiWindowFlags_ResizeFromAnySide flag to resize from any borders or from the lower-left corner of a window. This requires your backend to honor GetMouseCursor() requests for full usability. (#822) +- Window: Fixed a one frame glitch. When an appearing window claimed the focus themselves, the + title bar wouldn't use the focused color for one frame. +- Window: Added ImGuiWindowFlags_ResizeFromAnySide flag to resize from any borders or from the + lower-left corner of a window. This requires your backend to honor GetMouseCursor() requests + for full usability. (#822) - Window: Sizing fixes when using SetNextWindowSize() on individual axises. -- Window: Hide new window for one frame until they calculate their size. Also fixes SetNextWindowPos() given a non-zero pivot. (#1694) +- Window: Hide new window for one frame until they calculate their size. + Also fixes SetNextWindowPos() given a non-zero pivot. (#1694) - Window: Made mouse wheel scrolling accommodate better to windows that are smaller than the scroll step. -- Window: SetNextWindowContentSize() adjust for the size of decorations (title bar/menu bar), but _not_ for borders are we consistently make borders not affect layout. - If you need a non-child window of an exact size with border enabled but zero window padding, you'll need to accommodate for the border size yourself. -- Window: Using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. (#1380, #1502) +- Window: SetNextWindowContentSize() adjust for the size of decorations (title bar/menu bar), + but _not_ for borders are we consistently make borders not affect layout. + If you need a non-child window of an exact size with border enabled but zero window padding, + you'll need to accommodate for the border size yourself. +- Window: Using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel + event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar + are also set. (#1380, #1502) - Window: Active Modal window always set the WantCaptureKeyboard flag. (#744) - Window: Moving window doesn't use accumulating MouseDelta so straying out of imgui boundaries keeps moved imgui window at the same cursor-relative position. - IsWindowFocused(): Added ImGuiFocusedFlags_ChildWindows flag to include child windows in the focused test. (#1382). @@ -4799,39 +4855,52 @@ Other Changes: - IsWindowHovered(): Added ImGuiHoveredFlags_RootWindow flag to start hovered test from the root (top-most) window. The combination of both flags obsoletes IsRootWindowOrAnyChildHovered(). (#1382) - IsWindowHovered(): Fixed return value when an item is active to use the same logic as IsItemHovered(). (#1382, #1404) - IsWindowHovered(): Always return true when current window is being moved. (#1382) -- Scrollbar: Fixed issues with vertical scrollbar flickering/appearing, typically when manually resizing and using a pattern of filling available height (e.g. full sized BeginChild). +- Scrollbar: Fixed issues with vertical scrollbar flickering/appearing, typically when manually + resizing and using a pattern of filling available height (e.g. full sized BeginChild). - Scrollbar: Minor graphical fix for when scrollbar don't have enough visible space to display the full grab. -- Scrolling: Fixed padding and scrolling asymmetry where lower/right sides of a window wouldn't use WindowPadding properly + causing minor scrolling glitches. +- Scrolling: Fixed padding and scrolling asymmetry where lower/right sides of a window wouldn't + use WindowPadding properly + causing minor scrolling glitches. - Tree: TreePush with zero arguments was ambiguous. Resolved by making it call TreePush(const void*). [@JasonWilkins] - Tree: Renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. (#600, #1330) - MenuBar: Fixed minor rendering issues on the right size when resizing a window very small and using rounded window corners. -- MenuBar: better software clipping to handle small windows, in particular child window don't have minimum constraints so we need to render clipped menus better. +- MenuBar: better software clipping to handle small windows, in particular child window don't have + minimum constraints so we need to render clipped menus better. - BeginMenu(): Tweaked the Arrow/Triangle displayed on child menu items. -- Columns: Clipping columns borders on Y axis on CPU because some Linux GPU drivers appears to be unhappy with triangle spanning large regions. (#125) -- Columns: Added ImGuiColumnsFlags_GrowParentContentsSize to internal API to restore old content sizes behavior (may be obsolete). (#1444, #125) -- Columns: Columns width is no longer lost when dragging a column to the right side of the window, until releasing the mouse button you have a chance to save them. (#1499, #125). [@ggtucker] +- Columns: Clipping columns borders on Y axis on CPU because some Linux GPU drivers appears to + be unhappy with triangle spanning large regions. (#125) +- Columns: Added ImGuiColumnsFlags_GrowParentContentsSize to internal API to restore old content + sizes behavior (may be obsolete). (#1444, #125) +- Columns: Columns width is no longer lost when dragging a column to the right side of the window, + until releasing the mouse button you have a chance to save them. (#1499, #125). [@ggtucker] - Columns: Fixed dragging when using a same of columns multiple times in the frame. (#125) - Indent(), Unindent(): Allow passing negative values. - ColorEdit4(): Made IsItemActive() return true when picker pop-up is active. (#1489) - ColorEdit4(): Tweaked tooltip so that the color button aligns more correctly with text. -- ColorEdit4(): Support drag and drop. Color buttons can be used as drag sources, and ColorEdit widgets as drag targets. (#143) -- ColorPicker4(): Fixed continuously returning true when holding mouse button on the sat/value/alpha locations. We only return true on value change. (#1489) -- NewFrame(): using literal strings in the most-frequently firing IM_ASSERT expressions to increase the odd of programmers seeing them (especially those who don't use a debugger). -- NewFrame() now asserts if neither Render or EndFrame have been called. Exposed EndFrame(). Made it legal to call EndFrame() more than one. (#1423) +- ColorEdit4(): Support drag and drop. Color buttons can be used as drag sources, and ColorEdit + widgets as drag targets. (#143) +- ColorPicker4(): Fixed continuously returning true when holding mouse button on the sat/value/alpha + locations. We only return true on value change. (#1489) +- NewFrame(): using literal strings in the most-frequently firing IM_ASSERT expressions to + increase the odd of programmers seeing them (especially those who don't use a debugger). +- NewFrame() now asserts if neither Render or EndFrame have been called. Exposed EndFrame(). + Made it legal to call EndFrame() more than one. (#1423) - ImGuiStorage: Added BuildSortByKey() helper to rebuild storage from scratch. - ImFont: Added GetDebugName() helper. - ImFontAtlas: Added missing Thai punctuation in the GetGlyphRangesThai() ranges. (#1396) [@nProtect] - ImDrawList: Removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Anti-aliasing is controlled via the regular style.AntiAliased flags. - ImDrawList: Added ImDrawList::AddImageRounded() helper. (#845) [@thedmd] - ImDrawList: Refactored to make ImDrawList independent of ImGui. Removed static variable in PathArcToFast() which caused linking issues to some. -- ImDrawList: Exposed ImDrawCornerFlags, replaced occurrences of ~0 with an explicit ImDrawCornerFlags_All. NB: Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). +- ImDrawList: Exposed ImDrawCornerFlags, replaced occurrences of ~0 with an explicit ImDrawCornerFlags_All. + NB: Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). - ImVector: Added ImVector::push_front() helper. - ImVector: Added ImVector::contains() helper. - ImVector: insert() uses grow_capacity() instead of using grow policy inconsistent with push_back(). - Internals: Remove requirement to define IMGUI_DEFINE_PLACEMENT_NEW to use the IM_PLACEMENT_NEW macro. (#1103) -- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_NoHoldingActiveID flag from incorrectly setting the ActiveIdClickOffset field. - This had no known effect within imgui code but could have affected custom drag and drop patterns. And it is more correct this way! (#1418) -- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_AllowOverlapMode to avoid temporarily activating widgets on click before they have been correctly double-hovered. (#319, #600) +- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_NoHoldingActiveID flag from incorrectly + setting the ActiveIdClickOffset field. This had no known effect within imgui code but could have + affected custom drag and drop patterns. And it is more correct this way! (#1418) +- Internals: ButtonBehavior: Fixed ImGuiButtonFlags_AllowOverlapMode to avoid temporarily activating +widgets on click before they have been correctly double-hovered. (#319, #600) - Internals: Added SplitterBehavior() helper. (#319) - Internals: Added IM_NEW(), IM_DELETE() helpers. (#484, #504, #1517) - Internals: Basic refactor of the settings API which now allows external elements to be loaded/saved. @@ -4840,9 +4909,11 @@ Other Changes: - Demo: Renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). - Demo: Style Editor: Added a "Simplified settings" sections with check-boxes for border size and frame rounding. (#707, #1019) - Demo: Style Editor: Added combo box to select stock styles and select current font when multiple are loaded. (#707) -- Demo: Style Editor: Using local storage so Save/Revert button makes more sense without code passing its storage. Added horizontal scroll bar. Fixed Save/Revert button to be always accessible. (#1211) +- Demo: Style Editor: Using local storage so Save/Revert button makes more sense without code passing + its storage. Added horizontal scroll bar. Fixed Save/Revert button to be always accessible. (#1211) - Demo: Console: Fixed context menu issue. (#1404) -- Demo: Console: Fixed incorrect positioning which was hidden by a minor scroll issue (this would affect people who copied the Console code as is). +- Demo: Console: Fixed incorrect positioning which was hidden by a minor scroll issue (this would + affect people who copied the Console code as is). - Demo: Constrained Resize: Added more test cases. (#1417) - Demo: Custom Rendering: Fixed clipping rectangle extruding out of parent window. - Demo: Layout: Removed unnecessary and misleading BeginChild/EndChild calls. @@ -4864,24 +4935,41 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- IO: `io.MousePos` needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing, instead of ImVec2(-1,-1) as previously) This is needed so we can clear `io.MouseDelta` field when the mouse is made available again. -- Renamed `AlignFirstTextHeightToWidgets()` to `AlignTextToFramePadding()`. Kept inline redirection function (will obsolete). -- Obsoleted the legacy 5 parameters version of Begin(). Please avoid using it. If you need a transparent window background, uses `PushStyleColor()`. The old size parameter there was also misleading and equivalent to calling `SetNextWindowSize(size, ImGuiCond_FirstTimeEver)`. Kept inline redirection function (will obsolete). -- Obsoleted `IsItemHoveredRect()`, `IsMouseHoveringWindow()` in favor of using the newly introduced flags of `IsItemHovered()` and `IsWindowHovered()`. Kept inline redirection function (will obsolete). (#1382) -- Obsoleted 'SetNextWindowPosCenter()' in favor of using 1SetNextWindowPos()` with a pivot value which allows to do the same and more. Keep inline redirection function. -- Removed `IsItemRectHovered()`, `IsWindowRectHovered()` recently introduced in 1.51 which were merely the more consistent/correct names for the above functions which are now obsolete anyway. (#1382) -- Changed `IsWindowHovered()` default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it. (#1382) -- Renamed imconfig.h's `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS` to `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` for consistency. +- IO: `io.MousePos` needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing, + instead of ImVec2(-1,-1) as previously) This is needed so we can clear `io.MouseDelta` field when + the mouse is made available again. +- Renamed `AlignFirstTextHeightToWidgets()` to `AlignTextToFramePadding()`. + Kept inline redirection function (will obsolete). +- Obsoleted the legacy 5 parameters version of Begin(). Please avoid using it. If you need a + transparent window background, uses `PushStyleColor()`. The old size parameter there was also + misleading and equivalent to calling `SetNextWindowSize(size, ImGuiCond_FirstTimeEver)`. + Kept inline redirection function (will obsolete). +- Obsoleted `IsItemHoveredRect()`, `IsMouseHoveringWindow()` in favor of using the newly introduced + flags of `IsItemHovered()` and `IsWindowHovered()`. Kept inline redirection function (will obsolete). (#1382) +- Obsoleted 'SetNextWindowPosCenter()' in favor of using 1SetNextWindowPos()` with a pivot value which + allows to do the same and more. Keep inline redirection function. +- Removed `IsItemRectHovered()`, `IsWindowRectHovered()` recently introduced in 1.51 which were merely + the more consistent/correct names for the above functions which are now obsolete anyway. (#1382) +- Changed `IsWindowHovered()` default parameters behavior to return false if an item is active in + another window (e.g. click-dragging item from another window to this window). You can use the newly + introduced IsWindowHovered() flags to requests this specific behavior if you need it. (#1382) +- Renamed imconfig.h's `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS` + to `IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS`/`IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS` for consistency. - Renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete). Other Changes: - ProgressBar: fixed rendering when straddling rounded area. (#1296) -- SliderFloat, DragFloat: Using scientific notation e.g. "%.1e" in the displayed format string doesn't mistakenly trigger rounding of the value. [@MomentsInGraphics] -- Combo, InputFloat, InputInt: Made the small button on the right side align properly with the equivalent colored button of ColorEdit4(). -- IO: Tweaked logic for `io.WantCaptureMouse` so it now outputs false when e.g. hovering over void while an InputText() is active. (#621) [@pdoane] -- IO: Fixed `io.WantTextInput` from mistakenly outputting true when an activated Drag or Slider was previously turned into an InputText(). (#1317) -- Misc: Added flags to `IsItemHovered()`, `IsWindowHovered()` to access advanced hovering-test behavior. Generally useful for pop-ups and drag and drop behaviors: (relates to ~#439, #1013, #143, #925) +- SliderFloat, DragFloat: Using scientific notation e.g. "%.1e" in the displayed format string doesn't + mistakenly trigger rounding of the value. [@MomentsInGraphics] +- Combo, InputFloat, InputInt: Made the small button on the right side align properly with the + equivalent colored button of ColorEdit4(). +- IO: Tweaked logic for `io.WantCaptureMouse` so it now outputs false when e.g. hovering over void + while an InputText() is active. (#621) [@pdoane] +- IO: Fixed `io.WantTextInput` from mistakenly outputting true when an activated Drag or Slider was + previously turned into an InputText(). (#1317) +- Misc: Added flags to `IsItemHovered()`, `IsWindowHovered()` to access advanced hovering-test behavior. + Generally useful for pop-ups and drag and drop behaviors: (relates to ~#439, #1013, #143, #925) - `ImGuiHoveredFlags_AllowWhenBlockedByPopup` - `ImGuiHoveredFlags_AllowWhenBlockedByActiveItem` - `ImGuiHoveredFlags_AllowWhenOverlapped` @@ -4892,54 +4980,80 @@ Other Changes: - CheckBox: Now rendering a tick mark instead of a full square. - ColorEdit4: Added "Copy as..." option in context menu. (#346) - ColorPicker: Improved ColorPicker hue wheel color interpolation. (#1313) [@thevaber] -- ColorButton: Reduced bordering artifact that would be particularly visible with an opaque Col_FrameBg and FrameRounding enabled. -- ColorButton: Fixed rendering color button with a checkerboard if the transparency comes from the global style.Alpha and not from the actual source color. -- TreeNode: Added `ImGuiTreeNodeFlags_FramePadding` flag to conveniently create a tree node with full padding at the beginning of a line, without having to call `AlignTextToFramePadding()`. +- ColorButton: Reduced bordering artifact that would be particularly visible with an opaque + Col_FrameBg and FrameRounding enabled. +- ColorButton: Fixed rendering color button with a checkerboard if the transparency comes from the global + style.Alpha and not from the actual source color. +- TreeNode: Added `ImGuiTreeNodeFlags_FramePadding` flag to conveniently create a tree node with full + padding at the beginning of a line, without having to call `AlignTextToFramePadding()`. - Trees: Fixed calling `SetNextTreeNodeOpen()` on a collapsed window leaking to the first tree node item of the next frame. -- Layout: Horizontal layout is automatically enforced in a menu bar, so you can use non-MenuItem elements without calling SameLine(). -- Separator: Output a vertical separator when used inside a menu bar (or in general when horizontal layout is active, but that isn't exposed yet!). +- Layout: Horizontal layout is automatically enforced in a menu bar, so you can use non-MenuItem elements + without calling SameLine(). +- Separator: Output a vertical separator when used inside a menu bar (or in general when horizontal layout + is active, but that isn't exposed yet!). - Window: Added `IsWindowAppearing()` helper (helpful e.g. as a condition before initializing some of your own things.). - Window: Added pivot parameter to `SetNextWindowPos()`, making it possible to center or right align a window. Obsoleted `SetNextWindowPosCenter()`. - Window: Fixed title bar color of top-most window under a modal window. - Window: Fixed not being able to move a window by clicking on one of its child window. (#1337, #635) -- Window: Fixed `Begin()` auto-fit calculation code that predict the presence of a scrollbar so it works better when window size constraints are used. -- Window: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which in turn would set enable the Appearing condition for that frame. -- Window: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow user creating a window called "Debug" without losing their custom flags. -- Window: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move the parent window by clicking on SubChild. (#1381) +- Window: Fixed `Begin()` auto-fit calculation code that predict the presence of a scrollbar so it works + better when window size constraints are used. +- Window: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which + in turn would set enable the Appearing condition for that frame. +- Window: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow + user creating a window called "Debug" without losing their custom flags. +- Window: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup + with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move + the parent window by clicking on SubChild. (#1381) - Popups: Pop-ups can be closed with a right-click anywhere, without altering focus under the pop-up. (~#439) -- Popups: `BeginPopupContextItem()`, `BeginPopupContextWindow()` are now setup to allow reopening a context menu by right-clicking again. (~#439) +- Popups: `BeginPopupContextItem()`, `BeginPopupContextWindow()` are now setup to allow reopening + a context menu by right-clicking again. (~#439) - Popups: `BeginPopupContextItem()` now supports a NULL string identifier and uses the last item ID if available. - Popups: Added `OpenPopupOnItemClick()` helper which mimic `BeginPopupContextItem()` but doesn't do the BeginPopup(). - MenuItem: Only activating on mouse release. [@Urmeli0815] (was already fixed in nav branch). - MenuItem: Made tick mark thicker (thick mark?). -- MenuItem: Tweaks to be usable inside a menu bar (nb: it looks like a regular menu and thus is misleading, prefer using Button() and regular widgets in menu bar if you need to). (#1387) +- MenuItem: Tweaks to be usable inside a menu bar (nb: it looks like a regular menu and thus is misleading, + prefer using Button() and regular widgets in menu bar if you need to). (#1387) - ImDrawList: Fixed a rare draw call merging bug which could lead to undisplayed triangles. (#1172, #1368) -- ImDrawList: Fixed a rare bug in `ChannelsMerge()` when all contents has been clipped, leading to an extraneous draw call being created. (#1172, #1368) +- ImDrawList: Fixed a rare bug in `ChannelsMerge()` when all contents has been clipped, leading to + an extraneous draw call being created. (#1172, #1368) - ImFont: Added `AddGlyph()` building helper for use by custom atlas builders. -- ImFontAtlas: Added support for CustomRect API to submit custom rectangles to be packed into the atlas. You can map them as font glyphs, or use them for custom purposes. - After the atlas is built you can query the position of your rectangles in the texture and then copy your data there. You can use this features to create e.g. full color font-mapped icons. -- ImFontAtlas: Fixed fall-back handling when merging fonts, if a glyph was missing from the second font input it could have used a glyph from the first one. (#1349) [@inolen] -- ImFontAtlas: Fixed memory leak on build failure case when stbtt_InitFont failed (generally due to incorrect or supported font type). (#1391) (@Moka42) -- ImFontConfig: Added `RasterizerMultiply` option to alter the brightness of individual fonts at rasterization time, which may help increasing readability for some. -- ImFontConfig: Added `RasterizerFlags` to pass options to custom rasterizer (e.g. the [imgui_freetype](https://github.com/ocornut/imgui_club/tree/master/imgui_freetype) rasterizer in imgui_club has such options). +- ImFontAtlas: Added support for CustomRect API to submit custom rectangles to be packed into the atlas. + You can map them as font glyphs, or use them for custom purposes. + After the atlas is built you can query the position of your rectangles in the texture and then copy + your data there. You can use this features to create e.g. full color font-mapped icons. +- ImFontAtlas: Fixed fall-back handling when merging fonts, if a glyph was missing from the second font + input it could have used a glyph from the first one. (#1349) [@inolen] +- ImFontAtlas: Fixed memory leak on build failure case when stbtt_InitFont failed (generally due to + incorrect or supported font type). (#1391) (@Moka42) +- ImFontConfig: Added `RasterizerMultiply` option to alter the brightness of individual fonts at + rasterization time, which may help increasing readability for some. +- ImFontConfig: Added `RasterizerFlags` to pass options to custom rasterizer (e.g. the + [imgui_freetype](https://github.com/ocornut/imgui_club/tree/master/imgui_freetype) rasterizer in imgui_club has such options). - ImVector: added resize() variant with initialization value. -- Misc: Changed the internal name formatting of child windows identifier to use slashes (instead of dots) as separator, more readable. +- Misc: Changed the internal name formatting of child windows identifier to use slashes + (instead of dots) as separator, more readable. - Misc: Fixed compilation with `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` defined. - Misc: Marked all format+va_list functions with format attribute so GCC/Clang can warn about misuses. - Misc: Fixed compilation on NetBSD due to missing alloca.h (#1319) [@RyuKojiro] - Misc: Improved warnings compilation for newer versions of Clang. (#1324) (@waywardmonkeys) -- Misc: Added `io.WantMoveMouse flags` (from Nav branch) and honored in Examples applications. Currently unused but trying to spread Examples applications code that supports it. -- Misc: Added `IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS` support in imconfig.h to allow user reimplementing the `ImFormatString()` functions e.g. to use stb_printf(). (#1038) -- Misc: [Windows] Fixed default Win32 `SetClipboardText()` handler leaving the Win32 clipboard handler unclosed on failure. [@pdoane] -- Style: Added `ImGuiStyle::ScaleAllSizes(float)` helper to make it easier to have application transition e.g. from low to high DPI with a matching style. +- Misc: Added `io.WantMoveMouse flags` (from Nav branch) and honored in Examples applications. + Currently unused but trying to spread Examples applications code that supports it. +- Misc: Added `IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS` support in imconfig.h to allow user + reimplementing the `ImFormatString()` functions e.g. to use stb_printf(). (#1038) +- Misc: [Windows] Fixed default Win32 `SetClipboardText()` handler leaving the Win32 clipboard + handler unclosed on failure. [@pdoane] +- Style: Added `ImGuiStyle::ScaleAllSizes(float)` helper to make it easier to have application + transition e.g. from low to high DPI with a matching style. - Metrics: Draw window bounding boxes when hovering Pos/Size; List all draw layers; Trimming empty commands like Render() does. - Examples: OpenGL3: Save and restore sampler state. (#1145) [@nlguillemot] - Examples: OpenGL2, OpenGL3: Save and restore polygon mode. (#1307) [@JJscott] - Examples: DirectX11: Allow creating device with feature level 10 since we don't really need much for that example. (#1333) -- Examples: DirectX9/10/12: Using the Win32 SetCapture/ReleaseCapture API to read mouse coordinates when they are out of bounds. (#1375) [@Gargaj, @ocornut] +- Examples: DirectX9/10/12: Using the Win32 SetCapture/ReleaseCapture API to read mouse coordinates + when they are out of bounds. (#1375) [@Gargaj, @ocornut] - Tools: Fixed binary_to_compressed_c tool to return 0 when successful. (#1350) [@benvanik] - Internals: Exposed more helpers and unfinished features in imgui_internal.h. (use at your own risk!). -- Internals: A bunch of internal refactoring, hopefully haven't broken anything! Merged a bunch of internal changes from the upcoming Navigation branch. +- Internals: A bunch of internal refactoring, hopefully haven't broken anything! + Merged a bunch of internal changes from the upcoming Navigation branch. - Various tweaks, fixes and documentation changes. Beta Navigation Branch: @@ -4948,12 +5062,16 @@ Beta Navigation Branch: - Nav: Added `#define IMGUI_HAS_NAV` in imgui.h to ease sharing code between both branches. (#787) - Nav: MainMenuBar now releases focus when user gets out of the menu layer. (#787) - Nav: When applying focus to a window with only menus, the menu layer is automatically activated. (#787) -- Nav: Added `ImGuiNavInput_KeyMenu` (~Alt key) aside from ImGuiNavInput_PadMenu input as it is one differentiator of pad vs keyboard that was detrimental to the keyboard experience. Although isn't officially supported, it makes the current experience better. (#787) +- Nav: Added `ImGuiNavInput_KeyMenu` (~Alt key) aside from ImGuiNavInput_PadMenu input as it is + one differentiator of pad vs keyboard that was detrimental to the keyboard experience. + Although isn't officially supported, it makes the current experience better. (#787) - Nav: Move requests now wrap vertically inside Menus and Pop-ups. (#787) - Nav: Allow to collapse tree nodes with NavLeft and open them with NavRight. (#787, #1079). -- Nav: It's now possible to navigate sibling of a menu-bar while navigating inside one of their child. If a Left<>Right navigation request fails to find a match we forward the request to the root menu. (#787, #126) +- Nav: It's now possible to navigate sibling of a menu-bar while navigating inside one of their child. + If a Left<>Right navigation request fails to find a match we forward the request to the root menu. (#787, #126) - Nav: Fixed `SetItemDefaultFocus` from stealing default focus when we are initializing default focus for a menu bar layer. (#787) -- Nav: Support for fall-back horizontal scrolling with PadLeft/PadRight (nb: fall-back scrolling is only used to navigate windows that have no interactive items). (#787) +- Nav: Support for fall-back horizontal scrolling with PadLeft/PadRight (nb: fall-back scrolling + is only used to navigate windows that have no interactive items). (#787) - Nav: Fixed tool-tip from being selectable in the window selection list. (#787) - Nav: `CollapsingHeader(bool*)` variant: fixed for `IsItemHovered()` not working properly in the nav branch. (#600, #787) - Nav: InputText: Fixed using Up/Down history callback feature when Nav is enabled. (#787) @@ -4970,7 +5088,14 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -Work on dear imgui has been gradually resuming. It means that fixes and new features should be tackled at a faster rate than last year. However, in order to move forward with the library and get rid of some cruft, I have taken the liberty to be a little bit more aggressive than usual with API breaking changes. Read the details below and search for those names in your code! In the grand scheme of things, those changes are small and should not affect everyone, but this is technically our most aggressive release so far in term of API breakage. If you want to be extra forward-facing, you can enable `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h to disable the obsolete names/redirection. +Work on dear imgui has been gradually resuming. It means that fixes and new features should be tackled at +a faster rate than last year. However, in order to move forward with the library and get rid of some cruft, +I have taken the liberty to be a little bit more aggressive than usual with API breaking changes. +Read the details below and search for those names in your code! In the grand scheme of things, +those changes are small and should not affect everyone, but this is technically our most aggressive +release so far in term of API breakage. +If you want to be extra forward-facing, you can enable `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in +your imconfig.h to disable the obsolete names/redirection. - Renamed `IsItemHoveredRect()` to `IsItemRectHovered()`. Kept inline redirection function (will obsolete). - Renamed `IsMouseHoveringWindow()` to `IsWindowRectHovered()` for consistency. Kept inline redirection function (will obsolete). @@ -4978,43 +5103,79 @@ Work on dear imgui has been gradually resuming. It means that fixes and new feat - Renamed `ImGuiCol_Columns***` enums to `ImGuiCol_Separator***`. Kept redirection enums (will obsolete). - Renamed `ImGuiSetCond***` types and enums to `ImGuiCond***`. Kept redirection enums (will obsolete). - Renamed `GetStyleColName()` to `GetStyleColorName()` for consistency. Unlikely to be used by end-user! -- Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix. +- Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload, which _might_ cause an "ambiguous call" + compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix. - Marked the weird `IMGUI_ONCE_UPON_A_FRAME` helper macro as obsolete. Prefer using the more explicit `ImGuiOnceUponAFrame`. -- Changed `ColorEdit4(const char* label, float col[4], bool show_alpha = true)` signature to `ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)`, where flags 0x01 is a safe no-op (hello dodgy backward compatibility!). The new `ColorEdit4`/`ColorPicker4` functions have lots of available flags! Check and run the demo window, under "Color/Picker Widgets", to understand the various new options. -- Changed signature of `ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)` to `ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))`. This function was rarely used and was very dodgy (no explicit ID!). -- Changed `BeginPopupContextWindow(bool also_over_items=true, const char* str_id=NULL, int mouse_button=1)` signature to `(const char* str_id=NULL, int mouse_button=1, bool also_over_items=true)`. This is perhaps the most aggressive change in this update, but note that the majority of users relied on default parameters completely, so this will affect only a fraction of users of this already rarely used function. -- Removed `IsPosHoveringAnyWindow()`, which was partly broken and misleading. In the vast majority of cases, people using that function wanted to use `io.WantCaptureMouse` flag. Replaced with IM_ASSERT + comment redirecting user to `io.WantCaptureMouse`. (#1237) +- Changed `ColorEdit4(const char* label, float col[4], bool show_alpha = true)` signature to + `ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)`, where flags 0x01 is a safe no-op + (hello dodgy backward compatibility!). The new `ColorEdit4`/`ColorPicker4` functions have lots of available flags! + Check and run the demo window, under "Color/Picker Widgets", to understand the various new options. +- Changed signature of `ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)` + to `ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))`. + This function was rarely used and was very dodgy (no explicit ID!). +- Changed `BeginPopupContextWindow(bool also_over_items=true, const char* str_id=NULL, int mouse_button=1)` + signature to `(const char* str_id=NULL, int mouse_button=1, bool also_over_items=true)`. + This is perhaps the most aggressive change in this update, but note that the majority of users relied + on default parameters completely, so this will affect only a fraction of users of this already rarely + used function. +- Removed `IsPosHoveringAnyWindow()`, which was partly broken and misleading. In the vast majority of cases, + people using that function wanted to use `io.WantCaptureMouse` flag. Replaced with IM_ASSERT + a comment + redirecting user to `io.WantCaptureMouse`. (#1237) - Removed the old `ValueColor()` helpers, they are equivalent to calling `Text(label)` + `SameLine()` + `ColorButton()`. -- Removed `ColorEditMode()` and `ImGuiColorEditMode` type in favor of `ImGuiColorEditFlags` and parameters to the various Color*() functions. The `SetColorEditOptions()` function allows to initialize default but the user can still change them with right-click context menu. Commenting out your old call to `ColorEditMode()` may just be fine! +- Removed `ColorEditMode()` and `ImGuiColorEditMode` type in favor of `ImGuiColorEditFlags` and + parameters to the various Color*() functions. The `SetColorEditOptions()` function allows to + initialize default but the user can still change them with right-click context menu. + Commenting out your old call to `ColorEditMode()` may just be fine! Other Changes: -- Added flags to `ColorEdit3()`, `ColorEdit4()`. The color edit widget now has a context-menu and access to the color picker. (#346) +- Added flags to `ColorEdit3()`, `ColorEdit4()`. The color edit widget now has a context-menu + and access to the color picker. (#346) - Added flags to `ColorButton()`. (#346) -- Added `ColorPicker3()`, `ColorPicker4()`. The API along with those of the updated `ColorEdit4()` was designed so you may use them in various situation and hopefully compose your own picker if required. There are a bunch of available flags, check the Demo window and comment for `ImGuiColorEditFlags_`. Some of the options it supports are: two color picker types (hue bar + sat/val rectangle, hue wheel + rotating sat/val triangle), display as u8 or float, lifting 0.0..1.0 constraints (currently rgba only), context menus, alpha bar, background checkerboard options, preview tooltip, basic revert. For simple use, calling the existing `ColorEdit4()` function as you did before will be enough, as you can now open the color picker from there. (#346) [@r-lyeh, @nem0, @thennequin, @dariomanesku and @ocornut] -- Added `SetColorEditOptions()` to set default color options (e.g. if you want HSV over RGBA, float over u8, select a default picker mode etc. at startup time without a user intervention. Note that the user can still change options with the context menu unless disabled with `ImGuiColorFlags_NoOptions` or explicitly enforcing a display type/picker mode etc.). +- Added `ColorPicker3()`, `ColorPicker4()`. (#346) [@r-lyeh, @nem0, @thennequin, @dariomanesku and @ocornut] + The API along with those of the updated `ColorEdit4()` was designed so you may use them in various + situation and hopefully compose your own picker if required. There are a bunch of available flags, + check the Demo window and comment for `ImGuiColorEditFlags_`. + Some of the options it supports are: two color picker types (hue bar + sat/val rectangle, + hue wheel + rotating sat/val triangle), display as u8 or float, lifting 0.0..1.0 constraints + (currently rgba only), context menus, alpha bar, background checkerboard options, preview tooltip, + basic revert. For simple use, calling the existing `ColorEdit4()` function as you did before + will be enough, as you can now open the color picker from there. +- Added `SetColorEditOptions()` to set default color options (e.g. if you want HSV over RGBA, + float over u8, select a default picker mode etc. at startup time without a user intervention. + Note that the user can still change options with the context menu unless disabled with + `ImGuiColorFlags_NoOptions` or explicitly enforcing a display type/picker mode etc.). - Added user-facing `IsPopupOpen()` function. (#891) [@mkeeter] -- Added `GetColorU32(u32)` variant that perform the style alpha multiply without a floating-point round trip, and helps makes code more consistent when using ImDrawList APIs. +- Added `GetColorU32(u32)` variant that perform the style alpha multiply without a floating-point + round trip, and helps makes code more consistent when using ImDrawList APIs. - Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload. -- Added `GetStyleColorVec4(ImGuiCol idx)` which is equivalent to accessing `ImGui::GetStyle().Colors[idx]` (aka return the raw style color without alpha alteration). -- ImFontAtlas: Added `GlyphRangesBuilder` helper class, which makes it easier to build custom glyph ranges from your app/game localization data, or add into existing glyph ranges. +- Added `GetStyleColorVec4(ImGuiCol idx)` which is equivalent to accessing `ImGui::GetStyle().Colors[idx]` + (aka return the raw style color without alpha alteration). +- ImFontAtlas: Added `GlyphRangesBuilder` helper class, which makes it easier to build custom glyph ranges + from your app/game localization data, or add into existing glyph ranges. - ImFontAtlas: Added `TexGlyphPadding` option. (#1282) [@jadwallis] - ImFontAtlas: Made it possible to override size of AddFontDefault() (even if it isn't really recommended!). - ImDrawList: Added `GetClipRectMin()`, `GetClipRectMax()` helpers. - Fixed Ini saving crash if the ImGuiWindowFlags_NoSavedSettings gets removed from a window after its creation (unlikely!). (#1000) -- Fixed `PushID()`/`PopID()` from marking parent window as Accessed (which needlessly woke up the root "Debug" window when used outside of a regular window). (#747) +- Fixed `PushID()`/`PopID()` from marking parent window as Accessed (which needlessly woke up the + root "Debug" window when used outside of a regular window). (#747) - Fixed an assert when calling `CloseCurrentPopup()` twice in a row. [@nem0] - Window size can be loaded from .ini data even if ImGuiWindowFlags_NoResize flag is set. (#1048, #1056) - Columns: Added `SetColumnWidth()`. (#913) [@ggtucker] - Columns: Dragging a column preserve its width by default. (#913) [@ggtucker] - Columns: Fixed first column appearing wider than others. (#1266) -- Columns: Fixed allocating space on the right-most side with the assumption of a vertical scrollbar. The space is only allocated when needed. (#125, #913, #893, #1138) -- Columns: Fixed the right-most column from registering its content width to the parent window, which led to various issues when using auto-resizing window or e.g. horizontal scrolling. (#519, #125, #913) +- Columns: Fixed allocating space on the right-most side with the assumption of a vertical scrollbar. + The space is only allocated when needed. (#125, #913, #893, #1138) +- Columns: Fixed the right-most column from registering its content width to the parent window, + which led to various issues when using auto-resizing window or e.g. horizontal scrolling. (#519, #125, #913) - Columns: Refactored some of the columns code internally toward a better API (not yet exposed) + minor optimizations. (#913) [@ggtucker, @ocornut] -- Popups: Most pop-ups windows can be moved by the user after appearing (if they don't have explicit positions provided by caller, or e.g. sub-menu pop-up). The previous restriction was totally arbitrary. (#1252) -- Tooltip: `SetTooltip()` is expanded immediately into a window, honoring current font / styling setting. Add internal mechanism to override tooltips. (#862) +- Popups: Most pop-ups windows can be moved by the user after appearing (if they don't have explicit + positions provided by caller, or e.g. sub-menu pop-up). The previous restriction was totally arbitrary. (#1252) +- Tooltip: `SetTooltip()` is expanded immediately into a window, honoring current font / styling setting. + Add internal mechanism to override tooltips. (#862) - PlotHistogram: bars are drawn based on zero-line, so negative values are going under. (#828) -- Scrolling: Fixed return values of `GetScrollMaxX()`, `GetScrollMaxY()` when both scrollbars were enabled. Tweak demo to display more data. (#1271) [@degracode] +- Scrolling: Fixed return values of `GetScrollMaxX()`, `GetScrollMaxY()` when both scrollbars were enabled. + Tweak demo to display more data. (#1271) [@degracode] - Scrolling: Fixes for Vertical Scrollbar not automatically getting enabled if enabled Horizontal Scrollbar straddle the vertical limit. (#1271, #246) - Scrolling: `SetScrollHere()`, `SetScrollFromPosY()`: Fixed Y scroll aiming when Horizontal Scrollbar is enabled. (#665). - [Windows] Clipboard: Fixed not closing Win32 clipboard on early open failure path. (#1264) @@ -5022,7 +5183,8 @@ Other Changes: - Demo: Rearranged everything under Widgets in a more consistent way. - Demo: Columns: Added Horizontal Scrolling demo. Tweaked another Columns demo. (#519, #125, #913) - Examples: OpenGL: Various makefiles for MINGW, Linux. (#1209, #1229, #1209) [@fr500, @acda] -- Examples: Enabled vsync by default in example applications, so it doesn't confuse people that the sample run at 2000+ fps and waste an entire CPU. (#1213, #1151). +- Examples: Enabled vsync by default in example applications, so it doesn't confuse people that + the sample run at 2000+ fps and waste an entire CPU. (#1213, #1151). - Various other small fixes, tweaks, comments, optimizations. @@ -5035,11 +5197,16 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: - Added a void* user_data parameter to Clipboard function handlers. (#875) -- SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal. +- SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. + This was sort of always the intent and hopefully breakage should be minimal. - Renamed ImDrawList::PathFill() - rarely used directly - to ImDrawList::PathFillConvex() for clarity and consistency. - Removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset. -- Style: style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. -- BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild(). +- Style: style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) + for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc. +- BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions + as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple + times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() + and use it instead of passing string to BeginChild(). Other Changes: @@ -5049,7 +5216,8 @@ Other Changes: - InputText(): Fixed pressing home key on last character when it isn't a trailing \n (#588, #815) - InputText(): Fixed state corruption/crash bug in stb_textedit.h redo logic when exhausting undo/redo char buffer. (#715. #681) - InputTextMultiline(): Fixed CTRL+DownArrow moving scrolling out of bounds. -- InputTextMultiline(): Scrollbar fix for when input and latched internal buffers differs in a way that affects vertical scrollbar existence. (#725) +- InputTextMultiline(): Scrollbar fix for when input and latched internal buffers differs in + a way that affects vertical scrollbar existence. (#725) - ImFormatString(): Fixed an overflow handling bug with implementation of vsnprintf() that do not return -1. (#793) - BeginChild(const char*) now applies stack id to provided label, consistent with other widgets. (#894, #713) - SameLine() with explicit X position is relative to left of group/columns. (ref #746, #125, #630) @@ -5068,7 +5236,8 @@ Other Changes: - Fixed PlotLines() PlotHistogram() calling with values_count == 0. - Fixed clicking on a window's void while staying still overzealously marking .ini settings as dirty. (#923) - Fixed assert triggering when a window has zero rendering but has a callback. (#810) -- Scrollbar: Fixed rendering when sizes are negative to reduce glitches (which can happen with certain style settings and zero WindowMinSize). +- Scrollbar: Fixed rendering when sizes are negative to reduce glitches (which can happen with + certain style settings and zero WindowMinSize). - EndGroup(): Made IsItemHovered() work when an item was activated within the group. (#849) - BulletText(): Fixed stopping to display formatted string after the '##' mark. - Closing the focused window restore focus to the first active root window in descending z-order .(part of #727) @@ -5078,7 +5247,8 @@ Other Changes: - ImGuiListClipper: Fixed automatic-height calc path dumbly having user display element 0 twice. (#661, #716) - ImGuiListClipper: Fix to behave within column. (#661, #662, #716) - ImDrawList: Renamed ImDrawList::PathFill() to ImDrawList::PathFillConvex() for clarity. (BREAKING API) -- Columns: End() avoid calling Columns(1) if no columns set is open, not sure why it wasn't the case already (pros: faster, cons: exercise less code). +- Columns: End() avoid calling Columns(1) if no columns set is open, not sure why it wasn't the + case already (pros: faster, cons: exercise less code). - ColorButton(): Fix ColorButton showing wrong hex value for alpha. (#1068) [@codecat] - ColorEdit4(): better preserve inputting value out of 0..255 range, display then clamped in Hexadecimal form. - Shutdown() clear out some remaining pointers for sanity. (#836) @@ -5089,7 +5259,8 @@ Other Changes: - ImFont: Added GetGlyphRangesThai() helper. [@nProtect] - ImFont: CalcWordWrapPositionA() fixed font scaling with fallback character. - ImFont: Calculate and store the approximate texture surface to get an idea of how costly each source font is. -- ImFontConfig: Added GlyphOffset to explicitly offset glyphs at font build time, useful for merged fonts. Removed MergeGlyphCenterV. (BREAKING API) +- ImFontConfig: Added GlyphOffset to explicitly offset glyphs at font build time, useful for merged fonts. + Removed MergeGlyphCenterV. (BREAKING API) - Clarified asserts in CheckStacksSize() when there is a stack mismatch. - Context: Support for #define-ing GImGui and IMGUI_SET_CURRENT_CONTEXT_FUNC to enable custom thread-based hackery (#586) - Updated stb_truetype.h to 1.14 (added OTF support, removed warnings). (#883, #976) @@ -5111,7 +5282,8 @@ Other Changes: - Examples: OpenGL*: Saving/restoring active texture number (the value modified by glActiveTexture). (#1087, #1088, #1116) - Examples: OpenGL*: Saving/restoring separate color/alpha blend functions correctly. (#1120) [@greggman] - Examples: OpenGL2: Uploading font texture as RGBA32 to increase compatibility with users shaders for beginners. (#824) -- Examples: Vulkan: Countless fixes and improvements. (#785, #804, #910, #1017, #1039, #1041, #1042, #1043, #1080) [@martty, @Loftilus, @ParticlePeter, @SaschaWillems] +- Examples: Vulkan: Countless fixes and improvements. (#785, #804, #910, #1017, #1039, #1041, + #1042, #1043, #1080) [@martty, @Loftilus, @ParticlePeter, @SaschaWillems] - Examples: DirectX9/10/10: Only call SetCursor(NULL) is io.MouseDrawCursor is set. (#585, #909) - Examples: DirectX9: Explicitly setting viewport to match that other examples are doing. (#937) - Examples: GLFW+OpenGL3: Fixed Shutdown() calling GL functions with NULL parameters if NewFrame was never called. (#800) @@ -5131,11 +5303,22 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: - Renamed `SetNextTreeNodeOpened()` to `SetNextTreeNodeOpen()` for consistency, no redirection. -- Removed confusing set of `GetInternalState()`, `GetInternalStateSize()`, `SetInternalState()` functions. Now using `CreateContext()`, `DestroyContext()`, `GetCurrentContext()`, `SetCurrentContext()`. If you were using multiple contexts the change should be obvious and trivial. -- Obsoleted old signature of `CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false)`, as extra parameters were badly designed and rarely used. Most uses were using 1 parameter and shouldn't affect you. You can replace the "default_open = true" flag in new API with `CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)`. -- Changed `ImDrawList::PushClipRect(ImVec4 rect)` to `ImDraw::PushClipRect(ImVec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false)`. Note that higher-level `ImGui::PushClipRect()` is preferable because it will clip at logic/widget level, whereas `ImDrawList::PushClipRect()` only affect your renderer. -- Title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore (see #655). If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. - This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. (Or If this is confusing, just pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.) +- Removed confusing set of `GetInternalState()`, `GetInternalStateSize()`, `SetInternalState()` functions. + Now using `CreateContext()`, `DestroyContext()`, `GetCurrentContext()`, `SetCurrentContext()`. + If you were using multiple contexts the change should be obvious and trivial. +- Obsoleted old signature of `CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false)`, + as extra parameters were badly designed and rarely used. Most uses were using 1 parameter and shouldn't affect you. + You can replace the "default_open = true" flag in new API with `CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)`. +- Changed `ImDrawList::PushClipRect(ImVec4 rect)` to `ImDraw::PushClipRect(ImVec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false)`. + Note that higher-level `ImGui::PushClipRect()` is preferable because it will clip at logic/widget level, whereas `ImDrawList::PushClipRect()` only affect your renderer. +- Title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background + (ImGuiCol_WindowBg color) anymore (see #655). If your TitleBg/TitleBgActive alpha was 1.0f or you are using + the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to + tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. + This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, + given the OLD color and the OLD WindowBg color. (Or If this is confusing, just pick the RGB value from + title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create + TitleBgActive from a tweaked TitleBg color.) ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { @@ -5146,9 +5329,11 @@ Breaking Changes: Other changes: -- New version of ImGuiListClipper helper calculates item height automatically. See comments and demo code. (#662, #661, #660) +- New version of ImGuiListClipper helper calculates item height automatically. + See comments and demo code. (#662, #661, #660) - Added SetNextWindowSizeConstraints() to enable basic min/max and programmatic size constraints on window. Added demo. (#668) -- Added PushClipRect()/PopClipRect() (previously part of imgui_internal.h). Changed ImDrawList::PushClipRect() prototype. (#610) +- Added PushClipRect()/PopClipRect() (previously part of imgui_internal.h). + Changed ImDrawList::PushClipRect() prototype. (#610) - Added IsRootWindowOrAnyChildHovered() helper. (#615) - Added TreeNodeEx() functions. (#581, #600, #190) - Added ImGuiTreeNodeFlags_Selected flag to display TreeNode as "selected". (#581, #190) @@ -5158,31 +5343,38 @@ Other changes: - Added ImGuiTreeNodeFlags_DefaultOpen flag (previously private). - Added ImGuiTreeNodeFlags_OpenOnDoubleClick flag. - Added ImGuiTreeNodeFlags_OpenOnArrow flag. -- Added ImGuiTreeNodeFlags_Leaf flag, always opened, no arrow, for convenience. For simple use case prefer using TreeAdvanceToLabelPos()+Text(). +- Added ImGuiTreeNodeFlags_Leaf flag, always opened, no arrow, for convenience. + For simple use case prefer using TreeAdvanceToLabelPos()+Text(). - Added ImGuiTreeNodeFlags_Bullet flag, to add a bullet to Leaf node or replace Arrow with a bullet. - Added TreeAdvanceToLabelPos(), GetTreeNodeToLabelSpacing() helpers. (#581, #324) -- Added CreateContext()/DestroyContext()/GetCurrentContext()/SetCurrentContext(). Obsoleted nearly identical GetInternalState()/SetInternalState() functions. (#586, #269) +- Added CreateContext()/DestroyContext()/GetCurrentContext()/SetCurrentContext(). + Obsoleted nearly identical GetInternalState()/SetInternalState() functions. (#586, #269) - Added NewLine() to undo a SameLine() and as a shy reminder that horizontal layout support hasn't been implemented yet. - Added IsItemClicked() helper. (#581) - Added CollapsingHeader() variant with close button. (#600) - Fixed MenuBar missing lower border when borders are enabled. - InputText(): Fixed clipping of cursor rendering in case it gets out of the box (which can be forced w/ ImGuiInputTextFlags_NoHorizontalScroll. (#601) - Style: Changed default IndentSpacing from 22 to 21. (#581, #324) -- Style: Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, which was inconsistent and causing visual artifact. (#655) - This broke the meaning of TitleBg and TitleBgActive. Only affect values where Alpha<1.0f. Fixed default theme. Read comments in "API BREAKING CHANGES" section to convert. +- Style: Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, which was + inconsistent and causing visual artifact. (#655) + This broke the meaning of TitleBg and TitleBgActive. Only affect values where Alpha<1.0f. + Fixed default theme. Read comments in "API BREAKING CHANGES" section to convert. - Relative rendering of order of Child windows creation is preserved, to allow more control with overlapping children. (#595) - Fixed GetWindowContentRegionMax() being off by ScrollbarSize amount when explicit SizeContents is set. - Indent(), Unindent(): optional non-default indenting width. (#324, #581) - Bullet(), BulletText(): Slightly bigger. Less polygons. -- ButtonBehavior(): fixed subtle old bug when a repeating button would also return true on mouse release (barely noticeable unless RepeatRate is set to be very slow). (#656) +- ButtonBehavior(): fixed subtle old bug when a repeating button would also return true on mouse + release (barely noticeable unless RepeatRate is set to be very slow). (#656) - BeginMenu(): a menu that becomes disabled while open gets closed down, facilitate user's code. (#126) - BeginGroup(): fixed using within Columns set. (#630) - Fixed a lag in reading the currently hovered window when dragging a window. (#635) - Obsoleted 4 parameters version of CollapsingHeader(). Refactored code into TreeNodeBehavior. (#600, #579) - Scrollbar: minor fix for top-right rounding of scrollbar background when window has menu bar but no title bar. - MenuItem(): the check mark renders in disabled color when menu item is disabled. -- Fixed clipping rectangle floating point representation to ensure renderer-side float point operations yield correct results in typical DirectX/GL settings. (#582, 597) -- Fixed GetFrontMostModalRootWindow(), fixing missing fade-out when a combo pop was used stacked over a modal window. (#604) +- Fixed clipping rectangle floating point representation to ensure renderer-side floating-point + operations yield correct results in typical DirectX/GL settings. (#582, 597) +- Fixed GetFrontMostModalRootWindow(), fixing missing fade-out when a combo pop was used stacked + over a modal window. (#604) - ImDrawList: Added AddQuad(), AddQuadFilled() helpers. - ImDrawList: AddText() refactor, moving some code to ImFont, reserving less unused vertices when large vertical clipping occurs. - ImFont: Added RenderChar() helper. @@ -5193,7 +5385,8 @@ Other changes: - Renamed majority of use of the word "opened" to "open" for clarity. Renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(). (#625, #579) - Examples: OpenGL3: Saving/restoring glActiveTexture() state. (#602) - Examples: DirectX9: save/restore all device state. -- Examples: DirectX9: Removed dependency on d3dx9.h, d3dx9.lib, dxguid.lib so it can be used in a DirectXMath.h only environment. (#611) +- Examples: DirectX9: Removed dependency on d3dx9.h, d3dx9.lib, dxguid.lib so it can be used in + a DirectXMath.h only environment. (#611) - Examples: DirectX10/X11: Apply depth-stencil state (no use of depth buffer). (#640, #636) - Examples: DirectX11/X11: Added comments on removing dependency on D3DCompiler. (#638) - Examples: SDL: Initialize video+timer subsystem only. @@ -5208,33 +5401,53 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- Consistently honoring exact width passed to PushItemWidth() (when positive), previously it would add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) -- Style: removed `style.WindowFillAlphaDefault` which was confusing and redundant, baked alpha into `ImGuiCol_WindowBg` color. If you had a custom WindowBg color but didn't change WindowFillAlphaDefault, multiply WindowBg alpha component by 0.7. Renamed `ImGuiCol_TooltipBg` to `ImGuiCol_PopupBG`, applies to other types of pop-ups. `bg_alpha` parameter of 5-parameters version of Begin() is an override. (#337) -- InputText(): Added BufTextLen field in ImGuiTextEditCallbackData. Requesting user to update it if the buffer is modified in the callback. Added a temporary length-check assert to minimize panic for the 3 people using the callback. (#541) -- Renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). (#340) +- Consistently honoring exact width passed to PushItemWidth() (when positive), previously it would + add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) +- Style: removed `style.WindowFillAlphaDefault` which was confusing and redundant, baked alpha into + `ImGuiCol_WindowBg` color. If you had a custom WindowBg color but didn't change WindowFillAlphaDefault, + multiply WindowBg alpha component by 0.7. Renamed `ImGuiCol_TooltipBg` to `ImGuiCol_PopupBG`, + applies to other types of pop-ups. `bg_alpha` parameter of 5-parameters version of Begin() is an override. (#337) +- InputText(): Added BufTextLen field in ImGuiTextEditCallbackData. Requesting user to update it + if the buffer is modified in the callback. Added a temporary length-check assert to minimize panic + for the 3 people using the callback. (#541) +- Renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). + Kept inline redirection function (will obsolete). (#340) Other Changes: -- Consistently honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) -- Fixed clipping of child windows within parent not taking account of child outer clipping boundaries (including scrollbar, etc.). (#506) -- TextUnformatted(): Fixed rare crash bug with large blurb of text (2k+) not finished with a '\n' and fully above the clipping Y line. (#535) +- Consistently honoring exact width passed to PushItemWidth(), previously it would add extra + FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) +- Fixed clipping of child windows within parent not taking account of child outer clipping + boundaries (including scrollbar, etc.). (#506) +- TextUnformatted(): Fixed rare crash bug with large blurb of text (2k+) not finished with + a '\n' and fully above the clipping Y line. (#535) - IO: Added 'KeySuper' field to hold CMD keyboard modifiers for OS X. Updated all examples accordingly. (#473) - Added ImGuiWindowFlags_ForceVerticalScrollbar, ImGuiWindowFlags_ForceHorizontalScrollbar flags. (#476) - Added IM_COL32 macros to generate a U32 packed color, convenient for direct use of ImDrawList api. (#346) - Added GetFontTexUvWhitePixel() helper, convenient for direct use of ImDrawList api. -- Selectable(): Added ImGuiSelectableFlags_AllowDoubleClick flag to allow user reacting on double-click. (@zapolnov) (#516) +- Selectable(): Added ImGuiSelectableFlags_AllowDoubleClick flag to allow user reacting + on double-click. (@zapolnov) (#516) - Begin(): made the close button explicitly set the boolean to false instead of toggling it. (#499) - BeginChild()/EndChild(): fixed incorrect layout to allow widgets submitted after an auto-fitted child window. (#540) -- BeginChild(): Added ImGuiWindowFlags_AlwaysUseWindowPadding flag to ensure non-bordered child window uses window padding. (#462) -- Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(), ProgressBar(): outer frame not honoring bordering. (#462, #503) +- BeginChild(): Added ImGuiWindowFlags_AlwaysUseWindowPadding flag to ensure non-bordered child window + uses window padding. (#462) +- Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(), ProgressBar(): outer frame not + honoring bordering. (#462, #503) - Fixed Image(), ImageButtion() rendering a rectangle 1 px too large on each axis. (#457) - SetItemAllowOverlap(): Promoted from imgui_internal.h to public imgui.h api. (#517) - Combo(): Right-most button stays highlighted when pop-up is open. - Combo(): Display pop-up above if there's isn't enough space below / or select largest side. (#505) -- DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) -- DragFloat(): Always apply value when mouse is held/widget active, so that an always-resetting variable (e.g. non saved local) can be passed. -- InputText(): OS X friendly behaviors: Word movement uses ALT key; Shortcuts uses CMD key; Double-clicking text select a single word; Jumping to next word sets cursor to end of current word instead of beginning of current word. (@zhiayang), (#473) -- InputText(): Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it if buffer is modified. Zero-ing structure properly before use. (#541) +- DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly + after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) +- DragFloat(): Always apply value when mouse is held/widget active, so that an always-resetting + variable (e.g. non saved local) can be passed. +- InputText(): OS X friendly behaviors: (@zhiayang), (#473) + - Word movement uses ALT key; + - Shortcuts uses CMD key; + - Double-clicking text select a single word; + - Jumping to next word sets cursor to end of current word instead of beginning of current word. +- InputText(): Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it + if buffer is modified. Zero-ing structure properly before use. (#541) - CheckboxFlags(): Added support for testing/setting multiple flags at the same time. (@DMartinek) (#555) - TreeNode(), CollapsingHeader() fixed not being able to use "##" sequence in a formatted label. - ColorEdit4(): Empty label doesn't add InnerSpacing.x, matching behavior of other widgets. (#346) @@ -5260,11 +5473,13 @@ Other Changes: - Demo: plot code doesn't use ImVector to avoid heap allocation and be more friendly to custom allocator users. (#538) - Fixed compilation on DragonFly BSD (@mneumann) (#563) - Examples: Vulkan: Added a Vulkan example (@Loftilus) (#549) -- Examples: DX10, DX11: Saving/restoring most device state so dropping render function in your codebase shouldn't have DX device side-effects. (#570) +- Examples: DX10, DX11: Saving/restoring most device state so dropping render function in your + codebase shouldn't have DX device side-effects. (#570) - Examples: DX10, DX11: Fixed ImGui_ImplDX??_NewFrame() from recreating device objects if render isn't called (g_pVB not set). - Examples: OpenGL3: Fix BindVertexArray/BindBuffer order. (@nlguillemot) (#527) - Examples: OpenGL: skip rendering and calling glViewport() if we have zero-fixed buffer. (#486) -- Examples: SDL2+OpenGL3: Fix context creation options. Made ImGui_ImplSdlGL3_NewFrame() signature match GL2 one. (#468, #463) +- Examples: SDL2+OpenGL3: Fix context creation options. Made ImGui_ImplSdlGL3_NewFrame() signature + match GL2 one. (#468, #463) - Examples: SDL2+OpenGL2/3: Fix for high-dpi displays. (@nickgravelyn) - Various extra comments and clarification in the code. - Various other fixes and optimizations. @@ -5388,7 +5603,11 @@ Breaking Changes: are now incorporating the scrolling amount. They were incorrectly not incorporating this amount previously. It PROBABLY shouldn't break anything, but that depends on how you used them. Namely: - If you always used SetCursorPos() with values relative to GetCursorPos() there shouldn't be a problem. - However if you used absolute coordinates, note that SetCursorPosY(100.0f) will put you at +100 from the initial Y position (which may be scrolled out of the view), NOT at +100 from the window top border. Since there wasn't any official scrolling value on X axis (past just manually moving the cursor) this can only affect you if you used to set absolute coordinates on the Y axis which is hopefully rare/unlikely, and trivial to fix. + However if you used absolute coordinates, note that SetCursorPosY(100.0f) will put you at +100 from the + initial Y position (which may be scrolled out of the view), NOT at +100 from the window top border. + Since there wasn't any official scrolling value on X axis (past just manually moving the cursor) this can + only affect you if you used to set absolute coordinates on the Y axis which is hopefully rare/unlikely, + and trivial to fix. - The value of GetWindowContentRegionMax() isn't necessarily close to GetWindowWidth() if horizontally scrolling. Previously they were roughly interchangeable (roughly because the content region exclude window padding). @@ -5416,9 +5635,11 @@ Other Changes: - TreeNode(): Fixed mouse interaction padding past the node label being accounted for in layout (#282). - BeginChild(): Passing a ImGuiWindowFlags_NoMove inhibits moving parent window from this child. - BeginChild() fixed missing rounding for child sizes which leaked into layout and have items misaligned. -- Begin(): Removed default name = "Debug" parameter. We already have a "Debug" window pushed to the stack in the first place so it's not really a useful default. +- Begin(): Removed default name = "Debug" parameter. We already have a "Debug" window pushed to the stack in + the first place so it's not really a useful default. - Begin(): Minor fixes with windows main clipping rectangle (e.g. child window with border). -- Begin(): Window flags are only read on the first call of the frame. Subsequent calls ignore flags, which allows appending to a window without worryin about flags. +- Begin(): Window flags are only read on the first call of the frame. Subsequent calls ignore flags, which allows + appending to a window without worryin about flags. - InputText(): ignore character input when ctrl/alt are held. (Normally those text input are ignored by most wrappers.) (#279). - Demo: Fixed incorrectly formed string passed to Combo (#298). - Demo: Added simple Log demo. @@ -5573,10 +5794,13 @@ Other Changes: - Added TitleBgActive color in style so focused window is made visible. (#253) - Added CaptureKeyboardFromApp() / CaptureMouseFromApp() to manually enforce inputs capturing. - Added DragFloatRange2() DragIntRange2() helpers. (#76) -- Added a Y centering ratio to SetScrollFromCursorPos() which can be used to aim the top or bottom of the window. (#150) +- Added a Y centering ratio to SetScrollFromCursorPos() which can be used to aim the top + or bottom of the window. (#150) - Added SetScrollY(), SetScrollFromPos(), GetCursorStartPos() for manual scrolling manipulations. (#150). -- Added GetKeyIndex() helper for converting from ImGuiKey_\* enum to user's keycodes. Basically pulls from io.KeysMap[]. -- Added missing ImGuiKey_PageUp, ImGuiKey_PageDown so more UI code can be written without referring to implementation-side keycodes. +- Added GetKeyIndex() helper for converting from ImGuiKey_\* enum to user's keycodes. + Basically pulls from io.KeysMap[]. +- Added missing ImGuiKey_PageUp, ImGuiKey_PageDown so more UI code can be written without + referring to implementation-side keycodes. - MenuItem() can be activated on release. (#245) - Allowing NewFrame() with DeltaTime==0.0f to not assert. - Fixed IsMouseDragging(). (#260) @@ -5587,8 +5811,8 @@ Other Changes: - Fixed text baseline alignment of small button (no padding) after regular buttons. - Fixed ListBoxHeader() not honoring negative sizes the same way as BeginChild() or BeginChildFrame(). (#263) - Fixed warnings for more pedantic compiler settings (#258). -- ImVector<> cannot be re-defined anymore, cannot be replaced with std::vector<>. Allowed us to clean up and optimize - lots of code. Yeah! (#262) +- ImVector<> cannot be re-defined anymore, cannot be replaced with std::vector<>. + Allowed us to clean up and optimize lots of code. Yeah! (#262) - ImDrawList: store pointer to their owner name for easier auditing/debugging. - Examples: added scroll tracking example with SetScrollFromCursorPos(). - Examples: metrics windows render clip rectangle when hovering over a draw call. @@ -5611,11 +5835,12 @@ Breaking Changes: Other Changes: -- Added InputTextMultiline() multi-line text editor, vertical scrolling, selection, optimized enough to handle rather - big chunks of text in stateless context (thousands of lines are ok), option for allowing Tab to be input, option - for validating with Return or Ctrl+Return (#200). -- Added modal window API, BeginPopupModal(), follows the popup api scheme. Modal windows can be closed by clicking - outside. By default the rest of the screen is dimmed (using ImGuiCol_ModalWindowDarkening). Modal windows can be stacked. +- Added InputTextMultiline() multi-line text editor, vertical scrolling, selection, optimized + enough to handle rather big chunks of text in stateless context (thousands of lines are ok), + option for allowing Tab to be input, option for validating with Return or Ctrl+Return (#200). +- Added modal window API, BeginPopupModal(), follows the popup api scheme. Modal windows can be closed + by clicking outside. By default the rest of the screen is dimmed (using ImGuiCol_ModalWindowDarkening). + Modal windows can be stacked. - Added GetGlyphRangesCyrillic() helper (#237). - Added SetNextWindowPosCenter() to center a window prior to knowing its size. (#249) - Added IsWindowHovered() helper. @@ -5631,7 +5856,8 @@ Other Changes: - Selectable(): Added flag ImGuiSelectableFlags_DontClosePopups. - Selectable(): Added flag ImGuiSelectableFlags_SpanAllColumns (#125). - Combo(): Fixed issue with activating a Combo() not taking active id (#241). -- ColorButton(), ColorEdit4(): fix to ensure that the colored square stays square when non-default padding settings are used. +- ColorButton(), ColorEdit4(): fix to ensure that the colored square stays square when + non-default padding settings are used. - BeginChildFrame(): returns bool like BeginChild() for clipping. - SetScrollPosHere(): takes account of item height + more accurate centering + fixed precision issue. - ImFont: ignoring '\r'. @@ -5653,26 +5879,30 @@ Breaking Changes: - The third parameter of Button(), 'repeat_if_held' has been removed. While it's been very rarely used, some code will possibly break if you didn't rely on the default parameter. Use PushButtonRepeat()/PopButtonRepeat() to configure repeat. -- Renamed IsRectClipped() to !IsRectVisible() for consistency (opposite return value!). Kept inline redirection function (will obsolete) -- Renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline indirection function (will obsolete). +- Renamed IsRectClipped() to !IsRectVisible() for consistency (opposite return value!). + Kept inline redirection function (will obsolete) +- Renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. + Kept inline indirection function (will obsolete). Other Changes: -- Menus: Added a menu system! Menus are typically populated with menu items and sub-menus, but you can add any sort of - widgets in them (buttons, text inputs, sliders, etc.). (#126) -- Menus: Added MenuItem() to append a menu item. Optional shortcut display, acts a button & toggle with checked/unchecked state, - disabled mode. Menu items can be used in any window. +- Menus: Added a menu system! Menus are typically populated with menu items and sub-menus, + but you can add any sort of widgets in them (buttons, text inputs, sliders, etc.). (#126) +- Menus: Added MenuItem() to append a menu item. Optional shortcut display, acts a button & toggle + with checked/unchecked state, disabled mode. Menu items can be used in any window. - Menus: Added BeginMenu() to append a sub-menu. Note that you generally want to add sub-menu inside a popup or a menu-bar. They will work inside a normal window but it will be a bit unusual. - Menus: Added BeginMenuBar() to append to window menu-bar (set ImGuiWindowFlags_MenuBar to enable). - Menus: Added BeginMainMenuBar() helper to append to a fullscreen main menu-bar. - Popups: Support for stacked popups. Each popup level inhibit inputs to lower levels. The menus system is based on this. (#126). -- Popups: Added BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid() to create a popup window on mouse-click. +- Popups: Added BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid() to + create a popup window on mouse-click. - Popups: Popups have borders by default (#197), attenuated border alpha in default theme. -- Popups & Tooltip: Fit within display. Handling various positioning/sizing/scrolling edge cases. Better hysteresis when moving - in corners. Tooltip always tries to stay away from mouse-cursor. +- Popups & Tooltip: Fit within display. Handling various positioning/sizing/scrolling edge + cases. Better hysteresis when moving in corners. Tooltip always tries to stay away from mouse-cursor. - Added ImGuiStorage::GetVoidPtrRef() for manipulating stored void*. -- Added IsKeyDown() IsMouseDown() as convenience and for consistency with existing functions (instead of reading them from IO structures). +- Added IsKeyDown() IsMouseDown() as convenience and for consistency with existing functions + (instead of reading them from IO structures). - Added Dummy() helper to advance layout by a given size. Unlike InvisibleButton() this doesn't catch any click. - Added configurable io.KeyRepeatDelay, io.KeyRepeatRate keyboard and mouse repeat rate. - Added PushButtonRepeat() / PopButtonRepeat() to enable hold-button-to-repeat press on any button. @@ -5698,7 +5928,8 @@ Other Changes: - Window: Added ImGuiSetCond_Appearing to test the hidden->visible transition in SetWindow***/SetNextWindow*** functions. - Window: Auto-fitting cancel out one worth of vertical spacing for vertical symmetry (like what group and tooltip do). - Window: Default item width for auto-resizing windows expressed as a factor of font height, scales better with different font. -- Window: Fixed auto-fit calculation mismatch of whether a scrollbar will be added by maximum height clamping. Also honor NoScrollBar in the case of height clamping, not adding extra horizontal space. +- Window: Fixed auto-fit calculation mismatch of whether a scrollbar will be added by maximum height + clamping. Also honor NoScrollBar in the case of height clamping, not adding extra horizontal space. - Window: Hovering require to hover same child window. Reverted 860cf57 (December 3). Might break something if you have child overlapping items in parent window. - Window: Fixed appending multiple times to an existing child via multiple BeginChild/EndChild calls to same child name. @@ -5707,7 +5938,8 @@ Other Changes: - Metrics: Added io.MetricsActiveWindows counter. (#213. - Metrics: Added io.MetricsAllocs counter (number of active memory allocations). - Metrics: ShowMetricsWindow() shows popups stack, allocations. -- Style: Added style.DisplayWindowPadding to prevent windows from reaching edges of display (similar to style.DisplaySafeAreaPadding which is still in effect and also affect popups/tooltips). +- Style: Added style.DisplayWindowPadding to prevent windows from reaching edges of display + (similar to style.DisplaySafeAreaPadding which is still in effect and also affect popups/tooltips). - Style: Removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same). - Style: Added style.ScrollbarRounding. (#212) - Style: Added ImGuiCol_TextDisabled for disabled text. Added TextDisabled() helper. @@ -5749,9 +5981,11 @@ Other Changes: Hold SHIFT/ALT to speed-up/slow-down. Double-click or CTRL+click to input text. Passing min >= max makes the widget unbounded. - Added DragFloat2(), DragFloat3(), DragFloat4(), DragInt2(), DragInt3(), DragInt4() helper variants. -- Added ShowMetricsWindow() which is mainly useful to debug ImGui internals. Added IO.MetricsRenderVertices counter. +- Added ShowMetricsWindow() which is mainly useful to debug ImGui internals. +- Added IO.MetricsRenderVertices counter. - Added ResetMouseDragDelta() for iterative dragging operations. -- Added ImFontAtlas::AddFontFromCompressedTTF() helper + binary_to_compressed_c.cpp tool to compress a file and create a .c array from it. +- Added ImFontAtlas::AddFontFromCompressedTTF() helper + binary_to_compressed_c.cpp tool to + compress a file and create a .c array from it. - Added PushId() GetId() variants that takes string range to avoid user making unnecessary copies. - Added IsItemVisible(). - Fixed IsRectClipped() incorrectly returning false when log is enabled. @@ -5773,7 +6007,8 @@ Other Changes: - ShowTestWindow(): added examples for DragFloat, DragInt and only custom label embedded in format strings. - ShowTestWindow(): fixed "manipulating titles" example not doing the right thing, broken in ff35d24 - Examples: OpenGL/GLFW: Fixed modifier key state setting in GLFW callbacks. -- Examples: OpenGL/GLFW: Added glBindTexture(0) in OpenGL fixed pipeline examples. Save restore current program and texture in the OpenGL3 example. +- Examples: OpenGL/GLFW: Added glBindTexture(0) in OpenGL fixed pipeline examples. + Save restore current program and texture in the OpenGL3 example. - Examples: DirectX11: Removed unnecessary vertices conversion and CUSTOMVERTEX types. - Comments, fixes, tweaks. @@ -5787,16 +6022,22 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: - Added a more convenient three parameters version of Begin() which covers the common uses better. -- Added mouse cursor types handling (resize, move, text input cursors, etc.) that user can query with GetMouseCursor(). Added demo and instructions in ShowTestWindow(). +- Added mouse cursor types handling (resize, move, text input cursors, etc.) that user + can query with GetMouseCursor(). Added demo and instructions in ShowTestWindow(). - Added embedded mouse cursor data for MouseDrawCursor software cursor rendering, for consoles/tablets/etc. (#155). -- Added first version of BeginPopup/EndPopup() helper API to create popup menus. Popups automatically lock their position to the mouse cursor when first appearing. They close automatically when clicking outside, and inhibit hovering items from other windows when active (to allow for clicking outside). (#126) +- Added first version of BeginPopup/EndPopup() helper API to create popup menus. Popups automatically + lock their position to the mouse cursor when first appearing. They close automatically when clicking + outside, and inhibit hovering items from other windows when active (to allow for clicking outside). (#126) - Added thickness parameter to ImDrawList::AddLine(). - Added ImDrawList::PushClipRectFullScreen() helper. -- Added style.DisplaySafeAreaPadding which was previously hard-coded (useful if you can't see the edges of your display, e.g. TV screens). +- Added style.DisplaySafeAreaPadding which was previously hard-coded. + (useful if you can't see the edges of your display, e.g. TV screens). - Added CalcItemRectClosestPoint() helper. -- Added GetMouseDragDelta(), IsMouseDragging() helpers, given a mouse button and an optional "unlock" threshold. Added io.MouseDragThreshold setting. (#167) +- Added GetMouseDragDelta(), IsMouseDragging() helpers, given a mouse button and an optional + "unlock" threshold. Added io.MouseDragThreshold setting. (#167) - IsItemHovered() return false if another widget is active, aka we can't use what we are hovering now. -- Added IsItemHoveredRect() if old behavior of IsItemHovered() is needed (e.g. for implementing the drop side of a drag'n drop operation). +- Added IsItemHoveredRect() if old behavior of IsItemHovered() is needed (e.g. for implementing + the drop side of a drag'n drop operation). - IsItemhovered() include space taken by label and behave consistently for all widgets (#145) - Auto-filling child window feed their content size to parent (#170) - InputText() removed the odd ~ characters when clipping. @@ -5806,15 +6047,20 @@ Other Changes: - Selectable(const char*, bool) version has bool defaulting to false. - Selectable(): fixed misusage of GetContentRegionMax().x leaking into auto-fitting. - Windows starting Collapsed runs initial auto-fit to retrieve a width for their title bar (#175) -- Fixed new window from having an incorrect content size on their first frame, if queried by user. Fixed SetWindowPos/SetNextWindowPos having a side-effect size computation (#175) +- Fixed new window from having an incorrect content size on their first frame, if queried by user. + Fixed SetWindowPos/SetNextWindowPos having a side-effect size computation (#175) - InputFloat(): fixed label alignment if total widget width forcefully bigger than space available. - Auto contents size aware of enforced vertical scrollbar if window is larger than display size. -- Fixed new windows auto-fitting bigger than their .ini saved size. This was a bug but it may be a desirable effect sometimes, may reconsider it. -- Fixed negative clipping rectangle when collapsing windows that could affect manual submission to ImDrawList and end-user rendering function if unhandled (#177) +- Fixed new windows auto-fitting bigger than their .ini saved size. + This was a bug but it may be a desirable effect sometimes, may reconsider it. +- Fixed negative clipping rectangle when collapsing windows that could affect manual + submission to ImDrawList and end-user rendering function if unhandled (#177) - Fixed bounding measurement of empty groups (fix #162) -- Fixed assignment order in Begin() making auto-fit size effectively lag by one frame. Also disabling "clamp into view" while windows are auto-fitting so that auto-fitting window in corners don't get pushed away. +- Fixed assignment order in Begin() making auto-fit size effectively lag by one frame. Also disabling + "clamp into view" while windows are auto-fitting so that auto-fitting window in corners don't get pushed away. - Fixed MouseClickedPos not updated on double-click update (#167) -- Fixed MouseDrawCursor feature submitting an empty trailing command in the draw list. Fixed unmerged draw calls for software mouse cursor. +- Fixed MouseDrawCursor feature submitting an empty trailing command in the draw list. + Fixed unmerged draw calls for software mouse cursor. - Fixed double-clicking on resize grip keeping the grip active if mouse button is kept held. - Bounding box tests exclude higher bound, so touching items (zero spacing) don't report double hover when cursor is on edge. - Setting io.LogFilename to NULL disable default LogToFile() (part of #175) @@ -5845,7 +6091,8 @@ Other Changes: - Added IsRootWindowFocused(), IsRootWindowOrAnyChildFocused(). - Added io.KeyAlt + support in examples apps, in prevision for future usage of Alt modifier (was missing). - Added ImGuiStyleVar_GrabMinSize enum value for PushStyleVar(). -- Various fixes related to vertical alignment of text after widget of varied sizes. Allow for multiple blocks of multiple lines text on the same "line". Added demos. +- Various fixes related to vertical alignment of text after widget of varied sizes. + Allow for multiple blocks of multiple lines text on the same "line". Added demos. - Explicit size passed to Plot*(), Button() includes the frame padding. - Style: Changed default Border and Column border colors to be most subtle. - Renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing. @@ -5874,8 +6121,10 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: -- Examples: refactored all examples application to make it easier to isolate and grab the code you need for OpenGL 2/3, DirectX 9/11, and toward a more sensible format for samples. -- Scrollbar grab have a minimum size (style.GrabSizeMin), always visible even with huge scroll amount. (#150). +- Examples: refactored all examples application to make it easier to isolate and grab the + code you need for OpenGL 2/3, DirectX 9/11, and toward a more sensible format for samples. +- Scrollbar grab have a minimum size (style.GrabSizeMin), always visible even with huge + scroll amount. (#150). - Scrollbar: Clicking inside the grab box doesn't modify scroll value. Subsequent movement always relative. - Added "###" labelling syntax to pass a label that isn't part of the hashed ID (#107), e.g. ("%d###static_id",rand()). - Added GetColumnIndex(), GetColumnsCount() (#154) @@ -5885,12 +6134,15 @@ Other Changes: - Fixed ListBoxHeader() incorrect handling of SkipItems early out when window is collapsed. - Fixed using IsItemHovered() after EndChild() (#151) - Fixed malformed UTF-8 decoding errors leading to infinite loops (#158) -- InputText() handles buffer limit correctly for multi-byte UTF-8 characters, won't insert an incomplete UTF-8 character when reaching buffer limit (fix #158) -- Handle double-width space (0x3000) in various places the same as single-width spaces, for Chinese/Japanese users. +- InputText() handles buffer limit correctly for multi-byte UTF-8 characters, won't insert + an incomplete UTF-8 character when reaching buffer limit (fix #158) +- Handle double-width space (0x3000) in various places the same as single-width spaces, + for Chinese/Japanese users. - Collapse triangle uses text color (not border color). - Fixed font fallback glyph width. - Renamed style.ScrollBarWidth to style.ScrollbarWidth to be consistent with other casing. -- Windows: setup a default handler for ImeSetInputScreenPosFn so the IME dialog (for Japanese/Chinese, etc.) is positioned correctly as you input text. +- Windows: setup a default handler for ImeSetInputScreenPosFn so the IME dialog + (for Japanese/Chinese, etc.) is positioned correctly as you input text. - Windows: default clipboard handlers for Windows handle UTF-8. - Examples: Fixed DirectX 9/11 examples applications handling of Microsoft IME. - Examples: Allow DirectX 9/11 examples applications to resize the window. @@ -5909,7 +6161,8 @@ Other Changes: - Added Bullet() helper - equivalent to BulletText(""), SameLine(). - Added SetWindowFocus(), SetWindowFocus(const char*), SetNextWindowFocus() (#146) - Added SetWindowPos(), SetWindowSize(), SetWindowCollaposed() given a window name. -- Added SetNextTreeNodeOpened() with optional condition flag in replacement of OpenNextNode() and consistent with other API. +- Added SetNextTreeNodeOpened() with optional condition flag in replacement of OpenNextNode() + and consistent with other API. - Renamed ImGuiSetCondition_* to ImGuiSetCond_* and ImGuiCondition_FirstUseThisSession to ImGuiCond_Once. - Added missing definition for ImGui::GetWindowCollapsed(). - Fixed GetGlyphRangesJapanese() actually missing katakana ranges and a few useful extensions. @@ -5940,18 +6193,23 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: -- InputText: having a InputText widget active doesn't steal mouse inputs from clicking on a button before losing focus (relate to #134) +- InputText: having a InputText widget active doesn't steal mouse inputs from clicking on + a button before losing focus (relate to #134) - InputText: cursor/selection/undo stack persist when using other widgets and getting back to same (#134). -- InputText: fix effective buffer size being smaller than necessary by 1 byte (so if you give 3 bytes you can input 2 ascii chars + zero terminator, which is correct). +- InputText: fix effective buffer size being smaller than necessary by 1 byte (so if you give + 3 bytes you can input 2 ascii chars + zero terminator, which is correct). - Added IsAnyItemActive(). -- Child window explicitly inherit collapse state from parent (so if user keeps submitting items even thought Begin has returned 'false' the child items will be clipped faster). +- Child window explicitly inherit collapse state from parent (so if user keeps submitting items + even thought Begin has returned 'false' the child items will be clipped faster). - BeginChild() return a bool the same way Begin() does. if true you can skip submitting content. - Removed extraneous (1,1) padding on child window (pointed out in #125) - Columns: doesn't bail out when SkipItems is set (fix #136) - Columns: Separator() within column correctly vertical offset all cells (pointed out in #125) -- GetColumnOffset() / SetColumnOffset() handles padding values more correctly so matching columns can be lined up between a parent and a child window (cf. #125) +- GetColumnOffset() / SetColumnOffset() handles padding values more correctly so matching columns + can be lined up between a parent and a child window (cf. #125) - Fix ImFont::BuildLookupTable() potential dangling pointer dereference (fix #131) -- Fix hovering of child window extending past their parent not taking account of parent clipping rectangle (fix #137) +- Fix hovering of child window extending past their parent not taking account of parent clipping + rectangle (fix #137) - Sliders: value text is clipped inside the frame when resizing sliders to be small. - ImGuITextFilter::Draw() use regular width call rather than computing its own arbitrary width. - ImGuiTextFilter: can take a default filter string during construction. @@ -5969,11 +6227,13 @@ Other Changes: - Added ListBox() (#129). - Added ListBoxHeader(), ListBoxFooter() for customized list traversal and creating multi-selection boxes. - Fixed title bar text clipping issue (fix #128). -- InputText: added ImGuiInputTextFlags_CallbackCharFilter system for filtering/replacement (#130). Callback now passed an "EventFlag" parameter. +- InputText: added ImGuiInputTextFlags_CallbackCharFilter system for filtering/replacement (#130). + Callback now passed an "EventFlag" parameter. - InputText: Added ImGuiInputTextFlags_CharsUppercase and ImGuiInputTextFlags_CharsNoBlank stock filters. - PushItemWidth() can take negative value to right-align items. - Optimisation: Columns offsets cached to avoid unnecessary binary search. -- Optimisation: Optimized CalcTextSize() function by about 25% (they are often the bottleneck when submitting thousands of clipped items). +- Optimisation: Optimized CalcTextSize() function by about 25% (they are often the bottleneck when + submitting thousands of clipped items). - Added ImGuiCol_ChildWindowBg, ImGuiStyleVar_ChildWindowRounding for completeness and flexibility. - Added BeginChild() variant that takes an ImGuiID. - Tweak default ImGuiCol_HeaderActive color to be less bright. @@ -5989,9 +6249,11 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Other Changes: - Added ImGuiWindowFlags_NoCollapse flag. -- Added a way to replace the internal state pointer so that we can optionally share it between modules (e.g. multiple DLLs). +- Added a way to replace the internal state pointer so that we can optionally share it between + modules (e.g. multiple DLLs). - Added tint_col parameter to ImageButton(). -- Added CalcListClipping() helper to perform faster/coarse clipping on user side (when manipulating lists with thousands of items). +- Added CalcListClipping() helper to perform faster/coarse clipping on user side + (when manipulating lists with thousands of items). - Added GetCursorPosX() / GetCursorPosY() shortcuts. - Renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing(). - Combo box always appears above other child windows of a same parent. @@ -6013,7 +6275,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- Big update! Initialisation had to be changed. You don't need to load PNG data anymore. The new system gives you uncompressed texture data. +- Big update! Initialisation had to be changed. You don't need to load PNG data anymore. Th + new system gives you uncompressed texture data. - This sequence: const void* png_data; unsigned int png_size; @@ -6026,19 +6289,23 @@ Breaking Changes: io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // io.Fonts->TexID = (your_texture_identifier); - - PixelCenterOffset has been removed and isn't a necessary setting anymore. Offset your projection matrix by 0.5 if you have rendering problems. + - PixelCenterOffset has been removed and isn't a necessary setting anymore. Offset your + projection matrix by 0.5 if you have rendering problems. Other Changes: - Loading TTF files with stb_truetype.h. - We still embed a compressed pixel-perfect TTF version of ProggyClean for convenience. - Runtime font rendering is a little faster than previously. -- You can load multiple fonts with multiple size inside the font atlas. Rendering with multiple fonts are still merged into a single draw call whenever possible. +- You can load multiple fonts with multiple size inside the font atlas. Rendering with multiple + fonts are still merged into a single draw call whenever possible. - The system handles UTF-8 and provide ranges to easily load e.g. characters for Japanese display. - Added PushFont() / PopFont(). - Added Image() and ImageButton() to display your own texture data. -- Added callback system in command-list. This can be used if you want to do your own rendering (e.g. render a 3D scene) inside ImGui widgets. -- Added IsItemActive() to tell if last widget is being held / modified (as opposed to just being hovered). Useful for custom dragging behaviors. +- Added callback system in command-list. This can be used if you want to do your own rendering + (e.g. render a 3D scene) inside ImGui widgets. +- Added IsItemActive() to tell if last widget is being held / modified (as opposed to just + being hovered). Useful for custom dragging behaviors. - Style: Added FrameRounding setting for a more rounded look (default to 0 for now). - Window: Fixed using multiple Begin/End pair on the same wnidow. - Window: Fixed style.WindowMinSize not being honored properly. @@ -6071,7 +6338,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Dragging outside area of a widget while it is active doesn't trigger hover on other widgets. - Activating widget bring parent window to front if not already. - Checkbox and Radio buttons activate on click-release to be consistent with other widgets and most UI. -- InputText() nows consume input characters immediately so they cannot be reused if ImGui::Update is called again with a call to ImGui::Render(). (fixes #105) +- InputText() nows consume input characters immediately so they cannot be reused if + ImGui::Update is called again with a call to ImGui::Render(). (fixes #105) - Examples: Console: added support for History callbacks + some cleanup. - Various small optimisations. - Cleanup and other fixes. @@ -6089,7 +6357,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Widgets more consistently handle empty labels (starting with ## mark) for their size calculation. - Fixed crashing with zero sized frame-buffer. - Fixed ImGui::Combo() not registering its size properly when clipped out of screen. -- Renamed second parameter to Begin() to 'bool* p_opened' to be a little more self-explanatory. Added more comments on the use of Begin(). +- Renamed second parameter to Begin() to 'bool* p_opened' to be a little more self-explanatory. + Added more comments on the use of Begin(). - Logging: Added LogText() to pass text straight to the log output (tty/clipboard/file) without rendering it. - Logging: Added LogFinish() to stop logging at an arbitrary point. - Logging: Log depth padding relative to start depth. @@ -6108,7 +6377,10 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Added ImGuiWindowFlags_NoScrollWithMouse, disable mouse wheel scrolling on a window. - Added ImGuiWindowFlags_NoSavedSettings, disable loading/saving window state to .ini file. -- Added SetNextWindowPos(), SetNextWindowSize(), SetNextWindowCollapsed() API along with SetWindowPos(), SetWindowSize(), SetWindowCollapsed(). All functions include an optional second parameter to easily set current value vs session default value vs persistent default value. +- Added SetNextWindowPos(), SetNextWindowSize(), SetNextWindowCollapsed() API along + with SetWindowPos(), SetWindowSize(), SetWindowCollapsed(). All functions include an + optional second parameter to easily set current value vs session default value vs. + persistent default value. - Removed rarely useful SetNewWindowDefaultPos() in favor of new API. - Fixed hovering of lower-right resize grip when it is above a child window. - Fixed InputInt() writing to output when it doesn't need to. @@ -6134,7 +6406,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Increased visibility of check box and radio button with smaller size. - Smooth mouse scrolling on OSX (uses floating point scroll/wheel input). - New version of IMGUI_ONCE_UPON_A_FRAME helper macro that works with all compilers. -- Moved IO.Font*** options to inside the IO.Font-> structure.. Added IO.FontGlobalScale setting (in addition to Font->Scale per individual font). +- Moved IO.Font*** options to inside the IO.Font-> structure. +- Added IO.FontGlobalScale setting (in addition to Font->Scale per individual font). - Fixed more Clang -Weverything warnings. - Examples: Added DirectX11 example application. - Examples: Created single .sln solution for all example projects. @@ -6162,7 +6435,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Fixed unaligned memory access for Emscripten compatibility. - Various pedantic warning fixes (now testing with Clang). - Added extra asserts to catch incorrect usage. -- PushStyleColor() / PushStyleVar() can be used outside the scope of a window (namely to change variables that are used within the Begin() call). +- PushStyleColor() / PushStyleVar() can be used outside the scope of a window (namely to change + variables that are used within the Begin() call). - PushTextWrapPos() defaults to 0.0 (right-end of current drawing region). - Fixed compatibility with std::vector if user decide to #define ImVector. - MouseWheel input is now normalized. @@ -6200,7 +6474,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Comments and fixes. - Added SetKeyboardFocusHere() to set input focus from code. - Added GetWindowFont(), GetWindowFontSize() for users of the low-level ImDrawList API. -- Added a UserData void *pointer so that the callback functions can access user state "Just in case a project has adverse reactions to adding globals or statics in their own code." +- Added a UserData void *pointer so that the callback functions can access user state + "Just in case a project has adverse reactions to adding globals or statics in their own code." - Renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL @@ -6228,7 +6503,8 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Added IsMouseHoveringWindow(), IsMouseHoveringAnyWindow(), IsPosHoveringAnyWindow() helpers. - Added va_list variations of all functions taking ellipsis (...) parameters. - Added section in documentation to explicitly document cases of API breaking changes (e.g. renamed IM_MALLOC below). -- Moved IM_MALLOC / IM_FREE defines. to IO structure members that can be set at runtime (also allowing precompiled ImGui to cover more use cases). +- Moved IM_MALLOC / IM_FREE defines. to IO structure members that can be set at runtime + (also allowing precompiled ImGui to cover more use cases). - Fixed OpenGL samples for Retina display. - Comments and minor fixes. @@ -6268,7 +6544,10 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- The behaviour of PixelCenterOffset changed! You may need to change your value if you had set it to non-default in your code and/or offset your projection matrix by 0.5 pixels. It is likely that the default PixelCenterOffset value of 0.0 is now suitable unless your rendering uses some form of multisampling. +- The behaviour of PixelCenterOffset changed! You may need to change your value if you had set + it to non-default in your code and/or offset your projection matrix by 0.5 pixels. It is + likely that the default PixelCenterOffset value of 0.0 is now suitable unless your rendering + uses some form of multisampling. Other Changes: @@ -6299,10 +6578,12 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.07 - Added InputFloat4(), SliderFloat4() helpers. -- Added global Alpha in ImGuiStyle structure. When Alpha=0.0, ImGui skips most of logic and all rendering processing. +- Added global Alpha in ImGuiStyle structure. When Alpha=0.0, ImGui skips most of logic + and all rendering processing. - Fix clipping of title bar text. - Fix to allow the user to call NewFrame() multiple times without calling Render(). -- Reduce inner window clipping to take account for the extend of CollapsingHeader() - share same clipping rectangle. +- Reduce inner window clipping to take account for the extend of CollapsingHeader() - share + same clipping rectangle. - Fix for child windows with inverted clip rectangles (when scrolled and out of screen, Etc.). - Minor fixes, tweaks, comments. From 57ab2b4226010f3291c79a9ba1e72e72041fbe9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=B6hme?= Date: Tue, 5 Nov 2024 23:26:41 +0100 Subject: [PATCH 019/716] Fixed unused function warning (#8130) --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 01a72c6b7b3c..9de1a81577d8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1210,9 +1210,11 @@ static int FindWindowFocusIndex(ImGuiWindow* window); // Error Checking and Debug Tools static void ErrorCheckNewFrameSanityChecks(); static void ErrorCheckEndFrameSanityChecks(); +#ifndef IMGUI_DISABLE_DEBUG_TOOLS static void UpdateDebugToolItemPicker(); static void UpdateDebugToolStackQueries(); static void UpdateDebugToolFlashStyleColor(); +#endif // Inputs static void UpdateKeyboardInputs(); From 6f287dd16d5d7f393d5b6089585dd87ea5ea0d92 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Nov 2024 16:56:51 +0100 Subject: [PATCH 020/716] (Breaking) Removed pre-1.87 obsolete io.KeyMap[], io.KeysDown[], io.NavInputs[]. Remove IMGUI_DISABLE_OBSOLETE_KEYIO. (#4921) --- backends/imgui_impl_allegro5.cpp | 2 +- backends/imgui_impl_allegro5.h | 2 +- backends/imgui_impl_android.cpp | 2 +- backends/imgui_impl_android.h | 2 +- backends/imgui_impl_glfw.cpp | 2 +- backends/imgui_impl_glfw.h | 2 +- backends/imgui_impl_glut.cpp | 2 +- backends/imgui_impl_glut.h | 2 +- backends/imgui_impl_osx.h | 2 +- backends/imgui_impl_osx.mm | 2 +- backends/imgui_impl_sdl2.cpp | 2 +- backends/imgui_impl_sdl2.h | 2 +- backends/imgui_impl_sdl3.cpp | 2 +- backends/imgui_impl_sdl3.h | 2 +- backends/imgui_impl_win32.cpp | 2 +- backends/imgui_impl_win32.h | 2 +- docs/CHANGELOG.txt | 12 +++ imconfig.h | 1 - imgui.cpp | 173 +++---------------------------- imgui.h | 57 +++------- imgui_demo.cpp | 8 -- 21 files changed, 60 insertions(+), 223 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index d5d65703e496..3e6d766470e0 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Clipboard support (from Allegro 5.1.12) // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Issues: diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index f1501eca8ff6..aba5c47701ea 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Clipboard support (from Allegro 5.1.12) // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Issues: diff --git a/backends/imgui_impl_android.cpp b/backends/imgui_impl_android.cpp index b0c46393111f..05939293cb84 100644 --- a/backends/imgui_impl_android.cpp +++ b/backends/imgui_impl_android.cpp @@ -2,7 +2,7 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // Missing features: // [ ] Platform: Clipboard support. diff --git a/backends/imgui_impl_android.h b/backends/imgui_impl_android.h index 92a044db028a..efe27dcb9568 100644 --- a/backends/imgui_impl_android.h +++ b/backends/imgui_impl_android.h @@ -2,7 +2,7 @@ // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3) // Implemented features: -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // Missing features: // [ ] Platform: Clipboard support. diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 774fb0d5d78a..afa2185a3b67 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -6,7 +6,7 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 60b95bd99d46..5d8940a0c98e 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -5,7 +5,7 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). diff --git a/backends/imgui_impl_glut.cpp b/backends/imgui_impl_glut.cpp index d8ffc9073688..6bb9eae7eeea 100644 --- a/backends/imgui_impl_glut.cpp +++ b/backends/imgui_impl_glut.cpp @@ -6,7 +6,7 @@ // !!! Nowadays, prefer using GLFW or SDL instead! // Implemented features: -// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values are obsolete since 1.87 and not supported since 1.91.5] // Issues: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: Missing horizontal mouse wheel support. diff --git a/backends/imgui_impl_glut.h b/backends/imgui_impl_glut.h index a7479e1d7480..feeca8b3fcd0 100644 --- a/backends/imgui_impl_glut.h +++ b/backends/imgui_impl_glut.h @@ -6,7 +6,7 @@ // !!! Nowadays, prefer using GLFW or SDL instead! // Implemented features: -// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values are obsolete since 1.87 and not supported since 1.91.5] // Issues: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: Missing horizontal mouse wheel support. diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 28e1331285df..4caab8ff5f73 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -6,7 +6,7 @@ // Implemented features: // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Mouse support. Can discriminate Mouse/Pen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: IME support. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 6ff4f19a42c5..69108ca4a5dc 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -6,7 +6,7 @@ // Implemented features: // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Mouse support. Can discriminate Mouse/Pen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: IME support. diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 529ca79e0a2f..14022159f8c4 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -6,7 +6,7 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index e551e52a2853..8ccc6fdc7c62 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -5,7 +5,7 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index de8b531582d8..3cd56a756a6a 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -7,7 +7,7 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 880ba9615b18..c4a5a1230e3c 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -7,7 +7,7 @@ // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index c213f8158011..687bc5a18d61 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -4,7 +4,7 @@ // Implemented features: // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index 3ad1a7eaf181..0dfd56a801be 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -4,7 +4,7 @@ // Implemented features: // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] +// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9e43a56a1faa..603828c39947 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,18 @@ HOW TO UPDATE? Breaking changes: +- Commented out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before). + - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). + - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). + - Pre-1.87 backends are not supported: + - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields. + - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields. + - For more reference: + - read 1.87 and 1.88 part of this section or read Changelog for 1.87 and 1.88. + - read https://github.com/ocornut/imgui/issues/4921 + - If you have trouble updating a very old codebase using legacy backend-specific key codes: + consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. + Other changes: - Selectable: selected Selectables use ImGuiCol_Header instead of an arbitrary lerp diff --git a/imconfig.h b/imconfig.h index 63d6ba081e99..fea89dea0913 100644 --- a/imconfig.h +++ b/imconfig.h @@ -29,7 +29,6 @@ //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names. //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS -//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS. //---- Disable all of Dear ImGui or don't implement standard windows/tools. // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp. diff --git a/imgui.cpp b/imgui.cpp index 9de1a81577d8..74da7355e0df 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -174,7 +174,6 @@ CODE - Set 'io.BackendFlags |= ImGuiBackendFlags_HasGamepad' + call io.AddKeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys. - For analog values (0.0f to 1.0f), backend is responsible to handling a dead-zone and rescaling inputs accordingly. Backend code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). - - BEFORE 1.87, BACKENDS USED TO WRITE TO io.NavInputs[]. This is now obsolete. Please call io functions instead! - If you need to share inputs between your game and the Dear ImGui interface, the easiest approach is to go all-or-nothing, with a buttons combo to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved. @@ -430,6 +429,16 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2024/11/06 (1.91.5) - commented/obsoleted out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before) + - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). + - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). + - pre-1.87 backends are not supported: + - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields. + - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields. + - for more reference: + - read 1.87 and 1.88 part of this section or read Changelog for 1.87 and 1.88. + - read https://github.com/ocornut/imgui/issues/4921 + - if you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. - 2024/10/18 (1.91.4) - renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor (for consistency with newly exposed and reworked features). Kept inline redirection enum (will obsolete). - 2024/10/14 (1.91.4) - moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!). @@ -1390,10 +1399,6 @@ ImGuiIO::ImGuiIO() IniSavingRate = 5.0f; IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same path as executables). LogFilename = "imgui_log.txt"; -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - for (int i = 0; i < ImGuiKey_COUNT; i++) - KeyMap[i] = -1; -#endif UserData = NULL; Fonts = NULL; @@ -1456,8 +1461,6 @@ ImGuiIO::ImGuiIO() for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; } AppAcceptingEvents = true; - BackendUsingLegacyKeyArrays = (ImS8)-1; - BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong } // Pass in translated ASCII characters for text input. @@ -1538,9 +1541,6 @@ void ImGuiIO::ClearEventsQueue() // Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. void ImGuiIO::ClearInputKeys() { -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - memset(KeysDown, 0, sizeof(KeysDown)); -#endif for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++) { if (ImGui::IsMouseKey((ImGuiKey)(n + ImGuiKey_KeysData_OFFSET))) @@ -1625,17 +1625,6 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) else if (key == ImGuiKey_RightCtrl) { key = ImGuiKey_RightSuper; } } - // Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data. -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays == 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); - if (BackendUsingLegacyKeyArrays == -1) - for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) - IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); - BackendUsingLegacyKeyArrays = 0; -#endif - if (ImGui::IsGamepadKey(key)) - BackendUsingLegacyNavInputArray = false; - // Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed) const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key); const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key); @@ -1671,20 +1660,10 @@ void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native return; IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512 IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey((ImGuiKey)native_legacy_index)); // >= 0 && <= 511 - IM_UNUSED(native_keycode); // Yet unused - IM_UNUSED(native_scancode); // Yet unused - - // Build native->imgui map so old user code can still call key functions with native 0..511 values. -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode; - if (!ImGui::IsLegacyKey((ImGuiKey)legacy_key)) - return; - KeyMap[legacy_key] = key; - KeyMap[key] = legacy_key; -#else - IM_UNUSED(key); - IM_UNUSED(native_legacy_index); -#endif + IM_UNUSED(key); // Yet unused + IM_UNUSED(native_keycode); // Yet unused + IM_UNUSED(native_scancode); // Yet unused + IM_UNUSED(native_legacy_index); // Yet unused } // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen. @@ -8928,27 +8907,10 @@ ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END); - if (IsLegacyKey(key) && g.IO.KeyMap[key] != -1) - key = (ImGuiKey)g.IO.KeyMap[key]; // Remap native->imgui or imgui->native -#else IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); -#endif return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET]; } -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO -// Formally moved to obsolete section in 1.90.5 in spite of documented as obsolete since 1.87 -ImGuiKey ImGui::GetKeyIndex(ImGuiKey key) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(IsNamedKey(key)); - const ImGuiKeyData* key_data = GetKeyData(key); - return (ImGuiKey)(key_data - g.IO.KeysData); -} -#endif - // Those names a provided for debugging purpose and are not meant to be saved persistently not compared. static const char* const GKeyNames[] = { @@ -8980,18 +8942,7 @@ const char* ImGui::GetKeyName(ImGuiKey key) { if (key == ImGuiKey_None) return "None"; -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO IM_ASSERT(IsNamedKeyOrMod(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code."); -#else - ImGuiContext& g = *GImGui; - if (IsLegacyKey(key)) - { - if (g.IO.KeyMap[key] == -1) - return "N/A"; - IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key])); - key = (ImGuiKey)g.IO.KeyMap[key]; - } -#endif if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); if (!IsNamedKey(key)) @@ -9635,74 +9586,6 @@ static void ImGui::UpdateKeyboardInputs() if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard) io.ClearInputKeys(); - // Import legacy keys or verify they are not used -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - if (io.BackendUsingLegacyKeyArrays == 0) - { - // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally. - for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++) - IM_ASSERT((io.KeysDown[n] == false || IsKeyDown((ImGuiKey)n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!"); - } - else - { - if (g.FrameCount == 0) - for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) - IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to write to io.KeyMap[0..511]!"); - - // Build reverse KeyMap (Named -> Legacy) - for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++) - if (io.KeyMap[n] != -1) - { - IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n])); - io.KeyMap[io.KeyMap[n]] = n; - } - - // Import legacy keys into new ones - for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKey_END; n++) - if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1) - { - const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n); - IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key)); - io.KeysData[key].Down = io.KeysDown[n]; - if (key != n) - io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends - io.BackendUsingLegacyKeyArrays = 1; - } - if (io.BackendUsingLegacyKeyArrays == 1) - { - GetKeyData(ImGuiMod_Ctrl)->Down = io.KeyCtrl; - GetKeyData(ImGuiMod_Shift)->Down = io.KeyShift; - GetKeyData(ImGuiMod_Alt)->Down = io.KeyAlt; - GetKeyData(ImGuiMod_Super)->Down = io.KeySuper; - } - } -#endif - - // Import legacy ImGuiNavInput_ io inputs and convert to gamepad keys -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; - if (io.BackendUsingLegacyNavInputArray && nav_gamepad_active) - { - #define MAP_LEGACY_NAV_INPUT_TO_KEY1(_KEY, _NAV1) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f); io.KeysData[_KEY].AnalogValue = io.NavInputs[_NAV1]; } while (0) - #define MAP_LEGACY_NAV_INPUT_TO_KEY2(_KEY, _NAV1, _NAV2) do { io.KeysData[_KEY].Down = (io.NavInputs[_NAV1] > 0.0f) || (io.NavInputs[_NAV2] > 0.0f); io.KeysData[_KEY].AnalogValue = ImMax(io.NavInputs[_NAV1], io.NavInputs[_NAV2]); } while (0) - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown); - MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, ImGuiNavInput_TweakSlow); - MAP_LEGACY_NAV_INPUT_TO_KEY2(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakFast); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp); - MAP_LEGACY_NAV_INPUT_TO_KEY1(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown); - #undef NAV_MAP_KEY - } -#endif - // Update aliases for (int n = 0; n < ImGuiMouseButton_COUNT; n++) UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f); @@ -10100,13 +9983,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) key_changed_mask.SetBit(key_data_index); if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input) key_changed_nonchar = true; - - // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - io.KeysDown[key_data_index] = key_data->Down; - if (io.KeyMap[key_data_index] != -1) - io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down; -#endif } else if (e->Type == ImGuiInputEventType_Text) { @@ -10468,14 +10344,6 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++) - IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)"); - - // Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP) - if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1) - IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation."); -#endif // Error handling: we do not accept 100% silent recovery! Please contact me if you feel this is getting in your way. if (g.IO.ConfigErrorRecovery) @@ -15732,18 +15600,11 @@ void ImGui::ShowMetricsWindow(bool* p_open) { Text("KEYBOARD/GAMEPAD/MOUSE KEYS"); { - // We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends. // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. Indent(); -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; -#else - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key >= 0 && key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array - //Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } } -#endif - Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } - Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } - Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (!IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } + Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (!IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (!IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. DebugRenderKeyboardPreview(GetWindowDrawList()); diff --git a/imgui.h b/imgui.h index 973a52f53468..824cea059ad3 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.5 WIP" -#define IMGUI_VERSION_NUM 19143 +#define IMGUI_VERSION_NUM 19144 #define IMGUI_HAS_TABLE /* @@ -961,9 +961,8 @@ namespace ImGui // Inputs Utilities: Keyboard/Mouse/Gamepad // - the ImGuiKey enum contains all possible keyboard, mouse and gamepad inputs (e.g. ImGuiKey_A, ImGuiKey_MouseLeft, ImGuiKey_GamepadDpadUp...). - // - before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. About use of those legacy ImGuiKey values: - // - without IMGUI_DISABLE_OBSOLETE_KEYIO (legacy support): you can still use your legacy native/user indices (< 512) according to how your backend/engine stored them in io.KeysDown[], but need to cast them to ImGuiKey. - // - with IMGUI_DISABLE_OBSOLETE_KEYIO (this is the way forward): any use of ImGuiKey will assert with key < 512. GetKeyIndex() is pass-through and therefore deprecated (gone if IMGUI_DISABLE_OBSOLETE_KEYIO is defined). + // - (legacy: before v1.87, we used ImGuiKey to carry native/user indices as defined by each backends. This was obsoleted in 1.87 (2022-02) and completely removed in 1.91.5 (2024-11). See https://github.com/ocornut/imgui/issues/4921) + // - (legacy: any use of ImGuiKey will assert when key < 512 to detect passing legacy native/user indices) IMGUI_API bool IsKeyDown(ImGuiKey key); // is key being held. IMGUI_API bool IsKeyPressed(ImGuiKey key, bool repeat = true); // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? @@ -1415,15 +1414,10 @@ enum ImGuiSortDirection : ImU8 ImGuiSortDirection_Descending = 2 // Descending = 9->0, Z->A etc. }; -// Since 1.90, defining IMGUI_DISABLE_OBSOLETE_FUNCTIONS automatically defines IMGUI_DISABLE_OBSOLETE_KEYIO as well. -#if defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(IMGUI_DISABLE_OBSOLETE_KEYIO) -#define IMGUI_DISABLE_OBSOLETE_KEYIO -#endif - // A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value): can represent Keyboard, Mouse and Gamepad values. -// All our named keys are >= 512. Keys value 0 to 511 are left unused as legacy native/opaque key values (< 1.87). -// Since >= 1.89 we increased typing (went from int to enum), some legacy code may need a cast to ImGuiKey. -// Read details about the 1.87 and 1.89 transition : https://github.com/ocornut/imgui/issues/4921 +// All our named keys are >= 512. Keys value 0 to 511 are left unused and were legacy native/opaque key values (< 1.87). +// Support for legacy keys was completely removed in 1.91.5. +// Read details about the 1.87+ transition : https://github.com/ocornut/imgui/issues/4921 // Note that "Keys" related to physical keys and are not the same concept as input "Characters", the later are submitted via io.AddInputCharacter(). // The keyboard key enum values are named after the keys on a standard US keyboard, and on other keyboard types the keys reported may not match the keycaps. enum ImGuiKey : int @@ -1535,19 +1529,12 @@ enum ImGuiKey : int ImGuiMod_Super = 1 << 15, // Windows/Super (non-macOS), Ctrl (macOS) ImGuiMod_Mask_ = 0xF000, // 4-bits - // [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array. - // We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE) - // If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. + // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. ImGuiKey_NamedKey_BEGIN = 512, ImGuiKey_NamedKey_END = ImGuiKey_COUNT, ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. -#else - ImGuiKey_KeysData_SIZE = ImGuiKey_COUNT, // Size of KeysData[]: hold legacy 0..512 keycodes + named keys - ImGuiKey_KeysData_OFFSET = 0, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. -#endif #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl @@ -1581,18 +1568,6 @@ enum ImGuiInputFlags_ ImGuiInputFlags_Tooltip = 1 << 18, // Automatically display a tooltip when hovering item [BETA] Unsure of right api (opt-in/opt-out) }; -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO -// OBSOLETED in 1.88 (from July 2022): ImGuiNavInput and io.NavInputs[]. -// Official backends between 1.60 and 1.86: will keep working and feed gamepad inputs as long as IMGUI_DISABLE_OBSOLETE_KEYIO is not set. -// Custom backends: feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. -enum ImGuiNavInput -{ - ImGuiNavInput_Activate, ImGuiNavInput_Cancel, ImGuiNavInput_Input, ImGuiNavInput_Menu, ImGuiNavInput_DpadLeft, ImGuiNavInput_DpadRight, ImGuiNavInput_DpadUp, ImGuiNavInput_DpadDown, - ImGuiNavInput_LStickLeft, ImGuiNavInput_LStickRight, ImGuiNavInput_LStickUp, ImGuiNavInput_LStickDown, ImGuiNavInput_FocusPrev, ImGuiNavInput_FocusNext, ImGuiNavInput_TweakSlow, ImGuiNavInput_TweakFast, - ImGuiNavInput_COUNT, -}; -#endif - // Configuration flags stored in io.ConfigFlags. Set by user/application. enum ImGuiConfigFlags_ { @@ -2425,20 +2400,18 @@ struct ImGuiIO float PenPressure; // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui. bool AppFocusLost; // Only modify via AddFocusEvent() bool AppAcceptingEvents; // Only modify via SetAppAcceptingEvents() - ImS8 BackendUsingLegacyKeyArrays; // -1: unknown, 0: using AddKeyEvent(), 1: using legacy io.KeysDown[] - bool BackendUsingLegacyNavInputArray; // 0: using AddKeyAnalogEvent(), 1: writing to legacy io.NavInputs[] directly ImWchar16 InputQueueSurrogate; // For AddInputCharacterUTF16() ImVector InputQueueCharacters; // Queue of _characters_ input (obtained by platform backend). Fill using AddInputCharacter() helper. // Legacy: before 1.87, we required backend to fill io.KeyMap[] (imgui->native map) during initialization and io.KeysDown[] (native indices) every frame. // This is still temporarily supported as a legacy feature. However the new preferred scheme is for backend to call io.AddKeyEvent(). // Old (<1.87): ImGui::IsKeyPressed(ImGui::GetIO().KeyMap[ImGuiKey_Space]) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) -#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO - int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. - bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. - float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. + // Old (<1.87): ImGui::IsKeyPressed(MYPLATFORM_KEY_SPACE) --> New (1.87+) ImGui::IsKeyPressed(ImGuiKey_Space) + // Read https://github.com/ocornut/imgui/issues/4921 for details. + //int KeyMap[ImGuiKey_COUNT]; // [LEGACY] Input: map of indices into the KeysDown[512] entries array which represent your "native" keyboard state. The first 512 are now unused and should be kept zero. Legacy backend will write into KeyMap[] using ImGuiKey_ indices which are always >512. + //bool KeysDown[ImGuiKey_COUNT]; // [LEGACY] Input: Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys). This used to be [512] sized. It is now ImGuiKey_COUNT to allow legacy io.KeysDown[GetKeyIndex(...)] to work without an overflow. + //float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. -#endif // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). @@ -3617,9 +3590,6 @@ namespace ImGui // OBSOLETED in 1.89.4 (from March 2023) static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } static inline void PopAllowKeyboardFocus() { PopItemFlag(); } - // OBSOLETED in 1.87 (from February 2022 but more formally obsoleted April 2024) - IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value! - //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) //-- OBSOLETED in 1.89 (from August 2022) @@ -3627,6 +3597,9 @@ namespace ImGui //-- OBSOLETED in 1.88 (from May 2022) //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value. //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value. + //-- OBSOLETED in 1.87 (from February 2022, more formally obsoleted April 2024) + //IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); const ImGuiKeyData* key_data = GetKeyData(key); return (ImGuiKey)(key_data - g.IO.KeysData); } // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value! + //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; } //-- OBSOLETED in 1.86 (from November 2021) //IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Code removed, see 1.90 for last version of the code. Calculate range of visible items for large list of evenly sized items. Prefer using ImGuiListClipper. //-- OBSOLETED in 1.85 (from August 2021) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f5e16f06c161..e28ca3b7aac4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7370,13 +7370,8 @@ static void ShowDemoWindowInputs() // displaying the data for old/new backends. // User code should never have to go through such hoops! // You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } }; ImGuiKey start_key = ImGuiKey_NamedKey_BEGIN; -#else - struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key >= 0 && key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array - ImGuiKey start_key = (ImGuiKey)0; -#endif ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); } ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. @@ -7699,9 +7694,6 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS"); #endif -#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO - ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_KEYIO"); -#endif #ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS"); #endif From 738d6db3e6b9b28284aa1026dbf082238d9c9aab Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Nov 2024 17:42:02 +0100 Subject: [PATCH 021/716] (Breaking) Removed used of ImGuiKey_KeysData_SIZE, ImGuiKey_KeysData_OFFSET. (#4921) --- imgui.cpp | 39 ++++++++++++++++++++------------------- imgui.h | 6 +++--- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 74da7355e0df..028f08c3c7ae 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1541,13 +1541,15 @@ void ImGuiIO::ClearEventsQueue() // Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons. void ImGuiIO::ClearInputKeys() { - for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++) + ImGuiContext& g = *Ctx; + for (int key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key++) { - if (ImGui::IsMouseKey((ImGuiKey)(n + ImGuiKey_KeysData_OFFSET))) + if (ImGui::IsMouseKey((ImGuiKey)key)) continue; - KeysData[n].Down = false; - KeysData[n].DownDuration = -1.0f; - KeysData[n].DownDurationPrev = -1.0f; + ImGuiKeyData* key_data = &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN]; + key_data->Down = false; + key_data->DownDuration = -1.0f; + key_data->DownDurationPrev = -1.0f; } KeyCtrl = KeyShift = KeyAlt = KeySuper = false; KeyMods = ImGuiMod_None; @@ -1558,7 +1560,7 @@ void ImGuiIO::ClearInputMouse() { for (ImGuiKey key = ImGuiKey_Mouse_BEGIN; key < ImGuiKey_Mouse_END; key = (ImGuiKey)(key + 1)) { - ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_KeysData_OFFSET]; + ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_NamedKey_BEGIN]; key_data->Down = false; key_data->DownDuration = -1.0f; key_data->DownDurationPrev = -1.0f; @@ -8908,7 +8910,7 @@ ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend & user code."); - return &g.IO.KeysData[key - ImGuiKey_KeysData_OFFSET]; + return &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN]; } // Those names a provided for debugging purpose and are not meant to be saved persistently not compared. @@ -9609,22 +9611,21 @@ static void ImGui::UpdateKeyboardInputs() // Clear gamepad data if disabled if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0) - for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++) + for (int key = ImGuiKey_Gamepad_BEGIN; key < ImGuiKey_Gamepad_END; key++) { - io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false; - io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f; + io.KeysData[key - ImGuiKey_NamedKey_BEGIN].Down = false; + io.KeysData[key - ImGuiKey_NamedKey_BEGIN].AnalogValue = 0.0f; } // Update keys - for (int i = 0; i < ImGuiKey_KeysData_SIZE; i++) + for (int key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key++) { - ImGuiKeyData* key_data = &io.KeysData[i]; + ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_NamedKey_BEGIN]; key_data->DownDurationPrev = key_data->DownDuration; key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f; if (key_data->DownDuration == 0.0f) { - ImGuiKey key = (ImGuiKey)(ImGuiKey_KeysData_OFFSET + i); - if (IsKeyboardKey(key)) + if (IsKeyboardKey((ImGuiKey)key)) g.LastKeyboardKeyPressTime = g.Time; else if (key == ImGuiKey_ReservedForModCtrl || key == ImGuiKey_ReservedForModShift || key == ImGuiKey_ReservedForModAlt || key == ImGuiKey_ReservedForModSuper) g.LastKeyboardKeyPressTime = g.Time; @@ -9634,7 +9635,7 @@ static void ImGui::UpdateKeyboardInputs() // Update keys/input owner (named keys only): one entry per key for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { - ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_KeysData_OFFSET]; + ImGuiKeyData* key_data = &io.KeysData[key - ImGuiKey_NamedKey_BEGIN]; ImGuiKeyOwnerData* owner_data = &g.KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; owner_data->OwnerCurr = owner_data->OwnerNext; if (!key_data->Down) // Important: ownership is released on the frame after a release. Ensure a 'MouseDown -> CloseWindow -> MouseUp' chain doesn't lead to someone else seeing the MouseUp. @@ -9920,7 +9921,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) bool mouse_moved = false, mouse_wheeled = false, key_changed = false, key_changed_nonchar = false, text_inputted = false; int mouse_button_changed = 0x00; - ImBitArray key_changed_mask; + ImBitArray key_changed_mask; int event_n = 0; for (; event_n < g.InputEventsQueue.Size; event_n++) @@ -15602,9 +15603,9 @@ void ImGui::ShowMetricsWindow(bool* p_open) { // User code should never have to go through such hoops! You can generally iterate between ImGuiKey_NamedKey_BEGIN and ImGuiKey_NamedKey_END. Indent(); - Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (!IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } - Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (!IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } - Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (!IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys down:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); } + Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } + Text("Keys released:"); for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (!IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); } Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : ""); Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public. DebugRenderKeyboardPreview(GetWindowDrawList()); diff --git a/imgui.h b/imgui.h index 824cea059ad3..6965c5e6bbec 100644 --- a/imgui.h +++ b/imgui.h @@ -1533,8 +1533,8 @@ enum ImGuiKey : int ImGuiKey_NamedKey_BEGIN = 512, ImGuiKey_NamedKey_END = ImGuiKey_COUNT, ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, - ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys - ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_KeysData_OFFSET) index. + //ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys + //ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_NamedKey_BEGIN) index. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl @@ -2380,7 +2380,7 @@ struct ImGuiIO // Other state maintained from data above + IO function calls ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. Read-only, updated by NewFrame() - ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this. + ImGuiKeyData KeysData[ImGuiKey_NamedKey_COUNT];// Key state for all known keys. Use IsKeyXXX() functions to access this. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) ImVec2 MouseClickedPos[5]; // Position at time of clicking From df0776e931d2be6efe5d8a6e465b97851b23c9d5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Nov 2024 17:49:52 +0100 Subject: [PATCH 022/716] (Breaking) Removed ImGuiKey_COUNT. (#4921) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 1 + imgui.h | 7 ++++--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 603828c39947..1e8016a133e9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,8 @@ Breaking changes: - read https://github.com/ocornut/imgui/issues/4921 - If you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. + - Obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). + Probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END? Other changes: diff --git a/imgui.cpp b/imgui.cpp index 028f08c3c7ae..7f853fa0f433 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -439,6 +439,7 @@ CODE - read 1.87 and 1.88 part of this section or read Changelog for 1.87 and 1.88. - read https://github.com/ocornut/imgui/issues/4921 - if you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. + - obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END? - 2024/10/18 (1.91.4) - renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor (for consistency with newly exposed and reworked features). Kept inline redirection enum (will obsolete). - 2024/10/14 (1.91.4) - moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!). diff --git a/imgui.h b/imgui.h index 6965c5e6bbec..ec3d6c0a7109 100644 --- a/imgui.h +++ b/imgui.h @@ -1424,6 +1424,8 @@ enum ImGuiKey : int { // Keyboard ImGuiKey_None = 0, + ImGuiKey_NamedKey_BEGIN = 512, // First valid key value (other than 0) + ImGuiKey_Tab = 512, // == ImGuiKey_NamedKey_BEGIN ImGuiKey_LeftArrow, ImGuiKey_RightArrow, @@ -1511,7 +1513,7 @@ enum ImGuiKey : int // [Internal] Reserved for mod storage ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, - ImGuiKey_COUNT, + ImGuiKey_NamedKey_END, // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing @@ -1530,13 +1532,12 @@ enum ImGuiKey : int ImGuiMod_Mask_ = 0xF000, // 4-bits // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. - ImGuiKey_NamedKey_BEGIN = 512, - ImGuiKey_NamedKey_END = ImGuiKey_COUNT, ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, //ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys //ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_NamedKey_BEGIN) index. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiKey_COUNT = ImGuiKey_NamedKey_END, // Obsoleted in 1.91.5 because it was extremely misleading (since named keys don't start at 0 anymore) ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl ImGuiKey_ModCtrl = ImGuiMod_Ctrl, ImGuiKey_ModShift = ImGuiMod_Shift, ImGuiKey_ModAlt = ImGuiMod_Alt, ImGuiKey_ModSuper = ImGuiMod_Super, // Renamed in 1.89 //ImGuiKey_KeyPadEnter = ImGuiKey_KeypadEnter, // Renamed in 1.87 From d97bbf19042c8addf7098978609de20fef9978e6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Nov 2024 18:08:15 +0100 Subject: [PATCH 023/716] Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default styles. --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1e8016a133e9..abf339421f9a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,8 @@ Other changes: - Fonts: removed const qualifiers from most font functions. - InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within a callback would sometimes prevents further appending to the buffer. +- Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default + styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). - Log/Capture: better decorating of BeginMenu() and TabItem() output. - Log/Capture: a non terminated log ends automatically in the window which called it. - Log/Capture: added experimental io.ConfigWindowsCopyContentsWithCtrlC option to diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ac6d0228196e..43a49eb299c6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -218,7 +218,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 0.00f); colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); @@ -281,7 +281,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabDimmedSelectedOverline] = colors[ImGuiCol_HeaderActive]; + colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.53f, 0.53f, 0.87f, 0.00f); colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); @@ -345,7 +345,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f); colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f); - colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 1.00f); + colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 0.00f); colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f); colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); From 3543dfda953beefd9add1316328e2c7cfb4aa637 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 6 Nov 2024 18:14:44 +0100 Subject: [PATCH 024/716] Docs: document removal of ImFont const qualifier as potentially breaking. --- docs/CHANGELOG.txt | 34 +++++++++++++++++----------------- imgui.cpp | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index abf339421f9a..ebc128a04ac7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,7 @@ Breaking changes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. - Obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). Probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END? +- Fonts: removed const qualifiers from most font functions in prevision for upcoming fonts improvements. Other changes: @@ -61,7 +62,6 @@ Other changes: between _Header and _HeaderHovered which was introduced v1.91 (#8106, #1861) - Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use PressedOnClick instead of PressedOnClickRelease when unspecified. -- Fonts: removed const qualifiers from most font functions. - InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within a callback would sometimes prevents further appending to the buffer. - Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default @@ -74,9 +74,9 @@ Other changes: and (3) text output comes in submission order rather than spatial order. - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. -- Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the - actual include. (#8095, #7967, #3190) [@sev-] -- Backends: SDL2, SDL3: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing +- Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the + actual include. (#8095, #7967, #3190) [@sev-] +- Backends: SDL2, SDL3: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten target. (#4019, #6096, #1463) - Examples: SDL3+Vulkan: Added example. (#8084, #8085) - Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll() @@ -88,7 +88,7 @@ Other changes: Breaking changes: -- Style: renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor, for consistency with +- Style: renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor, for consistency with newly exposed and reworked features. Kept inline redirection enum (will obsolete). - The typedef for ImTextureID now defaults to ImU64 instead of void*. (#1641) - This removes the requirement to redefine it for backends which are e.g. storing @@ -104,9 +104,9 @@ Breaking changes: - Note that you can always define ImTextureID to be your own high-level structures (with dedicated constructors and extra render parameters) if you like. - IO: moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. -- IO: moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool +- IO: moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!). (#2517, #2009) - Kept legacy names (will obsolete) + code that copies settings once the first time. + Kept legacy names (will obsolete) + code that copies settings once the first time. Dynamically changing the old value won't work. Switch to using the new value! Other changes: @@ -122,48 +122,48 @@ Other changes: - Set io.ConfigNavCursorVisibleAuto = true (default) to enable automatic toggling of cursor visibility (mouse click hide the cursor, arrow keys makes it visible). - Set io.ConfigNavCursorVisibleAlways to keep cursor always visible. - - Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of + - Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of navigation cursor (e.g. set default state, or after some actions). (#1074, #2048, #7237, #8059) - Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) - Set io.ConfigNavEscapeClearFocusItem = true (default) to clear focused item and highlight. - Set io.ConfigNavEscapeClearFocusItem = false for Escape to not have an effect. - Set io.ConfigNavEscapeClearFocusWindow = true to completely unfocus the dear imgui window, - is for some reason your app relies on imgui focus to take other decisions. + is for some reason your app relies on imgui focus to take other decisions. - Nav: pressing escape to hide the navigation cursor doesn't clear location, so it may be restored when Ctrl+Tabbing back into the same window later. - Nav: fixed Ctrl+Tab initiated with no focused window from skipping the top-most window. (#3200) - - Nav: navigation cursor is not rendered for items with `ImGuiItemFlags_NoNav`. Can be relevant + - Nav: navigation cursor is not rendered for items with `ImGuiItemFlags_NoNav`. Can be relevant when e.g activating a _NoNav item with mouse, then Ctrl+Tabbing back and forth. -- Disabled: clicking a disabled item focuses parent window. (#8064) +- Disabled: clicking a disabled item focuses parent window. (#8064) - InvisibleButton, Nav: fixed an issue when InvisibleButton() would be navigable into but not display navigation highlight. Properly navigation on it by default. (#8057) - InvisibleButton: added ImGuiButtonFlags_EnableNav to enable navigation. (#8057) -- Tooltips: fixed incorrect tooltip positioning when using keyboard/gamepad navigation +- Tooltips: fixed incorrect tooltip positioning when using keyboard/gamepad navigation (1.91.3 regression). (#8036) - DrawList: AddCallback() added an optional size parameter allowing to copy and store any amount of user data for usage by callbacks: (#6969, #4770, #7665) - If userdata_size == 0: we copy/store the 'userdata' argument as-is (existing behavior). It will be available unmodified in ImDrawCmd::UserCallbackData during render. - If userdata_size > 0, we copy/store 'userdata_size' bytes pointed to by 'userdata' (new behavior). - We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData + We store them in a buffer stored inside the drawlist. ImDrawCmd::UserCallbackData will point inside that buffer so you have to retrieve data from there. Your callback may need to use ImDrawCmd::UserCallbackDataSize if you expect dynamically-sized data. - Note that we use a raw type-less copy. - Tables: fixed initial auto-sizing issue with synced-instances. (#8045, #7218) - InputText: fixed an issue with not declaring ownership of Delete/Backspace/Arrow keys, - preventing use of external shortcuts that are not guarded by an ActiveId check. (#8048) + preventing use of external shortcuts that are not guarded by an ActiveId check. (#8048) [@geertbleyen] -- InputText: ensure mouse cursor shape is set regardless of whether keyboard mode is +- InputText: ensure mouse cursor shape is set regardless of whether keyboard mode is enabled or not. (#6417) - InputScalar: added an assert to clarify that ImGuiInputTextFlags_EnterReturnsTrue is not supported by InputFloat, InputInt, InputScalar etc. widgets. It actually never was. (#8065, #3946) -- imgui_freetype: Added support for plutosvg (as an alternative to lunasvg) to render +- imgui_freetype: Added support for plutosvg (as an alternative to lunasvg) to render OpenType SVG fonts. Requires defining IMGUI_ENABLE_FREETYPE_PLUTOSVG along with IMGUI_ENABLE_FREETYPE. Providing headers/librairies for plutosvg + plutovg is up to you (see #7927 for help). (#7927, #7187, #6591, #6607) [@pthom] - Backends: DX11, DX12, SDLRenderer2/3. Vulkan, WGPU: expose selected state in - ImGui_ImplXXXX_RenderState structures during render loop user draw callbacks. + ImGui_ImplXXXX_RenderState structures during render loop user draw callbacks. (#6969, #5834, #7468, #3590) - Backends: DX9, DX10, DX11, DX12, OpenGL, Vulkan, WGPU: Changed default texture sampler to Clamp instead of Repeat/Wrap. (#7468, #7511, #5999, #5502, #7230) diff --git a/imgui.cpp b/imgui.cpp index 7f853fa0f433..1f2dbc09a84b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -440,6 +440,7 @@ CODE - read https://github.com/ocornut/imgui/issues/4921 - if you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. - obsoleted ImGuiKey_COUNT (it is unusually error-prone/misleading since valid keys don't start at 0). probably use ImGuiKey_NamedKey_BEGIN/ImGuiKey_NamedKey_END? + - fonts: removed const qualifiers from most font functions in prevision for upcoming font improvements. - 2024/10/18 (1.91.4) - renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor (for consistency with newly exposed and reworked features). Kept inline redirection enum (will obsolete). - 2024/10/14 (1.91.4) - moved ImGuiConfigFlags_NavEnableSetMousePos to standalone io.ConfigNavMoveSetMousePos bool. moved ImGuiConfigFlags_NavNoCaptureKeyboard to standalone io.ConfigNavCaptureKeyboard bool (note the inverted value!). From 3b683927ee623d010725c7664cd4e2c4ac20085c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 7 Nov 2024 14:39:54 +0100 Subject: [PATCH 025/716] imgui_freetype: Fixed a crash in build font atlas when using merged fonts and the first font in a merged set has no loaded glyph. (#8081) --- docs/CHANGELOG.txt | 2 ++ misc/freetype/imgui_freetype.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ebc128a04ac7..a1655fdabd90 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other changes: automatically copy window contents into clipboard using CTRL+C. This is experimental because (1) it currently breaks on nested Begin/End, (2) text output quality varies, and (3) text output comes in submission order rather than spatial order. +- imgui_freetype: Fixed a crash in build font atlas when using merged fonts and the + first font in a merged set has no loaded glyph. (#8081) - Backends: DX12: Unmap() call specify written range. The range is informational and may be used by debug tools. - Backends: SDL2: Replace SDL_Vulkan_GetDrawableSize() forward declaration with the diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 646a3b14e2ec..c2d5f074c0fa 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -681,8 +681,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; // When merging fonts with MergeMode=true: // - We can have multiple input fonts writing into a same destination font. @@ -693,6 +691,9 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u const float ascent = src_tmp.Font.Info.Ascender; const float descent = src_tmp.Font.Info.Descender; ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); + + if (src_tmp.GlyphsCount == 0) + continue; const float font_off_x = cfg.GlyphOffset.x; const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); From 17bd417a3d18610dbdaba4b56296bdcf87c7cbbf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 7 Nov 2024 14:57:16 +0100 Subject: [PATCH 026/716] AddCustomRectFontGlyph: added storage for Colored bool in ImFontAtlasCustomRect. (#8133) --- imgui.h | 5 +++-- imgui_draw.cpp | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index ec3d6c0a7109..de6ec7b1c2cf 100644 --- a/imgui.h +++ b/imgui.h @@ -3278,11 +3278,12 @@ struct ImFontAtlasCustomRect { unsigned short Width, Height; // Input // Desired rectangle dimension unsigned short X, Y; // Output // Packed position in Atlas - unsigned int GlyphID; // Input // For custom font glyphs only (ID < 0x110000) + unsigned int GlyphID : 31; // Input // For custom font glyphs only (ID < 0x110000) + unsigned int GlyphColored : 1; // Input // For custom font glyphs only: glyph is colored, removed tinting. float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset ImFont* Font; // Input // For custom font glyphs only: target font - ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } + ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } bool IsPacked() const { return X != 0xFFFF; } }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 43a49eb299c6..c0a5b5b7585b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2676,6 +2676,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int r.Width = (unsigned short)width; r.Height = (unsigned short)height; r.GlyphID = id; + r.GlyphColored = 0; // Set to 1 manually to mark glyph as colored // FIXME: No official API for that (#8133) r.GlyphAdvanceX = advance_x; r.GlyphOffset = offset; r.Font = font; @@ -3286,6 +3287,8 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) ImVec2 uv0, uv1; atlas->CalcCustomRectUV(r, &uv0, &uv1); r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); + if (r->GlyphColored) + r->Font->Glyphs.back().Colored = 1; } // Build all fonts lookup tables From 419a9ada16eb9b6d84ead4911b9c2a32820cfffb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 7 Nov 2024 19:08:37 +0100 Subject: [PATCH 027/716] Ignore clang warning Wnontrivial-memaccess (#8129, #8135) Amend 88e2327 Use void* cast in backend where the memset are infrequent. --- backends/imgui_impl_metal.mm | 9 +-------- backends/imgui_impl_osx.mm | 9 +-------- backends/imgui_impl_vulkan.cpp | 6 +++--- imgui.cpp | 1 + imgui.h | 1 + imgui_tables.cpp | 1 + imgui_widgets.cpp | 1 + 7 files changed, 9 insertions(+), 19 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 102f6982afd8..12dc3d50f52c 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -38,13 +38,6 @@ #import #import -#if defined(__clang__) -#if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' -#endif -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type -#endif - #pragma mark - Support classes // A wrapper around a MTLBuffer object that knows the last time it was reused @@ -83,7 +76,7 @@ - (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id #import -#if defined(__clang__) -#if __has_warning("-Wunknown-warning-option") -#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' -#endif -#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type -#endif - // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: @@ -94,7 +87,7 @@ id Monitor; NSWindow* Window; - ImGui_ImplOSX_Data() { memset(this, 0, sizeof(*this)); } + ImGui_ImplOSX_Data() { memset((void*)this, 0, sizeof(*this)); } }; static ImGui_ImplOSX_Data* ImGui_ImplOSX_GetBackendData() { return (ImGui_ImplOSX_Data*)ImGui::GetIO().BackendPlatformUserData; } diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 4e4e332fc207..d499ecb92350 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -489,7 +489,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm wrb->Index = 0; wrb->Count = v->ImageCount; wrb->FrameRenderBuffers = (ImGui_ImplVulkan_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); - memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); + memset((void*)wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); } IM_ASSERT(wrb->Count == v->ImageCount); wrb->Index = (wrb->Index + 1) % wrb->Count; @@ -1445,8 +1445,8 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V wd->SemaphoreCount = wd->ImageCount + 1; wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount); wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->SemaphoreCount); - memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); - memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->SemaphoreCount); + memset((void*)wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); + memset((void*)wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->SemaphoreCount); for (uint32_t i = 0; i < wd->ImageCount; i++) wd->Frames[i].Backbuffer = backbuffers[i]; } diff --git a/imgui.cpp b/imgui.cpp index 1f2dbc09a84b..2ea9417b44ac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1135,6 +1135,7 @@ CODE #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) // We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association. #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind diff --git a/imgui.h b/imgui.h index de6ec7b1c2cf..32425db89a12 100644 --- a/imgui.h +++ b/imgui.h @@ -135,6 +135,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 03007bb79913..122cd87b1a72 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -229,6 +229,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9d572422283f..bb445d977311 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -79,6 +79,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"// warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked From 01d27a4acde14c13e86adfcd0569e752f181e205 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 7 Nov 2024 16:58:50 +0100 Subject: [PATCH 028/716] Internals: added IM_LIKELY(), IM_UNLIKELY() helper macros (yet unused). Added ImFontGetCharAdvanceX() macro. --- imgui_draw.cpp | 16 +++++++++------- imgui_internal.h | 9 +++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c0a5b5b7585b..7934949ec95c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3847,7 +3847,7 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) return &Glyphs.Data[i]; } -// Wrapping skips upcoming blanks +// Trim trailing space and find beginning of next line static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) { while (text < text_end && ImCharIsBlankA(*text)) @@ -3857,6 +3857,8 @@ static inline const char* CalcWordWrapNextLineStartA(const char* text, const cha return text; } +#define ImFontGetCharAdvanceX(_FONT, _CH) ((int)(_CH) < (_FONT)->IndexAdvanceX.Size ? (_FONT)->IndexAdvanceX.Data[_CH] : (_FONT)->FallbackAdvanceX) + // Simple word-wrapping for English, not full-featured. Please submit failing cases! // This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) @@ -3909,7 +3911,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } } - const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); + const float char_width = ImFontGetCharAdvanceX(this, c); if (ImCharIsBlankW(c)) { if (inside_word) @@ -4014,7 +4016,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale; + const float char_width = ImFontGetCharAdvanceX(this, c); if (line_width + char_width >= max_width) { s = prev_s; @@ -4063,9 +4065,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im if (y > clip_rect.w) return; - const float start_x = x; const float scale = size / FontSize; const float line_height = FontSize * scale; + const float origin_x = x; const bool word_wrap_enabled = (wrap_width > 0.0f); // Fast-forward to first visible line @@ -4124,11 +4126,11 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) - word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - start_x)); + word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - origin_x)); if (s >= word_wrap_eol) { - x = start_x; + x = origin_x; y += line_height; if (y > clip_rect.w) break; // break out of main loop @@ -4149,7 +4151,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { if (c == '\n') { - x = start_x; + x = origin_x; y += line_height; if (y > clip_rect.w) break; // break out of main loop diff --git a/imgui_internal.h b/imgui_internal.h index 6d84f1027aca..9e6452bcb37e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -260,6 +260,15 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IM_FLOOR IM_TRUNC #endif +// Hint for branch prediction +#if (defined(__cplusplus) && (__cplusplus >= 202002L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L)) +#define IM_LIKELY [[likely]] +#define IM_UNLIKELY [[unlikely]] +#else +#define IM_LIKELY +#define IM_UNLIKELY +#endif + // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall #ifdef _MSC_VER #define IMGUI_CDECL __cdecl From 31b967f098dc53a6bb36f9be36f4a9e5d592f775 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 7 Nov 2024 19:35:00 +0100 Subject: [PATCH 029/716] Fix 01d27a4 (sorry I cherry-picked from wrong branch) --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7934949ec95c..48d42f392822 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4016,7 +4016,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ImFontGetCharAdvanceX(this, c); + const float char_width = ImFontGetCharAdvanceX(this, c) * scale; if (line_width + char_width >= max_width) { s = prev_s; From f401021d5a5d56fe2304056c391e78f81c8d4b8f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 7 Nov 2024 19:38:30 +0100 Subject: [PATCH 030/716] Version 1.91.5 --- docs/CHANGELOG.txt | 14 +++++++++----- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a1655fdabd90..ce752ca290d0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,9 +36,11 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.5 WIP (In Progress) + VERSION 1.91.5 (Released 2024-11-07) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.5 + Breaking changes: - Commented out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before). @@ -47,8 +49,8 @@ Breaking changes: - Pre-1.87 backends are not supported: - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields. - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields. - - For more reference: - - read 1.87 and 1.88 part of this section or read Changelog for 1.87 and 1.88. + - For more references: + - read 1.87 and 1.88 part of API BREAKING CHANGES in imgui.cpp or read Changelog for 1.87 and 1.88. - read https://github.com/ocornut/imgui/issues/4921 - If you have trouble updating a very old codebase using legacy backend-specific key codes: consider updating to 1.91.4 first, then #define IMGUI_DISABLE_OBSOLETE_KEYIO, then update to latest. @@ -66,12 +68,12 @@ Other changes: a callback would sometimes prevents further appending to the buffer. - Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). -- Log/Capture: better decorating of BeginMenu() and TabItem() output. -- Log/Capture: a non terminated log ends automatically in the window which called it. - Log/Capture: added experimental io.ConfigWindowsCopyContentsWithCtrlC option to automatically copy window contents into clipboard using CTRL+C. This is experimental because (1) it currently breaks on nested Begin/End, (2) text output quality varies, and (3) text output comes in submission order rather than spatial order. +- Log/Capture: better decorating of BeginMenu() and TabItem() output. +- Log/Capture: a non terminated log ends automatically in the window which called it. - imgui_freetype: Fixed a crash in build font atlas when using merged fonts and the first font in a merged set has no loaded glyph. (#8081) - Backends: DX12: Unmap() call specify written range. The range is informational and @@ -88,6 +90,8 @@ Other changes: VERSION 1.91.4 (Released 2024-10-18) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.4 + Breaking changes: - Style: renamed ImGuiCol_NavHighlight to ImGuiCol_NavCursor, for consistency with diff --git a/imgui.cpp b/imgui.cpp index 2ea9417b44ac..4624c45d9ee0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 32425db89a12..d6286592bb91 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.5 WIP" -#define IMGUI_VERSION_NUM 19144 +#define IMGUI_VERSION "1.91.5" +#define IMGUI_VERSION_NUM 19150 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e28ca3b7aac4..76a06cc7d334 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 48d42f392822..fa82a9419376 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 9e6452bcb37e..49452ab0ad22 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 122cd87b1a72..e36e6f17289e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bb445d977311..b5d66baa02af 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 WIP +// dear imgui, v1.91.5 // (widgets code) /* From 3381ab423b359bda18ef47e9919643bbaf5cc131 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 12 Nov 2024 11:44:29 +0100 Subject: [PATCH 031/716] Version 1.91.6 WIP + fixed typo in tooltip. --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 4 ++-- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ce752ca290d0..67d5bef53308 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,14 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.91.6 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + ----------------------------------------------------------------------- VERSION 1.91.5 (Released 2024-11-07) ----------------------------------------------------------------------- @@ -86,6 +94,7 @@ Other changes: - Examples: Android+OpenGL: Using ALooper_pollOnce() instead of ALooper_pollAll() which has been deprecated. (#8013) [@feather179] + ----------------------------------------------------------------------- VERSION 1.91.4 (Released 2024-10-18) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 4624c45d9ee0..431cac9c168e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (main code and documentation) // Help: @@ -10579,7 +10579,7 @@ void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip() BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!"); BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!"); //BulletText("Code intending to use duplicate ID may use e.g. PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()"); // Not making this too visible for fear of it being abused. - BulletText("Set io.ConfigDebugDetectIdConflicts=false to disable this warning in non-programmers builds."); + BulletText("Set io.ConfigDebugHighlightIdConflicts=false to disable this warning in non-programmers builds."); Separator(); Text("(Hold CTRL to: use"); SameLine(); diff --git a/imgui.h b/imgui.h index d6286592bb91..815b079242bf 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.5" -#define IMGUI_VERSION_NUM 19150 +#define IMGUI_VERSION "1.91.6 WIP" +#define IMGUI_VERSION_NUM 19151 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 76a06cc7d334..ac34e6b1d5da 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index fa82a9419376..0003fe1e2963 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 49452ab0ad22..2af196cb789e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e36e6f17289e..5254f7858743 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b5d66baa02af..c60378f82140 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.5 +// dear imgui, v1.91.6 WIP // (widgets code) /* From e97b97467e434d2c53b76a19563d641e55130e16 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 12 Nov 2024 19:09:00 +0100 Subject: [PATCH 032/716] Error Handling: fixed cases where recoverable error handling would crash. (#1651) --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 67d5bef53308..6586cba20486 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,10 @@ Breaking changes: Other changes: +- Error Handling: fixed cases where recoverable error handling would crash when + processing errors outside of the NewFrame()..EndFrame() scope. (#1651) + + ----------------------------------------------------------------------- VERSION 1.91.5 (Released 2024-11-07) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 431cac9c168e..45af644aed36 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10542,7 +10542,7 @@ bool ImGui::ErrorLog(const char* msg) // Output to tooltip if (g.IO.ConfigErrorRecoveryEnableTooltip) { - if (BeginErrorTooltip()) + if (g.WithinFrameScope && BeginErrorTooltip()) { if (g.ErrorCountCurrentFrame < 20) { From 8be0723fb7a626f0fad6e70a2ad9139e442c4008 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 13 Nov 2024 16:55:06 +0100 Subject: [PATCH 033/716] Amend Changelog to better document how changing button behavior of InputInt/InputFloat step buttons affected some mis-uses (#8149) --- docs/CHANGELOG.txt | 5 +++++ imgui.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6586cba20486..0dc526e24dbb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,11 @@ Other changes: between _Header and _HeaderHovered which was introduced v1.91 (#8106, #1861) - Buttons: using ImGuiItemFlags_ButtonRepeat makes default button behavior use PressedOnClick instead of PressedOnClickRelease when unspecified. + - This is intended to make the +/- buttons of InputInt/InputFloat react on the + initial mouse down event. + - Note that it may reveal incorrect usage if you were using InputInt/InputFloat + without persistent storage by relying solely on e.g. IsItemDeactivatedAfterEdit(): + this was never supported and didn't work consistantly (see #8149). - InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within a callback would sometimes prevents further appending to the buffer. - Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default diff --git a/imgui.cpp b/imgui.cpp index 45af644aed36..3512ec87dda9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5788,7 +5788,7 @@ bool ImGui::IsItemDeactivatedAfterEdit() return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); } -// == GetItemID() == GetFocusID() +// == (GetItemID() == GetFocusID() && GetFocusID() != 0) bool ImGui::IsItemFocused() { ImGuiContext& g = *GImGui; From 3260ea6954554f5cfac7461e94bc18d14cce3617 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Nov 2024 16:03:58 +0100 Subject: [PATCH 034/716] Examples: Win32+DX12: Tweaks. --- backends/imgui_impl_dx12.cpp | 3 ++ backends/imgui_impl_dx12.h | 3 ++ examples/example_win32_directx12/main.cpp | 36 +++++++++++------------ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 7a428a1a5ad1..24b195bda900 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -6,6 +6,9 @@ // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. +// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ + // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Learn about Dear ImGui: diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 1e36d730f77b..b5a8dde2e7f2 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -6,6 +6,9 @@ // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. +// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ + // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Learn about Dear ImGui: diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 4173a8010c6b..168b6966038e 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -22,20 +22,20 @@ #pragma comment(lib, "dxguid.lib") #endif -#include "imgui_internal.h" +// Config for example app +static const int APP_NUM_FRAMES_IN_FLIGHT = 3; +static const int APP_NUM_BACK_BUFFERS = 3; struct FrameContext { - ID3D12CommandAllocator* CommandAllocator; - UINT64 FenceValue; + ID3D12CommandAllocator* CommandAllocator; + UINT64 FenceValue; }; // Data -static int const NUM_FRAMES_IN_FLIGHT = 3; -static FrameContext g_frameContext[NUM_FRAMES_IN_FLIGHT] = {}; +static FrameContext g_frameContext[APP_NUM_FRAMES_IN_FLIGHT] = {}; static UINT g_frameIndex = 0; -static int const NUM_BACK_BUFFERS = 3; static ID3D12Device* g_pd3dDevice = nullptr; static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = nullptr; static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = nullptr; @@ -47,8 +47,8 @@ static UINT64 g_fenceLastSignaledValue = 0; static IDXGISwapChain3* g_pSwapChain = nullptr; static bool g_SwapChainOccluded = false; static HANDLE g_hSwapChainWaitableObject = nullptr; -static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = {}; -static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = {}; +static ID3D12Resource* g_mainRenderTargetResource[APP_NUM_BACK_BUFFERS] = {}; +static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[APP_NUM_BACK_BUFFERS] = {}; // Forward declarations of helper functions bool CreateDeviceD3D(HWND hWnd); @@ -249,7 +249,7 @@ bool CreateDeviceD3D(HWND hWnd) DXGI_SWAP_CHAIN_DESC1 sd; { ZeroMemory(&sd, sizeof(sd)); - sd.BufferCount = NUM_BACK_BUFFERS; + sd.BufferCount = APP_NUM_BACK_BUFFERS; sd.Width = 0; sd.Height = 0; sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -292,7 +292,7 @@ bool CreateDeviceD3D(HWND hWnd) { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - desc.NumDescriptors = NUM_BACK_BUFFERS; + desc.NumDescriptors = APP_NUM_BACK_BUFFERS; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; desc.NodeMask = 1; if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dRtvDescHeap)) != S_OK) @@ -300,7 +300,7 @@ bool CreateDeviceD3D(HWND hWnd) SIZE_T rtvDescriptorSize = g_pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = g_pd3dRtvDescHeap->GetCPUDescriptorHandleForHeapStart(); - for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) { g_mainRenderTargetDescriptor[i] = rtvHandle; rtvHandle.ptr += rtvDescriptorSize; @@ -325,7 +325,7 @@ bool CreateDeviceD3D(HWND hWnd) return false; } - for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) + for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++) if (g_pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&g_frameContext[i].CommandAllocator)) != S_OK) return false; @@ -351,7 +351,7 @@ bool CreateDeviceD3D(HWND hWnd) return false; swapChain1->Release(); dxgiFactory->Release(); - g_pSwapChain->SetMaximumFrameLatency(NUM_BACK_BUFFERS); + g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS); g_hSwapChainWaitableObject = g_pSwapChain->GetFrameLatencyWaitableObject(); } @@ -364,7 +364,7 @@ void CleanupDeviceD3D() CleanupRenderTarget(); if (g_pSwapChain) { g_pSwapChain->SetFullscreenState(false, nullptr); g_pSwapChain->Release(); g_pSwapChain = nullptr; } if (g_hSwapChainWaitableObject != nullptr) { CloseHandle(g_hSwapChainWaitableObject); } - for (UINT i = 0; i < NUM_FRAMES_IN_FLIGHT; i++) + for (UINT i = 0; i < APP_NUM_FRAMES_IN_FLIGHT; i++) if (g_frameContext[i].CommandAllocator) { g_frameContext[i].CommandAllocator->Release(); g_frameContext[i].CommandAllocator = nullptr; } if (g_pd3dCommandQueue) { g_pd3dCommandQueue->Release(); g_pd3dCommandQueue = nullptr; } if (g_pd3dCommandList) { g_pd3dCommandList->Release(); g_pd3dCommandList = nullptr; } @@ -386,7 +386,7 @@ void CleanupDeviceD3D() void CreateRenderTarget() { - for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) { ID3D12Resource* pBackBuffer = nullptr; g_pSwapChain->GetBuffer(i, IID_PPV_ARGS(&pBackBuffer)); @@ -399,13 +399,13 @@ void CleanupRenderTarget() { WaitForLastSubmittedFrame(); - for (UINT i = 0; i < NUM_BACK_BUFFERS; i++) + for (UINT i = 0; i < APP_NUM_BACK_BUFFERS; i++) if (g_mainRenderTargetResource[i]) { g_mainRenderTargetResource[i]->Release(); g_mainRenderTargetResource[i] = nullptr; } } void WaitForLastSubmittedFrame() { - FrameContext* frameCtx = &g_frameContext[g_frameIndex % NUM_FRAMES_IN_FLIGHT]; + FrameContext* frameCtx = &g_frameContext[g_frameIndex % APP_NUM_FRAMES_IN_FLIGHT]; UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue == 0) @@ -427,7 +427,7 @@ FrameContext* WaitForNextFrameResources() HANDLE waitableObjects[] = { g_hSwapChainWaitableObject, nullptr }; DWORD numWaitableObjects = 1; - FrameContext* frameCtx = &g_frameContext[nextFrameIndex % NUM_FRAMES_IN_FLIGHT]; + FrameContext* frameCtx = &g_frameContext[nextFrameIndex % APP_NUM_FRAMES_IN_FLIGHT]; UINT64 fenceValue = frameCtx->FenceValue; if (fenceValue != 0) // means no fence was signaled { From 40b2286d16e92ea017347a62cb91e63f378ff455 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Nov 2024 19:02:26 +0100 Subject: [PATCH 035/716] (Breaking) Backends: DX12: changed ImGui_ImplDX12_Init() signature. Added ImGui_ImplDX12_InitInfo. Added support for Srv allocators. Ref 7708 --- backends/imgui_impl_dx12.cpp | 67 +++++++++++++++++++---- backends/imgui_impl_dx12.h | 40 ++++++++++---- docs/CHANGELOG.txt | 10 ++++ examples/example_win32_directx12/main.cpp | 66 ++++++++++++++++++++-- 4 files changed, 155 insertions(+), 28 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 24b195bda900..105bcb213289 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -19,6 +19,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). +// 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. // 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools. // 2024-10-07: DirectX12: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: DirectX12: Expose selected render state in ImGui_ImplDX12_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -57,6 +59,7 @@ struct ImGui_ImplDX12_RenderBuffers; struct ImGui_ImplDX12_Data { + ImGui_ImplDX12_InitInfo InitInfo; ID3D12Device* pd3dDevice; ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; @@ -695,8 +698,14 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() ImGuiIO& io = ImGui::GetIO(); SafeRelease(bd->pRootSignature); SafeRelease(bd->pPipelineState); + + // Free SRV descriptor used by texture +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (bd->InitInfo.SrvDescriptorFreeFn != NULL) +#endif + bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, bd->hFontSrvCpuDescHandle, bd->hFontSrvGpuDescHandle); SafeRelease(bd->pFontTextureResource); - io.Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. + io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well. for (UINT i = 0; i < bd->numFramesInFlight; i++) { @@ -706,8 +715,7 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() } } -bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap, - D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) +bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) { ImGuiIO& io = ImGui::GetIO(); IMGUI_CHECKVERSION(); @@ -715,21 +723,39 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO // Setup backend capabilities flags ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)(); + + bd->InitInfo = *init_info; // Deep copy + bd->pd3dDevice = init_info->Device; + bd->RTVFormat = init_info->RTVFormat; + bd->numFramesInFlight = init_info->NumFramesInFlight; + bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap; + io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx12"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - bd->pd3dDevice = device; - bd->RTVFormat = rtv_format; - bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle; - bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle; - bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[num_frames_in_flight]; - bd->numFramesInFlight = num_frames_in_flight; - bd->pd3dSrvDescHeap = cbv_srv_heap; - bd->frameIndex = UINT_MAX; + // Allocate 1 SRV descriptor for the font texture + if (init_info->SrvDescriptorAllocFn != NULL) + { + IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL); + init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->hFontSrvCpuDescHandle, &bd->hFontSrvGpuDescHandle); + } + else + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); + bd->hFontSrvCpuDescHandle = init_info->LegacySingleSrvCpuDescriptor; + bd->hFontSrvGpuDescHandle = init_info->LegacySingleSrvGpuDescriptor; +#else + IM_ASSERT(init_info->SrvDescriptorAllocFn != NULL); + IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL); +#endif + } // Create buffers with a default size (they will later be grown as needed) - for (int i = 0; i < num_frames_in_flight; i++) + bd->frameIndex = UINT_MAX; + bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[bd->numFramesInFlight]; + for (int i = 0; i < (int)bd->numFramesInFlight; i++) { ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i]; fr->IndexBuffer = nullptr; @@ -741,6 +767,22 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO return true; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy initialization API Obsoleted in 1.91.5 +// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' +bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle) +{ + ImGui_ImplDX12_InitInfo init_info; + init_info.Device = device; + init_info.NumFramesInFlight = num_frames_in_flight; + init_info.RTVFormat = rtv_format; + init_info.SrvDescriptorHeap = srv_descriptor_heap; + init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle; + init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle;; + return ImGui_ImplDX12_Init(&init_info); +} +#endif + void ImGui_ImplDX12_Shutdown() { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); @@ -750,6 +792,7 @@ void ImGui_ImplDX12_Shutdown() // Clean up windows and device objects ImGui_ImplDX12_InvalidateDeviceObjects(); delete[] bd->pFrameResources; + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index b5a8dde2e7f2..34938fb56347 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -21,24 +21,42 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE #include // DXGI_FORMAT +#include // D3D12_CPU_DESCRIPTOR_HANDLE -struct ID3D12Device; -struct ID3D12DescriptorHeap; -struct ID3D12GraphicsCommandList; -struct D3D12_CPU_DESCRIPTOR_HANDLE; -struct D3D12_GPU_DESCRIPTOR_HANDLE; +// Initialization data, for ImGui_ImplDX12_Init() +struct ImGui_ImplDX12_InitInfo +{ + ID3D12Device* Device; + ID3D12CommandQueue* CommandQueue; + int NumFramesInFlight; + DXGI_FORMAT RTVFormat; + void* UserData; -// Follow "Getting Started" link and check examples/ folder to learn about using backends! + // Allocating SRV descriptors for textures is up to the application, so we provide callbacks. + // (current version of the backend will only allocate one descriptor, future versions will need to allocate more) + ID3D12DescriptorHeap* SrvDescriptorHeap; + void (*SrvDescriptorAllocFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle); + void (*SrvDescriptorFreeFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + D3D12_CPU_DESCRIPTOR_HANDLE LegacySingleSrvCpuDescriptor; // To facilitate transition from single descriptor to allocator callback, you may use those. + D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor; +#endif -// Before calling the render function, caller must prepare the command list by resetting it and setting the appropriate -// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle. -// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture. -IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap, - D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); + ImGui_ImplDX12_InitInfo() { memset(this, 0, sizeof(*this)); } +}; + +// Follow "Getting Started" link and check examples/ folder to learn about using backends! +IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* info); IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown(); IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame(); IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// Legacy initialization API Obsoleted in 1.91.5 +// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' +IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); +#endif + // Use if you want to reset your rendering device without losing Dear ImGui state. IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0dc526e24dbb..ef42ebc4d11e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,10 +41,20 @@ HOW TO UPDATE? Breaking changes: +- Backends: DX12: Changed ImGui_ImplDX12_Init() signature to take a + ImGui_ImplDX12_InitInfo struct. + - Using the new API, application is now required to pass function pointers + to allocate/free SRV Descriptors. + - We provide convenience legacy fields to pass a single descriptor, + matching the old API, but upcoming features will want multiple. + - Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). + Other changes: - Error Handling: fixed cases where recoverable error handling would crash when processing errors outside of the NewFrame()..EndFrame() scope. (#1651) +- Examples: Win32+DX12: Using a basic free-list allocator to manage multiple + SRV descriptors. ----------------------------------------------------------------------- diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 168b6966038e..257410e2cb2e 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -25,6 +25,7 @@ // Config for example app static const int APP_NUM_FRAMES_IN_FLIGHT = 3; static const int APP_NUM_BACK_BUFFERS = 3; +static const int APP_SRV_HEAP_SIZE = 64; struct FrameContext { @@ -32,6 +33,51 @@ struct FrameContext UINT64 FenceValue; }; +// Simple free list based allocator +struct ExampleDescriptorHeapAllocator +{ + ID3D12DescriptorHeap* Heap = nullptr; + D3D12_DESCRIPTOR_HEAP_TYPE HeapType = D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; + D3D12_CPU_DESCRIPTOR_HANDLE HeapStartCpu; + D3D12_GPU_DESCRIPTOR_HANDLE HeapStartGpu; + UINT HeapHandleIncrement; + ImVector FreeIndices; + + void Create(ID3D12Device* device, ID3D12DescriptorHeap* heap) + { + IM_ASSERT(Heap == nullptr && FreeIndices.empty()); + Heap = heap; + D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc(); + HeapType = desc.Type; + HeapStartCpu = Heap->GetCPUDescriptorHandleForHeapStart(); + HeapStartGpu = Heap->GetGPUDescriptorHandleForHeapStart(); + HeapHandleIncrement = device->GetDescriptorHandleIncrementSize(HeapType); + FreeIndices.reserve((int)desc.NumDescriptors); + for (int n = desc.NumDescriptors; n > 0; n--) + FreeIndices.push_back(n); + } + void Destroy() + { + Heap = NULL; + FreeIndices.clear(); + } + void Alloc(D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle) + { + IM_ASSERT(FreeIndices.Size > 0); + int idx = FreeIndices.back(); + FreeIndices.pop_back(); + out_cpu_desc_handle->ptr = HeapStartCpu.ptr + (idx * HeapHandleIncrement); + out_gpu_desc_handle->ptr = HeapStartGpu.ptr + (idx * HeapHandleIncrement); + } + void Free(D3D12_CPU_DESCRIPTOR_HANDLE out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE out_gpu_desc_handle) + { + int cpu_idx = (int)((out_cpu_desc_handle.ptr - HeapStartCpu.ptr) / HeapHandleIncrement); + int gpu_idx = (int)((out_gpu_desc_handle.ptr - HeapStartGpu.ptr) / HeapHandleIncrement); + IM_ASSERT(cpu_idx == gpu_idx); + FreeIndices.push_back(cpu_idx); + } +}; + // Data static FrameContext g_frameContext[APP_NUM_FRAMES_IN_FLIGHT] = {}; static UINT g_frameIndex = 0; @@ -39,6 +85,7 @@ static UINT g_frameIndex = 0; static ID3D12Device* g_pd3dDevice = nullptr; static ID3D12DescriptorHeap* g_pd3dRtvDescHeap = nullptr; static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = nullptr; +static ExampleDescriptorHeapAllocator g_pd3dSrvDescHeapAlloc; static ID3D12CommandQueue* g_pd3dCommandQueue = nullptr; static ID3D12GraphicsCommandList* g_pd3dCommandList = nullptr; static ID3D12Fence* g_fence = nullptr; @@ -93,10 +140,18 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); - ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT, - DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, - g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), - g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); + + ImGui_ImplDX12_InitInfo init_info = {}; + init_info.Device = g_pd3dDevice; + init_info.CommandQueue = g_pd3dCommandQueue; + init_info.NumFramesInFlight = APP_NUM_FRAMES_IN_FLIGHT; + init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + // Allocating SRV descriptors (for textures) is up to the application, so we provide callbacks. + // (current version of the backend will only allocate one descriptor, future versions will need to allocate more) + init_info.SrvDescriptorHeap = g_pd3dSrvDescHeap; + init_info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) { return g_pd3dSrvDescHeapAlloc.Alloc(out_cpu_handle, out_gpu_handle); }; + init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle) { return g_pd3dSrvDescHeapAlloc.Free(cpu_handle, gpu_handle); }; + ImGui_ImplDX12_Init(&init_info); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. @@ -310,10 +365,11 @@ bool CreateDeviceD3D(HWND hWnd) { D3D12_DESCRIPTOR_HEAP_DESC desc = {}; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = 1; + desc.NumDescriptors = APP_SRV_HEAP_SIZE; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; if (g_pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)) != S_OK) return false; + g_pd3dSrvDescHeapAlloc.Create(g_pd3dDevice, g_pd3dSrvDescHeap); } { From 08400f5be7fa8a83682b99d611ab7cdc66258425 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 15 Nov 2024 19:14:04 +0100 Subject: [PATCH 036/716] Backends: DX12: tidying up, added a ImGui_ImplDX12_Texture helper struct. --- backends/imgui_impl_dx12.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 105bcb213289..8f9eb090c274 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -55,8 +55,16 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif -// DirectX data +// DirectX12 data struct ImGui_ImplDX12_RenderBuffers; + +struct ImGui_ImplDX12_Texture +{ + ID3D12Resource* pTextureResource; + D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle; + D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle; +}; + struct ImGui_ImplDX12_Data { ImGui_ImplDX12_InitInfo InitInfo; @@ -64,9 +72,7 @@ struct ImGui_ImplDX12_Data ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; DXGI_FORMAT RTVFormat; - ID3D12Resource* pFontTextureResource; - D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle; - D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle; + ImGui_ImplDX12_Texture FontTexture; ID3D12DescriptorHeap* pd3dSrvDescHeap; UINT numFramesInFlight; @@ -316,6 +322,7 @@ static void ImGui_ImplDX12_CreateFontsTexture() io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Upload texture to graphics system + ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; { D3D12_HEAP_PROPERTIES props; memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); @@ -446,13 +453,13 @@ static void ImGui_ImplDX12_CreateFontsTexture() srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle); - SafeRelease(bd->pFontTextureResource); - bd->pFontTextureResource = pTexture; + bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, font_tex->hFontSrvCpuDescHandle); + SafeRelease(font_tex->pTextureResource); + font_tex->pTextureResource = pTexture; } // Store our identifier - io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr); + io.Fonts->SetTexID((ImTextureID)font_tex->hFontSrvGpuDescHandle.ptr); } bool ImGui_ImplDX12_CreateDeviceObjects() @@ -700,11 +707,12 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() SafeRelease(bd->pPipelineState); // Free SRV descriptor used by texture + ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (bd->InitInfo.SrvDescriptorFreeFn != NULL) #endif - bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, bd->hFontSrvCpuDescHandle, bd->hFontSrvGpuDescHandle); - SafeRelease(bd->pFontTextureResource); + bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); + SafeRelease(font_tex->pTextureResource); io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well. for (UINT i = 0; i < bd->numFramesInFlight; i++) @@ -738,14 +746,14 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) if (init_info->SrvDescriptorAllocFn != NULL) { IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL); - init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->hFontSrvCpuDescHandle, &bd->hFontSrvGpuDescHandle); + init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); } else { #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); - bd->hFontSrvCpuDescHandle = init_info->LegacySingleSrvCpuDescriptor; - bd->hFontSrvGpuDescHandle = init_info->LegacySingleSrvGpuDescriptor; + bd->FontTexture.hFontSrvCpuDescHandle = init_info->LegacySingleSrvCpuDescriptor; + bd->FontTexture.hFontSrvGpuDescHandle = init_info->LegacySingleSrvGpuDescriptor; #else IM_ASSERT(init_info->SrvDescriptorAllocFn != NULL); IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL); From 142827f7d8618d107f18d995da3530dab8aefd8f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 Nov 2024 15:16:41 +0100 Subject: [PATCH 037/716] Backends: DX12: rework legacy path for handling ImGui_ImplDX12_Init() being called with space for a single descriptor. --- backends/imgui_impl_dx12.cpp | 48 +++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 8f9eb090c274..acf98858b55f 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -72,13 +72,15 @@ struct ImGui_ImplDX12_Data ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; DXGI_FORMAT RTVFormat; - ImGui_ImplDX12_Texture FontTexture; ID3D12DescriptorHeap* pd3dSrvDescHeap; UINT numFramesInFlight; ImGui_ImplDX12_RenderBuffers* pFrameResources; UINT frameIndex; + ImGui_ImplDX12_Texture FontTexture; + bool LegacySingleDescriptorUsed; + ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); frameIndex = UINT_MAX; } }; @@ -708,10 +710,7 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() // Free SRV descriptor used by texture ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (bd->InitInfo.SrvDescriptorFreeFn != NULL) -#endif - bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); + bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); SafeRelease(font_tex->pTextureResource); io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well. @@ -731,8 +730,9 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) // Setup backend capabilities flags ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)(); - bd->InitInfo = *init_info; // Deep copy + init_info = &bd->InitInfo; + bd->pd3dDevice = init_info->Device; bd->RTVFormat = init_info->RTVFormat; bd->numFramesInFlight = init_info->NumFramesInFlight; @@ -742,23 +742,31 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) io.BackendRendererName = "imgui_impl_dx12"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - // Allocate 1 SRV descriptor for the font texture - if (init_info->SrvDescriptorAllocFn != NULL) - { - IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL); - init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); - } - else - { #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (init_info->SrvDescriptorAllocFn == NULL) + { + // Wrap legacy behavior of passing space for a single descriptor IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); - bd->FontTexture.hFontSrvCpuDescHandle = init_info->LegacySingleSrvCpuDescriptor; - bd->FontTexture.hFontSrvGpuDescHandle = init_info->LegacySingleSrvGpuDescriptor; -#else - IM_ASSERT(init_info->SrvDescriptorAllocFn != NULL); - IM_ASSERT(init_info->SrvDescriptorFreeFn != NULL); -#endif + init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) + { + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + IM_ASSERT(bd->LegacySingleDescriptorUsed == false); + *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor; + *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor; + bd->LegacySingleDescriptorUsed = true; + }; + init_info->SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE) + { + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + IM_ASSERT(bd->LegacySingleDescriptorUsed == true); + bd->LegacySingleDescriptorUsed = false; + }; } +#endif + + // Allocate 1 SRV descriptor for the font texture + IM_ASSERT(init_info->SrvDescriptorAllocFn != NULL && init_info->SrvDescriptorFreeFn != NULL); + init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); // Create buffers with a default size (they will later be grown as needed) bd->frameIndex = UINT_MAX; From eb0ad66d88d96be3ccad31e22ef9d3126ec79ef2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 18 Nov 2024 18:46:27 +0100 Subject: [PATCH 038/716] Demo: example tree used by Property Editor & Selection demos properly freed on app closure. (#8158) --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ef42ebc4d11e..29d1cf98ab99 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,8 @@ Other changes: - Error Handling: fixed cases where recoverable error handling would crash when processing errors outside of the NewFrame()..EndFrame() scope. (#1651) +- Demo: example tree used by Property Editor & Selection demos properly freed + on application closure. (#8158) [@Legulysse] - Examples: Win32+DX12: Using a basic free-list allocator to manage multiple SRV descriptors. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ac34e6b1d5da..c822c162e567 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -308,6 +308,13 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl return node; } +static void ExampleTree_DestroyNode(ExampleTreeNode* node) +{ + for (ExampleTreeNode* child_node : node->Childs) + ExampleTree_DestroyNode(child_node); + IM_DELETE(node); +} + // Create example tree data // (this allocates _many_ more times than most other code in either Dear ImGui or others demo) static ExampleTreeNode* ExampleTree_CreateDemoTree() @@ -343,7 +350,7 @@ static ExampleTreeNode* ExampleTree_CreateDemoTree() // [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- -// Data to be shared accross different functions of the demo. +// Data to be shared across different functions of the demo. struct ImGuiDemoWindowData { // Examples Apps (accessible from the "Examples" menu) @@ -371,6 +378,8 @@ struct ImGuiDemoWindowData // Other data ExampleTreeNode* DemoTree = NULL; + + ~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); } }; // Demonstrate most Dear ImGui features (this is big function!) From 5ae3dd52a07e4996c777dfb0a85682260f968674 Mon Sep 17 00:00:00 2001 From: chuikingshek Date: Tue, 19 Nov 2024 02:36:26 +0800 Subject: [PATCH 039/716] Fonts: added IMGUI_DISABLE_DEFAULT_FONT macro. (#8161) --- docs/CHANGELOG.txt | 2 ++ imconfig.h | 1 + imgui_draw.cpp | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 29d1cf98ab99..f04eccd6f15a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,8 @@ Other changes: - Error Handling: fixed cases where recoverable error handling would crash when processing errors outside of the NewFrame()..EndFrame() scope. (#1651) +- Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) + [@demonese] - Demo: example tree used by Property Editor & Selection demos properly freed on application closure. (#8158) [@Legulysse] - Examples: Win32+DX12: Using a basic free-list allocator to manage multiple diff --git a/imconfig.h b/imconfig.h index fea89dea0913..adc69d1a3e52 100644 --- a/imconfig.h +++ b/imconfig.h @@ -48,6 +48,7 @@ //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). +//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~14 KB from output binary. AddFontDefault() will assert. //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Enable Test Engine / Automation features. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0003fe1e2963..731dd05988bb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2560,7 +2560,9 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) static unsigned int stb_decompress_length(const unsigned char* input); static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); +#ifndef IMGUI_DISABLE_DEFAULT_FONT static const char* GetDefaultCompressedFontDataTTFBase85(); +#endif static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } static void Decode85(const unsigned char* src, unsigned char* dst) { @@ -2576,6 +2578,7 @@ static void Decode85(const unsigned char* src, unsigned char* dst) // Load embedded ProggyClean.ttf at size 13, disable oversampling ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) { +#ifndef IMGUI_DISABLE_DEFAULT_FONT ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); if (!font_cfg_template) { @@ -2593,6 +2596,11 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); return font; +#else + IM_ASSERT(0 && "AddFontDefault() disabled in this build."); + IM_UNUSED(font_cfg_template); + return NULL; +#endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT } ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) @@ -4578,6 +4586,8 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i // Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). // The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. //----------------------------------------------------------------------------- + +#ifndef IMGUI_DISABLE_DEFAULT_FONT static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" "2*>]b(MC;$jPfY.;h^`IWM9 Date: Wed, 20 Nov 2024 14:02:44 +0100 Subject: [PATCH 040/716] Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). (#8161) Encoding as char to ensure compatibility with big endian (#81) --- docs/CHANGELOG.txt | 1 + imconfig.h | 2 +- imgui_draw.cpp | 280 +++++++++++++++++--------- misc/fonts/binary_to_compressed_c.cpp | 23 ++- 4 files changed, 206 insertions(+), 100 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f04eccd6f15a..5305b889e51a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,7 @@ Other changes: - Error Handling: fixed cases where recoverable error handling would crash when processing errors outside of the NewFrame()..EndFrame() scope. (#1651) +- Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). - Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) [@demonese] - Demo: example tree used by Property Editor & Selection demos properly freed diff --git a/imconfig.h b/imconfig.h index adc69d1a3e52..3504a4e4d369 100644 --- a/imconfig.h +++ b/imconfig.h @@ -48,7 +48,7 @@ //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies) //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). -//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~14 KB from output binary. AddFontDefault() will assert. +//#define IMGUI_DISABLE_DEFAULT_FONT // Disable default embedded font (ProggyClean.ttf), remove ~9.5 KB from output binary. AddFontDefault() will assert. //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Enable Test Engine / Automation features. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 731dd05988bb..0f74a98b3d07 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2560,9 +2560,6 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) static unsigned int stb_decompress_length(const unsigned char* input); static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length); -#ifndef IMGUI_DISABLE_DEFAULT_FONT -static const char* GetDefaultCompressedFontDataTTFBase85(); -#endif static unsigned int Decode85Byte(char c) { return c >= '\\' ? c-36 : c-35; } static void Decode85(const unsigned char* src, unsigned char* dst) { @@ -2574,6 +2571,9 @@ static void Decode85(const unsigned char* src, unsigned char* dst) dst += 4; } } +#ifndef IMGUI_DISABLE_DEFAULT_FONT +static const char* GetDefaultCompressedFontDataTTF(int* out_size); +#endif // Load embedded ProggyClean.ttf at size 13, disable oversampling ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) @@ -2592,9 +2592,10 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) font_cfg.EllipsisChar = (ImWchar)0x0085; font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units - const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); + int ttf_compressed_size = 0; + const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); - ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges); + ImFont* font = AddFontFromMemoryCompressedTTF(ttf_compressed, ttf_compressed_size, font_cfg.SizePixels, &font_cfg, glyph_ranges); return font; #else IM_ASSERT(0 && "AddFontDefault() disabled in this build."); @@ -4583,102 +4584,185 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i // Download and more information at http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php //----------------------------------------------------------------------------- // File: 'ProggyClean.ttf' (41208 bytes) -// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding). -// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size. +// Exported using "misc/fonts/binary_to_compressed_c.exe ../ProggyClean.ttf proggy_clean_ttf_compressed (with compression, no base85 encoding). //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_DEFAULT_FONT -static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] = - "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/" - "2*>]b(MC;$jPfY.;h^`IWM9Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1=Ke$$'5F%)]0^#0X@U.a$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;--VsM.M0rJfLH2eTM`*oJMHRC`N" - "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`�j@'DbG&#^$PG.Ll+DNa&VZ>1i%h1S9u5o@YaaW$e+bROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc." - "x]Ip.PH^'/aqUO/$1WxLoW0[iLAw=4h(9.`G" - "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?Ggv:[7MI2k).'2($5FNP&EQ(,)" - "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#" - "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM" - "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu" - "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/" - "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[Ket`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO" - "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%" - "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$MhLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]" - "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et" - "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:" - "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VBpqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<-+k?'(^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M" - "D?@f&1'BW-)Ju#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(" - "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs" - "bIu)'Z,*[>br5fX^:FPAWr-m2KgLQ_nN6'8uTGT5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q" - "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aege0jT6'N#(q%.O=?2S]u*(m<-" - "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i" - "sZ88+dKQ)W6>J%CL`.d*(B`-n8D9oK-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P r+$%CE=68>K8r0=dSC%%(@p7" - ".m7jilQ02'0-VWAgTlGW'b)Tq7VT9q^*^$$.:&N@@" - "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*" - "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u" - "@-W$U%VEQ/,,>>#)D#%8cY#YZ?=,`Wdxu/ae&#" - "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$so8lKN%5/$(vdfq7+ebA#" - "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoFDoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8" - "6e%B/:=>)N4xeW.*wft-;$'58-ESqr#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#" - "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjLV#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#SfD07&6D@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5" - "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%" - "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;" - "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmLq9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:" - "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3$U4O]GKx'm9)b@p7YsvK3w^YR-" - "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*" - "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdFTi1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IXSsDiWP,##P`%/L-" - "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdFl*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj" - "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#$(>.Z-I&J(Q0Hd5Q%7Co-b`-cP)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8WlA2);Sa" - ">gXm8YB`1d@K#n]76-a$U,mF%Ul:#/'xoFM9QX-$.QN'>" - "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I" - "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-uW%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)" - "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo" - "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P" - "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*'IAO" - "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#" - ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T" - "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4" - "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#" - "/QHC#3^ZC#7jmC#;v)D#?,)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP" - "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp" - "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#"; - -static const char* GetDefaultCompressedFontDataTTFBase85() -{ - return proggy_clean_ttf_compressed_data_base85; +static const unsigned int proggy_clean_ttf_compressed_size = 9583; +static const unsigned char proggy_clean_ttf_compressed_data[9583] = +{ + 87,188,0,0,0,0,0,0,0,0,160,248,0,4,0,0,55,0,1,0,0,0,12,0,128,0,3,0,64,79,83,47,50,136,235,116,144,0,0,1,72,130,21,44,78,99,109,97,112,2,18,35,117,0,0,3,160,130,19,36,82,99,118,116, + 32,130,23,130,2,33,4,252,130,4,56,2,103,108,121,102,18,175,137,86,0,0,7,4,0,0,146,128,104,101,97,100,215,145,102,211,130,27,32,204,130,3,33,54,104,130,16,39,8,66,1,195,0,0,1,4,130, + 15,59,36,104,109,116,120,138,0,126,128,0,0,1,152,0,0,2,6,108,111,99,97,140,115,176,216,0,0,5,130,30,41,2,4,109,97,120,112,1,174,0,218,130,31,32,40,130,16,44,32,110,97,109,101,37,89, + 187,150,0,0,153,132,130,19,44,158,112,111,115,116,166,172,131,239,0,0,155,36,130,51,44,210,112,114,101,112,105,2,1,18,0,0,4,244,130,47,32,8,132,203,46,1,0,0,60,85,233,213,95,15,60, + 245,0,3,8,0,131,0,34,183,103,119,130,63,43,0,0,189,146,166,215,0,0,254,128,3,128,131,111,130,241,33,2,0,133,0,32,1,130,65,38,192,254,64,0,0,3,128,131,16,130,5,32,1,131,7,138,3,33,2, + 0,130,17,36,1,1,0,144,0,130,121,130,23,38,2,0,8,0,64,0,10,130,9,32,118,130,9,130,6,32,0,130,59,33,1,144,131,200,35,2,188,2,138,130,16,32,143,133,7,37,1,197,0,50,2,0,131,0,33,4,9,131, + 5,145,3,43,65,108,116,115,0,64,0,0,32,172,8,0,131,0,35,5,0,1,128,131,77,131,3,33,3,128,191,1,33,1,128,130,184,35,0,0,128,0,130,3,131,11,32,1,130,7,33,0,128,131,1,32,1,136,9,32,0,132, + 15,135,5,32,1,131,13,135,27,144,35,32,1,149,25,131,21,32,0,130,0,32,128,132,103,130,35,132,39,32,0,136,45,136,97,133,17,130,5,33,0,0,136,19,34,0,128,1,133,13,133,5,32,128,130,15,132, + 131,32,3,130,5,32,3,132,27,144,71,32,0,133,27,130,29,130,31,136,29,131,63,131,3,65,63,5,132,5,132,205,130,9,33,0,0,131,9,137,119,32,3,132,19,138,243,130,55,32,1,132,35,135,19,131,201, + 136,11,132,143,137,13,130,41,32,0,131,3,144,35,33,128,0,135,1,131,223,131,3,141,17,134,13,136,63,134,15,136,53,143,15,130,96,33,0,3,131,4,130,3,34,28,0,1,130,5,34,0,0,76,130,17,131, + 9,36,28,0,4,0,48,130,17,46,8,0,8,0,2,0,0,0,127,0,255,32,172,255,255,130,9,34,0,0,129,132,9,130,102,33,223,213,134,53,132,22,33,1,6,132,6,64,4,215,32,129,165,216,39,177,0,1,141,184, + 1,255,133,134,45,33,198,0,193,1,8,190,244,1,28,1,158,2,20,2,136,2,252,3,20,3,88,3,156,3,222,4,20,4,50,4,80,4,98,4,162,5,22,5,102,5,188,6,18,6,116,6,214,7,56,7,126,7,236,8,78,8,108, + 8,150,8,208,9,16,9,74,9,136,10,22,10,128,11,4,11,86,11,200,12,46,12,130,12,234,13,94,13,164,13,234,14,80,14,150,15,40,15,176,16,18,16,116,16,224,17,82,17,182,18,4,18,110,18,196,19, + 76,19,172,19,246,20,88,20,174,20,234,21,64,21,128,21,166,21,184,22,18,22,126,22,198,23,52,23,142,23,224,24,86,24,186,24,238,25,54,25,150,25,212,26,72,26,156,26,240,27,92,27,200,28, + 4,28,76,28,150,28,234,29,42,29,146,29,210,30,64,30,142,30,224,31,36,31,118,31,166,31,166,32,16,130,1,52,46,32,138,32,178,32,200,33,20,33,116,33,152,33,238,34,98,34,134,35,12,130,1, + 33,128,35,131,1,60,152,35,176,35,216,36,0,36,74,36,104,36,144,36,174,37,6,37,96,37,130,37,248,37,248,38,88,38,170,130,1,8,190,216,39,64,39,154,40,10,40,104,40,168,41,14,41,32,41,184, + 41,248,42,54,42,96,42,96,43,2,43,42,43,94,43,172,43,230,44,32,44,52,44,154,45,40,45,92,45,120,45,170,45,232,46,38,46,166,47,38,47,182,47,244,48,94,48,200,49,62,49,180,50,30,50,158, + 51,30,51,130,51,238,52,92,52,206,53,58,53,134,53,212,54,38,54,114,54,230,55,118,55,216,56,58,56,166,57,18,57,116,57,174,58,46,58,154,59,6,59,124,59,232,60,58,60,150,61,34,61,134,61, + 236,62,86,62,198,63,42,63,154,64,18,64,106,64,208,65,54,65,162,66,8,66,64,66,122,66,184,66,240,67,98,67,204,68,42,68,138,68,238,69,88,69,182,69,226,70,84,70,180,71,20,71,122,71,218, + 72,84,72,198,73,64,0,36,70,21,8,8,77,3,0,7,0,11,0,15,0,19,0,23,0,27,0,31,0,35,0,39,0,43,0,47,0,51,0,55,0,59,0,63,0,67,0,71,0,75,0,79,0,83,0,87,0,91,0,95,0,99,0,103,0,107,0,111,0,115, + 0,119,0,123,0,127,0,131,0,135,0,139,0,143,0,0,17,53,51,21,49,150,3,32,5,130,23,32,33,130,3,211,7,151,115,32,128,133,0,37,252,128,128,2,128,128,190,5,133,74,32,4,133,6,206,5,42,0,7, + 1,128,0,0,2,0,4,0,0,65,139,13,37,0,1,53,51,21,7,146,3,32,3,130,19,32,1,141,133,32,3,141,14,131,13,38,255,0,128,128,0,6,1,130,84,35,2,128,4,128,140,91,132,89,32,51,65,143,6,139,7,33, + 1,0,130,57,32,254,130,3,32,128,132,4,32,4,131,14,138,89,35,0,0,24,0,130,0,33,3,128,144,171,66,55,33,148,115,65,187,19,32,5,130,151,143,155,163,39,32,1,136,182,32,253,134,178,132,7, + 132,200,145,17,32,3,65,48,17,165,17,39,0,0,21,0,128,255,128,3,65,175,17,65,3,27,132,253,131,217,139,201,155,233,155,27,131,67,131,31,130,241,33,255,0,131,181,137,232,132,15,132,4,138, + 247,34,255,0,128,179,238,32,0,130,0,32,20,65,239,48,33,0,19,67,235,10,32,51,65,203,14,65,215,11,32,7,154,27,135,39,32,33,130,35,33,128,128,130,231,32,253,132,231,32,128,132,232,34, + 128,128,254,133,13,136,8,32,253,65,186,5,130,36,130,42,176,234,133,231,34,128,0,0,66,215,44,33,0,1,68,235,6,68,211,19,32,49,68,239,14,139,207,139,47,66,13,7,32,51,130,47,33,1,0,130, + 207,35,128,128,1,0,131,222,131,5,130,212,130,6,131,212,32,0,130,10,133,220,130,233,130,226,32,254,133,255,178,233,39,3,1,128,3,0,2,0,4,68,15,7,68,99,12,130,89,130,104,33,128,4,133, + 93,130,10,38,0,0,11,1,0,255,0,68,63,16,70,39,9,66,215,8,32,7,68,77,6,68,175,14,32,29,68,195,6,132,7,35,2,0,128,255,131,91,132,4,65,178,5,141,111,67,129,23,165,135,140,107,142,135,33, + 21,5,69,71,6,131,7,33,1,0,140,104,132,142,130,4,137,247,140,30,68,255,12,39,11,0,128,0,128,3,0,3,69,171,15,67,251,7,65,15,8,66,249,11,65,229,7,67,211,7,66,13,7,35,1,128,128,254,133, + 93,32,254,131,145,132,4,132,18,32,2,151,128,130,23,34,0,0,9,154,131,65,207,8,68,107,15,68,51,7,32,7,70,59,7,135,121,130,82,32,128,151,111,41,0,0,4,0,128,255,0,1,128,1,137,239,33,0, + 37,70,145,10,65,77,10,65,212,14,37,0,0,0,5,0,128,66,109,5,70,123,10,33,0,19,72,33,18,133,237,70,209,11,33,0,2,130,113,137,119,136,115,33,1,0,133,43,130,5,34,0,0,10,69,135,6,70,219, + 13,66,155,7,65,9,12,66,157,11,66,9,11,32,7,130,141,132,252,66,151,9,137,9,66,15,30,36,0,20,0,128,0,130,218,71,11,42,68,51,8,65,141,7,73,19,15,69,47,23,143,39,66,81,7,32,1,66,55,6,34, + 1,128,128,68,25,5,69,32,6,137,6,136,25,32,254,131,42,32,3,66,88,26,148,26,32,0,130,0,32,14,164,231,70,225,12,66,233,7,67,133,19,71,203,15,130,161,32,255,130,155,32,254,139,127,134, + 12,164,174,33,0,15,164,159,33,59,0,65,125,20,66,25,7,32,5,68,191,6,66,29,7,144,165,65,105,9,35,128,128,255,0,137,2,133,182,164,169,33,128,128,197,171,130,155,68,235,7,32,21,70,77,19, + 66,21,10,68,97,8,66,30,5,66,4,43,34,0,17,0,71,19,41,65,253,20,71,25,23,65,91,15,65,115,7,34,2,128,128,66,9,8,130,169,33,1,0,66,212,13,132,28,72,201,43,35,0,0,0,18,66,27,38,76,231,5, + 68,157,20,135,157,32,7,68,185,13,65,129,28,66,20,5,32,253,66,210,11,65,128,49,133,61,32,0,65,135,6,74,111,37,72,149,12,66,203,19,65,147,19,68,93,7,68,85,8,76,4,5,33,255,0,133,129,34, + 254,0,128,68,69,8,181,197,34,0,0,12,65,135,32,65,123,20,69,183,27,133,156,66,50,5,72,87,10,67,137,32,33,0,19,160,139,78,251,13,68,55,20,67,119,19,65,91,36,69,177,15,32,254,143,16,65, + 98,53,32,128,130,0,32,0,66,43,54,70,141,23,66,23,15,131,39,69,47,11,131,15,70,129,19,74,161,9,36,128,255,0,128,254,130,153,65,148,32,67,41,9,34,0,0,4,79,15,5,73,99,10,71,203,8,32,3, + 72,123,6,72,43,8,32,2,133,56,131,99,130,9,34,0,0,6,72,175,5,73,159,14,144,63,135,197,132,189,133,66,33,255,0,73,6,7,70,137,12,35,0,0,0,10,130,3,73,243,25,67,113,12,65,73,7,69,161,7, + 138,7,37,21,2,0,128,128,254,134,3,73,116,27,33,128,128,130,111,39,12,0,128,1,0,3,128,2,72,219,21,35,43,0,47,0,67,47,20,130,111,33,21,1,68,167,13,81,147,8,133,230,32,128,77,73,6,32, + 128,131,142,134,18,130,6,32,255,75,18,12,131,243,37,128,0,128,3,128,3,74,231,21,135,123,32,29,134,107,135,7,32,21,74,117,7,135,7,134,96,135,246,74,103,23,132,242,33,0,10,67,151,28, + 67,133,20,66,141,11,131,11,32,3,77,71,6,32,128,130,113,32,1,81,4,6,134,218,66,130,24,131,31,34,0,26,0,130,0,77,255,44,83,15,11,148,155,68,13,7,32,49,78,231,18,79,7,11,73,243,11,32, + 33,65,187,10,130,63,65,87,8,73,239,19,35,0,128,1,0,131,226,32,252,65,100,6,32,128,139,8,33,1,0,130,21,32,253,72,155,44,73,255,20,32,128,71,67,8,81,243,39,67,15,20,74,191,23,68,121, + 27,32,1,66,150,6,32,254,79,19,11,131,214,32,128,130,215,37,2,0,128,253,0,128,136,5,65,220,24,147,212,130,210,33,0,24,72,219,42,84,255,13,67,119,16,69,245,19,72,225,19,65,3,15,69,93, + 19,131,55,132,178,71,115,14,81,228,6,142,245,33,253,0,132,43,172,252,65,16,11,75,219,8,65,219,31,66,223,24,75,223,10,33,29,1,80,243,10,66,175,8,131,110,134,203,133,172,130,16,70,30, + 7,164,183,130,163,32,20,65,171,48,65,163,36,65,143,23,65,151,19,65,147,13,65,134,17,133,17,130,216,67,114,5,164,217,65,137,12,72,147,48,79,71,19,74,169,22,80,251,8,65,173,7,66,157, + 15,74,173,15,32,254,65,170,8,71,186,45,72,131,6,77,143,40,187,195,152,179,65,123,38,68,215,57,68,179,15,65,85,7,69,187,14,32,21,66,95,15,67,19,25,32,1,83,223,6,32,2,76,240,7,77,166, + 43,65,8,5,130,206,32,0,67,39,54,143,167,66,255,19,82,193,11,151,47,85,171,5,67,27,17,132,160,69,172,11,69,184,56,66,95,6,33,12,1,130,237,32,2,68,179,27,68,175,16,80,135,15,72,55,7, + 71,87,12,73,3,12,132,12,66,75,32,76,215,5,169,139,147,135,148,139,81,12,12,81,185,36,75,251,7,65,23,27,76,215,9,87,165,12,65,209,15,72,157,7,65,245,31,32,128,71,128,6,32,1,82,125,5, + 34,0,128,254,131,169,32,254,131,187,71,180,9,132,27,32,2,88,129,44,32,0,78,47,40,65,79,23,79,171,14,32,21,71,87,8,72,15,14,65,224,33,130,139,74,27,62,93,23,7,68,31,7,75,27,7,139,15, + 74,3,7,74,23,27,65,165,11,65,177,15,67,123,5,32,1,130,221,32,252,71,96,5,74,12,12,133,244,130,25,34,1,0,128,130,2,139,8,93,26,8,65,9,32,65,57,14,140,14,32,0,73,79,67,68,119,11,135, + 11,32,51,90,75,14,139,247,65,43,7,131,19,139,11,69,159,11,65,247,6,36,1,128,128,253,0,90,71,9,33,1,0,132,14,32,128,89,93,14,69,133,6,130,44,131,30,131,6,65,20,56,33,0,16,72,179,40, + 75,47,12,65,215,19,74,95,19,65,43,11,131,168,67,110,5,75,23,17,69,106,6,75,65,5,71,204,43,32,0,80,75,47,71,203,15,159,181,68,91,11,67,197,7,73,101,13,68,85,6,33,128,128,130,214,130, + 25,32,254,74,236,48,130,194,37,0,18,0,128,255,128,77,215,40,65,139,64,32,51,80,159,10,65,147,39,130,219,84,212,43,130,46,75,19,97,74,33,11,65,201,23,65,173,31,33,1,0,79,133,6,66,150, + 5,67,75,48,85,187,6,70,207,37,32,71,87,221,13,73,163,14,80,167,15,132,15,83,193,19,82,209,8,78,99,9,72,190,11,77,110,49,89,63,5,80,91,35,99,63,32,70,235,23,81,99,10,69,148,10,65,110, + 36,32,0,65,99,47,95,219,11,68,171,51,66,87,7,72,57,7,74,45,17,143,17,65,114,50,33,14,0,65,111,40,159,195,98,135,15,35,7,53,51,21,100,78,9,95,146,16,32,254,82,114,6,32,128,67,208,37, + 130,166,99,79,58,32,17,96,99,14,72,31,19,72,87,31,82,155,7,67,47,14,32,21,131,75,134,231,72,51,17,72,78,8,133,8,80,133,6,33,253,128,88,37,9,66,124,36,72,65,12,134,12,71,55,43,66,139, + 27,85,135,10,91,33,12,65,35,11,66,131,11,71,32,8,90,127,6,130,244,71,76,11,168,207,33,0,12,66,123,32,32,0,65,183,15,68,135,11,66,111,7,67,235,11,66,111,15,32,254,97,66,12,160,154,67, + 227,52,80,33,15,87,249,15,93,45,31,75,111,12,93,45,11,77,99,9,160,184,81,31,12,32,15,98,135,30,104,175,7,77,249,36,69,73,15,78,5,12,32,254,66,151,19,34,128,128,4,87,32,12,149,35,133, + 21,96,151,31,32,19,72,35,5,98,173,15,143,15,32,21,143,99,158,129,33,0,0,65,35,52,65,11,15,147,15,98,75,11,33,1,0,143,151,132,15,32,254,99,200,37,132,43,130,4,39,0,10,0,128,1,128,3, + 0,104,151,14,97,187,20,69,131,15,67,195,11,87,227,7,33,128,128,132,128,33,254,0,68,131,9,65,46,26,42,0,0,0,7,0,0,255,128,3,128,0,88,223,15,33,0,21,89,61,22,66,209,12,65,2,12,37,0,2, + 1,0,3,128,101,83,8,36,0,1,53,51,29,130,3,34,21,1,0,66,53,8,32,0,68,215,6,100,55,25,107,111,9,66,193,11,72,167,8,73,143,31,139,31,33,1,0,131,158,32,254,132,5,33,253,128,65,16,9,133, + 17,89,130,25,141,212,33,0,0,93,39,8,90,131,25,93,39,14,66,217,6,106,179,8,159,181,71,125,15,139,47,138,141,87,11,14,76,23,14,65,231,26,140,209,66,122,8,81,179,5,101,195,26,32,47,74, + 75,13,69,159,11,83,235,11,67,21,16,136,167,131,106,130,165,130,15,32,128,101,90,24,134,142,32,0,65,103,51,108,23,11,101,231,15,75,173,23,74,237,23,66,15,6,66,46,17,66,58,17,65,105, + 49,66,247,55,71,179,12,70,139,15,86,229,7,84,167,15,32,1,95,72,12,89,49,6,33,128,128,65,136,38,66,30,9,32,0,100,239,7,66,247,29,70,105,20,65,141,19,69,81,15,130,144,32,128,83,41,5, + 32,255,131,177,68,185,5,133,126,65,97,37,32,0,130,0,33,21,0,130,55,66,195,28,67,155,13,34,79,0,83,66,213,13,73,241,19,66,59,19,65,125,11,135,201,66,249,16,32,128,66,44,11,66,56,17, + 68,143,8,68,124,38,67,183,12,96,211,9,65,143,29,112,171,5,32,0,68,131,63,34,33,53,51,71,121,11,32,254,98,251,16,32,253,74,231,10,65,175,37,133,206,37,0,0,8,1,0,0,107,123,11,113,115, + 9,33,0,1,130,117,131,3,73,103,7,66,51,18,66,44,5,133,75,70,88,5,32,254,65,39,12,68,80,9,34,12,0,128,107,179,28,68,223,6,155,111,86,147,15,32,2,131,82,141,110,33,254,0,130,15,32,4,103, + 184,15,141,35,87,176,5,83,11,5,71,235,23,114,107,11,65,189,16,70,33,15,86,153,31,135,126,86,145,30,65,183,41,32,0,130,0,32,10,65,183,24,34,35,0,39,67,85,9,65,179,15,143,15,33,1,0,65, + 28,17,157,136,130,123,32,20,130,3,32,0,97,135,24,115,167,19,80,71,12,32,51,110,163,14,78,35,19,131,19,155,23,77,229,8,78,9,17,151,17,67,231,46,94,135,8,73,31,31,93,215,56,82,171,25, + 72,77,8,162,179,169,167,99,131,11,69,85,19,66,215,15,76,129,13,68,115,22,72,79,35,67,113,5,34,0,0,19,70,31,46,65,89,52,73,223,15,85,199,33,95,33,8,132,203,73,29,32,67,48,16,177,215, + 101,13,15,65,141,43,69,141,15,75,89,5,70,0,11,70,235,21,178,215,36,10,0,128,0,0,71,207,24,33,0,19,100,67,6,80,215,11,66,67,7,80,43,12,71,106,7,80,192,5,65,63,5,66,217,26,33,0,13,156, + 119,68,95,5,72,233,12,134,129,85,81,11,76,165,20,65,43,8,73,136,8,75,10,31,38,128,128,0,0,0,13,1,130,4,32,3,106,235,29,114,179,12,66,131,23,32,7,77,133,6,67,89,12,131,139,116,60,9, + 89,15,37,32,0,74,15,7,103,11,22,65,35,5,33,55,0,93,81,28,67,239,23,78,85,5,107,93,14,66,84,17,65,193,26,74,183,10,66,67,34,143,135,79,91,15,32,7,117,111,8,75,56,9,84,212,9,154,134, + 32,0,130,0,32,18,130,3,70,171,41,83,7,16,70,131,19,84,191,15,84,175,19,84,167,30,84,158,12,154,193,68,107,15,33,0,0,65,79,42,65,71,7,73,55,7,118,191,16,83,180,9,32,255,76,166,9,154, + 141,32,0,130,0,69,195,52,65,225,15,151,15,75,215,31,80,56,10,68,240,17,100,32,9,70,147,39,65,93,12,71,71,41,92,85,15,84,135,23,78,35,15,110,27,10,84,125,8,107,115,29,136,160,38,0,0, + 14,0,128,255,0,82,155,24,67,239,8,119,255,11,69,131,11,77,29,6,112,31,8,134,27,105,203,8,32,2,75,51,11,75,195,12,74,13,29,136,161,37,128,0,0,0,11,1,130,163,82,115,8,125,191,17,69,35, + 12,74,137,15,143,15,32,1,65,157,12,136,12,161,142,65,43,40,65,199,6,65,19,24,102,185,11,76,123,11,99,6,12,135,12,32,254,130,8,161,155,101,23,9,39,8,0,0,1,128,3,128,2,78,63,17,72,245, + 12,67,41,11,90,167,9,32,128,97,49,9,32,128,109,51,14,132,97,81,191,8,130,97,125,99,12,121,35,9,127,75,15,71,79,12,81,151,23,87,97,7,70,223,15,80,245,16,105,97,15,32,254,113,17,6,32, + 128,130,8,105,105,8,76,122,18,65,243,21,74,63,7,38,4,1,0,255,0,2,0,119,247,28,133,65,32,255,141,91,35,0,0,0,16,67,63,36,34,59,0,63,77,59,9,119,147,11,143,241,66,173,15,66,31,11,67, + 75,8,81,74,16,32,128,131,255,87,181,42,127,43,5,34,255,128,2,120,235,11,37,19,0,23,0,0,37,109,191,14,118,219,7,127,43,14,65,79,14,35,0,0,0,3,73,91,5,130,5,38,3,0,7,0,11,0,0,70,205, + 11,88,221,12,32,0,73,135,7,87,15,22,73,135,10,79,153,15,97,71,19,65,49,11,32,1,131,104,121,235,11,80,65,11,142,179,144,14,81,123,46,32,1,88,217,5,112,5,8,65,201,15,83,29,15,122,147, + 11,135,179,142,175,143,185,67,247,39,66,199,7,35,5,0,128,3,69,203,15,123,163,12,67,127,7,130,119,71,153,10,141,102,70,175,8,32,128,121,235,30,136,89,100,191,11,116,195,11,111,235,15, + 72,39,7,32,2,97,43,5,132,5,94,67,8,131,8,125,253,10,32,3,65,158,16,146,16,130,170,40,0,21,0,128,0,0,3,128,5,88,219,15,24,64,159,32,135,141,65,167,15,68,163,10,97,73,49,32,255,82,58, + 7,93,80,8,97,81,16,24,67,87,52,34,0,0,5,130,231,33,128,2,80,51,13,65,129,8,113,61,6,132,175,65,219,5,130,136,77,152,17,32,0,95,131,61,70,215,6,33,21,51,90,53,10,78,97,23,105,77,31, + 65,117,7,139,75,24,68,195,9,24,64,22,9,33,0,128,130,11,33,128,128,66,25,5,121,38,5,134,5,134,45,66,40,36,66,59,18,34,128,0,0,66,59,81,135,245,123,103,19,120,159,19,77,175,12,33,255, + 0,87,29,10,94,70,21,66,59,54,39,3,1,128,3,0,2,128,4,24,65,7,15,66,47,7,72,98,12,37,0,0,0,3,1,0,24,65,55,21,131,195,32,1,67,178,6,33,4,0,77,141,8,32,6,131,47,74,67,16,24,69,3,20,24, + 65,251,7,133,234,130,229,94,108,17,35,0,0,6,0,141,175,86,59,5,162,79,85,166,8,70,112,13,32,13,24,64,67,26,24,71,255,7,123,211,12,80,121,11,69,215,15,66,217,11,69,71,10,131,113,132, + 126,119,90,9,66,117,19,132,19,32,0,130,0,24,64,47,59,33,7,0,73,227,5,68,243,15,85,13,12,76,37,22,74,254,15,130,138,33,0,4,65,111,6,137,79,65,107,16,32,1,77,200,6,34,128,128,3,75,154, + 12,37,0,16,0,0,2,0,104,115,36,140,157,68,67,19,68,51,15,106,243,15,134,120,70,37,10,68,27,10,140,152,65,121,24,32,128,94,155,7,67,11,8,24,74,11,25,65,3,12,83,89,18,82,21,37,67,200, + 5,130,144,24,64,172,12,33,4,0,134,162,74,80,14,145,184,32,0,130,0,69,251,20,32,19,81,243,5,82,143,8,33,5,53,89,203,5,133,112,79,109,15,33,0,21,130,71,80,175,41,36,75,0,79,0,83,121, + 117,9,87,89,27,66,103,11,70,13,15,75,191,11,135,67,87,97,20,109,203,5,69,246,8,108,171,5,78,195,38,65,51,13,107,203,11,77,3,17,24,75,239,17,65,229,28,79,129,39,130,175,32,128,123,253, + 7,132,142,24,65,51,15,65,239,41,36,128,128,0,0,13,65,171,5,66,163,28,136,183,118,137,11,80,255,15,67,65,7,74,111,8,32,0,130,157,32,253,24,76,35,10,103,212,5,81,175,9,69,141,7,66,150, + 29,131,158,24,75,199,28,124,185,7,76,205,15,68,124,14,32,3,123,139,16,130,16,33,128,128,108,199,6,33,0,3,65,191,35,107,11,6,73,197,11,24,70,121,15,83,247,15,24,70,173,23,69,205,14, + 32,253,131,140,32,254,136,4,94,198,9,32,3,78,4,13,66,127,13,143,13,32,0,130,0,33,16,0,24,69,59,39,109,147,12,76,253,19,24,69,207,15,69,229,15,130,195,71,90,10,139,10,130,152,73,43, + 40,91,139,10,65,131,37,35,75,0,79,0,84,227,12,143,151,68,25,15,80,9,23,95,169,11,34,128,2,128,112,186,5,130,6,83,161,19,76,50,6,130,37,65,145,44,110,83,5,32,16,67,99,6,71,67,15,76, + 55,17,140,215,67,97,23,76,69,15,77,237,11,104,211,23,77,238,11,65,154,43,33,0,10,83,15,28,83,13,20,67,145,19,67,141,14,97,149,21,68,9,15,86,251,5,66,207,5,66,27,37,82,1,23,127,71,12, + 94,235,10,110,175,24,98,243,15,132,154,132,4,24,66,69,10,32,4,67,156,43,130,198,35,2,1,0,4,75,27,9,69,85,9,95,240,7,32,128,130,35,32,28,66,43,40,24,82,63,23,83,123,12,72,231,15,127, + 59,23,116,23,19,117,71,7,24,77,99,15,67,111,15,71,101,8,36,2,128,128,252,128,127,60,11,32,1,132,16,130,18,141,24,67,107,9,32,3,68,194,15,175,15,38,0,11,0,128,1,128,2,80,63,25,32,0, + 24,65,73,11,69,185,15,83,243,16,32,0,24,81,165,8,130,86,77,35,6,155,163,88,203,5,24,66,195,30,70,19,19,24,80,133,15,32,1,75,211,8,32,254,108,133,8,79,87,20,65,32,9,41,0,0,7,0,128,0, + 0,2,128,2,68,87,15,66,1,16,92,201,16,24,76,24,17,133,17,34,128,0,30,66,127,64,34,115,0,119,73,205,9,66,43,11,109,143,15,24,79,203,11,90,143,15,131,15,155,31,65,185,15,86,87,11,35,128, + 128,253,0,69,7,6,130,213,33,1,0,119,178,15,142,17,66,141,74,83,28,6,36,7,0,0,4,128,82,39,18,76,149,12,67,69,21,32,128,79,118,15,32,0,130,0,32,8,131,206,32,2,79,83,9,100,223,14,102, + 113,23,115,115,7,24,65,231,12,130,162,32,4,68,182,19,130,102,93,143,8,69,107,29,24,77,255,12,143,197,72,51,7,76,195,15,132,139,85,49,15,130,152,131,18,71,81,23,70,14,11,36,0,10,0,128, + 2,69,59,9,89,151,15,66,241,11,76,165,12,71,43,15,75,49,13,65,12,23,132,37,32,0,179,115,130,231,95,181,16,132,77,32,254,67,224,8,65,126,20,79,171,8,32,2,89,81,5,75,143,6,80,41,8,34, + 2,0,128,24,81,72,9,32,0,130,0,35,17,0,0,255,77,99,39,95,65,36,67,109,15,24,69,93,11,77,239,5,95,77,23,35,128,1,0,128,24,86,7,8,132,167,32,2,69,198,41,130,202,33,0,26,120,75,44,24,89, + 51,15,71,243,12,70,239,11,24,84,3,11,66,7,11,71,255,10,32,21,69,155,35,88,151,12,32,128,74,38,10,65,210,8,74,251,5,65,226,5,75,201,13,32,3,65,9,41,146,41,40,0,0,0,9,1,0,1,0,2,91,99, + 19,32,35,106,119,13,70,219,15,83,239,12,137,154,32,2,67,252,19,36,128,0,0,4,1,130,196,32,2,130,8,91,107,8,32,0,135,81,24,73,211,8,132,161,73,164,13,36,0,8,0,128,2,105,123,26,139,67, + 76,99,15,34,1,0,128,135,76,83,156,20,92,104,8,67,251,30,24,86,47,27,123,207,12,24,86,7,15,71,227,8,32,4,65,20,20,131,127,32,0,130,123,32,0,71,223,26,32,19,90,195,22,71,223,15,84,200, + 6,32,128,133,241,24,84,149,9,67,41,25,36,0,0,0,22,0,88,111,49,32,87,66,21,5,77,3,27,123,75,7,71,143,19,135,183,71,183,19,130,171,74,252,5,131,5,89,87,17,32,1,132,18,130,232,68,11,10, + 33,1,128,70,208,16,66,230,18,147,18,130,254,223,255,75,27,23,65,59,15,135,39,155,255,34,128,128,254,104,92,8,33,0,128,65,32,11,65,1,58,33,26,0,130,0,72,71,18,78,55,17,76,11,19,86,101, + 12,75,223,11,89,15,11,24,76,87,15,75,235,15,131,15,72,95,7,85,71,11,72,115,11,73,64,6,34,1,128,128,66,215,9,34,128,254,128,134,14,33,128,255,67,102,5,32,0,130,16,70,38,11,66,26,57, + 88,11,8,24,76,215,34,78,139,7,95,245,7,32,7,24,73,75,23,32,128,131,167,130,170,101,158,9,82,49,22,118,139,6,32,18,67,155,44,116,187,9,108,55,14,80,155,23,66,131,15,93,77,10,131,168, + 32,128,73,211,12,24,75,187,22,32,4,96,71,20,67,108,19,132,19,120,207,8,32,5,76,79,15,66,111,21,66,95,8,32,3,190,211,111,3,8,211,212,32,20,65,167,44,34,75,0,79,97,59,13,32,33,112,63, + 10,65,147,19,69,39,19,143,39,24,66,71,9,130,224,65,185,43,94,176,12,65,183,24,71,38,8,24,72,167,7,65,191,38,136,235,24,96,167,12,65,203,62,115,131,13,65,208,42,175,235,67,127,6,32, + 4,76,171,29,114,187,5,32,71,65,211,5,65,203,68,72,51,8,164,219,32,0,172,214,71,239,58,78,3,27,66,143,15,77,19,15,147,31,35,33,53,51,21,66,183,10,173,245,66,170,30,150,30,34,0,0,23, + 80,123,54,76,1,16,73,125,15,82,245,11,167,253,24,76,85,12,70,184,5,32,254,131,185,37,254,0,128,1,0,128,133,16,117,158,18,92,27,38,65,3,17,130,251,35,17,0,128,254,24,69,83,39,140,243, + 121,73,19,109,167,7,81,41,15,24,95,175,12,102,227,15,121,96,11,24,95,189,7,32,3,145,171,154,17,24,77,47,9,33,0,5,70,71,37,68,135,7,32,29,117,171,11,69,87,15,24,79,97,19,24,79,149,23, + 131,59,32,1,75,235,5,72,115,11,72,143,7,132,188,71,27,46,131,51,32,0,69,95,6,175,215,32,21,131,167,81,15,19,151,191,151,23,131,215,71,43,5,32,254,24,79,164,24,74,109,8,77,166,13,65, + 176,26,88,162,5,98,159,6,171,219,120,247,6,79,29,8,99,169,10,103,59,19,65,209,35,131,35,91,25,19,112,94,15,83,36,8,173,229,33,20,0,88,75,43,71,31,12,65,191,71,33,1,0,130,203,32,254, + 131,4,68,66,7,67,130,6,104,61,13,173,215,38,13,1,0,0,0,2,128,67,111,28,74,129,16,104,35,19,79,161,16,87,14,7,138,143,132,10,67,62,36,114,115,5,162,151,67,33,16,108,181,15,143,151,67, + 5,5,24,100,242,15,170,153,34,0,0,14,65,51,34,32,55,79,75,9,32,51,74,7,10,65,57,38,132,142,32,254,72,0,14,139,163,32,128,80,254,8,67,158,21,65,63,7,32,4,72,227,27,95,155,12,67,119,19, + 124,91,24,149,154,72,177,34,97,223,8,155,151,24,108,227,15,88,147,16,72,117,19,68,35,11,92,253,15,70,199,15,24,87,209,17,32,2,87,233,7,32,1,24,88,195,10,119,24,8,32,3,81,227,24,65, + 125,21,35,128,128,0,25,76,59,48,24,90,187,9,97,235,12,66,61,11,91,105,19,24,79,141,11,24,79,117,15,24,79,129,27,90,53,13,130,13,32,253,131,228,24,79,133,40,69,70,8,66,137,31,65,33, + 19,96,107,8,68,119,29,66,7,5,68,125,16,65,253,19,65,241,27,24,90,179,13,24,79,143,18,33,128,128,130,246,32,254,130,168,68,154,36,77,51,9,97,47,5,167,195,32,21,131,183,78,239,27,155, + 195,78,231,14,201,196,77,11,6,32,5,73,111,37,97,247,12,77,19,31,155,207,78,215,19,162,212,69,17,14,66,91,19,80,143,57,78,203,39,159,215,32,128,93,134,8,24,80,109,24,66,113,15,169,215, + 66,115,6,32,4,69,63,33,32,0,101,113,7,86,227,35,143,211,36,49,53,51,21,1,77,185,14,65,159,28,69,251,34,67,56,8,33,9,0,24,107,175,25,90,111,12,110,251,11,119,189,24,119,187,34,87,15, + 9,32,4,66,231,37,90,39,7,66,239,8,84,219,15,69,105,23,24,85,27,27,87,31,11,33,1,128,76,94,6,32,1,85,241,7,33,128,128,106,48,10,33,128,128,69,136,11,133,13,24,79,116,49,84,236,8,24, + 91,87,9,32,5,165,255,69,115,12,66,27,15,159,15,24,72,247,12,74,178,5,24,80,64,15,33,0,128,143,17,77,89,51,130,214,24,81,43,7,170,215,74,49,8,159,199,143,31,139,215,69,143,5,32,254, + 24,81,50,35,181,217,84,123,70,143,195,159,15,65,187,16,66,123,7,65,175,15,65,193,29,68,207,39,79,27,5,70,131,6,32,4,68,211,33,33,67,0,83,143,14,159,207,143,31,140,223,33,0,128,24,80, + 82,14,24,93,16,23,32,253,65,195,5,68,227,40,133,214,107,31,7,32,5,67,115,27,87,9,8,107,31,43,66,125,6,32,0,103,177,23,131,127,72,203,36,32,0,110,103,8,155,163,73,135,6,32,19,24,112, + 99,10,65,71,11,73,143,19,143,31,126,195,5,24,85,21,9,24,76,47,14,32,254,24,93,77,36,68,207,11,39,25,0,0,255,128,3,128,4,66,51,37,95,247,13,82,255,24,76,39,19,147,221,66,85,27,24,118, + 7,8,24,74,249,12,76,74,8,91,234,8,67,80,17,131,222,33,253,0,121,30,44,73,0,16,69,15,6,32,0,65,23,38,69,231,12,65,179,6,98,131,16,86,31,27,24,108,157,14,80,160,8,24,65,46,17,33,4,0, + 96,2,18,144,191,65,226,8,68,19,5,171,199,80,9,15,180,199,67,89,5,32,255,24,79,173,28,174,201,24,79,179,50,32,1,24,122,5,10,82,61,10,180,209,83,19,8,32,128,24,80,129,27,111,248,43,131, + 71,24,115,103,8,67,127,41,78,213,24,100,247,19,66,115,39,75,107,5,32,254,165,219,78,170,40,24,112,163,49,32,1,97,203,6,65,173,64,32,0,83,54,7,133,217,88,37,12,32,254,131,28,33,128, + 3,67,71,44,84,183,6,32,5,69,223,33,96,7,7,123,137,16,192,211,24,112,14,9,32,255,67,88,29,68,14,10,84,197,38,33,0,22,116,47,50,32,87,106,99,9,116,49,15,89,225,15,97,231,23,70,41,19, + 82,85,8,93,167,6,32,253,132,236,108,190,7,89,251,5,116,49,58,33,128,128,131,234,32,15,24,74,67,38,70,227,24,24,83,45,23,89,219,12,70,187,12,89,216,19,32,2,69,185,24,141,24,70,143,66, + 24,82,119,56,78,24,10,32,253,133,149,132,6,24,106,233,7,69,198,48,178,203,81,243,12,68,211,15,106,255,23,66,91,15,69,193,7,100,39,10,24,83,72,16,176,204,33,19,0,88,207,45,68,21,12, + 68,17,10,65,157,53,68,17,6,32,254,92,67,10,65,161,25,69,182,43,24,118,91,47,69,183,18,181,209,111,253,12,89,159,8,66,112,12,69,184,45,35,0,0,0,9,24,80,227,26,73,185,16,118,195,15,131, + 15,33,1,0,65,59,15,66,39,27,160,111,66,205,12,148,111,143,110,33,128,128,156,112,24,81,199,8,75,199,23,66,117,20,155,121,32,254,68,126,12,72,213,29,134,239,149,123,89,27,16,148,117, + 65,245,8,24,71,159,14,141,134,134,28,73,51,55,109,77,15,105,131,11,68,67,11,76,169,27,107,209,12,102,174,8,32,128,72,100,18,116,163,56,79,203,11,75,183,44,85,119,19,71,119,23,151,227, + 32,1,93,27,8,65,122,5,77,102,8,110,120,20,66,23,8,66,175,17,66,63,12,133,12,79,35,8,74,235,33,67,149,16,69,243,15,78,57,15,69,235,16,67,177,7,151,192,130,23,67,84,29,141,192,174,187, + 77,67,15,69,11,12,159,187,77,59,10,199,189,24,70,235,50,96,83,19,66,53,23,105,65,19,77,47,12,163,199,66,67,37,78,207,50,67,23,23,174,205,67,228,6,71,107,13,67,22,14,66,85,11,83,187, + 38,124,47,49,95,7,19,66,83,23,67,23,19,24,96,78,17,80,101,16,71,98,40,33,0,7,88,131,22,24,89,245,12,84,45,12,102,213,5,123,12,9,32,2,126,21,14,43,255,0,128,128,0,0,20,0,128,255,128, + 3,126,19,39,32,75,106,51,7,113,129,15,24,110,135,19,126,47,15,115,117,11,69,47,11,32,2,109,76,9,102,109,9,32,128,75,2,10,130,21,32,254,69,47,6,32,3,94,217,47,32,0,65,247,10,69,15,46, + 65,235,31,65,243,15,101,139,10,66,174,14,65,247,16,72,102,28,69,17,14,84,243,9,165,191,88,47,48,66,53,12,32,128,71,108,6,203,193,32,17,75,187,42,73,65,16,65,133,52,114,123,9,167,199, + 69,21,37,86,127,44,75,171,11,180,197,78,213,12,148,200,81,97,46,24,95,243,9,32,4,66,75,33,113,103,9,87,243,36,143,225,24,84,27,31,90,145,8,148,216,67,49,5,24,84,34,14,75,155,27,67, + 52,13,140,13,36,0,20,0,128,255,24,135,99,46,88,59,43,155,249,80,165,7,136,144,71,161,23,32,253,132,33,32,254,88,87,44,136,84,35,128,0,0,21,81,103,5,94,47,44,76,51,12,143,197,151,15, + 65,215,31,24,64,77,13,65,220,20,65,214,14,71,4,40,65,213,13,32,0,130,0,35,21,1,2,0,135,0,34,36,0,72,134,10,36,1,0,26,0,130,134,11,36,2,0,14,0,108,134,11,32,3,138,23,32,4,138,11,34, + 5,0,20,134,33,34,0,0,6,132,23,32,1,134,15,32,18,130,25,133,11,37,1,0,13,0,49,0,133,11,36,2,0,7,0,38,134,11,36,3,0,17,0,45,134,11,32,4,138,35,36,5,0,10,0,62,134,23,32,6,132,23,36,3, + 0,1,4,9,130,87,131,167,133,11,133,167,133,11,133,167,133,11,37,3,0,34,0,122,0,133,11,133,167,133,11,133,167,133,11,133,167,34,50,0,48,130,1,34,52,0,47,134,5,8,49,49,0,53,98,121,32, + 84,114,105,115,116,97,110,32,71,114,105,109,109,101,114,82,101,103,117,108,97,114,84,84,88,32,80,114,111,103,103,121,67,108,101,97,110,84,84,50,48,48,52,47,130,2,53,49,53,0,98,0,121, + 0,32,0,84,0,114,0,105,0,115,0,116,0,97,0,110,130,15,32,71,132,15,36,109,0,109,0,101,130,9,32,82,130,5,36,103,0,117,0,108,130,29,32,114,130,43,34,84,0,88,130,35,32,80,130,25,34,111, + 0,103,130,1,34,121,0,67,130,27,32,101,132,59,32,84,130,31,33,0,0,65,155,9,34,20,0,0,65,11,6,130,8,135,2,33,1,1,130,9,8,120,1,1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,1,11,1,12,1,13,1,14, + 1,15,1,16,1,17,1,18,1,19,1,20,1,21,1,22,1,23,1,24,1,25,1,26,1,27,1,28,1,29,1,30,1,31,1,32,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,16,0,17,0,18,0,19,0,20,0,21,0, + 22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,31,130,187,8,66,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0, + 57,0,58,0,59,0,60,0,61,0,62,0,63,0,64,0,65,0,66,130,243,9,75,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0, + 92,0,93,0,94,0,95,0,96,0,97,1,33,1,34,1,35,1,36,1,37,1,38,1,39,1,40,1,41,1,42,1,43,1,44,1,45,1,46,1,47,1,48,1,49,1,50,1,51,1,52,1,53,1,54,1,55,1,56,1,57,1,58,1,59,1,60,1,61,1,62,1, + 63,1,64,1,65,0,172,0,163,0,132,0,133,0,189,0,150,0,232,0,134,0,142,0,139,0,157,0,169,0,164,0,239,0,138,0,218,0,131,0,147,0,242,0,243,0,141,0,151,0,136,0,195,0,222,0,241,0,158,0,170, + 0,245,0,244,0,246,0,162,0,173,0,201,0,199,0,174,0,98,0,99,0,144,0,100,0,203,0,101,0,200,0,202,0,207,0,204,0,205,0,206,0,233,0,102,0,211,0,208,0,209,0,175,0,103,0,240,0,145,0,214,0, + 212,0,213,0,104,0,235,0,237,0,137,0,106,0,105,0,107,0,109,0,108,0,110,0,160,0,111,0,113,0,112,0,114,0,115,0,117,0,116,0,118,0,119,0,234,0,120,0,122,0,121,0,123,0,125,0,124,0,184,0, + 161,0,127,0,126,0,128,0,129,0,236,0,238,0,186,14,117,110,105,99,111,100,101,35,48,120,48,48,48,49,141,14,32,50,141,14,32,51,141,14,32,52,141,14,32,53,141,14,32,54,141,14,32,55,141, + 14,32,56,141,14,32,57,141,14,32,97,141,14,32,98,141,14,32,99,141,14,32,100,141,14,32,101,141,14,32,102,140,14,33,49,48,141,14,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49, + 141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,32,49,141,239,45,49,102,6,100,101,108,101,116,101,4,69,117,114, + 111,140,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236,32,56,141,236, + 32,56,141,236,32,56,141,236,32,56,65,220,13,32,57,65,220,13,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141, + 239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,32,57,141,239,35,57,102,0,0,5,250,72,249,98,247, +}; + +static const char* GetDefaultCompressedFontDataTTF(int* out_size) +{ + *out_size = proggy_clean_ttf_compressed_size; + return (const char*)proggy_clean_ttf_compressed_data; } #endif // #ifndef IMGUI_DISABLE_DEFAULT_FONT diff --git a/misc/fonts/binary_to_compressed_c.cpp b/misc/fonts/binary_to_compressed_c.cpp index f41d20f75733..f16c3b2c3af1 100644 --- a/misc/fonts/binary_to_compressed_c.cpp +++ b/misc/fonts/binary_to_compressed_c.cpp @@ -113,21 +113,42 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_b } fprintf(out, "\";\n\n"); } +#if 0 else { + // As individual bytes, not subject to endianness issues. + fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); + fprintf(out, "%sconst unsigned char %s_%sdata[%d] =\n{", static_str, symbol, compressed_str, (int)compressed_sz); + int column = 0; + for (int i = 0; i < compressed_sz; i++) + { + unsigned char d = *(unsigned char*)(compressed + i); + if (column == 0) + fprintf(out, "\n "); + column += fprintf(out, "%d,", d); + if (column >= 180) + column = 0; + } + fprintf(out, "\n};\n\n"); + } +#else + else + { + // As integers fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); fprintf(out, "%sconst unsigned int %s_%sdata[%d/4] =\n{", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*4); int column = 0; for (int i = 0; i < compressed_sz; i += 4) { unsigned int d = *(unsigned int*)(compressed + i); - if ((column++ % 12) == 0) + if ((column++ % 14) == 0) fprintf(out, "\n 0x%08x, ", d); else fprintf(out, "0x%08x, ", d); } fprintf(out, "\n};\n\n"); } +#endif // Cleanup delete[] data; From 551b6c4d662a3938f0cd197e79cc29922feec1ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 20 Nov 2024 14:32:44 +0100 Subject: [PATCH 041/716] Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. --- docs/CHANGELOG.txt | 1 + imgui_draw.cpp | 6 ++-- misc/fonts/binary_to_compressed_c.cpp | 51 +++++++++++++++++---------- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5305b889e51a..5a49416e20c9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other changes: - Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). - Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) [@demonese] +- Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. - Demo: example tree used by Property Editor & Selection demos properly freed on application closure. (#8158) [@Legulysse] - Examples: Win32+DX12: Using a basic free-list allocator to manage multiple diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0f74a98b3d07..5647f53fde72 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4583,11 +4583,11 @@ static unsigned int stb_decompress(unsigned char *output, const unsigned char *i // MIT license (see License.txt in http://www.proggyfonts.net/index.php?menu=download) // Download and more information at http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php //----------------------------------------------------------------------------- -// File: 'ProggyClean.ttf' (41208 bytes) -// Exported using "misc/fonts/binary_to_compressed_c.exe ../ProggyClean.ttf proggy_clean_ttf_compressed (with compression, no base85 encoding). -//----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_DEFAULT_FONT + +// File: 'ProggyClean.ttf' (41208 bytes) +// Exported using binary_to_compressed_c.exe -u8 "ProggyClean.ttf" proggy_clean_ttf static const unsigned int proggy_clean_ttf_compressed_size = 9583; static const unsigned char proggy_clean_ttf_compressed_data[9583] = { diff --git a/misc/fonts/binary_to_compressed_c.cpp b/misc/fonts/binary_to_compressed_c.cpp index f16c3b2c3af1..b0a243a710df 100644 --- a/misc/fonts/binary_to_compressed_c.cpp +++ b/misc/fonts/binary_to_compressed_c.cpp @@ -2,10 +2,11 @@ // (binary_to_compressed_c.cpp) // Helper tool to turn a file into a C array, if you want to embed font data in your source code. -// The data is first compressed with stb_compress() to reduce source code size, -// then encoded in Base85 to fit in a string so we can fit roughly 4 bytes of compressed data into 5 bytes of source code (suggested by @mmalex) -// (If we used 32-bit constants it would require take 11 bytes of source code to encode 4 bytes, and be endianness dependent) -// Note that even with compression, the output array is likely to be bigger than the binary file.. +// The data is first compressed with stb_compress() to reduce source code size. +// Then stored in a C array: +// - Base85: ~5 bytes of source code for 4 bytes of input data. 5 bytes stored in binary (suggested by @mmalex). +// - As int: ~11 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Endianness dependant, need swapping on big-endian CPU. +// - As char: ~12 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Not endianness dependant. // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() // Build with, e.g: @@ -15,10 +16,12 @@ // You can also find a precompiled Windows binary in the binary/demo package available from https://github.com/ocornut/imgui // Usage: -// binary_to_compressed_c.exe [-base85] [-nocompress] [-nostatic] +// binary_to_compressed_c.exe [-nocompress] [-nostatic] [-base85] // Usage example: // # binary_to_compressed_c.exe myfont.ttf MyFont > myfont.cpp // # binary_to_compressed_c.exe -base85 myfont.ttf MyFont > myfont.cpp +// Note: +// Base85 encoding will be obsoleted by future version of Dear ImGui! #define _CRT_SECURE_NO_WARNINGS #include @@ -31,23 +34,36 @@ typedef unsigned int stb_uint; typedef unsigned char stb_uchar; stb_uint stb_compress(stb_uchar* out, stb_uchar* in, stb_uint len); -static bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression, bool use_static); +enum SourceEncoding +{ + SourceEncoding_U8, // New default since 2024/11 + SourceEncoding_U32, + SourceEncoding_Base85, +}; + +static bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEncoding source_encoding, bool use_compression, bool use_static); int main(int argc, char** argv) { if (argc < 3) { - printf("Syntax: %s [-base85] [-nocompress] [-nostatic] \n", argv[0]); + printf("Syntax: %s [-u8|-u32|-base85] [-nocompress] [-nostatic] \n", argv[0]); + printf("Source encoding types:\n"); + printf(" -u8 = ~12 bytes of source per 4 bytes of data. 4 bytes in binary.\n"); + printf(" -u32 = ~11 bytes of source per 4 bytes of data. 4 bytes in binary. Need endianness swapping on big-endian.\n"); + printf(" -base85 = ~5 bytes of source per 4 bytes of data. 5 bytes in binary. Need decoder.\n"); return 0; } int argn = 1; - bool use_base85_encoding = false; bool use_compression = true; bool use_static = true; + SourceEncoding source_encoding = SourceEncoding_U8; // New default while (argn < (argc - 2) && argv[argn][0] == '-') { - if (strcmp(argv[argn], "-base85") == 0) { use_base85_encoding = true; argn++; } + if (strcmp(argv[argn], "-u8") == 0) { source_encoding = SourceEncoding_U8; argn++; } + else if (strcmp(argv[argn], "-u32") == 0) { source_encoding = SourceEncoding_U32; argn++; } + else if (strcmp(argv[argn], "-base85") == 0) { source_encoding = SourceEncoding_Base85; argn++; } else if (strcmp(argv[argn], "-nocompress") == 0) { use_compression = false; argn++; } else if (strcmp(argv[argn], "-nostatic") == 0) { use_static = false; argn++; } else @@ -57,7 +73,7 @@ int main(int argc, char** argv) } } - bool ret = binary_to_compressed_c(argv[argn], argv[argn + 1], use_base85_encoding, use_compression, use_static); + bool ret = binary_to_compressed_c(argv[argn], argv[argn + 1], source_encoding, use_compression, use_static); if (!ret) fprintf(stderr, "Error opening or reading file: '%s'\n", argv[argn]); return ret ? 0 : 1; @@ -69,7 +85,7 @@ char Encode85Byte(unsigned int x) return (char)((x >= '\\') ? x + 1 : x); } -bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_base85_encoding, bool use_compression, bool use_static) +bool binary_to_compressed_c(const char* filename, const char* symbol, SourceEncoding source_encoding, bool use_compression, bool use_static) { // Read file FILE* f = fopen(filename, "rb"); @@ -91,11 +107,11 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_b // Output as Base85 encoded FILE* out = stdout; fprintf(out, "// File: '%s' (%d bytes)\n", filename, (int)data_sz); - fprintf(out, "// Exported using binary_to_compressed_c.cpp\n"); const char* static_str = use_static ? "static " : ""; const char* compressed_str = use_compression ? "compressed_" : ""; - if (use_base85_encoding) + if (source_encoding == SourceEncoding_Base85) { + fprintf(out, "// Exported using binary_to_compressed_c.exe -base85 \"%s\" %s\n", filename, symbol); fprintf(out, "%sconst char %s_%sdata_base85[%d+1] =\n \"", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*5); char prev_c = 0; for (int src_i = 0; src_i < compressed_sz; src_i += 4) @@ -113,10 +129,10 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_b } fprintf(out, "\";\n\n"); } -#if 0 - else + else if (source_encoding == SourceEncoding_U8) { // As individual bytes, not subject to endianness issues. + fprintf(out, "// Exported using binary_to_compressed_c.exe -u8 \"%s\" %s\n", filename, symbol); fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); fprintf(out, "%sconst unsigned char %s_%sdata[%d] =\n{", static_str, symbol, compressed_str, (int)compressed_sz); int column = 0; @@ -131,10 +147,10 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_b } fprintf(out, "\n};\n\n"); } -#else - else + else if (source_encoding == SourceEncoding_U32) { // As integers + fprintf(out, "// Exported using binary_to_compressed_c.exe -u32 \"%s\" %s\n", filename, symbol); fprintf(out, "%sconst unsigned int %s_%ssize = %d;\n", static_str, symbol, compressed_str, (int)compressed_sz); fprintf(out, "%sconst unsigned int %s_%sdata[%d/4] =\n{", static_str, symbol, compressed_str, (int)((compressed_sz + 3) / 4)*4); int column = 0; @@ -148,7 +164,6 @@ bool binary_to_compressed_c(const char* filename, const char* symbol, bool use_b } fprintf(out, "\n};\n\n"); } -#endif // Cleanup delete[] data; From 20360e00ceb26b67a4569521b762fbd89d9db61c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 20 Nov 2024 21:46:47 +0100 Subject: [PATCH 042/716] Merge miscellaneous small changes to reduce drift with texture update branch. - ImGuiDebugLogFlags_EventFont is yet unused. --- backends/imgui_impl_opengl3.cpp | 3 +- imgui.cpp | 28 +++++----- imgui.h | 19 ++++--- imgui_draw.cpp | 90 ++++++++++++++++++-------------- imgui_internal.h | 25 ++++----- misc/freetype/imgui_freetype.cpp | 1 + 6 files changed, 95 insertions(+), 71 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index c03156a7e174..57c699421d19 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -164,6 +164,7 @@ // In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.). // If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp): // - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped +// Typically you would run: python3 ./gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt // - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases // Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version. #define IMGL3W_IMPL @@ -689,7 +690,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture() #endif GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); - // Store our identifier + // Store identifier io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); // Restore state diff --git a/imgui.cpp b/imgui.cpp index 3512ec87dda9..a8c86cc57bcb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4010,7 +4010,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) StackSizesInBeginForCurrentWindow = NULL; DebugDrawIdConflictsCount = 0; - DebugLogFlags = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_OutputToTTY; + DebugLogFlags = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_OutputToTTY | ImGuiDebugLogFlags_EventFont; DebugLocateId = 0; DebugLogSkippedErrors = 0; DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None; @@ -4226,8 +4226,8 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL FontWindowScale = 1.0f; SettingsOffset = -1; DrawList = &DrawListInst; - DrawList->_Data = &Ctx->DrawListSharedData; DrawList->_OwnerName = Name; + DrawList->_Data = &Ctx->DrawListSharedData; NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX); } @@ -5025,7 +5025,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } -// Calling SetupDrawListSharedData() is followed by SetCurrentFont() which sets up the remaining data. +// Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. static void SetupDrawListSharedData() { ImGuiContext& g = *GImGui; @@ -15180,6 +15180,17 @@ void ImGui::UpdateDebugToolFlashStyleColor() DebugFlashStyleColorStop(); } +static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id) +{ + union { void* ptr; int integer; } tex_id_opaque; + memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id))); + if (sizeof(tex_id) >= sizeof(void*)) + ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr); + else + ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer); + return buf; +} + // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. static void MetricsHelpMarker(const char* desc) { @@ -15868,16 +15879,6 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns* columns) TreePop(); } -static void FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id) -{ - union { void* ptr; int integer; } tex_id_opaque; - memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id))); - if (sizeof(tex_id) >= sizeof(void*)) - ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr); - else - ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer); -} - // [DEBUG] Display contents of ImDrawList void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label) { @@ -16379,6 +16380,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) ShowDebugLogFlag("Clipper", ImGuiDebugLogFlags_EventClipper); ShowDebugLogFlag("Focus", ImGuiDebugLogFlags_EventFocus); ShowDebugLogFlag("IO", ImGuiDebugLogFlags_EventIO); + //ShowDebugLogFlag("Font", ImGuiDebugLogFlags_EventFont); ShowDebugLogFlag("Nav", ImGuiDebugLogFlags_EventNav); ShowDebugLogFlag("Popup", ImGuiDebugLogFlags_EventPopup); ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection); diff --git a/imgui.h b/imgui.h index 815b079242bf..12dc7d0082e7 100644 --- a/imgui.h +++ b/imgui.h @@ -2309,6 +2309,7 @@ struct ImGuiIO // (the imgui_impl_xxxx backend files are setting those up for you) //------------------------------------------------------------------ + // Nowadays those would be stored in ImGuiPlatformIO but we are leaving them here for legacy reasons. // Optional: Platform/Renderer backend name (informational only! will be displayed in About Window) + User data for backend/wrappers to store their own stuff. const char* BackendPlatformName; // = NULL const char* BackendRendererName; // = NULL @@ -3064,10 +3065,11 @@ struct ImDrawList float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content const char* _OwnerName; // Pointer to owner window's name for debugging - // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) - ImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; } - - ~ImDrawList() { _ClearFreeMemory(); } + // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData(). + // (advanced: you may create and use your own ImDrawListSharedData so you can use ImDrawList without ImGui, but that's more involved) + IMGUI_API ImDrawList(ImDrawListSharedData* shared_data); + IMGUI_API ~ImDrawList(); + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const 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(); IMGUI_API void PopClipRect(); @@ -3277,14 +3279,16 @@ struct ImFontGlyphRangesBuilder // See ImFontAtlas::AddCustomRectXXX functions. struct ImFontAtlasCustomRect { - unsigned short Width, Height; // Input // Desired rectangle dimension unsigned short X, Y; // Output // Packed position in Atlas + + // [Internal] + unsigned short Width, Height; // Input // Desired rectangle dimension unsigned int GlyphID : 31; // Input // For custom font glyphs only (ID < 0x110000) unsigned int GlyphColored : 1; // Input // For custom font glyphs only: glyph is colored, removed tinting. float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset ImFont* Font; // Input // For custom font glyphs only: target font - ImFontAtlasCustomRect() { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } + ImFontAtlasCustomRect() { X = Y = 0xFFFF; Width = Height = 0; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } bool IsPacked() const { return X != 0xFFFF; } }; @@ -3431,8 +3435,9 @@ struct ImFont const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) // Members: Cold ~32/40 bytes + // Conceptually ConfigData[] is the list of font sources merged to create this font. ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into - const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData + const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5647f53fde72..fd1feb0a84a5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -14,7 +14,7 @@ Index of this file: // [SECTION] Helpers ShadeVertsXXX functions // [SECTION] ImFontConfig // [SECTION] ImFontAtlas -// [SECTION] ImFontAtlas glyph ranges helpers +// [SECTION] ImFontAtlas: glyph ranges helpers // [SECTION] ImFontGlyphRangesBuilder // [SECTION] ImFont // [SECTION] ImGui Internal Render Helpers @@ -394,6 +394,17 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); } +ImDrawList::ImDrawList(ImDrawListSharedData* shared_data) +{ + memset(this, 0, sizeof(*this)); + _Data = shared_data; +} + +ImDrawList::~ImDrawList() +{ + _ClearFreeMemory(); +} + // Initialize before use in a new frame. We always have a command ready in the buffer. // In the majority of cases, you would want to call PushClipRect() and PushTextureID() after this. void ImDrawList::_ResetForNewFrame() @@ -2528,6 +2539,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); IM_ASSERT(font_cfg->OversampleH > 0 && font_cfg->OversampleV > 0 && "Is ImFontConfig struct correctly initialized?"); + IM_ASSERT(font_cfg->RasterizerDensity > 0.0f); // Create new font if (!font_cfg->MergeMode) @@ -2546,9 +2558,16 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); } + // Round font size + // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. + // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes. + // - We may support it better later and remove this rounding. + new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels); + if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; + // Pointers to ConfigData and BuilderData are otherwise dangling ImFontAtlasUpdateConfigDataPointers(this); // Invalidate texture @@ -3163,35 +3182,35 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) IM_ASSERT(r->IsPacked()); const int w = atlas->TexWidth; - if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) + if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) { - // Render/copy pixels - IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); - const int x_for_white = r->X; - const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + // White pixels only + IM_ASSERT(r->Width == 2 && r->Height == 2); + const int offset = (int)r->X + (int)r->Y * w; if (atlas->TexPixelsAlpha8 != NULL) { - ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); - ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; } else { - ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); - ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; } } else { - // Render 4 white pixels - IM_ASSERT(r->Width == 2 && r->Height == 2); - const int offset = (int)r->X + (int)r->Y * w; + // White pixels and mouse cursor + IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); + const int x_for_white = r->X; + const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; if (atlas->TexPixelsAlpha8 != NULL) { - atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); } else { - atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); } } atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); @@ -3205,38 +3224,38 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); IM_ASSERT(r->IsPacked()); - for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row + for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle - unsigned int y = n; - unsigned int line_width = n; - unsigned int pad_left = (r->Width - line_width) / 2; - unsigned int pad_right = r->Width - (pad_left + line_width); + int y = n; + int line_width = n; + int pad_left = (r->Width - line_width) / 2; + int pad_right = r->Width - (pad_left + line_width); // Write each slice IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels if (atlas->TexPixelsAlpha8 != NULL) { unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; - for (unsigned int i = 0; i < pad_left; i++) + for (int i = 0; i < pad_left; i++) *(write_ptr + i) = 0x00; - for (unsigned int i = 0; i < line_width; i++) + for (int i = 0; i < line_width; i++) *(write_ptr + pad_left + i) = 0xFF; - for (unsigned int i = 0; i < pad_right; i++) + for (int i = 0; i < pad_right; i++) *(write_ptr + pad_left + line_width + i) = 0x00; } else { unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; - for (unsigned int i = 0; i < pad_left; i++) + for (int i = 0; i < pad_left; i++) *(write_ptr + i) = IM_COL32(255, 255, 255, 0); - for (unsigned int i = 0; i < line_width; i++) + for (int i = 0; i < line_width; i++) *(write_ptr + pad_left + i) = IM_COL32_WHITE; - for (unsigned int i = 0; i < pad_right; i++) + for (int i = 0; i < pad_right; i++) *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); } @@ -3251,13 +3270,6 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) // Note: this is called / shared by both the stb_truetype and the FreeType builder void ImFontAtlasBuildInit(ImFontAtlas* atlas) { - // Round font size - // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. - // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes. - // - We may support it better later and remove this rounding. - for (ImFontConfig& cfg : atlas->ConfigData) - cfg.SizePixels = ImTrunc(cfg.SizePixels); - // Register texture region for mouse cursors or standard white pixels if (atlas->PackIdMouseCursors < 0) { @@ -3308,6 +3320,10 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) atlas->TexReady = true; } +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas: glyph ranges helpers +//------------------------------------------------------------------------- + // Retrieve list of range (2 int per range, values are inclusive) const ImWchar* ImFontAtlas::GetGlyphRangesDefault() { @@ -3369,10 +3385,6 @@ static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* out_ranges[0] = 0; } -//------------------------------------------------------------------------- -// [SECTION] ImFontAtlas glyph ranges helpers -//------------------------------------------------------------------------- - const ImWchar* ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon() { // Store 2500 regularly used characters for Simplified Chinese. @@ -3799,8 +3811,9 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa advance_x += cfg->GlyphExtraSpacing.x; } + int glyph_idx = Glyphs.Size; Glyphs.resize(Glyphs.Size + 1); - ImFontGlyph& glyph = Glyphs.back(); + ImFontGlyph& glyph = Glyphs[glyph_idx]; glyph.Codepoint = (unsigned int)codepoint; glyph.Visible = (x0 != x1) && (y0 != y1); glyph.Colored = false; @@ -3836,6 +3849,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; } +// Find glyph, return fallback if missing const ImFontGlyph* ImFont::FindGlyph(ImWchar c) { if (c >= (size_t)IndexLookup.Size) diff --git a/imgui_internal.h b/imgui_internal.h index 2af196cb789e..40cf3c0c37ae 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -212,11 +212,6 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif // Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. -#ifndef IMGUI_DISABLE_DEBUG_TOOLS -#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) -#else -#define IMGUI_DEBUG_LOG(...) ((void)0) -#endif #define IMGUI_DEBUG_LOG_ERROR(...) do { ImGuiContext& g2 = *GImGui; if (g2.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g2.DebugLogSkippedErrors++; } while (0) #define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) @@ -225,6 +220,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_FONT(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Static Asserts @@ -760,10 +756,13 @@ IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStorag #define IM_DRAWLIST_ARCFAST_SAMPLE_MAX IM_DRAWLIST_ARCFAST_TABLE_SIZE // Sample index _PathArcToFastEx() for 360 angle. // Data shared between all ImDrawList instances -// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. +// Conceptually this could have been called e.g. ImDrawListSharedContext +// Typically one ImGui context would create and maintain one of this. +// You may want to create your own instance of you try to ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. struct IMGUI_API ImDrawListSharedData { ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas + const ImVec4* TexUvLines; // UV of anti-aliased lines 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 FontScale; // Current/default font scale (== FontSize / Font->FontSize) @@ -779,7 +778,6 @@ struct IMGUI_API ImDrawListSharedData ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) - const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas ImDrawListSharedData(); void SetCircleTessellationMaxError(float max_error); @@ -1919,6 +1917,7 @@ typedef void (*ImGuiErrorCallback)(ImGuiContext* ctx, void* user_data, const cha // [SECTION] Metrics, Debug Tools //----------------------------------------------------------------------------- +// See IMGUI_DEBUG_LOG() and IMGUI_DEBUG_LOG_XXX() macros. enum ImGuiDebugLogFlags_ { // Event types @@ -1931,11 +1930,12 @@ enum ImGuiDebugLogFlags_ ImGuiDebugLogFlags_EventClipper = 1 << 5, ImGuiDebugLogFlags_EventSelection = 1 << 6, ImGuiDebugLogFlags_EventIO = 1 << 7, - ImGuiDebugLogFlags_EventInputRouting = 1 << 8, - ImGuiDebugLogFlags_EventDocking = 1 << 9, // Unused in this branch - ImGuiDebugLogFlags_EventViewport = 1 << 10, // Unused in this branch + ImGuiDebugLogFlags_EventFont = 1 << 8, + ImGuiDebugLogFlags_EventInputRouting = 1 << 9, + ImGuiDebugLogFlags_EventDocking = 1 << 10, // Unused in this branch + ImGuiDebugLogFlags_EventViewport = 1 << 11, // Unused in this branch - ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, ImGuiDebugLogFlags_OutputToTTY = 1 << 20, // Also send output to TTY ImGuiDebugLogFlags_OutputToTestEngine = 1 << 21, // Also send output to Test Engine }; @@ -3524,7 +3524,8 @@ namespace ImGui // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -// This structure is likely to evolve as we add support for incremental atlas updates +// This structure is likely to evolve as we add support for incremental atlas updates. +// Conceptually this could be in ImGuiPlatformIO, but we are far from ready to make this public. struct ImFontBuilderIO { bool (*FontBuilder_Build)(ImFontAtlas* atlas); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index c2d5f074c0fa..e68a2af40bbd 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -169,6 +169,7 @@ namespace const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr); + FreeTypeFont() { memset(this, 0, sizeof(*this)); } ~FreeTypeFont() { CloseFont(); } // [Internals] From dfbf1b4f6b1a12b3854c58ef7cc160c998a66537 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 20 Nov 2024 22:19:34 +0100 Subject: [PATCH 043/716] Backends: DX9: cache result of ImGui_ImplDX9_CheckFormatSupport() as we are going to need it more often. --- backends/imgui_impl_dx9.cpp | 47 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index f1b069df11fe..4d1527b5a137 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -52,6 +52,7 @@ struct ImGui_ImplDX9_Data LPDIRECT3DTEXTURE9 FontTexture; int VertexBufferSize; int IndexBufferSize; + bool HasRgbaSupport; ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } }; @@ -291,6 +292,24 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) state_block->Release(); } +static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMAT format) +{ + LPDIRECT3D9 pd3d = nullptr; + if (pDevice->GetDirect3D(&pd3d) != D3D_OK) + return false; + D3DDEVICE_CREATION_PARAMETERS param = {}; + D3DDISPLAYMODE mode = {}; + if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK) + { + pd3d->Release(); + return false; + } + // Font texture should support linear filter, color blend and write to render-target + bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK; + pd3d->Release(); + return support; +} + bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) { ImGuiIO& io = ImGui::GetIO(); @@ -305,6 +324,7 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) bd->pd3dDevice = device; bd->pd3dDevice->AddRef(); + bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); return true; } @@ -323,24 +343,6 @@ void ImGui_ImplDX9_Shutdown() IM_DELETE(bd); } -static bool ImGui_ImplDX9_CheckFormatSupport(IDirect3DDevice9* pDevice, D3DFORMAT format) -{ - IDirect3D9* pd3d = nullptr; - if (pDevice->GetDirect3D(&pd3d) != D3D_OK) - return false; - D3DDEVICE_CREATION_PARAMETERS param = {}; - D3DDISPLAYMODE mode = {}; - if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK) - { - pd3d->Release(); - return false; - } - // Font texture should support linear filter, color blend and write to render-target - bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK; - pd3d->Release(); - return support; -} - static bool ImGui_ImplDX9_CreateFontsTexture() { // Build texture atlas @@ -352,21 +354,18 @@ static bool ImGui_ImplDX9_CreateFontsTexture() // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) #ifndef IMGUI_USE_BGRA_PACKED_COLOR - const bool rgba_support = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); - if (!rgba_support && io.Fonts->TexPixelsUseColors) + if (!bd->HasRgbaSupport && io.Fonts->TexPixelsUseColors) { ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) *dst = IMGUI_COL_TO_DX9_ARGB(*src); pixels = (unsigned char*)dst_start; } -#else - const bool rgba_support = false; #endif // Upload texture to graphics system bd->FontTexture = nullptr; - if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, rgba_support ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) return false; D3DLOCKED_RECT tex_locked_rect; if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) @@ -379,7 +378,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() io.Fonts->SetTexID((ImTextureID)bd->FontTexture); #ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (!rgba_support && io.Fonts->TexPixelsUseColors) + if (!bd->HasRgbaSupport && io.Fonts->TexPixelsUseColors) ImGui::MemFree(pixels); #endif From 5b7feebfd8f3e58392d955b4c8ae01f77eae25ed Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 21 Nov 2024 16:57:51 +0100 Subject: [PATCH 044/716] Backends: DX9: extract RGBA convert loop as we are going to need it more often. --- backends/imgui_impl_dx9.cpp | 42 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 4d1527b5a137..c97d3c740ef9 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -343,6 +343,28 @@ void ImGui_ImplDX9_Shutdown() IM_DELETE(bd); } +// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) +static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h) +{ +#ifndef IMGUI_USE_BGRA_PACKED_COLOR + ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); + const bool convert_rgba_to_bgra = (!bd->HasRgbaSupport && tex_use_colors); +#else + const bool convert_rgba_to_bgra = false; + IM_UNUSED(tex_use_colors); +#endif + for (int y = 0; y < h; y++) + { + ImU32* src_p = (ImU32*)((unsigned char*)src + src_pitch * y); + ImU32* dst_p = (ImU32*)((unsigned char*)dst + dst_pitch * y); + if (convert_rgba_to_bgra) + for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy + *dst_p = IMGUI_COL_TO_DX9_ARGB(*src_p); + else + memcpy(dst_p, src_p, w * 4); // Raw copy + } +} + static bool ImGui_ImplDX9_CreateFontsTexture() { // Build texture atlas @@ -352,17 +374,6 @@ static bool ImGui_ImplDX9_CreateFontsTexture() int width, height, bytes_per_pixel; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); - // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) -#ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (!bd->HasRgbaSupport && io.Fonts->TexPixelsUseColors) - { - ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); - for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) - *dst = IMGUI_COL_TO_DX9_ARGB(*src); - pixels = (unsigned char*)dst_start; - } -#endif - // Upload texture to graphics system bd->FontTexture = nullptr; if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) @@ -370,18 +381,11 @@ static bool ImGui_ImplDX9_CreateFontsTexture() D3DLOCKED_RECT tex_locked_rect; if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) return false; - for (int y = 0; y < height; y++) - memcpy((unsigned char*)tex_locked_rect.pBits + (size_t)tex_locked_rect.Pitch * y, pixels + (size_t)width * bytes_per_pixel * y, (size_t)width * bytes_per_pixel); + ImGui_ImplDX9_CopyTextureRegion(io.Fonts->TexPixelsUseColors, (ImU32*)pixels, width * bytes_per_pixel, (ImU32*)tex_locked_rect.pBits, (int)tex_locked_rect.Pitch, width, height); bd->FontTexture->UnlockRect(0); // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->FontTexture); - -#ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (!bd->HasRgbaSupport && io.Fonts->TexPixelsUseColors) - ImGui::MemFree(pixels); -#endif - return true; } From 9b273294377dfe0e054614489f90632bfb7af0e3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 25 Nov 2024 18:59:56 +0100 Subject: [PATCH 045/716] Comments on ImageButton(). (#8165) + comments on Emscripten -sSINGLE_FILE option. (#8153) --- examples/example_glfw_opengl3/Makefile.emscripten | 3 +++ examples/example_glfw_wgpu/Makefile.emscripten | 3 +++ examples/example_sdl2_opengl3/Makefile.emscripten | 3 +++ examples/example_sdl3_opengl3/Makefile.emscripten | 3 +++ imgui.h | 3 ++- imgui_widgets.cpp | 5 ++--- 6 files changed, 16 insertions(+), 4 deletions(-) diff --git a/examples/example_glfw_opengl3/Makefile.emscripten b/examples/example_glfw_opengl3/Makefile.emscripten index bd972abffc85..bba4ac9dc579 100644 --- a/examples/example_glfw_opengl3/Makefile.emscripten +++ b/examples/example_glfw_opengl3/Makefile.emscripten @@ -35,6 +35,9 @@ EMS = EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s USE_GLFW=3 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 +# Build as single file (binary text encoded in .html file) +#LDFLAGS += -sSINGLE_FILE + # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp #EMS += -s SAFE_HEAP=1 ## Adds overhead diff --git a/examples/example_glfw_wgpu/Makefile.emscripten b/examples/example_glfw_wgpu/Makefile.emscripten index 5c79f0c77dbb..78d64b4d3179 100644 --- a/examples/example_glfw_wgpu/Makefile.emscripten +++ b/examples/example_glfw_wgpu/Makefile.emscripten @@ -36,6 +36,9 @@ EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s USE_GLFW=3 -s USE_WEBGPU=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 +# Build as single file (binary text encoded in .html file) +#LDFLAGS += -sSINGLE_FILE + # Emscripten allows preloading a file or folder to be accessible at runtime. # The Makefile for this example project suggests embedding the misc/fonts/ folder into our application, it will then be accessible as "/fonts" # See documentation for more details: https://emscripten.org/docs/porting/files/packaging_files.html diff --git a/examples/example_sdl2_opengl3/Makefile.emscripten b/examples/example_sdl2_opengl3/Makefile.emscripten index da0348435d03..bc06adeb74b6 100644 --- a/examples/example_sdl2_opengl3/Makefile.emscripten +++ b/examples/example_sdl2_opengl3/Makefile.emscripten @@ -36,6 +36,9 @@ EMS += -s USE_SDL=2 EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 +# Build as single file (binary text encoded in .html file) +#LDFLAGS += -sSINGLE_FILE + # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp #EMS += -s SAFE_HEAP=1 ## Adds overhead diff --git a/examples/example_sdl3_opengl3/Makefile.emscripten b/examples/example_sdl3_opengl3/Makefile.emscripten index 9e9ffd6034f7..57247ff21265 100644 --- a/examples/example_sdl3_opengl3/Makefile.emscripten +++ b/examples/example_sdl3_opengl3/Makefile.emscripten @@ -40,6 +40,9 @@ EMS += -s USE_SDL=2 EMS += -s DISABLE_EXCEPTION_CATCHING=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 +# Build as single file (binary text encoded in .html file) +#LDFLAGS += -sSINGLE_FILE + # Uncomment next line to fix possible rendering bugs with Emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp #EMS += -s SAFE_HEAP=1 ## Adds overhead diff --git a/imgui.h b/imgui.h index 12dc7d0082e7..35a903889246 100644 --- a/imgui.h +++ b/imgui.h @@ -564,6 +564,7 @@ namespace ImGui // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. // - Note that Image() may add +2.0f to provided size if a border is visible, ImageButton() adds style.FramePadding*2.0f to provided size. + // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0)); IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); @@ -3069,7 +3070,7 @@ struct ImDrawList // (advanced: you may create and use your own ImDrawListSharedData so you can use ImDrawList without ImGui, but that's more involved) IMGUI_API ImDrawList(ImDrawListSharedData* shared_data); IMGUI_API ~ImDrawList(); - + IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const 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(); IMGUI_API void PopClipRect(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c60378f82140..81b480cb174b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1073,8 +1073,6 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const I window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); } -// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390) -// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API. bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) { ImGuiContext& g = *GImGui; @@ -1102,7 +1100,8 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& imag return pressed; } -// Note that ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a button. +// - ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a button. +// - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. (#8165) // FIXME: Maybe that's not the best design? bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { ImGuiContext& g = *GImGui; From 61ab94d5534b0809079c136fd1301227e91f6003 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Fri, 22 Nov 2024 07:40:30 +0900 Subject: [PATCH 046/716] Backends: Vulkan: Make descriptor pool optional (#8172, #4867) Comments/amends by ocornut --- backends/imgui_impl_vulkan.cpp | 31 +++++++++++++++++++++++++++---- backends/imgui_impl_vulkan.h | 16 ++++++++++++---- docs/CHANGELOG.txt | 3 +++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index d499ecb92350..1d2d8a19d66a 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) // 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: Vulkan: Expose selected render state in ImGui_ImplVulkan_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-10-07: Vulkan: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*. @@ -131,6 +132,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetViewport) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateCommandPool) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorPool) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateDescriptorSetLayout) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFence) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateFramebuffer) \ @@ -221,6 +223,7 @@ struct ImGui_ImplVulkan_Data VkPipeline Pipeline; VkShaderModule ShaderModuleVert; VkShaderModule ShaderModuleFrag; + VkDescriptorPool DescriptorPool; // Font data VkSampler FontSampler; @@ -1010,6 +1013,20 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } + if (v->DescriptorPoolSize) + { + VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_info.maxSets = v->DescriptorPoolSize; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &pool_size; + + err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool); + check_vk_result(err); + } + if (!bd->PipelineLayout) { // Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix @@ -1048,6 +1065,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } + if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } } bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) @@ -1110,7 +1128,10 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE); IM_ASSERT(info->Device != VK_NULL_HANDLE); IM_ASSERT(info->Queue != VK_NULL_HANDLE); - IM_ASSERT(info->DescriptorPool != VK_NULL_HANDLE); + if (info->DescriptorPool != VK_NULL_HANDLE) // Either DescriptorPool or DescriptorPoolSize must be set, not both! + IM_ASSERT(info->DescriptorPoolSize == 0); + else + IM_ASSERT(info->DescriptorPoolSize > 0); IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); if (info->UseDynamicRendering == false) @@ -1159,19 +1180,20 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) bd->VulkanInitInfo.MinImageCount = min_image_count; } -// Register a texture +// Register a texture by creating a descriptor // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; // Create Descriptor Set: VkDescriptorSet descriptor_set; { VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - alloc_info.descriptorPool = v->DescriptorPool; + alloc_info.descriptorPool = pool; alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &bd->DescriptorSetLayout; VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set); @@ -1199,7 +1221,8 @@ void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - vkFreeDescriptorSets(v->Device, v->DescriptorPool, 1, &descriptor_set); + VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool; + vkFreeDescriptorSets(v->Device, pool, 1, &descriptor_set); } void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index ca5b4db64100..8d9e19f9a7ee 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -62,10 +62,15 @@ #endif // Initialization data, for ImGui_ImplVulkan_Init() -// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, -// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor. -// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. // [Please zero-clear before use!] +// - About descriptor pool: +// - A VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, +// and must contain a pool size large enough to hold a small number of VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptors. +// - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you. +// - Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). +// - It is expected that as early as Q1 2025 the backend will use a few more descriptors, so aim at 10 + number of desierd calls to ImGui_ImplVulkan_AddTexture(). +// - About dynamic rendering: +// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. struct ImGui_ImplVulkan_InitInfo { VkInstance Instance; @@ -73,7 +78,7 @@ struct ImGui_ImplVulkan_InitInfo VkDevice Device; uint32_t QueueFamily; VkQueue Queue; - VkDescriptorPool DescriptorPool; // See requirements in note above + VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 VkRenderPass RenderPass; // Ignored if using dynamic rendering uint32_t MinImageCount; // >= 2 uint32_t ImageCount; // >= MinImageCount @@ -83,6 +88,9 @@ struct ImGui_ImplVulkan_InitInfo VkPipelineCache PipelineCache; uint32_t Subpass; + // (Optional) Set to create internal descriptor pool instead of using DescriptorPool + uint32_t DescriptorPoolSize; + // (Optional) Dynamic Rendering // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. bool UseDynamicRendering; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5a49416e20c9..642adfc31ef3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,9 @@ Other changes: - Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. - Demo: example tree used by Property Editor & Selection demos properly freed on application closure. (#8158) [@Legulysse] +- Backends: Vulkan: Make user-provided descriptor pool optional. As a convenience, + when setting init_info->DescriptorPoolSize then the backend will create and manage + one itself. (#8172, #4867) [@zeux] - Examples: Win32+DX12: Using a basic free-list allocator to manage multiple SRV descriptors. From e6dd8f626a189d984a078d9e2f6d4d36a7af91cb Mon Sep 17 00:00:00 2001 From: Teselka <53512153+Teselka@users.noreply.github.com> Date: Fri, 22 Nov 2024 13:33:25 +0200 Subject: [PATCH 047/716] Misc: changed CRC32 table to use crc32c polynomial in order to be compatible with SSE 4.2 instructions. (#8169, #4933) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 34 ++++++++++++++++++---------------- imgui.h | 2 +- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 642adfc31ef3..e901e437eb69 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,9 @@ Breaking changes: - We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. - Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). +- Misc: changed CRC32 table to use CRC32c polynomial in order to be compatible + with the result of SSE 4.2 instructions. As a result, old .ini data may be + partially lost. (#8169, #4933) [@Teselka] Other changes: diff --git a/imgui.cpp b/imgui.cpp index a8c86cc57bcb..072c09799635 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -429,6 +429,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2024/11/27 (1.91.6) - changed CRC32 table to use CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. As a result, old .ini data may be partially lost. - 2024/11/06 (1.91.5) - commented/obsoleted out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before) - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). @@ -2152,24 +2153,25 @@ void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. +// On 2024/11/27 this was changed from crc32-adler to crc32c (polynomial 0x1EDC6F41), which invalidated some hashes stored in .ini files. static const ImU32 GCrc32LookupTable[256] = { - 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, - 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, - 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, - 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, - 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, - 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, - 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, - 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, - 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, - 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, - 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, - 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, - 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, - 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, - 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, - 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, + 0x00000000,0xF26B8303,0xE13B70F7,0x1350F3F4,0xC79A971F,0x35F1141C,0x26A1E7E8,0xD4CA64EB,0x8AD958CF,0x78B2DBCC,0x6BE22838,0x9989AB3B,0x4D43CFD0,0xBF284CD3,0xAC78BF27,0x5E133C24, + 0x105EC76F,0xE235446C,0xF165B798,0x030E349B,0xD7C45070,0x25AFD373,0x36FF2087,0xC494A384,0x9A879FA0,0x68EC1CA3,0x7BBCEF57,0x89D76C54,0x5D1D08BF,0xAF768BBC,0xBC267848,0x4E4DFB4B, + 0x20BD8EDE,0xD2D60DDD,0xC186FE29,0x33ED7D2A,0xE72719C1,0x154C9AC2,0x061C6936,0xF477EA35,0xAA64D611,0x580F5512,0x4B5FA6E6,0xB93425E5,0x6DFE410E,0x9F95C20D,0x8CC531F9,0x7EAEB2FA, + 0x30E349B1,0xC288CAB2,0xD1D83946,0x23B3BA45,0xF779DEAE,0x05125DAD,0x1642AE59,0xE4292D5A,0xBA3A117E,0x4851927D,0x5B016189,0xA96AE28A,0x7DA08661,0x8FCB0562,0x9C9BF696,0x6EF07595, + 0x417B1DBC,0xB3109EBF,0xA0406D4B,0x522BEE48,0x86E18AA3,0x748A09A0,0x67DAFA54,0x95B17957,0xCBA24573,0x39C9C670,0x2A993584,0xD8F2B687,0x0C38D26C,0xFE53516F,0xED03A29B,0x1F682198, + 0x5125DAD3,0xA34E59D0,0xB01EAA24,0x42752927,0x96BF4DCC,0x64D4CECF,0x77843D3B,0x85EFBE38,0xDBFC821C,0x2997011F,0x3AC7F2EB,0xC8AC71E8,0x1C661503,0xEE0D9600,0xFD5D65F4,0x0F36E6F7, + 0x61C69362,0x93AD1061,0x80FDE395,0x72966096,0xA65C047D,0x5437877E,0x4767748A,0xB50CF789,0xEB1FCBAD,0x197448AE,0x0A24BB5A,0xF84F3859,0x2C855CB2,0xDEEEDFB1,0xCDBE2C45,0x3FD5AF46, + 0x7198540D,0x83F3D70E,0x90A324FA,0x62C8A7F9,0xB602C312,0x44694011,0x5739B3E5,0xA55230E6,0xFB410CC2,0x092A8FC1,0x1A7A7C35,0xE811FF36,0x3CDB9BDD,0xCEB018DE,0xDDE0EB2A,0x2F8B6829, + 0x82F63B78,0x709DB87B,0x63CD4B8F,0x91A6C88C,0x456CAC67,0xB7072F64,0xA457DC90,0x563C5F93,0x082F63B7,0xFA44E0B4,0xE9141340,0x1B7F9043,0xCFB5F4A8,0x3DDE77AB,0x2E8E845F,0xDCE5075C, + 0x92A8FC17,0x60C37F14,0x73938CE0,0x81F80FE3,0x55326B08,0xA759E80B,0xB4091BFF,0x466298FC,0x1871A4D8,0xEA1A27DB,0xF94AD42F,0x0B21572C,0xDFEB33C7,0x2D80B0C4,0x3ED04330,0xCCBBC033, + 0xA24BB5A6,0x502036A5,0x4370C551,0xB11B4652,0x65D122B9,0x97BAA1BA,0x84EA524E,0x7681D14D,0x2892ED69,0xDAF96E6A,0xC9A99D9E,0x3BC21E9D,0xEF087A76,0x1D63F975,0x0E330A81,0xFC588982, + 0xB21572C9,0x407EF1CA,0x532E023E,0xA145813D,0x758FE5D6,0x87E466D5,0x94B49521,0x66DF1622,0x38CC2A06,0xCAA7A905,0xD9F75AF1,0x2B9CD9F2,0xFF56BD19,0x0D3D3E1A,0x1E6DCDEE,0xEC064EED, + 0xC38D26C4,0x31E6A5C7,0x22B65633,0xD0DDD530,0x0417B1DB,0xF67C32D8,0xE52CC12C,0x1747422F,0x49547E0B,0xBB3FFD08,0xA86F0EFC,0x5A048DFF,0x8ECEE914,0x7CA56A17,0x6FF599E3,0x9D9E1AE0, + 0xD3D3E1AB,0x21B862A8,0x32E8915C,0xC083125F,0x144976B4,0xE622F5B7,0xF5720643,0x07198540,0x590AB964,0xAB613A67,0xB831C993,0x4A5A4A90,0x9E902E7B,0x6CFBAD78,0x7FAB5E8C,0x8DC0DD8F, + 0xE330A81A,0x115B2B19,0x020BD8ED,0xF0605BEE,0x24AA3F05,0xD6C1BC06,0xC5914FF2,0x37FACCF1,0x69E9F0D5,0x9B8273D6,0x88D28022,0x7AB90321,0xAE7367CA,0x5C18E4C9,0x4F48173D,0xBD23943E, + 0xF36E6F75,0x0105EC76,0x12551F82,0xE03E9C81,0x34F4F86A,0xC69F7B69,0xD5CF889D,0x27A40B9E,0x79B737BA,0x8BDCB4B9,0x988C474D,0x6AE7C44E,0xBE2DA0A5,0x4C4623A6,0x5F16D052,0xAD7D5351 }; // Known size hash diff --git a/imgui.h b/imgui.h index 35a903889246..30115e810b30 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.6 WIP" -#define IMGUI_VERSION_NUM 19151 +#define IMGUI_VERSION_NUM 19152 #define IMGUI_HAS_TABLE /* From 326dc95f9c7ab7adf6ee63f4221b64b4002b6bed Mon Sep 17 00:00:00 2001 From: Teselka <53512153+Teselka@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:10:36 +0200 Subject: [PATCH 048/716] Misc: use native crc32 instructions on SEE 4.2 targets. (#8169, #4933) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 18 ++++++++++++++++++ imgui_internal.h | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e901e437eb69..b93888c85f63 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,7 @@ Other changes: - Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. - Demo: example tree used by Property Editor & Selection demos properly freed on application closure. (#8158) [@Legulysse] +- Misc: use SSE 4.2 crc32 instructions when available. (#8169, #4933) [@Teselka] - Backends: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize then the backend will create and manage one itself. (#8172, #4867) [@zeux] diff --git a/imgui.cpp b/imgui.cpp index 072c09799635..ff5d25408cc7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2150,6 +2150,7 @@ void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, } } +#ifndef IMGUI_ENABLE_SSE4_2 // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. @@ -2173,6 +2174,7 @@ static const ImU32 GCrc32LookupTable[256] = 0xE330A81A,0x115B2B19,0x020BD8ED,0xF0605BEE,0x24AA3F05,0xD6C1BC06,0xC5914FF2,0x37FACCF1,0x69E9F0D5,0x9B8273D6,0x88D28022,0x7AB90321,0xAE7367CA,0x5C18E4C9,0x4F48173D,0xBD23943E, 0xF36E6F75,0x0105EC76,0x12551F82,0xE03E9C81,0x34F4F86A,0xC69F7B69,0xD5CF889D,0x27A40B9E,0x79B737BA,0x8BDCB4B9,0x988C474D,0x6AE7C44E,0xBE2DA0A5,0x4C4623A6,0x5F16D052,0xAD7D5351 }; +#endif // Known size hash // It is ok to call ImHashData on a string with known length but the ### operator won't be supported. @@ -2181,10 +2183,16 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) { ImU32 crc = ~seed; const unsigned char* data = (const unsigned char*)data_p; +#ifndef IMGUI_ENABLE_SSE4_2 const ImU32* crc32_lut = GCrc32LookupTable; while (data_size-- != 0) crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; return ~crc; +#else + while (data_size-- != 0) + crc = _mm_crc32_u8(crc, *data++); + return ~crc; +#endif } // Zero-terminated string hash, with support for ### to reset back to seed value @@ -2198,7 +2206,9 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) seed = ~seed; ImU32 crc = seed; const unsigned char* data = (const unsigned char*)data_p; +#ifndef IMGUI_ENABLE_SSE4_2 const ImU32* crc32_lut = GCrc32LookupTable; +#endif if (data_size != 0) { while (data_size-- != 0) @@ -2206,7 +2216,11 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) unsigned char c = *data++; if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') crc = seed; +#ifndef IMGUI_ENABLE_SSE4_2 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; +#else + crc = _mm_crc32_u8(crc, c); +#endif } } else @@ -2215,7 +2229,11 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) { if (c == '#' && data[0] == '#' && data[1] == '#') crc = seed; +#ifndef IMGUI_ENABLE_SSE4_2 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; +#else + crc = _mm_crc32_u8(crc, c); +#endif } } return ~crc; diff --git a/imgui_internal.h b/imgui_internal.h index 40cf3c0c37ae..fd8a185a597d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -61,6 +61,10 @@ Index of this file: #if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) #define IMGUI_ENABLE_SSE #include +#if (defined __AVX__ || defined __SSE4_2__) +#define IMGUI_ENABLE_SSE4_2 +#include +#endif #endif // Visual Studio warnings From 2d660108b27a5c03ea8bd8bbd70a0aa3054b995a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 12:34:16 +0100 Subject: [PATCH 049/716] Misc: amend crc32 to use _mm_crc32_u32. (#8169, #4933) --- imgui.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ff5d25408cc7..5f6c859007c5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2183,13 +2183,19 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) { ImU32 crc = ~seed; const unsigned char* data = (const unsigned char*)data_p; + const unsigned char *data_end = (const unsigned char*)data_p + data_size; #ifndef IMGUI_ENABLE_SSE4_2 const ImU32* crc32_lut = GCrc32LookupTable; - while (data_size-- != 0) + while (data < data_end) crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; return ~crc; #else - while (data_size-- != 0) + while (data + 4 <= data_end) + { + crc = _mm_crc32_u32(crc, *(ImU32*)data); + data += 4; + } + while (data < data_end) crc = _mm_crc32_u8(crc, *data++); return ~crc; #endif From 96877eb9c30192d8d99b632a66418c037b92913e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 12:38:12 +0100 Subject: [PATCH 050/716] Backends: Vulkan: fixed build with VK_NO_PROTOTYPES. (#8172, #4867) Amend 61ab94d --- backends/imgui_impl_vulkan.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 1d2d8a19d66a..8a61a81ba9d2 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -147,6 +147,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkCreateSwapchainKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyCommandPool) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorPool) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyDescriptorSetLayout) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFence) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroyFramebuffer) \ From 90dd510df1e2fa85c490ddc97e2ea059c46e9fd3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Oct 2024 17:45:28 +0200 Subject: [PATCH 051/716] Backends: DX11: create sampler outside of ImGui_ImplDX11_CreateFontsTexture(). --- backends/imgui_impl_dx11.cpp | 40 +++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index b928bb86fbc0..4316a9f1069b 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -364,21 +364,16 @@ static void ImGui_ImplDX11_CreateFontsTexture() // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); +} - // Create texture sampler - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) +static void ImGui_ImplDX11_DestroyFontsTexture() +{ + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); + if (bd->pFontTextureView) { - D3D11_SAMPLER_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; - desc.MipLODBias = 0.f; - desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; - desc.MinLOD = 0.f; - desc.MaxLOD = 0.f; - bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); + bd->pFontTextureView->Release(); + bd->pFontTextureView = nullptr; + ImGui::GetIO().Fonts->SetTexID(0); // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. } } @@ -531,6 +526,22 @@ bool ImGui_ImplDX11_CreateDeviceObjects() bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); } + // Create texture sampler + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + { + D3D11_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); + } + ImGui_ImplDX11_CreateFontsTexture(); return true; @@ -542,8 +553,9 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (!bd->pd3dDevice) return; + ImGui_ImplDX11_DestroyFontsTexture(); + if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } - if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } From c1123fd8d0519942c4347708af999d876e7b7728 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 14:17:32 +0100 Subject: [PATCH 052/716] Backends: Vulkan: small refactor to use a texture struct. --- backends/imgui_impl_vulkan.cpp | 101 ++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 8a61a81ba9d2..2d966408986e 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -213,6 +213,16 @@ struct ImGui_ImplVulkan_WindowRenderBuffers ImGui_ImplVulkan_FrameRenderBuffers* FrameRenderBuffers; }; +struct ImGui_ImplVulkan_Texture +{ + VkDeviceMemory Memory; + VkImage Image; + VkImageView ImageView; + VkDescriptorSet DescriptorSet; + + ImGui_ImplVulkan_Texture() { memset(this, 0, sizeof(*this)); } +}; + // Vulkan data struct ImGui_ImplVulkan_Data { @@ -226,14 +236,11 @@ struct ImGui_ImplVulkan_Data VkShaderModule ShaderModuleFrag; VkDescriptorPool DescriptorPool; - // Font data - VkSampler FontSampler; - VkDeviceMemory FontMemory; - VkImage FontImage; - VkImageView FontView; - VkDescriptorSet FontDescriptorSet; - VkCommandPool FontCommandPool; - VkCommandBuffer FontCommandBuffer; + // Texture management + ImGui_ImplVulkan_Texture FontTexture; + VkSampler TexSampler; + VkCommandPool TexCommandPool; + VkCommandBuffer TexCommandBuffer; // Render buffers for main window ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; @@ -598,8 +605,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (sizeof(ImTextureID) < sizeof(ImU64)) { // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used. - IM_ASSERT(pcmd->GetTexID() == (ImTextureID)bd->FontDescriptorSet); - desc_set[0] = bd->FontDescriptorSet; + IM_ASSERT(pcmd->GetTexID() == (ImTextureID)bd->FontTexture.DescriptorSet); + desc_set[0] = bd->FontTexture.DescriptorSet; } vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr); @@ -631,39 +638,39 @@ bool ImGui_ImplVulkan_CreateFontsTexture() VkResult err; // Destroy existing texture (if any) - if (bd->FontView || bd->FontImage || bd->FontMemory || bd->FontDescriptorSet) + if (bd->FontTexture.DescriptorSet) { vkQueueWaitIdle(v->Queue); ImGui_ImplVulkan_DestroyFontsTexture(); } // Create command pool/buffer - if (bd->FontCommandPool == VK_NULL_HANDLE) + if (bd->TexCommandPool == VK_NULL_HANDLE) { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; info.flags = 0; info.queueFamilyIndex = v->QueueFamily; - vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->FontCommandPool); + vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->TexCommandPool); } - if (bd->FontCommandBuffer == VK_NULL_HANDLE) + if (bd->TexCommandBuffer == VK_NULL_HANDLE) { VkCommandBufferAllocateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = bd->FontCommandPool; + info.commandPool = bd->TexCommandPool; info.commandBufferCount = 1; - err = vkAllocateCommandBuffers(v->Device, &info, &bd->FontCommandBuffer); + err = vkAllocateCommandBuffers(v->Device, &info, &bd->TexCommandBuffer); check_vk_result(err); } // Start command buffer { - err = vkResetCommandPool(v->Device, bd->FontCommandPool, 0); + err = vkResetCommandPool(v->Device, bd->TexCommandPool, 0); check_vk_result(err); VkCommandBufferBeginInfo begin_info = {}; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(bd->FontCommandBuffer, &begin_info); + err = vkBeginCommandBuffer(bd->TexCommandBuffer, &begin_info); check_vk_result(err); } @@ -673,6 +680,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() size_t upload_size = width * height * 4 * sizeof(char); // Create the Image: + ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; { VkImageCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -688,17 +696,17 @@ bool ImGui_ImplVulkan_CreateFontsTexture() info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - err = vkCreateImage(v->Device, &info, v->Allocator, &bd->FontImage); + err = vkCreateImage(v->Device, &info, v->Allocator, &backend_tex->Image); check_vk_result(err); VkMemoryRequirements req; - vkGetImageMemoryRequirements(v->Device, bd->FontImage, &req); + vkGetImageMemoryRequirements(v->Device, backend_tex->Image, &req); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->FontMemory); + err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &backend_tex->Memory); check_vk_result(err); - err = vkBindImageMemory(v->Device, bd->FontImage, bd->FontMemory, 0); + err = vkBindImageMemory(v->Device, backend_tex->Image, backend_tex->Memory, 0); check_vk_result(err); } @@ -706,18 +714,18 @@ bool ImGui_ImplVulkan_CreateFontsTexture() { VkImageViewCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - info.image = bd->FontImage; + info.image = backend_tex->Image; info.viewType = VK_IMAGE_VIEW_TYPE_2D; info.format = VK_FORMAT_R8G8B8A8_UNORM; info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; info.subresourceRange.levelCount = 1; info.subresourceRange.layerCount = 1; - err = vkCreateImageView(v->Device, &info, v->Allocator, &bd->FontView); + err = vkCreateImageView(v->Device, &info, v->Allocator, &backend_tex->ImageView); check_vk_result(err); } // Create the Descriptor Set: - bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSampler, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); // Create the Upload Buffer: VkDeviceMemory upload_buffer_memory; @@ -767,11 +775,11 @@ bool ImGui_ImplVulkan_CreateFontsTexture() copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - copy_barrier[0].image = bd->FontImage; + copy_barrier[0].image = backend_tex->Image; copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->FontCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); + vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -779,7 +787,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() region.imageExtent.width = width; region.imageExtent.height = height; region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(bd->FontCommandBuffer, upload_buffer, bd->FontImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + vkCmdCopyBufferToImage(bd->TexCommandBuffer, upload_buffer, backend_tex->Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier[1] = {}; use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -789,22 +797,22 @@ bool ImGui_ImplVulkan_CreateFontsTexture() use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - use_barrier[0].image = bd->FontImage; + use_barrier[0].image = backend_tex->Image; use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->FontCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); + vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); } // Store our identifier - io.Fonts->SetTexID((ImTextureID)bd->FontDescriptorSet); + io.Fonts->SetTexID((ImTextureID)backend_tex->DescriptorSet); // End command buffer VkSubmitInfo end_info = {}; end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &bd->FontCommandBuffer; - err = vkEndCommandBuffer(bd->FontCommandBuffer); + end_info.pCommandBuffers = &bd->TexCommandBuffer; + err = vkEndCommandBuffer(bd->TexCommandBuffer); check_vk_result(err); err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); check_vk_result(err); @@ -825,16 +833,17 @@ void ImGui_ImplVulkan_DestroyFontsTexture() ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (bd->FontDescriptorSet) + ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; + + if (backend_tex->DescriptorSet) { - ImGui_ImplVulkan_RemoveTexture(bd->FontDescriptorSet); - bd->FontDescriptorSet = VK_NULL_HANDLE; + ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); + backend_tex->DescriptorSet = VK_NULL_HANDLE; io.Fonts->SetTexID(0); } - - if (bd->FontView) { vkDestroyImageView(v->Device, bd->FontView, v->Allocator); bd->FontView = VK_NULL_HANDLE; } - if (bd->FontImage) { vkDestroyImage(v->Device, bd->FontImage, v->Allocator); bd->FontImage = VK_NULL_HANDLE; } - if (bd->FontMemory) { vkFreeMemory(v->Device, bd->FontMemory, v->Allocator); bd->FontMemory = VK_NULL_HANDLE; } + if (backend_tex->ImageView) { vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); backend_tex->ImageView = VK_NULL_HANDLE; } + if (backend_tex->Image) { vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); backend_tex->Image = VK_NULL_HANDLE; } + if (backend_tex->Memory) { vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); backend_tex->Memory = VK_NULL_HANDLE; } } static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) @@ -982,7 +991,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; VkResult err; - if (!bd->FontSampler) + if (!bd->TexSampler) { // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. VkSamplerCreateInfo info = {}; @@ -996,7 +1005,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() info.minLod = -1000; info.maxLod = 1000; info.maxAnisotropy = 1.0f; - err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->FontSampler); + err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->TexSampler); check_vk_result(err); } @@ -1058,11 +1067,11 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); ImGui_ImplVulkan_DestroyFontsTexture(); - if (bd->FontCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->FontCommandPool, 1, &bd->FontCommandBuffer); bd->FontCommandBuffer = VK_NULL_HANDLE; } - if (bd->FontCommandPool) { vkDestroyCommandPool(v->Device, bd->FontCommandPool, v->Allocator); bd->FontCommandPool = VK_NULL_HANDLE; } + if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; } + if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; } + if (bd->TexSampler) { vkDestroySampler(v->Device, bd->TexSampler, v->Allocator); bd->TexSampler = VK_NULL_HANDLE; } if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } - if (bd->FontSampler) { vkDestroySampler(v->Device, bd->FontSampler, v->Allocator); bd->FontSampler = VK_NULL_HANDLE; } if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; } if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; } if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; } @@ -1163,7 +1172,7 @@ void ImGui_ImplVulkan_NewFrame() ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?"); - if (!bd->FontDescriptorSet) + if (!bd->FontTexture.DescriptorSet) ImGui_ImplVulkan_CreateFontsTexture(); } From dda7672008e4f447a4a179d30cf5745fd5a18fb0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 Nov 2024 19:23:01 +0100 Subject: [PATCH 053/716] Backends: Vulkan: removed sizeof(ImTextureID) check. (not necessary anymore and it happens to when with a later coming change of ImTextureID, so best removed earlier). --- backends/imgui_impl_vulkan.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 2d966408986e..69f4937629cb 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -601,14 +601,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm vkCmdSetScissor(command_buffer, 0, 1, &scissor); // Bind DescriptorSet with font or user texture - VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->GetTexID() }; - if (sizeof(ImTextureID) < sizeof(ImU64)) - { - // We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used. - IM_ASSERT(pcmd->GetTexID() == (ImTextureID)bd->FontTexture.DescriptorSet); - desc_set[0] = bd->FontTexture.DescriptorSet; - } - vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, nullptr); + VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID(); + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr); // Draw vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); From 9b26743c6b30d647662c3ef315d9968fde4c1033 Mon Sep 17 00:00:00 2001 From: Diego Mateos Date: Fri, 29 Nov 2024 13:31:11 +0100 Subject: [PATCH 054/716] SliderAngle: only write back to value v_rad on value_changed. (#8193) --- imgui_widgets.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 81b480cb174b..f9939cec430f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3329,7 +3329,8 @@ bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, fl format = "%.0f deg"; float v_deg = (*v_rad) * 360.0f / (2 * IM_PI); bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags); - *v_rad = v_deg * (2 * IM_PI) / 360.0f; + if (value_changed) + *v_rad = v_deg * (2 * IM_PI) / 360.0f; return value_changed; } From 19a1f2a5d2cb1366d7c702e905e6aa5ed4b1ab12 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 18:46:17 +0100 Subject: [PATCH 055/716] Fonts: fixed AddCustomRect() not being packed with TexGlyphPadding + not accounted in surface area. (#8107) --- docs/CHANGELOG.txt | 2 ++ imgui.h | 6 +++--- imgui_draw.cpp | 18 +++++++++++------- misc/freetype/imgui_freetype.cpp | 4 +++- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b93888c85f63..6650debf0238 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,8 @@ Other changes: - Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. - Demo: example tree used by Property Editor & Selection demos properly freed on application closure. (#8158) [@Legulysse] +- Fonts: fixed AddCustomRect() not being packed with TexGlyphPadding + not accounted + for surface area used to determine best-guess texture size. (#8107) [@YarikTH, @ocornut] - Misc: use SSE 4.2 crc32 instructions when available. (#8169, #4933) [@Teselka] - Backends: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize then the backend will create and manage diff --git a/imgui.h b/imgui.h index 30115e810b30..423e2a8bae82 100644 --- a/imgui.h +++ b/imgui.h @@ -3230,8 +3230,8 @@ struct ImFontConfig float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. - bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. - ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. + bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font @@ -3389,7 +3389,7 @@ struct ImFontAtlas ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. - int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index fd1feb0a84a5..631472a71dd6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2941,6 +2941,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) int total_surface = 0; int buf_rects_out_n = 0; int buf_packedchars_out_n = 0; + const int pack_padding = atlas->TexGlyphPadding; for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; @@ -2964,18 +2965,19 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity); - const int padding = atlas->TexGlyphPadding; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) { int x0, y0, x1, y1; const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); IM_ASSERT(glyph_index_in_font != 0); stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); - src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + cfg.OversampleH - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + cfg.OversampleV - 1); total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } + for (int i = 0; i < atlas->CustomRects.Size; i++) + total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding); // We need a width for the skyline algorithm, any width! // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. @@ -2991,7 +2993,8 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). const int TEX_HEIGHT_MAX = 1024 * 32; stbtt_pack_context spc = {}; - stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL); + stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, 0, NULL); + spc.padding = atlas->TexGlyphPadding; // Because we mixup stbtt_PackXXX and stbrp_PackXXX there's a bit of a hack here, not passing the value to stbtt_PackBegin() allows us to still pack a TexWidth-1 wide item. (#8107) ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. @@ -3137,13 +3140,14 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343) #endif + const int pack_padding = atlas->TexGlyphPadding; ImVector pack_rects; pack_rects.resize(user_rects.Size); memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); for (int i = 0; i < user_rects.Size; i++) { - pack_rects[i].w = user_rects[i].Width; - pack_rects[i].h = user_rects[i].Height; + pack_rects[i].w = user_rects[i].Width + pack_padding; + pack_rects[i].h = user_rects[i].Height + pack_padding; } stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); for (int i = 0; i < pack_rects.Size; i++) @@ -3151,7 +3155,7 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa { user_rects[i].X = (unsigned short)pack_rects[i].x; user_rects[i].Y = (unsigned short)pack_rects[i].y; - IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); + IM_ASSERT(pack_rects[i].w == user_rects[i].Width + pack_padding && pack_rects[i].h == user_rects[i].Height + pack_padding); atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); } } diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index e68a2af40bbd..bee15ba08399 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -573,6 +573,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // 8. Render/rasterize font characters into the texture int total_surface = 0; int buf_rects_out_n = 0; + const int pack_padding = atlas->TexGlyphPadding; for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; @@ -590,7 +591,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); // Gather the sizes of all rectangles we will need to pack - const int padding = atlas->TexGlyphPadding; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) { ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; @@ -623,6 +623,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } + for (int i = 0; i < atlas->CustomRects.Size; i++) + total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding); // We need a width for the skyline algorithm, any width! // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. From ee2119d7cbe1361689f9a7a6ef6853c1deae08f6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 19:10:39 +0100 Subject: [PATCH 056/716] imgui_freetype: Fix build broken by 19a1f2a (#8107) --- misc/freetype/imgui_freetype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index bee15ba08399..1bd3be65ad7a 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -618,8 +618,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u buf_bitmap_current_used_bytes += bitmap_size_in_bytes; src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr); - src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + pack_padding); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + pack_padding); total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } From 43c51eb12d187d9113af0f646d24da9e8cc04c83 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Dec 2024 13:23:09 +0100 Subject: [PATCH 057/716] Tables: fixed SetNextWindowScroll() value being ignored by BeginTable() during the first frame or when scrolling flags have changed. (#8196) --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6650debf0238..874c7502f5bb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,8 @@ Other changes: - Error Handling: fixed cases where recoverable error handling would crash when processing errors outside of the NewFrame()..EndFrame() scope. (#1651) +- Tables: fixed SetNextWindowScroll() value being ignored by BeginTable() during + the first frame or when scrolling flags have changed. (#8196) - Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). - Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) [@demonese] diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5254f7858743..db34aa347d00 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -410,7 +410,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Reset scroll if we are reactivating it if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) - SetNextWindowScroll(ImVec2(0.0f, 0.0f)); + if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) == 0) + SetNextWindowScroll(ImVec2(0.0f, 0.0f)); // Create scrolling region (without border and zero window padding) ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; From 923ca4765a8a6b4cc10b7f438c8e63a25d1f5c61 Mon Sep 17 00:00:00 2001 From: Thomas Hope Date: Sat, 30 Nov 2024 16:58:48 +0100 Subject: [PATCH 058/716] Backends: OpenGL3: Fix compile error with IMGUI_IMPL_OPENGL_ES2 and IMGUI_IMPL_OPENGL_DEBUG (#8197) --- backends/imgui_impl_opengl3.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 57c699421d19..8f3177837423 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -299,6 +299,8 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) // Query for GL version (e.g. 320 for GL 3.2) #if defined(IMGUI_IMPL_OPENGL_ES2) // GLES 2 + const char* gl_version_str = ""; + IM_UNUSED(gl_version_str); // For IMGUI_IMPL_OPENGL_DEBUG block below. bd->GlVersion = 200; bd->GlProfileIsES2 = true; #else @@ -336,7 +338,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) #endif #ifdef IMGUI_IMPL_OPENGL_DEBUG - printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] + printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2/IsEs3 = %d/%d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG] #endif #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET From 70b6ba42402f27b40760c15c7d7e926cc06c96fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Dec 2024 10:38:19 +0100 Subject: [PATCH 059/716] Clarify that IMGUI_USE_BGRA_PACKED_COLOR requires backend support. (#8201) --- backends/imgui_impl_dx9.cpp | 1 + backends/imgui_impl_dx9.h | 1 + imconfig.h | 2 +- imgui.h | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index c97d3c740ef9..ee0e239409b6 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -4,6 +4,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR is supported, as this is the optimal color encoding for DirectX9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index df6a0a012479..c096b3398e3c 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -4,6 +4,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR is supported, as this is the optimal color encoding for DirectX9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/imconfig.h b/imconfig.h index 3504a4e4d369..6790f147ac85 100644 --- a/imconfig.h +++ b/imconfig.h @@ -59,7 +59,7 @@ //#define IMGUI_INCLUDE_IMGUI_USER_H //#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h" -//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) +//---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support. //#define IMGUI_USE_BGRA_PACKED_COLOR //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) diff --git a/imgui.h b/imgui.h index 423e2a8bae82..b86c7d4e5d89 100644 --- a/imgui.h +++ b/imgui.h @@ -2715,7 +2715,8 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE #endif // Helpers macros to generate 32-bit encoded colors -// User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. +// - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. +// - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. #ifndef IM_COL32_R_SHIFT #ifdef IMGUI_USE_BGRA_PACKED_COLOR #define IM_COL32_R_SHIFT 16 From 6f6ac84228a6502b6f21c7dc3641195783a06fb2 Mon Sep 17 00:00:00 2001 From: Jack Holmes Date: Wed, 4 Dec 2024 17:59:51 +0000 Subject: [PATCH 060/716] Demo: Assets Browser: use correct axis for layout computation, to allow making items non-square. (#8207) --- imgui_demo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c822c162e567..5efbe6304538 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10175,7 +10175,7 @@ struct ExampleAssetsBrowser } ImGuiIO& io = ImGui::GetIO(); - ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.x + LayoutItemSpacing))); + ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.y + LayoutItemSpacing))); if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove)) { ImDrawList* draw_list = ImGui::GetWindowDrawList(); From 566558b17c528b82d88236d9e38d270eb766c261 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 12:25:02 +0100 Subject: [PATCH 061/716] Replacing NULL with nullptr in examples/backends when they creeped back. (#6313, #7071, #4537) --- backends/imgui_impl_dx11.cpp | 2 +- backends/imgui_impl_dx12.cpp | 6 +++--- backends/imgui_impl_glfw.cpp | 4 ++-- backends/imgui_impl_sdl2.cpp | 14 +++++++------- backends/imgui_impl_sdl2.h | 2 +- backends/imgui_impl_sdl3.cpp | 22 +++++++++++----------- backends/imgui_impl_sdl3.h | 2 +- backends/imgui_impl_sdlrenderer2.cpp | 2 +- backends/imgui_impl_sdlrenderer3.cpp | 2 +- backends/imgui_impl_vulkan.cpp | 4 ++-- backends/imgui_impl_wgpu.cpp | 2 +- backends/imgui_impl_win32.cpp | 4 ++-- examples/example_win32_directx12/main.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 2 +- 14 files changed, 35 insertions(+), 35 deletions(-) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 4316a9f1069b..4a87c23a17cc 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -298,7 +298,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = NULL; + platform_io.Renderer_RenderState = nullptr; // Restore modified DX state device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index acf98858b55f..a020941286b6 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -311,7 +311,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = NULL; + platform_io.Renderer_RenderState = nullptr; } static void ImGui_ImplDX12_CreateFontsTexture() @@ -743,7 +743,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (init_info->SrvDescriptorAllocFn == NULL) + if (init_info->SrvDescriptorAllocFn == nullptr) { // Wrap legacy behavior of passing space for a single descriptor IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); @@ -765,7 +765,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) #endif // Allocate 1 SRV descriptor for the font texture - IM_ASSERT(init_info->SrvDescriptorAllocFn != NULL && init_info->SrvDescriptorFreeFn != NULL); + IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr); init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); // Create buffers with a default size (they will later be grown as needed) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index afa2185a3b67..1cdb2534fe5c 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -595,8 +595,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Time = 0.0; ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(NULL, text); }; - platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(NULL); }; + platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(nullptr, text); }; + platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(nullptr); }; #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; #endif diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 14022159f8c4..af5f6b0132cb 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -324,7 +324,7 @@ static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id) { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL; + return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr; } // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. @@ -342,7 +342,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) { case SDL_MOUSEMOTION: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == NULL) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == nullptr) return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -351,7 +351,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_MOUSEWHEEL: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == NULL) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == nullptr) return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); #if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten! @@ -371,7 +371,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == NULL) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == nullptr) return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } @@ -388,7 +388,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_TEXTINPUT: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == NULL) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == nullptr) return false; io.AddInputCharactersUTF8(event->text.text); return true; @@ -396,7 +396,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) case SDL_KEYDOWN: case SDL_KEYUP: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == NULL) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr) return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); @@ -406,7 +406,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) } case SDL_WINDOWEVENT: { - if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == NULL) + if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == nullptr) return false; // - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right. // - However we won't get a correct LEAVE event for a captured window. diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 8ccc6fdc7c62..e071e97155e2 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -41,6 +41,6 @@ IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. // When using manual mode, caller is responsible for opening/closing gamepad. enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1); +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 3cd56a756a6a..0955859a5534 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -128,7 +128,7 @@ static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); const char* sdl_clipboard_text = SDL_GetClipboardText(); - bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : NULL; + bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : nullptr; return bd->ClipboardTextData; } @@ -142,7 +142,7 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; SDL_Window* window = SDL_GetWindowFromID(window_id); - if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != NULL) + if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != nullptr) { SDL_StopTextInput(bd->ImeWindow); bd->ImeWindow = nullptr; @@ -308,7 +308,7 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods) static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id) { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); - return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : NULL; + return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr; } // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. @@ -326,7 +326,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { case SDL_EVENT_MOUSE_MOTION: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == nullptr) return false; ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y); io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse); @@ -335,7 +335,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_MOUSE_WHEEL: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->wheel.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->wheel.windowID) == nullptr) return false; //IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY); float wheel_x = -event->wheel.x; @@ -347,7 +347,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->button.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->button.windowID) == nullptr) return false; int mouse_button = -1; if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; } @@ -364,7 +364,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_TEXT_INPUT: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->text.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->text.windowID) == nullptr) return false; io.AddInputCharactersUTF8(event->text.text); return true; @@ -372,7 +372,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_UP: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == nullptr) return false; //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); @@ -383,7 +383,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) } case SDL_EVENT_WINDOW_MOUSE_ENTER: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) return false; bd->MouseWindowID = event->window.windowID; bd->MousePendingLeaveFrame = 0; @@ -395,7 +395,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) return false; bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; @@ -403,7 +403,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_WINDOW_FOCUS_GAINED: case SDL_EVENT_WINDOW_FOCUS_LOST: { - if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == NULL) + if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr) return false; io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED); return true; diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index c4a5a1230e3c..b86aa1901839 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -42,6 +42,6 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. // When using manual mode, caller is responsible for opening/closing gamepad. enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual }; -IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = NULL, int manual_gamepads_count = -1); +IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 27c9522697a6..485adabb3438 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -208,7 +208,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* } } } - platform_io.Renderer_RenderState = NULL; + platform_io.Renderer_RenderState = nullptr; // Restore modified SDL_Renderer state SDL_RenderSetViewport(renderer, &old.Viewport); diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 5dabea199647..1238246c2fb4 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -227,7 +227,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* } } } - platform_io.Renderer_RenderState = NULL; + platform_io.Renderer_RenderState = nullptr; // Restore modified SDL_Renderer state SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr); diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 69f4937629cb..1491ccabf49c 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -611,7 +611,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = NULL; + platform_io.Renderer_RenderState = nullptr; // Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called. // Our last values will leak into user/application rendering IF: @@ -969,7 +969,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC if (bd->VulkanInitInfo.UseDynamicRendering) { IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be NULL"); + IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be nullptr"); info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 075f74734a1f..02a8caeb4c50 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -518,7 +518,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } - platform_io.Renderer_RenderState = NULL; + platform_io.Renderer_RenderState = nullptr; } static void ImGui_ImplWGPU_CreateFontsTexture() diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 687bc5a18d61..843ef161bfe0 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -588,7 +588,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA { // Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow(). // We silently allow both context or just only backend data to be nullptr. - if (ImGui::GetCurrentContext() == NULL) + if (ImGui::GetCurrentContext() == nullptr) return 0; return ImGui_ImplWin32_WndProcHandlerEx(hwnd, msg, wParam, lParam, ImGui::GetIO()); } @@ -597,7 +597,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io) { ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); - if (bd == NULL) + if (bd == nullptr) return 0; switch (msg) { diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 257410e2cb2e..eeff99c1be8b 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -58,7 +58,7 @@ struct ExampleDescriptorHeapAllocator } void Destroy() { - Heap = NULL; + Heap = nullptr; FreeIndices.clear(); } void Alloc(D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 1bd3be65ad7a..aeab6dfa0689 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -10,7 +10,7 @@ // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. // 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG'. (#6591) // 2023/01/04: fixed a packing issue which in some occurrences would prevent large amount of glyphs from being packed correctly. -// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL. +// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns nullptr. // 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs. // 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a preferred texture format. // 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+). From 43fbd7ce8405d48caa90cd2d2b244c059288744d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 12:43:04 +0100 Subject: [PATCH 062/716] Backends: standardized top of file comments. --- backends/imgui_impl_allegro5.cpp | 6 +++--- backends/imgui_impl_allegro5.h | 6 +++--- backends/imgui_impl_android.cpp | 4 ++-- backends/imgui_impl_android.h | 4 ++-- backends/imgui_impl_dx10.cpp | 2 +- backends/imgui_impl_dx10.h | 2 +- backends/imgui_impl_dx11.cpp | 2 +- backends/imgui_impl_dx11.h | 2 +- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx12.h | 2 +- backends/imgui_impl_dx9.cpp | 4 ++-- backends/imgui_impl_dx9.h | 4 ++-- backends/imgui_impl_glfw.cpp | 2 +- backends/imgui_impl_glfw.h | 2 +- backends/imgui_impl_glut.cpp | 2 +- backends/imgui_impl_glut.h | 2 +- backends/imgui_impl_metal.h | 2 +- backends/imgui_impl_metal.mm | 2 +- backends/imgui_impl_opengl2.cpp | 2 ++ backends/imgui_impl_opengl2.h | 2 ++ backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_opengl3.h | 2 +- backends/imgui_impl_osx.h | 4 ++-- backends/imgui_impl_osx.mm | 4 ++-- backends/imgui_impl_sdl2.cpp | 2 +- backends/imgui_impl_sdl2.h | 2 +- backends/imgui_impl_sdl3.cpp | 3 ++- backends/imgui_impl_sdl3.h | 3 ++- backends/imgui_impl_sdlrenderer2.cpp | 2 +- backends/imgui_impl_sdlrenderer2.h | 2 +- backends/imgui_impl_sdlrenderer3.cpp | 2 +- backends/imgui_impl_sdlrenderer3.h | 2 +- backends/imgui_impl_vulkan.cpp | 4 ++-- backends/imgui_impl_vulkan.h | 4 ++-- backends/imgui_impl_wgpu.cpp | 2 +- backends/imgui_impl_wgpu.h | 2 +- backends/imgui_impl_win32.cpp | 2 +- backends/imgui_impl_win32.h | 2 +- 38 files changed, 54 insertions(+), 48 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 3e6d766470e0..28d1b1536f47 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -4,9 +4,9 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Clipboard support (from Allegro 5.1.12) -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// Issues: +// [X] Platform: Clipboard support (from Allegro 5.1.12). +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features or Issues: // [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually. // [ ] Platform: Missing gamepad support. diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index aba5c47701ea..356ec7d0a9f4 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -4,9 +4,9 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Clipboard support (from Allegro 5.1.12) -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. -// Issues: +// [X] Platform: Clipboard support (from Allegro 5.1.12). +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features or Issues: // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. // [ ] Platform: Missing gamepad support. diff --git a/backends/imgui_impl_android.cpp b/backends/imgui_impl_android.cpp index 05939293cb84..1c2d62476002 100644 --- a/backends/imgui_impl_android.cpp +++ b/backends/imgui_impl_android.cpp @@ -4,10 +4,10 @@ // Implemented features: // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// Missing features: +// Missing features or Issues: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. +// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) diff --git a/backends/imgui_impl_android.h b/backends/imgui_impl_android.h index efe27dcb9568..3eaeca7253ae 100644 --- a/backends/imgui_impl_android.h +++ b/backends/imgui_impl_android.h @@ -4,10 +4,10 @@ // Implemented features: // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. -// Missing features: +// Missing features or Issues: // [ ] Platform: Clipboard support. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. +// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 2638caf9cadb..f160803ee6a1 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 667f296f17bd..29f339370f53 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 4a87c23a17cc..a2c67ec43f9e 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index c3b8379b14b7..69ae493586fb 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index a020941286b6..bad823c4a9ba 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 34938fb56347..0ade2ac99b36 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index ee0e239409b6..2cc8681a6d06 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -3,8 +3,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR is supported, as this is the optimal color encoding for DirectX9. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index c096b3398e3c..b693054d9b6b 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -3,8 +3,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR is supported, as this is the optimal color encoding for DirectX9. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 1cdb2534fe5c..01a6a5566397 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -8,7 +8,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 5d8940a0c98e..53a22415d87c 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -7,7 +7,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_glut.cpp b/backends/imgui_impl_glut.cpp index 6bb9eae7eeea..ef7f17922ec5 100644 --- a/backends/imgui_impl_glut.cpp +++ b/backends/imgui_impl_glut.cpp @@ -7,7 +7,7 @@ // Implemented features: // [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values are obsolete since 1.87 and not supported since 1.91.5] -// Issues: +// Missing features or Issues: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: Missing horizontal mouse wheel support. // [ ] Platform: Missing mouse cursor shape/visibility support. diff --git a/backends/imgui_impl_glut.h b/backends/imgui_impl_glut.h index feeca8b3fcd0..20e77dbceb70 100644 --- a/backends/imgui_impl_glut.h +++ b/backends/imgui_impl_glut.h @@ -7,7 +7,7 @@ // Implemented features: // [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values are obsolete since 1.87 and not supported since 1.91.5] -// Issues: +// Missing features or Issues: // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: Missing horizontal mouse wheel support. // [ ] Platform: Missing mouse cursor shape/visibility support. diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 2402c02c62c8..351c2eff735c 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 12dc3d50f52c..5680dea9d40c 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 789d74afb2b6..767731fb39ea 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -3,6 +3,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// Missing features or Issues: +// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index e7f7a58c1f0e..5832a176599f 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -3,6 +3,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// Missing features or Issues: +// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 8f3177837423..efcfb8217358 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -5,7 +5,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! -// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). +// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] // About WebGL/ES: // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index 54545f957b91..5de51cfddaf9 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -5,7 +5,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! -// [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only). +// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] // About WebGL/ES: // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 4caab8ff5f73..2e7eabb2b415 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -4,11 +4,11 @@ // - Requires linking with the GameController framework ("-framework GameController"). // Implemented features: -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Clipboard support is part of core Dear ImGui (no specific code in this backend). // [X] Platform: Mouse support. Can discriminate Mouse/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index c99ba1f06cab..c2a5f6378a45 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -4,11 +4,11 @@ // - Requires linking with the GameController framework ("-framework GameController"). // Implemented features: -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Clipboard support is part of core Dear ImGui (no specific code in this backend). // [X] Platform: Mouse support. Can discriminate Mouse/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index af5f6b0132cb..e937b5496654 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -8,7 +8,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index e071e97155e2..3c477569777c 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -7,7 +7,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 0955859a5534..a167c74cd617 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -9,7 +9,8 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: IME support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index b86aa1901839..0d906a65cd32 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -9,7 +9,8 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: IME support. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 485adabb3438..6d0ee564f1b3 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -9,7 +9,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index 804ca183d14a..7aed18d21809 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -9,7 +9,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 1238246c2fb4..1bcf7a228b0a 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -11,7 +11,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 7d4c609e8b25..3a7a51ee545e 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -11,7 +11,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 1491ccabf49c..b419703048e0 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -2,8 +2,8 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 8d9e19f9a7ee..37f700b62160 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -2,8 +2,8 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 02a8caeb4c50..2f34c0e0b345 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -4,7 +4,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index f9fb037764f6..7efb02afe109 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -11,7 +11,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 843ef161bfe0..f1cf6eccc52b 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -6,7 +6,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index 0dfd56a801be..083fe385f6fa 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -6,7 +6,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. From 18e5d769fd7fc48b809ee3b8f6bef6906289251d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 13:08:33 +0100 Subject: [PATCH 063/716] Backends: DX10: create sampler outside of ImGui_ImplDX11_CreateFontsTexture(). Analoguous to 90dd510 for DX11. --- backends/imgui_impl_dx10.cpp | 42 +++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index f160803ee6a1..15f0bb323f5d 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -341,21 +341,16 @@ static void ImGui_ImplDX10_CreateFontsTexture() // Store our identifier io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); +} - // Create texture sampler - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) +static void ImGui_ImplDX10_DestroyFontsTexture() +{ + ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); + if (bd->pFontTextureView) { - D3D10_SAMPLER_DESC desc; - ZeroMemory(&desc, sizeof(desc)); - desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; - desc.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; - desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; - desc.MipLODBias = 0.f; - desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; - desc.MinLOD = 0.f; - desc.MaxLOD = 0.f; - bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); + bd->pFontTextureView->Release(); + bd->pFontTextureView = nullptr; + ImGui::GetIO().Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. } } @@ -508,6 +503,22 @@ bool ImGui_ImplDX10_CreateDeviceObjects() bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); } + // Create texture sampler + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + { + D3D10_SAMPLER_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR; + desc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP; + desc.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP; + desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP; + desc.MipLODBias = 0.f; + desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS; + desc.MinLOD = 0.f; + desc.MaxLOD = 0.f; + bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); + } + ImGui_ImplDX10_CreateFontsTexture(); return true; @@ -519,8 +530,9 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() if (!bd->pd3dDevice) return; + ImGui_ImplDX10_DestroyFontsTexture(); + if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } - if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } @@ -582,7 +594,7 @@ void ImGui_ImplDX10_NewFrame() ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX10_Init()?"); - if (!bd->pFontSampler) + if (!bd->pVertexShader) ImGui_ImplDX10_CreateDeviceObjects(); } From 3f3c62a3c999ae7004d6871c504c0694c9b9e2b1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Dec 2024 11:43:00 +0100 Subject: [PATCH 064/716] ScrollbarEx: clarify use of flags and make them optional. (#8215) --- imgui_internal.h | 2 +- imgui_widgets.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index fd8a185a597d..147e30c3569c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3398,7 +3398,7 @@ namespace ImGui IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos); IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos); IMGUI_API void Scrollbar(ImGuiAxis axis); - IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags flags); + IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 avail_v, ImS64 contents_v, ImDrawFlags draw_rounding_flags = 0); IMGUI_API ImRect GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis); IMGUI_API ImGuiID GetWindowResizeCornerID(ImGuiWindow* window, int n); // 0..3: corners diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f9939cec430f..cf6891ea18d7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -950,7 +950,7 @@ void ImGui::Scrollbar(ImGuiAxis axis) // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal. // Still, the code should probably be made simpler.. -bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_visible_v, ImS64 size_contents_v, ImDrawFlags flags) +bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_visible_v, ImS64 size_contents_v, ImDrawFlags draw_rounding_flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -1041,7 +1041,7 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 // Render const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg); const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha); - window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags); + window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, draw_rounding_flags); ImRect grab_rect; if (axis == ImGuiAxis_X) grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y); From 2671f68f7f8cb77bf951779c0c8e437f6171a324 Mon Sep 17 00:00:00 2001 From: slowriot Date: Fri, 6 Dec 2024 17:50:44 +0000 Subject: [PATCH 065/716] Don't enable SSE4 under Emscripten (#8213, #8169, #4933) Amend 326dc95f9 --- imgui.cpp | 10 +++++----- imgui_internal.h | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5f6c859007c5..5833691dbf14 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2150,7 +2150,7 @@ void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, } } -#ifndef IMGUI_ENABLE_SSE4_2 +#ifndef IMGUI_ENABLE_SSE4_2_CRC // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. @@ -2184,7 +2184,7 @@ ImGuiID ImHashData(const void* data_p, size_t data_size, ImGuiID seed) ImU32 crc = ~seed; const unsigned char* data = (const unsigned char*)data_p; const unsigned char *data_end = (const unsigned char*)data_p + data_size; -#ifndef IMGUI_ENABLE_SSE4_2 +#ifndef IMGUI_ENABLE_SSE4_2_CRC const ImU32* crc32_lut = GCrc32LookupTable; while (data < data_end) crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++]; @@ -2212,7 +2212,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) seed = ~seed; ImU32 crc = seed; const unsigned char* data = (const unsigned char*)data_p; -#ifndef IMGUI_ENABLE_SSE4_2 +#ifndef IMGUI_ENABLE_SSE4_2_CRC const ImU32* crc32_lut = GCrc32LookupTable; #endif if (data_size != 0) @@ -2222,7 +2222,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) unsigned char c = *data++; if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#') crc = seed; -#ifndef IMGUI_ENABLE_SSE4_2 +#ifndef IMGUI_ENABLE_SSE4_2_CRC crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; #else crc = _mm_crc32_u8(crc, c); @@ -2235,7 +2235,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) { if (c == '#' && data[0] == '#' && data[1] == '#') crc = seed; -#ifndef IMGUI_ENABLE_SSE4_2 +#ifndef IMGUI_ENABLE_SSE4_2_CRC crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c]; #else crc = _mm_crc32_u8(crc, c); diff --git a/imgui_internal.h b/imgui_internal.h index 147e30c3569c..f11f272c3c03 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -66,6 +66,10 @@ Index of this file: #include #endif #endif +// Emscripten has partial SSE 4.2 support where _mm_crc32_u32 is not available. See https://emscripten.org/docs/porting/simd.html#id11 and #8213 +#if defined(IMGUI_ENABLE_SSE4_2) || !defined(__EMSCRIPTEN__) +#define IMGUI_ENABLE_SSE4_2_CRC +#endif // Visual Studio warnings #ifdef _MSC_VER From 53dd7552dcbef379a57f33bb5e35f12ae04a3d8d Mon Sep 17 00:00:00 2001 From: bmarques1995 Date: Mon, 9 Dec 2024 01:19:23 -0300 Subject: [PATCH 066/716] Backends: DX12: let the user specifies the DepthStencilView format. (#8217) This is particullarly important for those who use RenderPasses. --- backends/imgui_impl_dx12.cpp | 4 ++++ backends/imgui_impl_dx12.h | 3 ++- docs/CHANGELOG.txt | 2 ++ examples/example_win32_directx12/main.cpp | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index bad823c4a9ba..16dcf5392ffe 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -19,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. // 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). // 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. // 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools. @@ -72,6 +73,7 @@ struct ImGui_ImplDX12_Data ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; DXGI_FORMAT RTVFormat; + DXGI_FORMAT DSVFormat; ID3D12DescriptorHeap* pd3dSrvDescHeap; UINT numFramesInFlight; @@ -569,6 +571,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() psoDesc.SampleMask = UINT_MAX; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = bd->RTVFormat; + psoDesc.DSVFormat = bd->DSVFormat; psoDesc.SampleDesc.Count = 1; psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; @@ -735,6 +738,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) bd->pd3dDevice = init_info->Device; bd->RTVFormat = init_info->RTVFormat; + bd->DSVFormat = init_info->DSVFormat; bd->numFramesInFlight = init_info->NumFramesInFlight; bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap; diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 0ade2ac99b36..644c022fffbd 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -29,7 +29,8 @@ struct ImGui_ImplDX12_InitInfo ID3D12Device* Device; ID3D12CommandQueue* CommandQueue; int NumFramesInFlight; - DXGI_FORMAT RTVFormat; + DXGI_FORMAT RTVFormat; // RenderTarget format. + DXGI_FORMAT DSVFormat; // DepthStencilView format. void* UserData; // Allocating SRV descriptors for textures is up to the application, so we provide callbacks. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 874c7502f5bb..8a1cc931eefd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,8 @@ Other changes: - Fonts: fixed AddCustomRect() not being packed with TexGlyphPadding + not accounted for surface area used to determine best-guess texture size. (#8107) [@YarikTH, @ocornut] - Misc: use SSE 4.2 crc32 instructions when available. (#8169, #4933) [@Teselka] +- Backends: DirectX12: Let user specifies the DepthStencilView format by setting + ImGui_ImplDX12_InitInfo::DSVFormat. (#8217) [@bmarques1995] - Backends: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize then the backend will create and manage one itself. (#8172, #4867) [@zeux] diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index eeff99c1be8b..392ba18aab14 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -146,6 +146,7 @@ int main(int, char**) init_info.CommandQueue = g_pd3dCommandQueue; init_info.NumFramesInFlight = APP_NUM_FRAMES_IN_FLIGHT; init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + init_info.DSVFormat = DXGI_FORMAT_UNKNOWN; // Allocating SRV descriptors (for textures) is up to the application, so we provide callbacks. // (current version of the backend will only allocate one descriptor, future versions will need to allocate more) init_info.SrvDescriptorHeap = g_pd3dSrvDescHeap; From fce07bb1cb4cdd64dbf825223b74be1d9b28b76b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Dec 2024 12:43:49 +0100 Subject: [PATCH 067/716] Don't enable SSE4 under Emscripten - Fix. (#8213, #8169, #4933) --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index f11f272c3c03..cccecf702943 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -67,7 +67,7 @@ Index of this file: #endif #endif // Emscripten has partial SSE 4.2 support where _mm_crc32_u32 is not available. See https://emscripten.org/docs/porting/simd.html#id11 and #8213 -#if defined(IMGUI_ENABLE_SSE4_2) || !defined(__EMSCRIPTEN__) +#if defined(IMGUI_ENABLE_SSE4_2) && !defined(__EMSCRIPTEN__) #define IMGUI_ENABLE_SSE4_2_CRC #endif From 6b348622bb8c0cd4adf5b5f4ec6da5d24ba55a93 Mon Sep 17 00:00:00 2001 From: Thomas Hope Date: Sat, 30 Nov 2024 16:55:46 +0100 Subject: [PATCH 068/716] Examples: SDL2+OpenGL3: Provide ES3 context creation code + failure handling. (#8197) --- examples/example_sdl2_opengl3/main.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 2a4d7b9e7d9a..cb0ade097ac3 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -35,12 +35,19 @@ int main(int, char**) // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 + // GL ES 2.0 + GLSL 100 (WebGL 1.0) const char* glsl_version = "#version 100"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#elif defined(IMGUI_IMPL_OPENGL_ES3) + // GL ES 3.0 + GLSL 300 es (WebGL 2.0) + const char* glsl_version = "#version 300 es"; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(__APPLE__) // GL 3.2 Core + GLSL 150 const char* glsl_version = "#version 150"; @@ -75,6 +82,12 @@ int main(int, char**) } SDL_GLContext gl_context = SDL_GL_CreateContext(window); + if (gl_context == nullptr) + { + printf("Error: SDL_GL_CreateContext(): %s\n", SDL_GetError()); + return -1; + } + SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync From 921c22f5adce8b5941cbf47bb7efcd02e6cc8fe5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Dec 2024 12:55:33 +0100 Subject: [PATCH 069/716] Examples: GLFW+OpenGL3, SDL3+OpenGL3: Provide ES3 context creation code + failure handling. (#8197) Untested for GLFW example. --- examples/example_glfw_opengl3/main.cpp | 8 +++++++- examples/example_sdl3_opengl3/main.cpp | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 3afe251e3750..e5f29d40578d 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -43,11 +43,17 @@ int main(int, char**) // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 + // GL ES 2.0 + GLSL 100 (WebGL 1.0) const char* glsl_version = "#version 100"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); +#elif defined(IMGUI_IMPL_OPENGL_ES3) + // GL ES 3.0 + GLSL 300 es (WebGL 2.0) + const char* glsl_version = "#version 300 es"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); #elif defined(__APPLE__) // GL 3.2 + GLSL 150 const char* glsl_version = "#version 150"; diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index e7f239f4769b..5520a7da9293 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -35,12 +35,19 @@ int main(int, char**) // Decide GL+GLSL versions #if defined(IMGUI_IMPL_OPENGL_ES2) - // GL ES 2.0 + GLSL 100 + // GL ES 2.0 + GLSL 100 (WebGL 1.0) const char* glsl_version = "#version 100"; SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#elif defined(IMGUI_IMPL_OPENGL_ES3) + // GL ES 3.0 + GLSL 300 es (WebGL 2.0) + const char* glsl_version = "#version 300 es"; + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #elif defined(__APPLE__) // GL 3.2 Core + GLSL 150 const char* glsl_version = "#version 150"; @@ -70,6 +77,12 @@ int main(int, char**) } SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_GLContext gl_context = SDL_GL_CreateContext(window); + if (gl_context == nullptr) + { + printf("Error: SDL_GL_CreateContext(): %s\n", SDL_GetError()); + return -1; + } + SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync SDL_ShowWindow(window); From f3147f446a7f3ad79f642421a56d2742e6bd210d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Dec 2024 12:58:32 +0100 Subject: [PATCH 070/716] Backends: OpenGL3: call glGetString(GL_VERSION) even in GS ES 2.0 path. (#8197) Apparently as per specs works. I reckon the best way to confirm it is to try. --- backends/imgui_impl_opengl3.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index efcfb8217358..b47ac9ab1c97 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -297,15 +297,13 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) io.BackendRendererName = "imgui_impl_opengl3"; // Query for GL version (e.g. 320 for GL 3.2) + const char* gl_version_str = (const char*)glGetString(GL_VERSION); #if defined(IMGUI_IMPL_OPENGL_ES2) // GLES 2 - const char* gl_version_str = ""; - IM_UNUSED(gl_version_str); // For IMGUI_IMPL_OPENGL_DEBUG block below. bd->GlVersion = 200; bd->GlProfileIsES2 = true; #else // Desktop or GLES 3 - const char* gl_version_str = (const char*)glGetString(GL_VERSION); GLint major = 0; GLint minor = 0; glGetIntegerv(GL_MAJOR_VERSION, &major); From d2645423de8eb035a70de3cf1bed016d5c10161e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Dec 2024 14:26:53 +0100 Subject: [PATCH 071/716] InputText: reactivating last activated InputText() doesn't restore horizontal scrolling. Honestly not sure if the opposite is preferable or not (added commented out in the inactivate render path to test that). Current behavior added along with recycling: f9928e96c7c762f97bbdf8cf48e04097b56da84a --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8a1cc931eefd..42026c9cd514 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,8 @@ Other changes: processing errors outside of the NewFrame()..EndFrame() scope. (#1651) - Tables: fixed SetNextWindowScroll() value being ignored by BeginTable() during the first frame or when scrolling flags have changed. (#8196) +- InputText: reactivating last activated InputText() doesn't restore horizontal scrolling + (which was disabled during deactivation anyway). - Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). - Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) [@demonese] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index cf6891ea18d7..65a58d53ba48 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4537,6 +4537,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. state->TextLen = (int)strlen(buf); memcpy(state->TextA.Data, buf, state->TextLen + 1); + state->Scroll = ImVec2(0.0f, 0.0f); if (recycle_state) { @@ -4546,7 +4547,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } else { - state->Scroll = ImVec2(0.0f, 0.0f); stb_textedit_initialize_state(state->Stb, !is_multiline); } @@ -5287,8 +5287,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { + const ImVec2 draw_scroll = /*state ? ImVec2(state->Scroll.x, 0.0f) :*/ ImVec2(0.0f, 0.0f); // Preserve scroll when inactive? ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); - draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); + draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); } } From d78e823449f491dbd3cd158b72fdee7cd4d72aa6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 9 Dec 2024 14:31:28 +0100 Subject: [PATCH 072/716] InputText: added ImGuiInputTextFlags_ElideLeft. (#1442, #1440, #4391, #7208, #8216) --- docs/CHANGELOG.txt | 3 +++ imgui.h | 17 ++++++++++------- imgui_demo.cpp | 10 ++++++++++ imgui_widgets.cpp | 9 +++++++++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 42026c9cd514..70dfb7b9d97f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,9 @@ Other changes: processing errors outside of the NewFrame()..EndFrame() scope. (#1651) - Tables: fixed SetNextWindowScroll() value being ignored by BeginTable() during the first frame or when scrolling flags have changed. (#8196) +- InputText: added ImGuiInputTextFlags_ElideLeft to elide left side and ensure right side + of contents is visible when whole text is not fitting (useful for paths/filenames). + (#1442, #1440, #4391, #7208, #8216) [@kucoman, @ocornut] - InputText: reactivating last activated InputText() doesn't restore horizontal scrolling (which was disabled during deactivation anyway). - Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). diff --git a/imgui.h b/imgui.h index b86c7d4e5d89..c9b42e4c7511 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.6 WIP" -#define IMGUI_VERSION_NUM 19152 +#define IMGUI_VERSION_NUM 19153 #define IMGUI_HAS_TABLE /* @@ -1171,13 +1171,16 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_NoHorizontalScroll = 1 << 15, // Disable following the cursor horizontally ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + // Elide display / Alignment + ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only! + // Callback features - ImGuiInputTextFlags_CallbackCompletion = 1 << 17, // Callback on pressing TAB (for completion handling) - ImGuiInputTextFlags_CallbackHistory = 1 << 18, // Callback on pressing Up/Down arrows (for history handling) - ImGuiInputTextFlags_CallbackAlways = 1 << 19, // Callback on each iteration. User code may query cursor position, modify text buffer. - ImGuiInputTextFlags_CallbackCharFilter = 1 << 20, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. - ImGuiInputTextFlags_CallbackResize = 1 << 21, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) - ImGuiInputTextFlags_CallbackEdit = 1 << 22, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling) + ImGuiInputTextFlags_CallbackHistory = 1 << 19, // Callback on pressing Up/Down arrows (for history handling) + ImGuiInputTextFlags_CallbackAlways = 1 << 20, // Callback on each iteration. User code may query cursor position, modify text buffer. + ImGuiInputTextFlags_CallbackCharFilter = 1 << 21, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. + ImGuiInputTextFlags_CallbackResize = 1 << 22, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) + ImGuiInputTextFlags_CallbackEdit = 1 << 23, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) // Obsolete names //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5efbe6304538..ae91761a3db2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1830,6 +1830,16 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment"); + if (ImGui::TreeNode("Eliding, Alignment")) + { + static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp"; + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft; + ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft); + ImGui::InputText("Path", buf1, IM_ARRAYSIZE(buf1), flags); + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous"); if (ImGui::TreeNode("Miscellaneous")) { diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 65a58d53ba48..4a579d4e3f15 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4403,6 +4403,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ IM_ASSERT(buf != NULL && buf_size >= 0); IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys) IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key) + IM_ASSERT(!((flags & ImGuiInputTextFlags_ElideLeft) && (flags & ImGuiInputTextFlags_Multiline))); // Multiline will not work with left-trimming ImGuiContext& g = *GImGui; ImGuiIO& io = g.IO; @@ -4537,7 +4538,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. state->TextLen = (int)strlen(buf); memcpy(state->TextA.Data, buf, state->TextLen + 1); + + // Find initial scroll position for right alignment state->Scroll = ImVec2(0.0f, 0.0f); + if (flags & ImGuiInputTextFlags_ElideLeft) + state->Scroll.x += ImMax(0.0f, CalcTextSize(buf).x - frame_size.x + style.FramePadding.x * 2.0f); if (recycle_state) { @@ -5287,6 +5292,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { + // Find render position for right alignment + if (flags & ImGuiInputTextFlags_ElideLeft) + draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x); + const ImVec2 draw_scroll = /*state ? ImVec2(state->Scroll.x, 0.0f) :*/ ImVec2(0.0f, 0.0f); // Preserve scroll when inactive? ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text); draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect); From c3ffd4c53e90276f5ad1504553bf5c628f15c9ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Dec 2024 12:13:28 +0100 Subject: [PATCH 073/716] Misc: Added IMGUI_USE_LEGACY_CRC32_ADLER to use old tables. (#8169, #4933) --- docs/CHANGELOG.txt | 11 ++++++++--- imconfig.h | 3 +++ imgui.cpp | 26 ++++++++++++++++++++++++-- imgui.h | 2 +- imgui_internal.h | 2 +- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 70dfb7b9d97f..7ef8580b8157 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,9 +48,14 @@ Breaking changes: - We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. - Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). -- Misc: changed CRC32 table to use CRC32c polynomial in order to be compatible - with the result of SSE 4.2 instructions. As a result, old .ini data may be - partially lost. (#8169, #4933) [@Teselka] +- Misc: changed CRC32 table from CRC32-adler to CRC32c polynomial in order to + be compatible with the result of SSE 4.2 instructions. (#8169, #4933) [@Teselka] + - As a result, some .ini data may be partially lost when storing checksums + (docking and tables information particularly). + - Because some users have crafted and storing .ini data as a way to workaround + limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' + compile-time option to keep using old CRC32 tables if you cannot afford invalidating + old .ini data. Other changes: diff --git a/imconfig.h b/imconfig.h index 6790f147ac85..8f8bc3b9a9bb 100644 --- a/imconfig.h +++ b/imconfig.h @@ -62,6 +62,9 @@ //---- Pack vertex colors as BGRA8 instead of RGBA8 (to avoid converting from one to another). Need dedicated backend support. //#define IMGUI_USE_BGRA_PACKED_COLOR +//---- Use legacy CRC32-adler tables (used before 1.91.6), in order to preserve old .ini data that you cannot afford to invalidate. +//#define IMGUI_USE_LEGACY_CRC32_ADLER + //---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...) //#define IMGUI_USE_WCHAR32 diff --git a/imgui.cpp b/imgui.cpp index 5833691dbf14..e4199c2b07af 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -429,7 +429,9 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2024/11/27 (1.91.6) - changed CRC32 table to use CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. As a result, old .ini data may be partially lost. + - 2024/11/27 (1.91.6) - changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. + As a result, old .ini data may be partially lost (docking and tables information particularly). + Because some users have crafted and storing .ini data as a way to workaround limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' compile-time option to keep using old CRC32 tables if you cannot afford invalidating old .ini data. - 2024/11/06 (1.91.5) - commented/obsoleted out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before) - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). @@ -2154,9 +2156,28 @@ void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, // CRC32 needs a 1KB lookup table (not cache friendly) // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily: // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe. -// On 2024/11/27 this was changed from crc32-adler to crc32c (polynomial 0x1EDC6F41), which invalidated some hashes stored in .ini files. static const ImU32 GCrc32LookupTable[256] = { +#ifdef IMGUI_USE_LEGACY_CRC32_ADLER + // Legacy CRC32-adler table used pre 1.91.6 (before 2024/11/27). Only use if you cannot afford invalidating old .ini data. + 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, + 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, + 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, + 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, + 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, + 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, + 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, + 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, + 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, + 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, + 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, + 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, + 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, + 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, + 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, + 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, +#else + // CRC32c table compatible with SSE 4.2 instructions 0x00000000,0xF26B8303,0xE13B70F7,0x1350F3F4,0xC79A971F,0x35F1141C,0x26A1E7E8,0xD4CA64EB,0x8AD958CF,0x78B2DBCC,0x6BE22838,0x9989AB3B,0x4D43CFD0,0xBF284CD3,0xAC78BF27,0x5E133C24, 0x105EC76F,0xE235446C,0xF165B798,0x030E349B,0xD7C45070,0x25AFD373,0x36FF2087,0xC494A384,0x9A879FA0,0x68EC1CA3,0x7BBCEF57,0x89D76C54,0x5D1D08BF,0xAF768BBC,0xBC267848,0x4E4DFB4B, 0x20BD8EDE,0xD2D60DDD,0xC186FE29,0x33ED7D2A,0xE72719C1,0x154C9AC2,0x061C6936,0xF477EA35,0xAA64D611,0x580F5512,0x4B5FA6E6,0xB93425E5,0x6DFE410E,0x9F95C20D,0x8CC531F9,0x7EAEB2FA, @@ -2173,6 +2194,7 @@ static const ImU32 GCrc32LookupTable[256] = 0xD3D3E1AB,0x21B862A8,0x32E8915C,0xC083125F,0x144976B4,0xE622F5B7,0xF5720643,0x07198540,0x590AB964,0xAB613A67,0xB831C993,0x4A5A4A90,0x9E902E7B,0x6CFBAD78,0x7FAB5E8C,0x8DC0DD8F, 0xE330A81A,0x115B2B19,0x020BD8ED,0xF0605BEE,0x24AA3F05,0xD6C1BC06,0xC5914FF2,0x37FACCF1,0x69E9F0D5,0x9B8273D6,0x88D28022,0x7AB90321,0xAE7367CA,0x5C18E4C9,0x4F48173D,0xBD23943E, 0xF36E6F75,0x0105EC76,0x12551F82,0xE03E9C81,0x34F4F86A,0xC69F7B69,0xD5CF889D,0x27A40B9E,0x79B737BA,0x8BDCB4B9,0x988C474D,0x6AE7C44E,0xBE2DA0A5,0x4C4623A6,0x5F16D052,0xAD7D5351 +#endif }; #endif diff --git a/imgui.h b/imgui.h index c9b42e4c7511..8b5c358a9fc5 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.6 WIP" -#define IMGUI_VERSION_NUM 19153 +#define IMGUI_VERSION_NUM 19154 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index cccecf702943..379f6cb14c13 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -67,7 +67,7 @@ Index of this file: #endif #endif // Emscripten has partial SSE 4.2 support where _mm_crc32_u32 is not available. See https://emscripten.org/docs/porting/simd.html#id11 and #8213 -#if defined(IMGUI_ENABLE_SSE4_2) && !defined(__EMSCRIPTEN__) +#if defined(IMGUI_ENABLE_SSE4_2) && !defined(IMGUI_USE_LEGACY_CRC32_ADLER) && !defined(__EMSCRIPTEN__) #define IMGUI_ENABLE_SSE4_2_CRC #endif From 2ca83f0bc72fcaca5631766b5fcb05fd3d0e102d Mon Sep 17 00:00:00 2001 From: Stewart Mccready Date: Wed, 11 Dec 2024 13:14:46 +0000 Subject: [PATCH 074/716] Fixed missing symbols when using IMGUI_DISABLE_DEMO_WINDOWS (e.g. with ImPlot) (#8221) --- imgui_demo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ae91761a3db2..9e5c03fa37c7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10397,6 +10397,8 @@ void ImGui::ShowAboutWindow(bool*) {} void ImGui::ShowDemoWindow(bool*) {} void ImGui::ShowUserGuide() {} void ImGui::ShowStyleEditor(ImGuiStyle*) {} +bool ImGui::ShowStyleSelector(const char* label) { return false; } +void ImGui::ShowFontSelector(const char* label) {} #endif From 993fa347495860ed44b83574254ef2a317d0c14f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Dec 2024 14:17:45 +0100 Subject: [PATCH 075/716] Version 1.91.6 --- docs/CHANGELOG.txt | 14 +++++++------- docs/README.md | 2 +- imgui.cpp | 6 +++--- imgui.h | 16 ++++++++-------- imgui_demo.cpp | 2 +- imgui_draw.cpp | 4 ++-- imgui_internal.h | 10 ++++------ imgui_tables.cpp | 2 +- imgui_widgets.cpp | 8 ++++---- 9 files changed, 31 insertions(+), 33 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7ef8580b8157..2d04ee093390 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,7 +36,7 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.6 WIP (In Progress) + VERSION 1.91.6 (Released 2024-12-11) ----------------------------------------------------------------------- Breaking changes: @@ -48,18 +48,18 @@ Breaking changes: - We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. - Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). -- Misc: changed CRC32 table from CRC32-adler to CRC32c polynomial in order to +- Misc: changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. (#8169, #4933) [@Teselka] - As a result, some .ini data may be partially lost when storing checksums - (docking and tables information particularly). - - Because some users have crafted and storing .ini data as a way to workaround + (docking and tables information particularly). + - Because some users have crafted and storing .ini data as a way to workaround limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' compile-time option to keep using old CRC32 tables if you cannot afford invalidating old .ini data. Other changes: -- Error Handling: fixed cases where recoverable error handling would crash when +- Error Handling: fixed cases where recoverable error handling would crash when processing errors outside of the NewFrame()..EndFrame() scope. (#1651) - Tables: fixed SetNextWindowScroll() value being ignored by BeginTable() during the first frame or when scrolling flags have changed. (#8196) @@ -71,13 +71,13 @@ Other changes: - Misc: changed embedded ProggyClean encoding to save a bit of binary space (~12kb to 9.5kb). - Misc: added IMGUI_DISABLE_DEFAULT_FONT to strip embedded font from binary. (#8161) [@demonese] -- Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. - Demo: example tree used by Property Editor & Selection demos properly freed on application closure. (#8158) [@Legulysse] - Fonts: fixed AddCustomRect() not being packed with TexGlyphPadding + not accounted for surface area used to determine best-guess texture size. (#8107) [@YarikTH, @ocornut] - Misc: use SSE 4.2 crc32 instructions when available. (#8169, #4933) [@Teselka] -- Backends: DirectX12: Let user specifies the DepthStencilView format by setting +- Tools: binary_to_compressed_c: added -u8/-u32/-base85 export options. +- Backends: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. (#8217) [@bmarques1995] - Backends: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize then the backend will create and manage diff --git a/docs/README.md b/docs/README.md index c47f03b9bc5c..388d8eac63af 100644 --- a/docs/README.md +++ b/docs/README.md @@ -110,7 +110,7 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. [Here's how the demo looks](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: -- [imgui-demo-binaries-20240105.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20240105.zip) (Windows, 1.90.1 WIP, built 2024/01/05, master) or [older binaries](https://www.dearimgui.com/binaries). +- [imgui-demo-binaries-20241211.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20241211.zip) (Windows, 1.91.6, built 2024/11/11, master) or [older binaries](https://www.dearimgui.com/binaries). The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). diff --git a/imgui.cpp b/imgui.cpp index e4199c2b07af..26e56b80407e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (main code and documentation) // Help: @@ -4748,15 +4748,15 @@ void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr } if (size != (size_t)-1) { + //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, (int)size, ptr); entry->AllocCount++; info->TotalAllocCount++; - //printf("[%05d] MemAlloc(%d) -> 0x%p\n", frame_count, size, ptr); } else { + //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr); entry->FreeCount++; info->TotalFreeCount++; - //printf("[%05d] MemFree(0x%p)\n", frame_count, ptr); } } diff --git a/imgui.h b/imgui.h index 8b5c358a9fc5..64be995cb21a 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.6 WIP" -#define IMGUI_VERSION_NUM 19154 +#define IMGUI_VERSION "1.91.6" +#define IMGUI_VERSION_NUM 19160 #define IMGUI_HAS_TABLE /* @@ -3429,24 +3429,24 @@ struct ImFontAtlas // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). struct ImFont { - // Members: Hot ~20/24 bytes (for CalcTextSize) + // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize) ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) - // Members: Hot ~28/40 bytes (for CalcTextSize + render loop) + // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // // All glyphs. const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) - // Members: Cold ~32/40 bytes + // [Internal] Members: Cold ~32/40 bytes // Conceptually ConfigData[] is the list of font sources merged to create this font. ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. - ImWchar FallbackChar; // 2 // out // = FFFD/'?' // Character used if a glyph isn't found. - ImWchar EllipsisChar; // 2 // out // = '...'/'.'// Character used for ellipsis rendering. short EllipsisCharCount; // 1 // out // 1 or 3 + ImWchar EllipsisChar; // 2-4 // out // = '...'/'.'// Character used for ellipsis rendering. + ImWchar FallbackChar; // 2-4 // out // = FFFD/'?' // Character used if a glyph isn't found. float EllipsisWidth; // 4 // out // Width float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 bool DirtyLookupTables; // 1 // out // diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9e5c03fa37c7..a9f9d832ba11 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 631472a71dd6..9ae0162e42ff 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (drawing and font code) /* @@ -396,7 +396,7 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) ImDrawList::ImDrawList(ImDrawListSharedData* shared_data) { - memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(*this)); _Data = shared_data; } diff --git a/imgui_internal.h b/imgui_internal.h index 379f6cb14c13..45715cc31c1e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. @@ -778,11 +778,9 @@ struct IMGUI_API ImDrawListSharedData float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) + ImVector TempBuffer; // Temporary write buffer - // [Internal] Temp write buffer - ImVector TempBuffer; - - // [Internal] Lookup tables + // Lookup tables ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) @@ -3392,7 +3390,7 @@ namespace ImGui IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); - IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f); IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width); IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index db34aa347d00..f4e76225a828 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4a579d4e3f15..3fc500ab83f9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 WIP +// dear imgui, v1.91.6 // (widgets code) /* @@ -1073,7 +1073,7 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const I window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); } -bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -1095,7 +1095,7 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& imag RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); - window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); return pressed; } @@ -1114,7 +1114,7 @@ bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const I #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy API obsoleted in 1.89. Two differences with new ImageButton() -// - old ImageButton() used ImTextureId as item id (created issue with multiple buttons with same image, transient texture id values, opaque computation of ID) +// - old ImageButton() used ImTextureID as item id (created issue with multiple buttons with same image, transient texture id values, opaque computation of ID) // - new ImageButton() requires an explicit 'const char* str_id' // - old ImageButton() had frame_padding' override argument. // - new ImageButton() always use style.FramePadding. From f25665f36003abb5fa856b040b312344483f0031 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Dec 2024 15:37:16 +0100 Subject: [PATCH 076/716] Version 1.91.7 WIP --- docs/CHANGELOG.txt | 11 +++++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 20 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2d04ee093390..68f5d8d4c34f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,10 +35,21 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.91.7 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.91.6 (Released 2024-12-11) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.6 + Breaking changes: - Backends: DX12: Changed ImGui_ImplDX12_Init() signature to take a diff --git a/imgui.cpp b/imgui.cpp index 26e56b80407e..7325c1952795 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 64be995cb21a..0a61b1deaabc 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.6" -#define IMGUI_VERSION_NUM 19160 +#define IMGUI_VERSION "1.91.7 WIP" +#define IMGUI_VERSION_NUM 19161 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a9f9d832ba11..6010aad4409c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9ae0162e42ff..b231764b6e2e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 45715cc31c1e..1f7426696b22 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f4e76225a828..7dd97c6f214a 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3fc500ab83f9..2d0fed4e0a04 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.6 +// dear imgui, v1.91.7 WIP // (widgets code) /* From e487eb9da0805519261687339da2e77686ed9efc Mon Sep 17 00:00:00 2001 From: Mahmood - Zer0xFF <5013823+Zer0xFF@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:30:35 +0000 Subject: [PATCH 077/716] Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) --- backends/imgui_impl_vulkan.cpp | 11 ++++++----- docs/CHANGELOG.txt | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index b419703048e0..1de6e2353879 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-12-11: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) // 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) // 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: Vulkan: Expose selected render state in ImGui_ImplVulkan_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -1426,6 +1427,10 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // Create Swapchain { + VkSurfaceCapabilitiesKHR cap; + err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); + check_vk_result(err); + VkSwapchainCreateInfoKHR info = {}; info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; info.surface = wd->Surface; @@ -1435,19 +1440,15 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V info.imageArrayLayers = 1; info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; // Assume that graphics family == present family - info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + info.preTransform = (cap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : cap.currentTransform; info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; info.presentMode = wd->PresentMode; info.clipped = VK_TRUE; info.oldSwapchain = old_swapchain; - VkSurfaceCapabilitiesKHR cap; - err = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, wd->Surface, &cap); - check_vk_result(err); if (info.minImageCount < cap.minImageCount) info.minImageCount = cap.minImageCount; else if (cap.maxImageCount != 0 && info.minImageCount > cap.maxImageCount) info.minImageCount = cap.maxImageCount; - if (cap.currentExtent.width == 0xffffffff) { info.imageExtent.width = wd->Width = w; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 68f5d8d4c34f..d95012d9f72b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for + platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] + ----------------------------------------------------------------------- VERSION 1.91.6 (Released 2024-12-11) From 1d069cf43527bdf81b42289f7c385efac129c3a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Dec 2024 16:43:29 +0100 Subject: [PATCH 078/716] Fonts: store 0 for unset EllipsisChar/FallbackChar. Pull config in BuildLookupTable(). --- imgui.h | 2 +- imgui_draw.cpp | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/imgui.h b/imgui.h index 0a61b1deaabc..7fbb610f2dbe 100644 --- a/imgui.h +++ b/imgui.h @@ -3244,7 +3244,7 @@ struct ImFontConfig unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered. - ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + ImWchar EllipsisChar; // 0 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] char Name[40]; // Name (strictly to ease debugging) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b231764b6e2e..f51fff3a6357 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2377,7 +2377,7 @@ ImFontConfig::ImFontConfig() GlyphMaxAdvanceX = FLT_MAX; RasterizerMultiply = 1.0f; RasterizerDensity = 1.0f; - EllipsisChar = (ImWchar)-1; + EllipsisChar = 0; } //----------------------------------------------------------------------------- @@ -2564,9 +2564,6 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // - We may support it better later and remove this rounding. new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels); - if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1) - new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar; - // Pointers to ConfigData and BuilderData are otherwise dangling ImFontAtlasUpdateConfigDataPointers(this); @@ -3635,8 +3632,8 @@ ImFont::ImFont() { FontSize = 0.0f; FallbackAdvanceX = 0.0f; - FallbackChar = (ImWchar)-1; - EllipsisChar = (ImWchar)-1; + FallbackChar = 0; + EllipsisChar = 0; EllipsisWidth = EllipsisCharStep = 0.0f; EllipsisCharCount = 0; FallbackGlyph = NULL; @@ -3675,7 +3672,7 @@ static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_cha for (int n = 0; n < candidate_chars_count; n++) if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL) return candidate_chars[n]; - return (ImWchar)-1; + return 0; } void ImFont::BuildLookupTable() @@ -3742,17 +3739,17 @@ void ImFont::BuildLookupTable() // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. - const ImWchar ellipsis_chars[] = { (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar ellipsis_chars[] = { ConfigData->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; - if (EllipsisChar == (ImWchar)-1) + if (EllipsisChar == 0) EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); - if (EllipsisChar != (ImWchar)-1) + if (EllipsisChar != 0) { EllipsisCharCount = 1; EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; } - else if (dot_char != (ImWchar)-1) + else if (dot_char != 0) { const ImFontGlyph* glyph = FindGlyph(dot_char); EllipsisChar = dot_char; From 4cc464eadc12a158fb7ccd9b2843277ee894f163 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Dec 2024 15:14:14 +0100 Subject: [PATCH 079/716] BeginListBox(): Comments (#8220) --- imgui.h | 1 + imgui_widgets.cpp | 11 +++-------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index 7fbb610f2dbe..69f106dd6e90 100644 --- a/imgui.h +++ b/imgui.h @@ -692,6 +692,7 @@ namespace ImGui // Widgets: List Boxes // - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + // - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the same result. // - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items. // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d0fed4e0a04..9f4baef0fdf9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8206,15 +8206,10 @@ void ImGuiSelectionExternalStorage::ApplyRequests(ImGuiMultiSelectIO* ms_io) //------------------------------------------------------------------------- // This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. -// This handle some subtleties with capturing info from the label, but for 99% uses it could essentially be rewritten as: -// if (ImGui::BeginChild("...", ImVec2(ImGui::CalcItemWidth(), ImGui::GetTextLineHeight() * 7.5f), ImGuiChildFlags_FrameStyle)) -// { .... } -// ImGui::EndChild(); -// ImGui::SameLine(); -// ImGui::AlignTextToFramePadding(); -// ImGui::Text("Label"); +// This handle some subtleties with capturing info from the label. +// If you don't need a label you can pretty much directly use ImGui::BeginChild() with ImGuiChildFlags_FrameStyle. // Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" -// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.5f * item_height). bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) { ImGuiContext& g = *GImGui; From f9f4e22f6f7d08e31152e9219d8533e4c265f4de Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Dec 2024 16:40:08 +0100 Subject: [PATCH 080/716] InputText: some tidying up. (#7925) --- imgui_internal.h | 5 +++-- imgui_widgets.cpp | 49 +++++++++++++++++------------------------------ 2 files changed, 21 insertions(+), 33 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 1f7426696b22..fed655e03a42 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1121,6 +1121,7 @@ struct IMGUI_API ImGuiInputTextState { ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent). ImStbTexteditState* Stb; // State for stb_textedit.h + ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. ImGuiID ID; // widget id owning the text state int TextLen; // UTF-8 length of the string in TextA (in bytes) ImVector TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1). @@ -1132,9 +1133,8 @@ struct IMGUI_API ImGuiInputTextState bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool Edited; // edited this frame - ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. bool ReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version. - int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet. + int ReloadSelectionStart; int ReloadSelectionEnd; ImGuiInputTextState(); @@ -1159,6 +1159,7 @@ struct IMGUI_API ImGuiInputTextState // strcpy(my_buf, "hello"); // if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item // state->ReloadUserBufAndSelectAll(); + // THIS CURRENTLY RESETS THE UNDO STACK. void ReloadUserBufAndSelectAll(); void ReloadUserBufAndKeepSelection(); void ReloadUserBufAndMoveToEnd(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9f4baef0fdf9..efe0c8f7647a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4041,16 +4041,12 @@ static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) { + // Offset remaining text (+ copy zero terminator) char* dst = obj->TextA.Data + pos; - + char* src = obj->TextA.Data + pos + n; + memmove(dst, src, obj->TextLen - n - pos + 1); obj->Edited = true; obj->TextLen -= n; - - // Offset remaining text (FIXME-OPT: Use memmove) - const char* src = obj->TextA.Data + pos + n; - while (char c = *src++) - *dst++ = c; - *dst = '\0'; } static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const char* new_text, int new_text_len) @@ -4174,17 +4170,16 @@ ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() memset(this, 0, sizeof(*this)); } -// Public API to manipulate UTF-8 text -// We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar) +// Public API to manipulate UTF-8 text from within a callback. // FIXME: The existence of this rarely exercised code path is a bit of a nuisance. +// Historically they existed because STB_TEXTEDIT_INSERTCHARS() etc. worked on our ImWchar +// buffer, but nowadays they both work on UTF-8 data. Should aim to merge both. void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count) { IM_ASSERT(pos + bytes_count <= BufTextLen); char* dst = Buf + pos; const char* src = Buf + pos + bytes_count; - while (char c = *src++) - *dst++ = c; - *dst = '\0'; + memmove(dst, src, BufTextLen - bytes_count - pos + 1); if (CursorPos >= pos + bytes_count) CursorPos -= bytes_count; @@ -4209,7 +4204,6 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (!is_resizable) return; - // Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!) ImGuiContext& g = *Ctx; ImGuiInputTextState* edit_state = &g.InputTextState; IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); @@ -4333,26 +4327,23 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im return true; } -// Find the shortest single replacement we can make to get the new text from the old text. -// Important: needs to be run before TextW is rewritten with the new characters because calling STB_TEXTEDIT_GETCHAR() at the end. +// Find the shortest single replacement we can make to get from old_buf to new_buf +// Note that this doesn't directly alter state->TextA, state->TextLen. They are expected to be made valid separately. // FIXME: Ideally we should transition toward (1) making InsertChars()/DeleteChars() update undo-stack (2) discourage (and keep reconcile) or obsolete (and remove reconcile) accessing buffer directly. -static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state, const char* new_buf_a, int new_length_a) +static void InputTextReconcileUndoState(ImGuiInputTextState* state, const char* old_buf, int old_length, const char* new_buf, int new_length) { - const char* old_buf = state->CallbackTextBackup.Data; - const int old_length = state->CallbackTextBackup.Size - 1; - - const int shorter_length = ImMin(old_length, new_length_a); + const int shorter_length = ImMin(old_length, new_length); int first_diff; for (first_diff = 0; first_diff < shorter_length; first_diff++) - if (old_buf[first_diff] != new_buf_a[first_diff]) + if (old_buf[first_diff] != new_buf[first_diff]) break; - if (first_diff == old_length && first_diff == new_length_a) + if (first_diff == old_length && first_diff == new_length) return; int old_last_diff = old_length - 1; - int new_last_diff = new_length_a - 1; + int new_last_diff = new_length - 1; for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--) - if (old_buf[old_last_diff] != new_buf_a[new_last_diff]) + if (old_buf[old_last_diff] != new_buf[new_last_diff]) break; const int insert_len = new_last_diff - first_diff + 1; @@ -4544,16 +4535,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (flags & ImGuiInputTextFlags_ElideLeft) state->Scroll.x += ImMax(0.0f, CalcTextSize(buf).x - frame_size.x + style.FramePadding.x * 2.0f); + // Recycle existing cursor/selection/undo stack but clamp position + // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. if (recycle_state) - { - // Recycle existing cursor/selection/undo stack but clamp position - // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler. state->CursorClamp(); - } else - { stb_textedit_initialize_state(state->Stb, !is_multiline); - } if (init_reload_from_user_buf) { @@ -5039,7 +5026,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Callback may update buffer and thus set buf_dirty even in read-only mode. IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! - InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ? + InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen); state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() state->CursorAnimReset(); } From 4ad5496474b006376c2b5b55b54519335eadb873 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Dec 2024 18:39:28 +0100 Subject: [PATCH 081/716] Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. (#8223) --- docs/CHANGELOG.txt | 3 +++ imgui.h | 1 + imgui_demo.cpp | 2 ++ imgui_widgets.cpp | 6 +++--- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d95012d9f72b..21a927f4bf67 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard + modifiers altering the tweak speed. Useful if you want to alter tweak speed + yourself based on your own logic. (#8223) - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] diff --git a/imgui.h b/imgui.h index 69f106dd6e90..eec3dce65ce2 100644 --- a/imgui.h +++ b/imgui.h @@ -1788,6 +1788,7 @@ enum ImGuiSliderFlags_ ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max. Only supported by DragXXX() functions for now. ImGuiSliderFlags_ClampOnInput = 1 << 9, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds. ImGuiSliderFlags_ClampZeroRange = 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with those values. When your clamping limits are dynamic you almost always want to use it. + ImGuiSliderFlags_NoSpeedTweaks = 1 << 11, // Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange, ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed. }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6010aad4409c..c09c8eca7af7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2310,6 +2310,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks); + ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic."); ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index efe0c8f7647a..82b5714fcbf5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2434,9 +2434,9 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0, g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR)) { adjust_delta = g.IO.MouseDelta[axis]; - if (g.IO.KeyAlt) + if (g.IO.KeyAlt && !(flags & ImGuiSliderFlags_NoSpeedTweaks)) adjust_delta *= 1.0f / 100.0f; - if (g.IO.KeyShift) + if (g.IO.KeyShift && !(flags & ImGuiSliderFlags_NoSpeedTweaks)) adjust_delta *= 10.0f; } else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) @@ -2444,7 +2444,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0; const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow); const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast); - const float tweak_factor = tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f; + const float tweak_factor = (flags & ImGuiSliderFlags_NoSpeedTweaks) ? 1.0f : tweak_slow ? 1.0f / 10.0f : tweak_fast ? 10.0f : 1.0f; adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } From 8237ab450e3825e0888892c23d657b2bfaf18e47 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Dec 2024 18:48:42 +0100 Subject: [PATCH 082/716] Drags, Sliders: store initial value on activation, as a convenience for some mods. (#8223) --- imgui.cpp | 1 + imgui_internal.h | 1 + imgui_widgets.cpp | 8 ++++++++ 3 files changed, 10 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 7325c1952795..3aa3b1fbf7c0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3927,6 +3927,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) ActiveIdPreviousFrameIsAlive = false; ActiveIdPreviousFrameHasBeenEditedBefore = false; ActiveIdPreviousFrameWindow = NULL; + memset(&ActiveIdValueOnActivation, 0, sizeof(ActiveIdValueOnActivation)); LastActiveId = 0; LastActiveIdTimer = 0.0f; diff --git a/imgui_internal.h b/imgui_internal.h index fed655e03a42..14fea369115e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2109,6 +2109,7 @@ struct ImGuiContext bool ActiveIdPreviousFrameIsAlive; bool ActiveIdPreviousFrameHasBeenEditedBefore; ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiDataTypeStorage ActiveIdValueOnActivation; // Backup of initial value at the time of activation. ONLY SET BY SPECIFIC WIDGETS: DragXXX and SliderXXX. ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 82b5714fcbf5..4074a9d73eb3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2632,6 +2632,10 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, temp_input_is_active = true; } + // Store initial value (not used by main lib but available as a convenience but some mods e.g. to revert) + if (make_active) + memcpy(&g.ActiveIdValueOnActivation, p_data, DataTypeGetInfo(data_type)->Size); + if (make_active && !temp_input_is_active) { SetActiveID(id, window); @@ -3222,6 +3226,10 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if ((clicked && g.IO.KeyCtrl) || (g.NavActivateId == id && (g.NavActivateFlags & ImGuiActivateFlags_PreferInput))) temp_input_is_active = true; + // Store initial value (not used by main lib but available as a convenience but some mods e.g. to revert) + if (make_active) + memcpy(&g.ActiveIdValueOnActivation, p_data, DataTypeGetInfo(data_type)->Size); + if (make_active && !temp_input_is_active) { SetActiveID(id, window); From 324d4bb1402e0d075a30f17b3d3859f813292bb7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Dec 2024 17:19:56 +0100 Subject: [PATCH 083/716] InputText: calling ReloadUserBuf doesn't clear undo stack. (#2890) --- imgui_internal.h | 3 +-- imgui_widgets.cpp | 42 ++++++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 14fea369115e..d371ab9e674b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1133,7 +1133,7 @@ struct IMGUI_API ImGuiInputTextState bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!) bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection bool Edited; // edited this frame - bool ReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version. + bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version. int ReloadSelectionStart; int ReloadSelectionEnd; @@ -1159,7 +1159,6 @@ struct IMGUI_API ImGuiInputTextState // strcpy(my_buf, "hello"); // if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item // state->ReloadUserBufAndSelectAll(); - // THIS CURRENTLY RESETS THE UNDO STACK. void ReloadUserBufAndSelectAll(); void ReloadUserBufAndKeepSelection(); void ReloadUserBufAndMoveToEnd(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4074a9d73eb3..871759cec515 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4169,9 +4169,9 @@ int ImGuiInputTextState::GetCursorPos() const { return Stb->cursor int ImGuiInputTextState::GetSelectionStart() const { return Stb->select_start; } int ImGuiInputTextState::GetSelectionEnd() const { return Stb->select_end; } void ImGuiInputTextState::SelectAll() { Stb->select_start = 0; Stb->cursor = Stb->select_end = TextLen; Stb->has_preferred_x = 0; } -void ImGuiInputTextState::ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } -void ImGuiInputTextState::ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } -void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } +void ImGuiInputTextState::ReloadUserBufAndSelectAll() { WantReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; } +void ImGuiInputTextState::ReloadUserBufAndKeepSelection() { WantReloadUserBuf = true; ReloadSelectionStart = Stb->select_start; ReloadSelectionEnd = Stb->select_end; } +void ImGuiInputTextState::ReloadUserBufAndMoveToEnd() { WantReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; } ImGuiInputTextCallbackData::ImGuiInputTextCallbackData() { @@ -4503,32 +4503,40 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; - const bool init_reload_from_user_buf = (state != NULL && state->ReloadUserBuf); + const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf); const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); const bool init_state = (init_make_active || user_scroll_active); - if ((init_state && g.ActiveId != id) || init_changed_specs || init_reload_from_user_buf) + if (init_reload_from_user_buf) + { + int new_len = (int)strlen(buf); + state->WantReloadUserBuf = false; + InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len); + state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextLen = new_len; + memcpy(state->TextA.Data, buf, state->TextLen + 1); + state->Stb->select_start = state->ReloadSelectionStart; + state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; + state->CursorClamp(); + } + else if ((init_state && g.ActiveId != id) || init_changed_specs) { // Access state even if we don't own it yet. state = &g.InputTextState; state->CursorAnimReset(); - state->ReloadUserBuf = false; // Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714) InputTextDeactivateHook(state->ID); + // Take a copy of the initial buffer value. // From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode) const int buf_len = (int)strlen(buf); - if (!init_reload_from_user_buf) - { - // Take a copy of the initial buffer value. - state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. - memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); - } + state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); // Preserve cursor position and undo/redo stack if we come back to same widget // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? - bool recycle_state = (state->ID == id && !init_changed_specs && !init_reload_from_user_buf); + bool recycle_state = (state->ID == id && !init_changed_specs); if (recycle_state && (state->TextLen != buf_len || (strncmp(state->TextA.Data, buf, buf_len) != 0))) recycle_state = false; @@ -4550,13 +4558,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else stb_textedit_initialize_state(state->Stb, !is_multiline); - if (init_reload_from_user_buf) - { - state->Stb->select_start = state->ReloadSelectionStart; - state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; - state->CursorClamp(); - } - else if (!is_multiline) + if (!is_multiline) { if (flags & ImGuiInputTextFlags_AutoSelectAll) select_all = true; From f5f11e94be35078c3bbb5196f55269f88634b9bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 15 Dec 2024 15:46:33 +0100 Subject: [PATCH 084/716] InputText: Fixed a bug where character replacements performed from a callback were not applied when pasting from clipbard. (#8229) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 21a927f4bf67..b266f3a15360 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- InputText: Fixed a bug where character replacements performed from a callback + were not applied when pasting from clipbard. (#8229) - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 871759cec515..09c625d3d08d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4895,25 +4895,27 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { // Filter pasted buffer const int clipboard_len = (int)strlen(clipboard); - char* clipboard_filtered = (char*)IM_ALLOC(clipboard_len + 1); - int clipboard_filtered_len = 0; + ImVector clipboard_filtered; + clipboard_filtered.reserve(clipboard_len + 1); for (const char* s = clipboard; *s != 0; ) { unsigned int c; - int len = ImTextCharFromUtf8(&c, s, NULL); - s += len; + int in_len = ImTextCharFromUtf8(&c, s, NULL); + s += in_len; if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, true)) continue; - memcpy(clipboard_filtered + clipboard_filtered_len, s - len, len); - clipboard_filtered_len += len; + char c_utf8[5]; + ImTextCharToUtf8(c_utf8, c); + int out_len = (int)strlen(c_utf8); + clipboard_filtered.resize(clipboard_filtered.Size + out_len); + memcpy(clipboard_filtered.Data + clipboard_filtered.Size - out_len, c_utf8, out_len); } - clipboard_filtered[clipboard_filtered_len] = 0; - if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation + if (clipboard_filtered.Size > 0) // If everything was filtered, ignore the pasting operation { - stb_textedit_paste(state, state->Stb, clipboard_filtered, clipboard_filtered_len); + clipboard_filtered.push_back(0); + stb_textedit_paste(state, state->Stb, clipboard_filtered.Data, clipboard_filtered.Size - 1); state->CursorFollow = true; } - MemFree(clipboard_filtered); } } From 13c4084362b35ce58a25be70b9f1710dfe3377e9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 16 Dec 2024 10:51:33 +0100 Subject: [PATCH 085/716] Nav: Fixed an issue where Alt key would clear current active item on windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b266f3a15360..eb3db490932a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Other changes: - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) +- Nav: Fixed an issue where Alt key would clear current active item on + windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] diff --git a/imgui.cpp b/imgui.cpp index 3aa3b1fbf7c0..896830575b96 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4356,7 +4356,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) // This could be written in a more general way (e.g associate a hook to ActiveId), // but since this is currently quite an exception we'll leave it as is. - // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId() + // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveID() if (g.InputTextState.ID == g.ActiveId) InputTextDeactivateHook(g.ActiveId); } @@ -13625,15 +13625,16 @@ static void ImGui::NavUpdateWindowing() // Keyboard: Press and Release ALT to toggle menu layer const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt }; bool windowing_toggle_layer_start = false; - for (ImGuiKey windowing_toggle_key : windowing_toggle_keys) - if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner)) - { - windowing_toggle_layer_start = true; - g.NavWindowingToggleLayer = true; - g.NavWindowingToggleKey = windowing_toggle_key; - g.NavInputSource = ImGuiInputSource_Keyboard; - break; - } + if (g.NavWindow != NULL && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs)) + for (ImGuiKey windowing_toggle_key : windowing_toggle_keys) + if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner)) + { + windowing_toggle_layer_start = true; + g.NavWindowingToggleLayer = true; + g.NavWindowingToggleKey = windowing_toggle_key; + g.NavInputSource = ImGuiInputSource_Keyboard; + break; + } if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard) { // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370) From f31d53093b5031a1de0d43adc2a82c0e93d4d0f6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Dec 2024 13:02:48 +0100 Subject: [PATCH 086/716] TestEngine: for consistency, title bar / window items are registered in _Menu layer. --- imgui.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 896830575b96..87d0aaa47be7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7391,9 +7391,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { IM_ASSERT(window->IDStack.Size == 1); window->IDStack.Size = 0; // As window->IDStack[0] == window->ID here, make sure TestEngine doesn't erroneously see window as parent of itself. + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; IMGUI_TEST_ENGINE_ITEM_ADD(window->ID, window->Rect(), NULL); IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWindow == window) ? ImGuiItemStatusFlags_HoveredRect : 0); window->IDStack.Size = 1; + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + } #endif @@ -7653,7 +7656,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // [Test Engine] Register title bar / tab with MoveId. #ifdef IMGUI_ENABLE_TEST_ENGINE if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) + { + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.ID, g.LastItemData.Rect, &g.LastItemData); + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; + } #endif } else From e900571ac24039d41ebe934cd20d1d3bea7a8118 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Dec 2024 16:14:04 +0100 Subject: [PATCH 087/716] InputText: Fixed issue when activating a ReadOnly field when the underlying value is being modified. (#8242) --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_widgets.cpp | 41 ++++++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index eb3db490932a..25649c16f28d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - InputText: Fixed a bug where character replacements performed from a callback were not applied when pasting from clipbard. (#8229) +- InputText: Fixed issue when activating a ReadOnly field when the underlying + value is being modified. (#8242) - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) diff --git a/imgui.h b/imgui.h index eec3dce65ce2..98f0a4d20573 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19161 +#define IMGUI_VERSION_NUM 19162 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 09c625d3d08d..3d135dca923b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4507,12 +4507,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); const bool init_state = (init_make_active || user_scroll_active); + bool readonly_swapped_text_data = false; if (init_reload_from_user_buf) { int new_len = (int)strlen(buf); state->WantReloadUserBuf = false; InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len); - state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. + state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. state->TextLen = new_len; memcpy(state->TextA.Data, buf, state->TextLen + 1); state->Stb->select_start = state->ReloadSelectionStart; @@ -4537,14 +4538,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Preserve cursor position and undo/redo stack if we come back to same widget // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? bool recycle_state = (state->ID == id && !init_changed_specs); - if (recycle_state && (state->TextLen != buf_len || (strncmp(state->TextA.Data, buf, buf_len) != 0))) + if (recycle_state && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0))) recycle_state = false; // Start edition state->ID = id; - state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. state->TextLen = (int)strlen(buf); - memcpy(state->TextA.Data, buf, state->TextLen + 1); + if (!is_readonly) + { + state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. + memcpy(state->TextA.Data, buf, state->TextLen + 1); + } // Find initial scroll position for right alignment state->Scroll = ImVec2(0.0f, 0.0f); @@ -4610,6 +4614,21 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ state->Scroll.y = draw_window->Scroll.y; } + if (g.ActiveId == id && is_readonly) + { + // FIXME: Refresh buffer because cursor/selection code uses that data (see repro #8242) + // The "simple" way would be to copy buf into state->TextA, like in the block above. + // But because we like to live dangerously, we do a little swap.... + // Removing the swap and only doing a TextA.clear() is a way to identify who's using TextA.Data. + state->TextLen = (int)strlen(buf); + state->TextA.clear(); + state->TextA.Data = buf; // Ouch + state->TextA.Size = state->TextLen + 1; + readonly_swapped_text_data = true; // Need to always ensure that every code path below lead to this being handled + //state->TextA.resize(buf_size + 1); + //memcpy(state->TextA.Data, buf, state->TextLen + 1); + } + // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) if (g.ActiveId == id && state == NULL) ClearActiveID(); @@ -5008,10 +5027,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ callback_data.UserData = callback_user_data; // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 + char* callback_buf = is_readonly ? buf : state->TextA.Data; + state->CallbackTextBackup.resize(state->TextLen + 1); - memcpy(state->CallbackTextBackup.Data, state->TextA.Data, state->TextLen + 1); + memcpy(state->CallbackTextBackup.Data, callback_buf, state->TextLen + 1); - char* callback_buf = is_readonly ? buf : state->TextA.Data; callback_data.EventKey = event_key; callback_data.Buf = callback_buf; callback_data.BufTextLen = state->TextLen; @@ -5142,7 +5162,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // - Measure text height (for scrollbar) // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort) // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8. - const char* text_begin = state->TextA.Data; + const char* text_begin = buf_display; const char* text_end = text_begin + state->TextLen; ImVec2 cursor_offset, select_start_offset; @@ -5304,6 +5324,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_password && !is_displaying_hint) PopFont(); + if (readonly_swapped_text_data) + { + IM_ASSERT(state->TextA.Data == buf); + state->TextA.Size = 0; + state->TextA.Data = NULL; + } + if (is_multiline) { // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (see #4761, #7870)... From 32f11402f96f516be68b56f9eb338f382c544819 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Dec 2024 16:47:02 +0100 Subject: [PATCH 088/716] InputText: use TextSrc more consistently to facilitate accessing user buffer in text processing code. (#8242) Followup to e900571 Removed SetClipboardText() trick used in abd07f6d (#7925) --- imgui_internal.h | 1 + imgui_widgets.cpp | 79 +++++++++++++++++++++-------------------------- 2 files changed, 36 insertions(+), 44 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index d371ab9e674b..6be907bb573b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1124,6 +1124,7 @@ struct IMGUI_API ImGuiInputTextState ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. ImGuiID ID; // widget id owning the text state int TextLen; // UTF-8 length of the string in TextA (in bytes) + const char* TextSrc; // == TextA.Data unless read-only, in which case == buf passed to InputText(). Field only set and valid _inside_ the call InputText() call. ImVector TextA; // main UTF8 buffer. TextA.Size is a buffer size! Should always be >= buf_size passed by user (and of course >= CurLenA + 1). ImVector TextToRevertTo; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered) ImVector CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3d135dca923b..b0f28903ae1d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3938,12 +3938,12 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c namespace ImStb { static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->TextLen; } -static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextA[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextA.Data + line_start_idx + char_idx, obj->TextA.Data + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } +static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } static char STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { - const char* text = obj->TextA.Data; + const char* text = obj->TextSrc; const char* text_remaining = NULL; const ImVec2 size = InputTextCalcTextSize(obj->Ctx, text + line_start_idx, text + obj->TextLen, &text_remaining, NULL, true); r->x0 = 0.0f; @@ -3962,15 +3962,15 @@ static int IMSTB_TEXTEDIT_GETNEXTCHARINDEX_IMPL(ImGuiInputTextState* obj, int id if (idx >= obj->TextLen) return obj->TextLen + 1; unsigned int c; - return idx + ImTextCharFromUtf8(&c, obj->TextA.Data + idx, obj->TextA.Data + obj->TextLen); + return idx + ImTextCharFromUtf8(&c, obj->TextSrc + idx, obj->TextSrc + obj->TextLen); } static int IMSTB_TEXTEDIT_GETPREVCHARINDEX_IMPL(ImGuiInputTextState* obj, int idx) { if (idx <= 0) return -1; - const char* p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, obj->TextA.Data + idx); - return (int)(p - obj->TextA.Data); + const char* p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, obj->TextSrc + idx); + return (int)(p - obj->TextSrc); } static bool ImCharIsSeparatorW(unsigned int c) @@ -3993,10 +3993,10 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) return 0; - const char* curr_p = obj->TextA.Data + idx; - const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextA.Data + obj->TextLen); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextA.Data + obj->TextLen); + const char* curr_p = obj->TextSrc + idx; + const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); + unsigned int curr_c; ImTextCharFromUtf8(&curr_c, curr_p, obj->TextSrc + obj->TextLen); + unsigned int prev_c; ImTextCharFromUtf8(&prev_c, prev_p, obj->TextSrc + obj->TextLen); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4009,10 +4009,10 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0) return 0; - const char* curr_p = obj->TextA.Data + idx; - const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextA.Data, curr_p); - unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextA.Data + obj->TextLen); - unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextA.Data + obj->TextLen); + const char* curr_p = obj->TextSrc + idx; + const char* prev_p = ImTextFindPreviousUtf8Codepoint(obj->TextSrc, curr_p); + unsigned int prev_c; ImTextCharFromUtf8(&prev_c, curr_p, obj->TextSrc + obj->TextLen); + unsigned int curr_c; ImTextCharFromUtf8(&curr_c, prev_p, obj->TextSrc + obj->TextLen); bool prev_white = ImCharIsBlankW(prev_c); bool prev_separ = ImCharIsSeparatorW(prev_c); @@ -4050,6 +4050,7 @@ static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n) { // Offset remaining text (+ copy zero terminator) + IM_ASSERT(obj->TextSrc == obj->TextA.Data); char* dst = obj->TextA.Data + pos; char* src = obj->TextA.Data + pos + n; memmove(dst, src, obj->TextLen - n - pos + 1); @@ -4067,11 +4068,13 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const ch return false; // Grow internal buffer if needed + IM_ASSERT(obj->TextSrc == obj->TextA.Data); if (new_text_len + text_len + 1 > obj->TextA.Size) { if (!is_resizable) return false; obj->TextA.resize(text_len + ImClamp(new_text_len, 32, ImMax(256, new_text_len)) + 1); + obj->TextSrc = obj->TextA.Data; } char* text = obj->TextA.Data; @@ -4218,6 +4221,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons IM_ASSERT(Buf == edit_state->TextA.Data); int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; edit_state->TextA.resize(new_buf_size + 1); + edit_state->TextSrc = edit_state->TextA.Data; Buf = edit_state->TextA.Data; BufSize = edit_state->BufCapacity = new_buf_size; } @@ -4507,7 +4511,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav); const bool init_state = (init_make_active || user_scroll_active); - bool readonly_swapped_text_data = false; if (init_reload_from_user_buf) { int new_len = (int)strlen(buf); @@ -4612,22 +4615,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Expose scroll in a manner that is agnostic to us using a child window if (is_multiline && state != NULL) state->Scroll.y = draw_window->Scroll.y; - } - if (g.ActiveId == id && is_readonly) - { - // FIXME: Refresh buffer because cursor/selection code uses that data (see repro #8242) - // The "simple" way would be to copy buf into state->TextA, like in the block above. - // But because we like to live dangerously, we do a little swap.... - // Removing the swap and only doing a TextA.clear() is a way to identify who's using TextA.Data. - state->TextLen = (int)strlen(buf); - state->TextA.clear(); - state->TextA.Data = buf; // Ouch - state->TextA.Size = state->TextLen + 1; - readonly_swapped_text_data = true; // Need to always ensure that every code path below lead to this being handled - //state->TextA.resize(buf_size + 1); - //memcpy(state->TextA.Data, buf, state->TextLen + 1); + // Read-only mode always ever read from source buffer. Refresh TextLen when active. + if (is_readonly && state != NULL) + state->TextLen = (int)strlen(buf); + //if (is_readonly && state != NULL) + // state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation. } + if (state != NULL) + state->TextSrc = is_readonly ? buf : state->TextA.Data; // We have an edge case if ActiveId was set through another widget (e.g. widget being swapped), clear id immediately (don't wait until the end of the function) if (g.ActiveId == id && state == NULL) @@ -4892,13 +4888,13 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Cut, Copy if (g.PlatformIO.Platform_SetClipboardTextFn != NULL) { + // SetClipboardText() only takes null terminated strings + state->TextSrc may point to read-only user buffer, so we need to make a copy. const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0; const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->TextLen; - - char backup = state->TextA.Data[ie]; - state->TextA.Data[ie] = 0; // A bit of a hack since SetClipboardText only takes null terminated strings - SetClipboardText(state->TextA.Data + ib); - state->TextA.Data[ie] = backup; + g.TempBuffer.reserve(ie - ib + 1); + memcpy(g.TempBuffer.Data, state->TextSrc, ie - ib); + g.TempBuffer.Data[ie] = 0; + SetClipboardText(g.TempBuffer.Data); } if (is_cut) { @@ -5028,7 +5024,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // FIXME-OPT: Undo stack reconcile needs a backup of the data until we rework API, see #7925 char* callback_buf = is_readonly ? buf : state->TextA.Data; - + IM_ASSERT(callback_buf == state->TextSrc); state->CallbackTextBackup.resize(state->TextLen + 1); memcpy(state->CallbackTextBackup.Data, callback_buf, state->TextLen + 1); @@ -5066,9 +5062,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } // Will copy result string if modified - if (!is_readonly && strcmp(state->TextA.Data, buf) != 0) + if (!is_readonly && strcmp(state->TextSrc, buf) != 0) { - apply_new_text = state->TextA.Data; + apply_new_text = state->TextSrc; apply_new_text_length = state->TextLen; value_changed = true; } @@ -5324,13 +5320,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_password && !is_displaying_hint) PopFont(); - if (readonly_swapped_text_data) - { - IM_ASSERT(state->TextA.Data == buf); - state->TextA.Size = 0; - state->TextA.Data = NULL; - } - if (is_multiline) { // For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (see #4761, #7870)... @@ -5349,6 +5338,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ g.LastItemData.StatusFlags = item_data_backup.StatusFlags; } } + if (state) + state->TextSrc = NULL; // Log as text if (g.LogEnabled && (!is_password || is_displaying_hint)) From cd6c83cdccb78fa1ab20cece35ccc8c3317ecdc8 Mon Sep 17 00:00:00 2001 From: Raffaello Bertini Date: Wed, 18 Dec 2024 10:54:16 +0100 Subject: [PATCH 089/716] Fixes GCC warnings (#8241) --- imgui.cpp | 6 ++++-- imgui.h | 1 + imgui_demo.cpp | 3 +++ imgui_draw.cpp | 6 ++++-- imgui_internal.h | 3 ++- imgui_tables.cpp | 3 +++ imgui_widgets.cpp | 4 ++++ 7 files changed, 21 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 87d0aaa47be7..cf59a5a531d4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1095,7 +1095,7 @@ CODE #else #include #endif -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES) +#if defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) // The UWP and GDK Win32 API subsets don't support clipboard nor IME functions #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS @@ -1144,12 +1144,14 @@ CODE #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size -#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif // Debug options diff --git a/imgui.h b/imgui.h index 98f0a4d20573..e1b8796f3623 100644 --- a/imgui.h +++ b/imgui.h @@ -139,6 +139,7 @@ Index of this file: #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c09c8eca7af7..6425e318e6e7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -146,11 +146,14 @@ Index of this file: #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wformat-security" // warning: format string is not a string literal (potentially insecure) #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif // Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f51fff3a6357..2b1e10c4e9eb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -67,13 +67,16 @@ Index of this file: #pragma clang diagnostic ignored "-Wreserved-identifier" // warning: identifier '_Xxx' is reserved because it starts with '_' followed by a capital letter #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif //------------------------------------------------------------------------- @@ -105,13 +108,12 @@ namespace IMGUI_STB_NAMESPACE #pragma clang diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used #pragma clang diagnostic ignored "-Wmissing-prototypes" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" -#pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier #endif #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits] -#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" // warning: this statement may fall through #endif #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) diff --git a/imgui_internal.h b/imgui_internal.h index 6be907bb573b..947277489740 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -101,6 +101,7 @@ Index of this file: #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #endif @@ -460,7 +461,7 @@ static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } -template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * (T)t); } template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 7dd97c6f214a..96e46141809e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -232,8 +232,11 @@ Index of this file: #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #endif //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b0f28903ae1d..4e6cbee9acf5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -82,9 +82,13 @@ Index of this file: #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe +#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated +#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif //------------------------------------------------------------------------- From 457fae24e7a9fd30ad24b35e2f2ac714bca522bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Dec 2024 18:13:55 +0100 Subject: [PATCH 090/716] Silence more zealous GCC warning. (#8241) --- backends/imgui_impl_opengl3.cpp | 1 + imgui_demo.cpp | 1 + imgui_draw.cpp | 1 + imgui_tables.cpp | 3 ++- imgui_widgets.cpp | 3 ++- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index b47ac9ab1c97..efc1a3c49283 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -137,6 +137,7 @@ #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx' #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader) +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #endif // GL includes diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6425e318e6e7..621fc4f434b3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -153,6 +153,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub. +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2b1e10c4e9eb..6caba22fa5bd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -75,6 +75,7 @@ Index of this file: #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value #pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 96e46141809e..e90da3ec73ad 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -234,9 +234,10 @@ Index of this file: #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif //----------------------------------------------------------------------------- diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4e6cbee9acf5..b8680ab34714 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -85,9 +85,10 @@ Index of this file: #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'int'/'void*', but argument X has type 'unsigned int'/'ImGuiWindow*' #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked -#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" // warning: bitwise operation between different enumeration types ('XXXFlags_' and 'XXXFlagsPrivate_') is deprecated #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function +#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when simplifying division / ..when changing X +- C1 cmp C2 to X cmp C2 -+ C1 +#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers #endif From ae839620b9670ee5303860a0adbb76c9780eb856 Mon Sep 17 00:00:00 2001 From: Tiamat-Defender <166345691+Tiamat-Defender@users.noreply.github.com> Date: Thu, 19 Dec 2024 08:22:56 -0500 Subject: [PATCH 091/716] Docs: Updated EXAMPLES.md (#8246) --- docs/EXAMPLES.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 66ad24ef7f81..f84f9497b6dd 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -175,7 +175,7 @@ Raw Windows + OpenGL3 + example (modern, programmable pipeline)
**Building** -Unfortunately nowadays it is still tedious to create and maintain portable build files using external +Unfortunately, nowadays it is still tedious to create and maintain portable build files using external libraries (the kind we're using here to create a window and render 3D triangles) without relying on third party software and build systems. For most examples here we choose to provide: - Makefiles for Linux/OSX @@ -191,22 +191,22 @@ If you are interested in using Cmake to build and links examples, see: **About mouse cursor latency** -Dear ImGui has no particular extra lag for most behaviors, +Dear ImGui does not introduce significant extra lag for most behaviors, e.g. the last value passed to 'io.AddMousePosEvent()' before NewFrame() will result in windows being moved to the right spot at the time of EndFrame()/Render(). At 60 FPS your experience should be pleasant. -However, consider that OS mouse cursors are typically drawn through a very specific hardware accelerated -path and will feel smoother than the majority of contents rendered via regular graphics API (including, +However, consider that OS mouse cursors are typically rendered through a very specific hardware-accelerated +path, which makes them feel smoother than the majority of content rendered via regular graphics API (including, but not limited to Dear ImGui windows). Because UI rendering and interaction happens on the same plane as the mouse, that disconnect may be jarring to particularly sensitive users. You may experiment with enabling the io.MouseDrawCursor flag to request Dear ImGui to draw a mouse cursor using the regular graphics API, to help you visualize the difference between a "hardware" cursor and a regularly rendered software cursor. -However, rendering a mouse cursor at 60 FPS will feel sluggish so you likely won't want to enable that at +However, rendering a mouse cursor at 60 FPS will feel sluggish, so you likely won't want to enable that at all times. It might be beneficial for the user experience to switch to a software rendered cursor _only_ when an interactive drag is in progress. -Note that some setup or GPU drivers are likely to be causing extra display lag depending on their settings. -If you feel that dragging windows feels laggy and you are not sure what the cause is: try to build a simple -drawing a flat 2D shape directly under the mouse cursor! +Note that some setup configurations or GPU drivers may introduce additional display lag depending on their settings. +If you notice that dragging windows is laggy and you are not sure what the cause is: try drawing a simple +2D shape directly under the mouse cursor to help identify the issue! From 9b0e61aaaa7af2e39b8963d16542e2924813d3f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Dec 2024 15:10:44 +0100 Subject: [PATCH 092/716] InputText: sanity checks to e.g. detect non zero-terminated buffers + removed a redundant strlen() call during activation. --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 25649c16f28d..b6365be59053 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,8 @@ Other changes: were not applied when pasting from clipbard. (#8229) - InputText: Fixed issue when activating a ReadOnly field when the underlying value is being modified. (#8242) +- InputText: Added sanity check to detect some cases of passing a non + zero-terminated input buffer. - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b8680ab34714..335ab4cde32c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4389,6 +4389,7 @@ void ImGui::InputTextDeactivateHook(ImGuiID id) else { IM_ASSERT(state->TextA.Data != 0); + IM_ASSERT(state->TextA[state->TextLen] == 0); g.InputTextDeactivatedState.TextA.resize(state->TextLen + 1); memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->TextLen + 1); } @@ -4519,6 +4520,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (init_reload_from_user_buf) { int new_len = (int)strlen(buf); + IM_ASSERT(new_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); state->WantReloadUserBuf = false; InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len); state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. @@ -4540,6 +4542,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Take a copy of the initial buffer value. // From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode) const int buf_len = (int)strlen(buf); + IM_ASSERT(buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); @@ -4551,7 +4554,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Start edition state->ID = id; - state->TextLen = (int)strlen(buf); + state->TextLen = buf_len; if (!is_readonly) { state->TextA.resize(buf_size + 1); // we use +1 to make sure that .Data is always pointing to at least an empty string. From fd932297703c6da24b953f0be8e0733e0db4d9cf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Dec 2024 18:14:22 +0100 Subject: [PATCH 093/716] Tables, MultiSelect: Fixed an issue where column width may be mismeasured when calling BeginMultiSelect() while inside a table. (#8250) --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_widgets.cpp | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b6365be59053..afd6c57c122a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,8 @@ Other changes: value is being modified. (#8242) - InputText: Added sanity check to detect some cases of passing a non zero-terminated input buffer. +- Tables, MultiSelect: Fixed an issue where column width may be mismeasured + when calling BeginMultiSelect() while inside a table. (#8250) - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) diff --git a/imgui.h b/imgui.h index e1b8796f3623..68558fb4d336 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19162 +#define IMGUI_VERSION_NUM 19163 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 335ab4cde32c..0fef03ab5a8d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7518,6 +7518,12 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, int sel if (flags & ImGuiMultiSelectFlags_BoxSelect2d) flags &= ~ImGuiMultiSelectFlags_BoxSelect1d; + // FIXME: Workaround to the fact we override CursorMaxPos, meaning size measurement are lost. (#8250) + // They should perhaps be stacked properly? + if (ImGuiTable* table = g.CurrentTable) + if (table->CurrentColumn != -1) + TableEndCell(table); // This is currently safe to call multiple time. If that properly is lost we can extract the "save measurement" part of it. + // FIXME: BeginFocusScope() const ImGuiID id = window->IDStack.back(); ms->Clear(); From eed95027956805f83caddc0fd82dd05cdb2ee082 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 14:28:04 +0100 Subject: [PATCH 094/716] Error Handling: Fixed bugs recovering from within a table that created a child window, and from nested child windows. (#1651) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 29 +++++++++++++++++++---------- imgui_internal.h | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index afd6c57c122a..f91342903eb8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- Error Handling: Fixed bugs recovering from within a table that created + a child window, and from nested child windows. (#1651) - InputText: Fixed a bug where character replacements performed from a callback were not applied when pasting from clipbard. (#8229) - InputText: Fixed issue when activating a ReadOnly field when the underlying diff --git a/imgui.cpp b/imgui.cpp index cf59a5a531d4..c5ede70a3284 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3884,7 +3884,8 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; - WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false; + WithinEndChildID = 0; + WithinFrameScope = WithinFrameScopeWithImplicitWindow = false; GcCompactAll = false; TestEngineHookItems = false; TestEngine = NULL; @@ -6106,10 +6107,10 @@ void ImGui::EndChild() ImGuiContext& g = *GImGui; ImGuiWindow* child_window = g.CurrentWindow; - IM_ASSERT(g.WithinEndChild == false); + const ImGuiID backup_within_end_child_id = g.WithinEndChildID; IM_ASSERT(child_window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() calls - g.WithinEndChild = true; + g.WithinEndChildID = child_window->ID; ImVec2 child_size = child_window->Size; End(); if (child_window->BeginCount == 1) @@ -6141,7 +6142,7 @@ void ImGui::EndChild() if (g.HoveredWindow == child_window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; } - g.WithinEndChild = false; + g.WithinEndChildID = backup_within_end_child_id; g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } @@ -7773,7 +7774,7 @@ void ImGui::End() // Error checking: verify that user doesn't directly call End() on a child window. if (window->Flags & ImGuiWindowFlags_ChildWindow) - IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!"); + IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!"); // Close anything that is open if (window->DC.CurrentColumns) @@ -10485,8 +10486,16 @@ void ImGui::ErrorRecoveryTryToRecoverState(const ImGuiErrorRecoveryState* state_ ImGuiWindow* window = g.CurrentWindow; if (window->Flags & ImGuiWindowFlags_ChildWindow) { - IM_ASSERT_USER_ERROR(0, "Missing EndChild()"); - EndChild(); + if (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow) + { + IM_ASSERT_USER_ERROR(0, "Missing EndTable()"); + EndTable(); + } + else + { + IM_ASSERT_USER_ERROR(0, "Missing EndChild()"); + EndChild(); + } } else { @@ -11921,11 +11930,11 @@ void ImGui::EndPopup() NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); // Child-popups don't need to be laid out - IM_ASSERT(g.WithinEndChild == false); + const ImGuiID backup_within_end_child_id = g.WithinEndChildID; if (window->Flags & ImGuiWindowFlags_ChildWindow) - g.WithinEndChild = true; + g.WithinEndChildID = window->ID; End(); - g.WithinEndChild = false; + g.WithinEndChildID = backup_within_end_child_id; } // Helper to open a popup if mouse button is released over the item diff --git a/imgui_internal.h b/imgui_internal.h index 947277489740..316ac1844441 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2045,9 +2045,9 @@ struct ImGuiContext int FrameCount; int FrameCountEnded; int FrameCountRendered; + ImGuiID WithinEndChildID; // Set within EndChild() bool WithinFrameScope; // Set by NewFrame(), cleared by EndFrame() bool WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed - bool WithinEndChild; // Set within EndChild() bool GcCompactAll; // Request full GC bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log() void* TestEngine; // Test engine user data From 91e8f2b0febbbcb2c7eddf3f4f500fda71089118 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 15:13:49 +0100 Subject: [PATCH 095/716] Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f91342903eb8..8ecf76cde4e4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,8 @@ Other changes: yourself based on your own logic. (#8223) - Nav: Fixed an issue where Alt key would clear current active item on windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) +- Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even + if a popup is blocking mouse access to the debug log window. (#5855) - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] diff --git a/imgui.cpp b/imgui.cpp index c5ede70a3284..7d324a194464 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16501,7 +16501,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end) { TextUnformatted(line_begin, line_end); - if (!IsItemHovered()) + if (!IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) return; ImGuiContext& g = *GImGui; ImRect text_rect = g.LastItemData.Rect; From d30e102f3adab20865fd74864ddadd94d7559973 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 15:22:34 +0100 Subject: [PATCH 096/716] Scrollbar, TestEngine: for consistency, scrollbars are registered in _Menu layer. Amend f31d530. --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 7d324a194464..797f968d9ec7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6731,9 +6731,10 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImGuiStyle& style = g.Style; ImGuiWindowFlags flags = window->Flags; - // Ensure that ScrollBar doesn't read last frame's SkipItems + // Ensure that Scrollbar() doesn't read last frame's SkipItems IM_ASSERT(window->BeginCount == 0); window->SkipItems = false; + window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; // Draw window + handle manual resize // As we highlight the title bar when want_focus is set, multiple reappearing windows will have their title bar highlighted on their reappearing frame. @@ -6810,6 +6811,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar if (handle_borders_and_resize_grips) RenderWindowOuterBorders(window); } + window->DC.NavLayerCurrent = ImGuiNavLayer_Main; } // Render title text, collapse button, close button From 61d4bf95dc5345c77b97b279011fce2c46efcaa8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 17:17:40 +0100 Subject: [PATCH 097/716] Fonts: Allowing PushFont()/PopFont() to be called outside the imgui frame scope. (#3621) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8ecf76cde4e4..8a091be6a411 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,7 @@ Other changes: yourself based on your own logic. (#8223) - Nav: Fixed an issue where Alt key would clear current active item on windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) +- Fonts: Allowing PushFont()/PopFont() to be called outside the imgui frame scope. (#3621) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for diff --git a/imgui.cpp b/imgui.cpp index 797f968d9ec7..f074f4fe50cf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8018,7 +8018,8 @@ void ImGui::PushFont(ImFont* font) font = GetDefaultFont(); g.FontStack.push_back(font); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + if (ImGuiWindow* window = g.CurrentWindow) + window->DrawList->_SetTextureID(font->ContainerAtlas->TexID); } void ImGui::PopFont() @@ -8032,7 +8033,8 @@ void ImGui::PopFont() g.FontStack.pop_back(); ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + if (ImGuiWindow* window = g.CurrentWindow) + window->DrawList->_SetTextureID(font->ContainerAtlas->TexID); } void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) From 7219fa65c0212de1d352b5db8f7dfe43b11f00c9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 17:20:57 +0100 Subject: [PATCH 098/716] Revert "Fonts: Allowing PushFont()/PopFont() to be called outside the imgui frame scope. (#3621)" This reverts commit 61d4bf95dc5345c77b97b279011fce2c46efcaa8. --- docs/CHANGELOG.txt | 1 - imgui.cpp | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8a091be6a411..8ecf76cde4e4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,7 +58,6 @@ Other changes: yourself based on your own logic. (#8223) - Nav: Fixed an issue where Alt key would clear current active item on windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) -- Fonts: Allowing PushFont()/PopFont() to be called outside the imgui frame scope. (#3621) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for diff --git a/imgui.cpp b/imgui.cpp index f074f4fe50cf..797f968d9ec7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8018,8 +8018,7 @@ void ImGui::PushFont(ImFont* font) font = GetDefaultFont(); g.FontStack.push_back(font); SetCurrentFont(font); - if (ImGuiWindow* window = g.CurrentWindow) - window->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); } void ImGui::PopFont() @@ -8033,8 +8032,7 @@ void ImGui::PopFont() g.FontStack.pop_back(); ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); SetCurrentFont(font); - if (ImGuiWindow* window = g.CurrentWindow) - window->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); } void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) From 006721fbd6b0ee0f08256b89282e4b62e3378a79 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Dec 2024 18:15:28 +0100 Subject: [PATCH 099/716] Added ImFontAtlas section index in comments + minor tweaks to DX12 backends. --- backends/imgui_impl_dx12.cpp | 8 +++---- imgui_draw.cpp | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 16dcf5392ffe..24fdb7aa0025 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -19,7 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. +// 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. // 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). // 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. // 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools. @@ -409,7 +409,7 @@ static void ImGui_ImplDX12_CreateFontsTexture() hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); IM_ASSERT(SUCCEEDED(hr)); - HANDLE event = CreateEvent(0, 0, 0, 0); + HANDLE event = ::CreateEvent(0, 0, 0, 0); IM_ASSERT(event != nullptr); D3D12_COMMAND_QUEUE_DESC queueDesc = {}; @@ -440,12 +440,12 @@ static void ImGui_ImplDX12_CreateFontsTexture() IM_ASSERT(SUCCEEDED(hr)); fence->SetEventOnCompletion(1, event); - WaitForSingleObject(event, INFINITE); + ::WaitForSingleObject(event, INFINITE); cmdList->Release(); cmdAlloc->Release(); cmdQueue->Release(); - CloseHandle(event); + ::CloseHandle(event); fence->Release(); uploadBuffer->Release(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6caba22fa5bd..42bfb71625cf 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2386,6 +2386,38 @@ ImFontConfig::ImFontConfig() //----------------------------------------------------------------------------- // [SECTION] ImFontAtlas //----------------------------------------------------------------------------- +// - Default texture data encoded in ASCII +// - ImFontAtlas::ClearInputData() +// - ImFontAtlas::ClearTexData() +// - ImFontAtlas::ClearFonts() +// - ImFontAtlas::Clear() +// - ImFontAtlas::GetTexDataAsAlpha8() +// - ImFontAtlas::GetTexDataAsRGBA32() +// - ImFontAtlas::AddFont() +// - ImFontAtlas::AddFontDefault() +// - ImFontAtlas::AddFontFromFileTTF() +// - ImFontAtlas::AddFontFromMemoryTTF() +// - ImFontAtlas::AddFontFromMemoryCompressedTTF() +// - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF() +// - ImFontAtlas::AddCustomRectRegular() +// - ImFontAtlas::AddCustomRectFontGlyph() +// - ImFontAtlas::CalcCustomRectUV() +// - ImFontAtlas::GetMouseCursorTexData() +// - ImFontAtlas::Build() +// - ImFontAtlasBuildMultiplyCalcLookupTable() +// - ImFontAtlasBuildMultiplyRectAlpha8() +// - ImFontAtlasBuildWithStbTruetype() +// - ImFontAtlasGetBuilderForStbTruetype() +// - ImFontAtlasUpdateConfigDataPointers() +// - ImFontAtlasBuildSetupFont() +// - ImFontAtlasBuildPackCustomRects() +// - ImFontAtlasBuildRender8bppRectFromString() +// - ImFontAtlasBuildRender32bppRectFromString() +// - ImFontAtlasBuildRenderDefaultTexData() +// - ImFontAtlasBuildRenderLinesTexData() +// - ImFontAtlasBuildInit() +// - ImFontAtlasBuildFinish() +//----------------------------------------------------------------------------- // A work of art lies ahead! (. = white layer, X = black layer, others are blank) // The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes. @@ -3327,6 +3359,16 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) //------------------------------------------------------------------------- // [SECTION] ImFontAtlas: glyph ranges helpers //------------------------------------------------------------------------- +// - GetGlyphRangesDefault() +// - GetGlyphRangesGreek() +// - GetGlyphRangesKorean() +// - GetGlyphRangesChineseFull() +// - GetGlyphRangesChineseSimplifiedCommon() +// - GetGlyphRangesJapanese() +// - GetGlyphRangesCyrillic() +// - GetGlyphRangesThai() +// - GetGlyphRangesVietnamese() +//----------------------------------------------------------------------------- // Retrieve list of range (2 int per range, values are inclusive) const ImWchar* ImFontAtlas::GetGlyphRangesDefault() From 2a600bddcbe20fb7832cb0dfafb305704c0422be Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 23:11:37 +0100 Subject: [PATCH 100/716] ImGuiDebugLogFlags_EventFont should not be set by default (had no effect on master tho) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 797f968d9ec7..efa9c450130a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4062,7 +4062,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) StackSizesInBeginForCurrentWindow = NULL; DebugDrawIdConflictsCount = 0; - DebugLogFlags = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_OutputToTTY | ImGuiDebugLogFlags_EventFont; + DebugLogFlags = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_OutputToTTY; DebugLocateId = 0; DebugLogSkippedErrors = 0; DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None; From 18929bd6d6cffbacdae7a10732f58de9fdb540a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 23:26:21 +0100 Subject: [PATCH 101/716] Internals: merge ScaleWindowsInViewport() from docking branch. --- imgui.cpp | 19 +++++++++++++++++++ imgui_internal.h | 1 + 2 files changed, 20 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index efa9c450130a..47ac6046aa3c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14788,6 +14788,7 @@ void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count) //----------------------------------------------------------------------------- // - GetMainViewport() // - SetWindowViewport() [Internal] +// - ScaleWindowsInViewport() [Internal] // - UpdateViewportsNewFrame() [Internal] // (this section is more complete in the 'docking' branch) //----------------------------------------------------------------------------- @@ -14803,6 +14804,24 @@ void ImGui::SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport) window->Viewport = viewport; } +static void ScaleWindow(ImGuiWindow* window, float scale) +{ + ImVec2 origin = window->Viewport->Pos; + window->Pos = ImFloor((window->Pos - origin) * scale + origin); + window->Size = ImTrunc(window->Size * scale); + window->SizeFull = ImTrunc(window->SizeFull * scale); + window->ContentSize = ImTrunc(window->ContentSize * scale); +} + +// Scale all windows (position, size). Use when e.g. changing DPI. (This is a lossy operation!) +void ImGui::ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale) +{ + ImGuiContext& g = *GImGui; + for (ImGuiWindow* window : g.Windows) + if (window->Viewport == viewport) + ScaleWindow(window, scale); +} + // Update viewports and monitor infos static void ImGui::UpdateViewportsNewFrame() { diff --git a/imgui_internal.h b/imgui_internal.h index 316ac1844441..881e2ffd654f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3020,6 +3020,7 @@ namespace ImGui IMGUI_API void CallContextHooks(ImGuiContext* context, ImGuiContextHookType type); // Viewports + IMGUI_API void ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale); IMGUI_API void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport); // Settings From 6982ce43f5b143c5dce5fab0ce07dd4867b705ae Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Dec 2024 17:53:09 +0100 Subject: [PATCH 102/716] InputText: fixed badly broken clipboard copy/bug (#8254, #8242) Broken by 32f1140 --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0fef03ab5a8d..e19974f665b4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4900,8 +4900,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const int ib = state->HasSelection() ? ImMin(state->Stb->select_start, state->Stb->select_end) : 0; const int ie = state->HasSelection() ? ImMax(state->Stb->select_start, state->Stb->select_end) : state->TextLen; g.TempBuffer.reserve(ie - ib + 1); - memcpy(g.TempBuffer.Data, state->TextSrc, ie - ib); - g.TempBuffer.Data[ie] = 0; + memcpy(g.TempBuffer.Data, state->TextSrc + ib, ie - ib); + g.TempBuffer.Data[ie - ib] = 0; SetClipboardText(g.TempBuffer.Data); } if (is_cut) From 87f3109c1af835be0e5b4b4410baa1c66ced7b33 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Fri, 3 Jan 2025 21:07:42 +0100 Subject: [PATCH 103/716] Fix capitalization of ImGuiID in comment. (#8283) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 68558fb4d336..ca9d9bf3769f 100644 --- a/imgui.h +++ b/imgui.h @@ -2895,7 +2895,7 @@ struct ImGuiSelectionBasicStorage IMGUI_API void Clear(); // Clear selection IMGUI_API void Swap(ImGuiSelectionBasicStorage& r); // Swap two selections IMGUI_API void SetItemSelected(ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function) - IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiId id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' + IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }' inline ImGuiID GetStorageIdFromIndex(int idx) { return AdapterIndexToStorageId(this, idx); } // Convert index to item id based on provided adapter. }; From 2d2c7d3f9557074d7a24de4a5b8724ef09fad118 Mon Sep 17 00:00:00 2001 From: Helodity Date: Sun, 22 Dec 2024 22:48:07 -0500 Subject: [PATCH 104/716] Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). --- backends/imgui_impl_allegro5.cpp | 14 ++++++++++++-- docs/CHANGELOG.txt | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 28d1b1536f47..3718b64eace4 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn @@ -95,6 +96,7 @@ struct ImGui_ImplAllegro5_Data ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible; ALLEGRO_VERTEX_DECL* VertexDecl; char* ClipboardTextData; + ImGuiMouseCursor LastCursor; ImVector BufVertices; ImVector BufIndices; @@ -438,6 +440,7 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) bd->Display = display; + bd->LastCursor = ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE; // Create custom vertex declaration. // Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 floats. @@ -568,9 +571,16 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor() ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); - if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) + + // Hide OS mouse cursor if imgui is drawing it + if (io.MouseDrawCursor) + imgui_cursor = ImGuiMouseCursor_None; + + if (bd->LastCursor == imgui_cursor) + return; + bd->LastCursor = imgui_cursor; + if (imgui_cursor == ImGuiMouseCursor_None) { - // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible); } else diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8ecf76cde4e4..1ef576c3d80d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,6 +60,8 @@ Other changes: windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) +- Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears + to leak on on X11 (#8256). [@Helodity] - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] From c147a59bb0e9ad57ee0cac0056a744ff2d97bb3e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 13:58:02 +0100 Subject: [PATCH 105/716] Clarified alternative for ImGuiButtonFlags_Repeat being ImGuiItemFlags_ButtonRepeat. (#8293) --- imgui_internal.h | 2 +- imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 881e2ffd654f..db3c089ebb24 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -914,7 +914,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_PressedOnRelease = 1 << 7, // return true on release (default requires click+release) ImGuiButtonFlags_PressedOnDoubleClick = 1 << 8, // return true on double-click (default requires click+release) ImGuiButtonFlags_PressedOnDragDropHold = 1 << 9, // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) - //ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat + //ImGuiButtonFlags_Repeat = 1 << 10, // hold to repeat -> use ImGuiItemFlags_ButtonRepeat instead. ImGuiButtonFlags_FlattenChildren = 1 << 11, // allow interactions even if a child window is overlapping ImGuiButtonFlags_AllowOverlap = 1 << 12, // require previous frame HoveredId to either match id or be null before being usable. //ImGuiButtonFlags_DontClosePopups = 1 << 13, // disable automatically closing parent popup on press diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e19974f665b4..f8c5ad7a937d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -477,7 +477,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // - PressedOnDragDropHold can generally be associated with any flag. // - PressedOnDoubleClick can be associated by PressedOnClickRelease/PressedOnRelease, in which case the second release event won't be reported. //------------------------------------------------------------------------------------------------------------------------------------------------ -// The behavior of the return-value changes when ImGuiButtonFlags_Repeat is set: +// The behavior of the return-value changes when ImGuiItemFlags_ButtonRepeat is set: // Repeat+ Repeat+ Repeat+ Repeat+ // PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick //------------------------------------------------------------------------------------------------------------------------------------------------- From a0f907933d8def4ffcb29fffe887889339c82f11 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 14:07:06 +0100 Subject: [PATCH 106/716] Happy new year! --- LICENSE.txt | 2 +- imgui.cpp | 2 +- imgui.h | 1 + imgui_demo.cpp | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 3282f5b5b105..00ae473abe62 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2024 Omar Cornut +Copyright (c) 2014-2025 Omar Cornut Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/imgui.cpp b/imgui.cpp index 47ac6046aa3c..3bb95bfcea05 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -25,7 +25,7 @@ // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. // Everything else should be asked in 'Issues'! We are building a database of cross-linked knowledge there. -// Copyright (c) 2014-2024 Omar Cornut +// Copyright (c) 2014-2025 Omar Cornut // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. // See LICENSE.txt for copyright and licensing details (standard MIT License). // This library is free but needs your support to sustain development and maintenance. diff --git a/imgui.h b/imgui.h index ca9d9bf3769f..294eaee009ab 100644 --- a/imgui.h +++ b/imgui.h @@ -2694,6 +2694,7 @@ struct ImGuiListClipper // - It is important that we are keeping those disabled by default so they don't leak in user space. // - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h) // - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4. +// - We intentionally provide ImVec2*float but not float*ImVec2: this is rare enough and we want to reduce the surface for possible user mistake. #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 621fc4f434b3..c4d93bb74a97 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7692,7 +7692,8 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding"); ImGui::Separator(); - ImGui::Text("By Omar Cornut and all Dear ImGui contributors."); + ImGui::Text("(c) 2014-2025 Omar Cornut"); + ImGui::Text("Developed by Omar Cornut and all Dear ImGui contributors."); ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information."); ImGui::Text("If your company uses this, please consider funding the project."); From f169102c8eac86efba55aeca33bce5cc77626ae4 Mon Sep 17 00:00:00 2001 From: juur Date: Mon, 6 Jan 2025 12:58:05 +0000 Subject: [PATCH 107/716] Misc: fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) --- docs/CHANGELOG.txt | 1 + misc/cpp/imgui_stdlib.cpp | 3 +++ misc/cpp/imgui_stdlib.h | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1ef576c3d80d..aa5f96e0f7db 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,6 +60,7 @@ Other changes: windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) +- Misc: fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for diff --git a/misc/cpp/imgui_stdlib.cpp b/misc/cpp/imgui_stdlib.cpp index cf69aa89a630..c04d487cc77a 100644 --- a/misc/cpp/imgui_stdlib.cpp +++ b/misc/cpp/imgui_stdlib.cpp @@ -8,6 +8,7 @@ // https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness #include "imgui.h" +#ifndef IMGUI_DISABLE #include "imgui_stdlib.h" // Clang warnings with -Weverything @@ -83,3 +84,5 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* #if defined(__clang__) #pragma clang diagnostic pop #endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/misc/cpp/imgui_stdlib.h b/misc/cpp/imgui_stdlib.h index 835a808f2fae..697fc34ad2d3 100644 --- a/misc/cpp/imgui_stdlib.h +++ b/misc/cpp/imgui_stdlib.h @@ -9,6 +9,8 @@ #pragma once +#ifndef IMGUI_DISABLE + #include namespace ImGui @@ -19,3 +21,5 @@ namespace ImGui IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr); } + +#endif // #ifndef IMGUI_DISABLE From 80aafbc81b0956f9d657ab80838b6fcb2116a8b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 14:22:03 +0100 Subject: [PATCH 108/716] Data types: moved ImGuiDataType_String to public API as a convenience enum value only. (#8266) --- imgui.h | 3 ++- imgui_internal.h | 3 +-- imgui_widgets.cpp | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 294eaee009ab..0f7a99862432 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19163 +#define IMGUI_VERSION_NUM 19164 #define IMGUI_HAS_TABLE /* @@ -1399,6 +1399,7 @@ enum ImGuiDataType_ ImGuiDataType_Float, // float ImGuiDataType_Double, // double ImGuiDataType_Bool, // bool (provided for user convenience, not supported by scalar widgets) + ImGuiDataType_String, // char* (provided for user convenience, not supported by scalar widgets) ImGuiDataType_COUNT }; diff --git a/imgui_internal.h b/imgui_internal.h index db3c089ebb24..850136b0db2a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -827,8 +827,7 @@ struct ImGuiDataTypeInfo // Extend ImGuiDataType_ enum ImGuiDataTypePrivate_ { - ImGuiDataType_String = ImGuiDataType_COUNT + 1, - ImGuiDataType_Pointer, + ImGuiDataType_Pointer = ImGuiDataType_COUNT + 1, ImGuiDataType_ID, }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f8c5ad7a937d..854f09634bd0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2171,6 +2171,7 @@ static const ImGuiDataTypeInfo GDataTypeInfo[] = { sizeof(float), "float", "%.3f","%f" }, // ImGuiDataType_Float (float are promoted to double in va_arg) { sizeof(double), "double","%f", "%lf" }, // ImGuiDataType_Double { sizeof(bool), "bool", "%d", "%d" }, // ImGuiDataType_Bool + { 0, "char*","%s", "%s" }, // ImGuiDataType_String }; IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT); From 2f1194a29618b9ca19d8902643deb6efafe2769c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 14:35:57 +0100 Subject: [PATCH 109/716] Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) --- docs/CHANGELOG.txt | 3 ++- imgui_demo.cpp | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index aa5f96e0f7db..ab226ebaa0ad 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,7 +60,8 @@ Other changes: windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) -- Misc: fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] +- Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] +- Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c4d93bb74a97..36d8f441584b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -295,6 +295,7 @@ struct ExampleMemberInfo // Metadata description of ExampleTreeNode struct. static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] { + { "MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name) }, { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) }, { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) }, { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) }, @@ -8957,6 +8958,8 @@ struct ExampleAppPropertyEditor ImGui::Separator(); if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY)) { + // Push object ID after we entered the table, so table is shared for all objects + ImGui::PushID((int)node->UID); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger if (node->HasData) @@ -8995,10 +8998,16 @@ struct ExampleAppPropertyEditor ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max); break; } + case ImGuiDataType_String: + { + ImGui::InputText("##Editor", reinterpret_cast(field_ptr), 28); + break; + } } ImGui::PopID(); } } + ImGui::PopID(); ImGui::EndTable(); } } From d0021e16215309e3b4f5180cdd35f916ebc7c12a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 15:01:59 +0100 Subject: [PATCH 110/716] Backends: Metal: Fixed resource leak when using multiple contexts. (#7419) --- backends/imgui_impl_metal.mm | 11 ++++------- docs/CHANGELOG.txt | 1 + 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 5680dea9d40c..edd7fa181e29 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -306,17 +306,14 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c indexBufferOffset += (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx); } + __block MetalContext* sharedMetalContext = bd->SharedMetalContext; [commandBuffer addCompletedHandler:^(id) { dispatch_async(dispatch_get_main_queue(), ^{ - ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); - if (bd != nullptr) + @synchronized(bd->SharedMetalContext.bufferCache) { - @synchronized(bd->SharedMetalContext.bufferCache) - { - [bd->SharedMetalContext.bufferCache addObject:vertexBuffer]; - [bd->SharedMetalContext.bufferCache addObject:indexBuffer]; - } + [sharedMetalContext.bufferCache addObject:vertexBuffer]; + [sharedMetalContext.bufferCache addObject:indexBuffer]; } }); }]; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ab226ebaa0ad..da95a1aacc2a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,7 @@ Other changes: - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] +- Backends: Metal: Fixed resource leak when using multiple contexts. (#7419) [@anszom] - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] From e7e898ea179cfeb5a4d62f2387691e8e28395d5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 16:12:33 +0100 Subject: [PATCH 111/716] Tables: Fixed TableAngledHeadersRow() creating an infinite horizontal scrolling region when the table is hosted in a viewport with negative coordinates. --- docs/CHANGELOG.txt | 3 +++ imgui_tables.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index da95a1aacc2a..f440a7c63b00 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,9 @@ Other changes: value is being modified. (#8242) - InputText: Added sanity check to detect some cases of passing a non zero-terminated input buffer. +- Tables: Fixed TableAngledHeadersRow() creating an infinite horizontal + scrolling region when the table is hosted in a viewport with negative + coordinates. - Tables, MultiSelect: Fixed an issue where column width may be mismeasured when calling BeginMultiSelect() while inside a table. (#8250) - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e90da3ec73ad..1ab9c703ec5d 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3299,7 +3299,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label const ImVec2 align = g.Style.TableAngledHeadersTextAlign; // Draw background and labels in first pass, then all borders. - float max_x = 0.0f; + float max_x = -FLT_MAX; for (int pass = 0; pass < 2; pass++) for (int order_n = 0; order_n < data_count; order_n++) { From dbf76f62f9e1fbbc38d5cd2c50661994ff4956a1 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 6 Jan 2025 17:17:48 +0100 Subject: [PATCH 112/716] Update issue_template.yml --- .github/ISSUE_TEMPLATE/issue_template.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/issue_template.yml b/.github/ISSUE_TEMPLATE/issue_template.yml index 792d8f63ed49..c1b57de4b739 100644 --- a/.github/ISSUE_TEMPLATE/issue_template.yml +++ b/.github/ISSUE_TEMPLATE/issue_template.yml @@ -5,9 +5,11 @@ body: attributes: value: | FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions) - For anything else: we are happy to use 'GitHub Issues' for many types of open-ended questions. We are encouraging 'Issues' becoming a large, centralized and cross-referenced database of Dear ImGui contents. + For anything else: **we are happy to use 'GitHub Issues' for many types of open-ended questions**. We are encouraging 'Issues' becoming a large, centralized, tagged, cross-referenced database of Dear ImGui contents. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users. + + **If you are using Dear ImGui as part of a job that you are being well-paid for** and your company is not a sponsor. Please be mindful that this is a Free Software and you might be about to ask volunteers to help you doing your job. Please put extra effort describing your issue or question properly. If your company is wealthy, please read [Funding](https://github.com/ocornut/imgui/wiki/Funding) and consider getting in touch. - type: markdown attributes: value: | From a2e21727c0196beb3848b77483662f70f9245c5c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 17:29:04 +0100 Subject: [PATCH 113/716] Backends: Vulkan: moved helpers to backend: ImGui_ImplVulkanH_SelectPhysicalDevice(), ImGui_ImplVulkanH_SelectQueueFamilyIndex(). (#8180) --- backends/imgui_impl_vulkan.cpp | 44 +++++++++++++++++++++++ backends/imgui_impl_vulkan.h | 18 +++++++--- docs/CHANGELOG.txt | 2 ++ examples/example_glfw_vulkan/main.cpp | 48 +++----------------------- examples/example_sdl2_opengl3/main.cpp | 2 +- examples/example_sdl2_vulkan/main.cpp | 48 +++----------------------- examples/example_sdl3_vulkan/main.cpp | 48 +++----------------------- 7 files changed, 72 insertions(+), 138 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 1de6e2353879..1953288d92cf 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-06: Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. // 2024-12-11: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) // 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) // 2024-10-07: Vulkan: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -1334,6 +1335,49 @@ VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_d return VK_PRESENT_MODE_FIFO_KHR; // Always available } +VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance) +{ + uint32_t gpu_count; + VkResult err = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr); + check_vk_result(err); + IM_ASSERT(gpu_count > 0); + + ImVector gpus; + gpus.resize(gpu_count); + err = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.Data); + check_vk_result(err); + + // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers + // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple + // dedicated GPUs) is out of scope of this sample. + for (VkPhysicalDevice& device : gpus) + { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + return device; + } + + // Use first GPU (Integrated) is a Discrete one is not available. + if (gpu_count > 0) + return gpus[0]; + return VK_NULL_HANDLE; +} + + +uint32_t ImGui_ImplVulkanH_SelectQueueFamilyIndex(VkPhysicalDevice physical_device) +{ + uint32_t count; + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, nullptr); + ImVector queues_properties; + queues_properties.resize((int)count); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &count, queues_properties.Data); + for (uint32_t i = 0; i < count; i++) + if (queues_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + return i; + return (uint32_t)-1; +} + void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) { IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 37f700b62160..5621acbddb64 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -135,18 +135,24 @@ struct ImGui_ImplVulkan_RenderState //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers -// (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app.) //------------------------------------------------------------------------- +// Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own engine/app. +// // You probably do NOT need to use or care about those functions. // Those functions only exist because: // 1) they facilitate the readability and maintenance of the multiple main.cpp examples files. // 2) the multi-viewport / platform window implementation needs them internally. -// Generally we avoid exposing any kind of superfluous high-level helpers in the bindings, +// Generally we avoid exposing any kind of superfluous high-level helpers in the backends, // but it is too much code to duplicate everywhere so we exceptionally expose them. // -// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, render pass, frame buffers, etc.). -// You may read this code to learn about Vulkan, but it is recommended you use you own custom tailored code to do equivalent work. -// (The ImGui_ImplVulkanH_XXX functions do not interact with any of the state used by the regular ImGui_ImplVulkan_XXX functions) +// Your engine/app will likely _already_ have code to setup all that stuff (swap chain, +// render pass, frame buffers, etc.). You may read this code if you are curious, but +// it is recommended you use you own custom tailored code to do equivalent work. +// +// We don't provide a strong guarantee that we won't change those functions API. +// +// The ImGui_ImplVulkanH_XXX functions should NOT interact with any of the state used +// by the regular ImGui_ImplVulkan_XXX functions). //------------------------------------------------------------------------- struct ImGui_ImplVulkanH_Frame; @@ -157,6 +163,8 @@ IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkIns IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator); IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space); IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count); +IMGUI_IMPL_API VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance); +IMGUI_IMPL_API uint32_t ImGui_ImplVulkanH_SelectQueueFamilyIndex(VkPhysicalDevice physical_device); IMGUI_IMPL_API int ImGui_ImplVulkanH_GetMinImageCountFromPresentMode(VkPresentModeKHR present_mode); // Helper structure to hold the data needed by one rendering frame diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f440a7c63b00..01d00e0ca27c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -70,6 +70,8 @@ Other changes: - Backends: Metal: Fixed resource leak when using multiple contexts. (#7419) [@anszom] - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] +- Backends: Vulkan: Added a few more ImGui_ImplVulkanH_XXX helper functions + primarily for the purpose of making our examples simpler. ----------------------------------------------------------------------- diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 901b46c4cfd7..1197ca4e6c8b 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -85,35 +85,6 @@ static bool IsExtensionAvailable(const ImVector& properti return false; } -static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() -{ - uint32_t gpu_count; - VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); - check_vk_result(err); - IM_ASSERT(gpu_count > 0); - - ImVector gpus; - gpus.resize(gpu_count); - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); - check_vk_result(err); - - // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers - // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple - // dedicated GPUs) is out of scope of this sample. - for (VkPhysicalDevice& device : gpus) - { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - return device; - } - - // Use first GPU (Integrated) is a Discrete one is not available. - if (gpu_count > 0) - return gpus[0]; - return VK_NULL_HANDLE; -} - static void SetupVulkan(ImVector instance_extensions) { VkResult err; @@ -177,23 +148,12 @@ static void SetupVulkan(ImVector instance_extensions) } // Select Physical Device (GPU) - g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); + g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); + IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); // Select graphics queue family - { - uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); - VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); - for (uint32_t i = 0; i < count; i++) - if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - g_QueueFamily = i; - break; - } - free(queues); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); - } + g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); // Create Logical Device (with 1 queue) { diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index cb0ade097ac3..51add5c1ffaa 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -87,7 +87,7 @@ int main(int, char**) printf("Error: SDL_GL_CreateContext(): %s\n", SDL_GetError()); return -1; } - + SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index cb116b76eb29..fafa8ea42a76 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -73,35 +73,6 @@ static bool IsExtensionAvailable(const ImVector& properti return false; } -static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() -{ - uint32_t gpu_count; - VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); - check_vk_result(err); - IM_ASSERT(gpu_count > 0); - - ImVector gpus; - gpus.resize(gpu_count); - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); - check_vk_result(err); - - // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers - // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple - // dedicated GPUs) is out of scope of this sample. - for (VkPhysicalDevice& device : gpus) - { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - return device; - } - - // Use first GPU (Integrated) is a Discrete one is not available. - if (gpu_count > 0) - return gpus[0]; - return VK_NULL_HANDLE; -} - static void SetupVulkan(ImVector instance_extensions) { VkResult err; @@ -165,23 +136,12 @@ static void SetupVulkan(ImVector instance_extensions) } // Select Physical Device (GPU) - g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); + g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); + IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); // Select graphics queue family - { - uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); - VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); - for (uint32_t i = 0; i < count; i++) - if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - g_QueueFamily = i; - break; - } - free(queues); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); - } + g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); // Create Logical Device (with 1 queue) { diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index dde3c0d4c1f1..569eaeffb871 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -78,35 +78,6 @@ static bool IsExtensionAvailable(const ImVector& properti return false; } -static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() -{ - uint32_t gpu_count; - VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); - check_vk_result(err); - IM_ASSERT(gpu_count > 0); - - ImVector gpus; - gpus.resize(gpu_count); - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); - check_vk_result(err); - - // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers - // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple - // dedicated GPUs) is out of scope of this sample. - for (VkPhysicalDevice& device : gpus) - { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - return device; - } - - // Use first GPU (Integrated) is a Discrete one is not available. - if (gpu_count > 0) - return gpus[0]; - return VK_NULL_HANDLE; -} - static void SetupVulkan(ImVector instance_extensions) { VkResult err; @@ -170,23 +141,12 @@ static void SetupVulkan(ImVector instance_extensions) } // Select Physical Device (GPU) - g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); + g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); + IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); // Select graphics queue family - { - uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); - VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); - for (uint32_t i = 0; i < count; i++) - if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - g_QueueFamily = i; - break; - } - free(queues); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); - } + g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); // Create Logical Device (with 1 queue) { From 38e606a153b9e52f166ccfbd4ae105627fb12ae7 Mon Sep 17 00:00:00 2001 From: Jovan Ristic Date: Sat, 23 Nov 2024 12:41:19 -0800 Subject: [PATCH 114/716] Examples: Add Win32+Vulkan example. (#8180) --- examples/example_win32_vulkan/build_win32.bat | 9 + examples/example_win32_vulkan/build_win64.bat | 9 + .../example_win32_vulkan.vcxproj | 180 ++++++ .../example_win32_vulkan.vcxproj.filters | 65 ++ examples/example_win32_vulkan/main.cpp | 600 ++++++++++++++++++ examples/imgui_examples.sln | 10 + 6 files changed, 873 insertions(+) create mode 100644 examples/example_win32_vulkan/build_win32.bat create mode 100644 examples/example_win32_vulkan/build_win64.bat create mode 100644 examples/example_win32_vulkan/example_win32_vulkan.vcxproj create mode 100644 examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters create mode 100644 examples/example_win32_vulkan/main.cpp diff --git a/examples/example_win32_vulkan/build_win32.bat b/examples/example_win32_vulkan/build_win32.bat new file mode 100644 index 000000000000..4bfb7cafc68b --- /dev/null +++ b/examples/example_win32_vulkan/build_win32.bat @@ -0,0 +1,9 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_vulkan +@set INCLUDES=/I..\.. /I..\..\backends /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I %VULKAN_SDK%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp +@set LIBS=/libpath:%VULKAN_SDK%\lib32 vulkan-1.lib + +mkdir %OUT_DIR% +cl /nologo /Zi /MD /utf-8 %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% diff --git a/examples/example_win32_vulkan/build_win64.bat b/examples/example_win32_vulkan/build_win64.bat new file mode 100644 index 000000000000..f8c66f799531 --- /dev/null +++ b/examples/example_win32_vulkan/build_win64.bat @@ -0,0 +1,9 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +@set OUT_DIR=Debug +@set OUT_EXE=example_win32_vulkan +@set INCLUDES=/I..\.. /I..\..\backends /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I %VULKAN_SDK%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_vulkan.cpp ..\..\backends\imgui_impl_win32.cpp ..\..\imgui*.cpp +@set LIBS=/libpath:%VULKAN_SDK%\lib vulkan-1.lib + +mkdir %OUT_DIR% +cl /nologo /Zi /MD /utf-8 %INCLUDES% /D UNICODE /D _UNICODE %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj new file mode 100644 index 000000000000..cbf01a4ab2b3 --- /dev/null +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj @@ -0,0 +1,180 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47} + example_win32_vulkan + 10.0 + + + + Application + true + Unicode + v143 + + + Application + true + Unicode + v143 + + + Application + false + true + Unicode + v143 + + + Application + false + true + Unicode + v143 + + + + + + + + + + + + + + + + + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + + + + Level4 + Disabled + ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + vulkan-1.lib;%(AdditionalDependencies) + %VULKAN_SDK%\lib32;%(AdditionalLibraryDirectories) + Console + + + + + Level4 + Disabled + ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + vulkan-1.lib;%(AdditionalDependencies) + %VULKAN_SDK%\lib;%(AdditionalLibraryDirectories) + Console + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + true + true + vulkan-1.lib;%(AdditionalDependencies) + %VULKAN_SDK%\lib32;%(AdditionalLibraryDirectories) + Console + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) + _UNICODE;UNICODE;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + true + true + vulkan-1.lib;%(AdditionalDependencies) + %VULKAN_SDK%\lib;%(AdditionalLibraryDirectories) + Console + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters new file mode 100644 index 000000000000..a514e6830653 --- /dev/null +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {fb3d294f-51ec-478e-a627-25831c80fefd} + + + {4f33ddea-9910-456d-b868-4267eb3c2b19} + + + + + imgui + + + imgui + + + imgui + + + sources + + + sources + + + + + imgui + + + sources + + + imgui + + + imgui + + + sources + + + sources + + + imgui + + + imgui + + + + + + imgui + + + + + imgui + + + \ No newline at end of file diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp new file mode 100644 index 000000000000..f3f6367b04c7 --- /dev/null +++ b/examples/example_win32_vulkan/main.cpp @@ -0,0 +1,600 @@ +// Dear ImGui: standalone example application for Vulkan + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app. +// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h. +// You will use those if you want to use this rendering backend in your engine/app. +// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by +// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code. +// Read comments in imgui_impl_vulkan.h. + +#include "imgui.h" +#include "imgui_impl_win32.h" +#define VK_USE_PLATFORM_WIN32_KHR +#include "imgui_impl_vulkan.h" +#include +#include // printf, fprintf +#include // abort +#include + +// Volk headers +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK +#define VOLK_IMPLEMENTATION +#include +#endif + +//#define APP_USE_UNLIMITED_FRAME_RATE +#ifdef _DEBUG +#define APP_USE_VULKAN_DEBUG_REPORT +#endif + +// Data +static VkAllocationCallbacks* g_Allocator = nullptr; +static VkInstance g_Instance = VK_NULL_HANDLE; +static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; +static VkDevice g_Device = VK_NULL_HANDLE; +static uint32_t g_QueueFamily = (uint32_t)-1; +static VkQueue g_Queue = VK_NULL_HANDLE; +static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; +static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; +static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; + +static ImGui_ImplVulkanH_Window g_MainWindowData; +static uint32_t g_MinImageCount = 2; +static bool g_SwapChainRebuild = false; + +static void check_vk_result(VkResult err) +{ + if (err == 0) + return; + fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); + if (err < 0) + abort(); +} + +#ifdef APP_USE_VULKAN_DEBUG_REPORT +static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) +{ + (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments + fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage); + return VK_FALSE; +} +#endif // APP_USE_VULKAN_DEBUG_REPORT + +static bool IsExtensionAvailable(const ImVector& properties, const char* extension) +{ + for (const VkExtensionProperties& p : properties) + if (strcmp(p.extensionName, extension) == 0) + return true; + return false; +} + +static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() +{ + uint32_t gpu_count; + VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); + check_vk_result(err); + IM_ASSERT(gpu_count > 0); + + ImVector gpus; + gpus.resize(gpu_count); + err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); + check_vk_result(err); + + // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers + // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple + // dedicated GPUs) is out of scope of this sample. + for (VkPhysicalDevice& device : gpus) + { + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(device, &properties); + if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + return device; + } + + // Use first GPU (Integrated) is a Discrete one is not available. + if (gpu_count > 0) + return gpus[0]; + return VK_NULL_HANDLE; +} + +static void SetupVulkan(ImVector instance_extensions) +{ + VkResult err; +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK + volkInitialize(); +#endif + + // Create Vulkan Instance + { + VkInstanceCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + + // Enumerate available extensions + uint32_t properties_count; + ImVector properties; + vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, nullptr); + properties.resize(properties_count); + err = vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, properties.Data); + check_vk_result(err); + + // Enable required extensions + if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) + instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); +#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME)) + { + instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; + } +#endif + + // Enabling validation layers +#ifdef APP_USE_VULKAN_DEBUG_REPORT + const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; + create_info.enabledLayerCount = 1; + create_info.ppEnabledLayerNames = layers; + instance_extensions.push_back("VK_EXT_debug_report"); +#endif + + // Create Vulkan Instance + create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size; + create_info.ppEnabledExtensionNames = instance_extensions.Data; + err = vkCreateInstance(&create_info, g_Allocator, &g_Instance); + check_vk_result(err); +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK + volkLoadInstance(g_Instance); +#endif + + // Setup the debug report callback +#ifdef APP_USE_VULKAN_DEBUG_REPORT + auto f_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); + IM_ASSERT(f_vkCreateDebugReportCallbackEXT != nullptr); + VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; + debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; + debug_report_ci.pfnCallback = debug_report; + debug_report_ci.pUserData = nullptr; + err = f_vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport); + check_vk_result(err); +#endif + } + + // Select Physical Device (GPU) + g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); + + // Select graphics queue family + { + uint32_t count; + vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); + VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); + vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); + for (uint32_t i = 0; i < count; i++) + if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + g_QueueFamily = i; + break; + } + free(queues); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); + } + + // Create Logical Device (with 1 queue) + { + ImVector device_extensions; + device_extensions.push_back("VK_KHR_swapchain"); + + // Enumerate physical device extension + uint32_t properties_count; + ImVector properties; + vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, nullptr); + properties.resize(properties_count); + vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, properties.Data); +#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME + if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) + device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME); +#endif + + const float queue_priority[] = { 1.0f }; + VkDeviceQueueCreateInfo queue_info[1] = {}; + queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_info[0].queueFamilyIndex = g_QueueFamily; + queue_info[0].queueCount = 1; + queue_info[0].pQueuePriorities = queue_priority; + VkDeviceCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]); + create_info.pQueueCreateInfos = queue_info; + create_info.enabledExtensionCount = (uint32_t)device_extensions.Size; + create_info.ppEnabledExtensionNames = device_extensions.Data; + err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device); + check_vk_result(err); + vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue); + } + + // Create Descriptor Pool + // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) + // If you wish to load e.g. additional textures you may need to alter pools sizes. + { + VkDescriptorPoolSize pool_sizes[] = + { + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, + }; + VkDescriptorPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; + pool_info.maxSets = 1; + pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); + pool_info.pPoolSizes = pool_sizes; + err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); + check_vk_result(err); + } +} + +// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo. +// Your real engine/app may not use them. +static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height) +{ + wd->Surface = surface; + + // Check for WSI support + VkBool32 res; + vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, wd->Surface, &res); + if (res != VK_TRUE) + { + fprintf(stderr, "Error no WSI support on physical device 0\n"); + exit(-1); + } + + // Select Surface Format + const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; + const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); + + // Select Present Mode +#ifdef APP_UNLIMITED_FRAME_RATE + VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; +#else + VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; +#endif + wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes)); + //printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode); + + // Create SwapChain, RenderPass, Framebuffer, etc. + IM_ASSERT(g_MinImageCount >= 2); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount); +} + +static void CleanupVulkan() +{ + vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); + +#ifdef APP_USE_VULKAN_DEBUG_REPORT + // Remove the debug report callback + auto f_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); + f_vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator); +#endif // APP_USE_VULKAN_DEBUG_REPORT + + vkDestroyDevice(g_Device, g_Allocator); + vkDestroyInstance(g_Instance, g_Allocator); +} + +static void CleanupVulkanWindow() +{ + ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, &g_MainWindowData, g_Allocator); +} + +static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) +{ + VkResult err; + + VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; + err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + { + g_SwapChainRebuild = true; + return; + } + check_vk_result(err); + + ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; + { + err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking + check_vk_result(err); + + err = vkResetFences(g_Device, 1, &fd->Fence); + check_vk_result(err); + } + { + err = vkResetCommandPool(g_Device, fd->CommandPool, 0); + check_vk_result(err); + VkCommandBufferBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(fd->CommandBuffer, &info); + check_vk_result(err); + } + { + VkRenderPassBeginInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.renderPass = wd->RenderPass; + info.framebuffer = fd->Framebuffer; + info.renderArea.extent.width = wd->Width; + info.renderArea.extent.height = wd->Height; + info.clearValueCount = 1; + info.pClearValues = &wd->ClearValue; + vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE); + } + + // Record dear imgui primitives into command buffer + ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer); + + // Submit command buffer + vkCmdEndRenderPass(fd->CommandBuffer); + { + VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &image_acquired_semaphore; + info.pWaitDstStageMask = &wait_stage; + info.commandBufferCount = 1; + info.pCommandBuffers = &fd->CommandBuffer; + info.signalSemaphoreCount = 1; + info.pSignalSemaphores = &render_complete_semaphore; + + err = vkEndCommandBuffer(fd->CommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence); + check_vk_result(err); + } +} + +static void FramePresent(ImGui_ImplVulkanH_Window* wd) +{ + if (g_SwapChainRebuild) + return; + VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; + VkPresentInfoKHR info = {}; + info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + info.waitSemaphoreCount = 1; + info.pWaitSemaphores = &render_complete_semaphore; + info.swapchainCount = 1; + info.pSwapchains = &wd->Swapchain; + info.pImageIndices = &wd->FrameIndex; + VkResult err = vkQueuePresentKHR(g_Queue, &info); + if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) + { + g_SwapChainRebuild = true; + return; + } + check_vk_result(err); + wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores +} + +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +// Main code +int main(int, char**) +{ + // Create application window + //ImGui_ImplWin32_EnableDpiAwareness(); + WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; + ::RegisterClassExW(&wc); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + + ImVector extensions; + extensions.push_back("VK_KHR_surface"); + extensions.push_back("VK_KHR_win32_surface"); + SetupVulkan(extensions); + + // Create Window Surface + VkSurfaceKHR surface; + VkResult err; + VkWin32SurfaceCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + createInfo.hwnd = hwnd; + createInfo.hinstance = GetModuleHandle(nullptr); + if (vkCreateWin32SurfaceKHR(g_Instance, &createInfo, nullptr, &surface) != VK_SUCCESS) + { + printf("Failed to create Vulkan surface.\n"); + return 1; + } + + // Show the window + ImGui_ImplVulkanH_Window* wd = &g_MainWindowData; + SetupVulkanWindow(wd, surface, 1280, 800); + ::ShowWindow(hwnd, SW_SHOWDEFAULT); + ::UpdateWindow(hwnd); + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = g_Instance; + init_info.PhysicalDevice = g_PhysicalDevice; + init_info.Device = g_Device; + init_info.QueueFamily = g_QueueFamily; + init_info.Queue = g_Queue; + init_info.PipelineCache = g_PipelineCache; + init_info.DescriptorPool = g_DescriptorPool; + init_info.RenderPass = wd->RenderPass; + init_info.Subpass = 0; + init_info.MinImageCount = g_MinImageCount; + init_info.ImageCount = wd->ImageCount; + init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + init_info.Allocator = g_Allocator; + init_info.CheckVkResultFn = check_vk_result; + ImGui_ImplVulkan_Init(&init_info); + + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. + // - Read 'docs/FONTS.md' for more instructions and details. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //io.Fonts->AddFontDefault(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //IM_ASSERT(font != nullptr); + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop + bool done = false; + while (!done) + { + // Poll and handle messages (inputs, window resize, etc.) + // See the WndProc() function below for our to dispatch events to the Win32 backend. + MSG msg; + while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) + { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + if (msg.message == WM_QUIT) + done = true; + } + if (done) + break; + + // Start the Dear ImGui frame + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + + ImDrawData* draw_data = ImGui::GetDrawData(); + const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); + if (!is_minimized) + { + wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w; + wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w; + wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w; + wd->ClearValue.color.float32[3] = clear_color.w; + FrameRender(wd, draw_data); + FramePresent(wd); + } + } + + err = vkDeviceWaitIdle(g_Device); + check_vk_result(err); + + // Cleanup + ImGui_ImplVulkan_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + + CleanupVulkanWindow(); + CleanupVulkan(); + + ::DestroyWindow(hwnd); + ::UnregisterClassW(wc.lpszClassName, wc.hInstance); + + return 0; +} + +// Helper functions + +// Forward declare message handler from imgui_impl_win32.cpp +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +// Win32 message handler +// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. +// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) + return true; + + switch (msg) + { + case WM_SIZE: + if (g_Device != VK_NULL_HANDLE && wParam != SIZE_MINIMIZED) + { + // Resize swap chain + int fb_width = (UINT)LOWORD(lParam); + int fb_height = (UINT)HIWORD(lParam); + if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height)) + { + ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount); + ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, &g_MainWindowData, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount); + g_MainWindowData.FrameIndex = 0; + g_SwapChainRebuild = false; + } + } + return 0; + case WM_SYSCOMMAND: + if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu + return 0; + break; + case WM_DESTROY: + ::PostQuitMessage(0); + return 0; + } + return ::DefWindowProcW(hWnd, msg, wParam, lParam); +} diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index ea9f65cbd3e9..3a856462a490 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -35,6 +35,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_vulkan", "example_sdl3_vulkan\example_sdl3_vulkan.vcxproj", "{663A7E89-1E42-4222-921C-177F5B5910DF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "example_win32_vulkan\example_win32_vulkan.vcxproj", "{4CB8C22A-96F8-4D31-B747-FDAA6B742E47}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -171,6 +173,14 @@ Global {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|Win32.Build.0 = Release|Win32 {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|x64.ActiveCfg = Release|x64 {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|x64.Build.0 = Release|x64 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|Win32.ActiveCfg = Debug|Win32 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|Win32.Build.0 = Debug|Win32 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|x64.ActiveCfg = Debug|x64 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|x64.Build.0 = Debug|x64 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|Win32.ActiveCfg = Release|Win32 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|Win32.Build.0 = Release|Win32 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|x64.ActiveCfg = Release|x64 + {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 93a93071a27fc733c96368d179c51bb8e43ddc86 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 17:43:52 +0100 Subject: [PATCH 115/716] Examples: Add Win32+Vulkan example, amends. (#8180) --- docs/CHANGELOG.txt | 1 + docs/EXAMPLES.md | 6 +- examples/example_glfw_vulkan/main.cpp | 2 +- .../example_win32_vulkan.vcxproj | 18 +++--- .../example_win32_vulkan.vcxproj.filters | 26 ++++---- examples/example_win32_vulkan/main.cpp | 61 +++---------------- examples/imgui_examples.sln | 18 +++--- 7 files changed, 46 insertions(+), 86 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 01d00e0ca27c..412ddabdac8c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,7 @@ Other changes: platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] - Backends: Vulkan: Added a few more ImGui_ImplVulkanH_XXX helper functions primarily for the purpose of making our examples simpler. +- Examples: Added Win32+Vulkan example for completeness. (#8180) [@jristic] ----------------------------------------------------------------------- diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index f84f9497b6dd..224beb1c16a0 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -167,9 +167,13 @@ DirectX12 example, Windows only.
This is quite long and tedious, because: DirectX12. [example_win32_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_opengl3/)
-Raw Windows + OpenGL3 + example (modern, programmable pipeline)
+Raw Windows + OpenGL3 example (modern, programmable pipeline)
= main.cpp + imgui_impl_win32.cpp + imgui_impl_opengl3.cpp
+[example_win32_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_vulkan/)
+Raw Windows + Vulkan example
+= main.cpp + imgui_impl_win32.cpp + imgui_impl_vulkan.cpp
+ ### Miscellaneous diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 1197ca4e6c8b..9f8dced2f18d 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -52,7 +52,7 @@ static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; static ImGui_ImplVulkanH_Window g_MainWindowData; -static int g_MinImageCount = 2; +static uint32_t g_MinImageCount = 2; static bool g_SwapChainRebuild = false; static void glfw_error_callback(int error, const char* description) diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj index cbf01a4ab2b3..dab8afd4ed71 100644 --- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj @@ -19,36 +19,35 @@ - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47} - example_win32_vulkan - 10.0 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88} + example_win32_directx11 Application true Unicode - v143 + v140 Application true Unicode - v143 + v140 Application false true Unicode - v143 + v140 Application false true Unicode - v143 + v140 @@ -120,6 +119,7 @@ true ..\..;..\..\backends;%VULKAN_SDK%\include;%(AdditionalIncludeDirectories) _UNICODE;UNICODE;%(PreprocessorDefinitions) + false /utf-8 %(AdditionalOptions) @@ -169,11 +169,9 @@ + - - - diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters index a514e6830653..c91a95810cc1 100644 --- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters @@ -2,10 +2,10 @@ - {fb3d294f-51ec-478e-a627-25831c80fefd} + {0587d7a3-f2ce-4d56-b84f-a0005d3bfce6} - {4f33ddea-9910-456d-b868-4267eb3c2b19} + {08e36723-ce4f-4cff-9662-c40801cf1acf} @@ -18,10 +18,10 @@ imgui - + sources - + sources @@ -38,28 +38,26 @@ imgui - - sources + + imgui sources - - imgui + + sources - + imgui - + imgui - - - + imgui - + \ No newline at end of file diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index f3f6367b04c7..3fabf7a2dec5 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for Vulkan +// Dear ImGui: standalone example application for Win32 + Vulkan // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq @@ -74,35 +74,6 @@ static bool IsExtensionAvailable(const ImVector& properti return false; } -static VkPhysicalDevice SetupVulkan_SelectPhysicalDevice() -{ - uint32_t gpu_count; - VkResult err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, nullptr); - check_vk_result(err); - IM_ASSERT(gpu_count > 0); - - ImVector gpus; - gpus.resize(gpu_count); - err = vkEnumeratePhysicalDevices(g_Instance, &gpu_count, gpus.Data); - check_vk_result(err); - - // If a number >1 of GPUs got reported, find discrete GPU if present, or use first one available. This covers - // most common cases (multi-gpu/integrated+dedicated graphics). Handling more complicated setups (multiple - // dedicated GPUs) is out of scope of this sample. - for (VkPhysicalDevice& device : gpus) - { - VkPhysicalDeviceProperties properties; - vkGetPhysicalDeviceProperties(device, &properties); - if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - return device; - } - - // Use first GPU (Integrated) is a Discrete one is not available. - if (gpu_count > 0) - return gpus[0]; - return VK_NULL_HANDLE; -} - static void SetupVulkan(ImVector instance_extensions) { VkResult err; @@ -166,23 +137,12 @@ static void SetupVulkan(ImVector instance_extensions) } // Select Physical Device (GPU) - g_PhysicalDevice = SetupVulkan_SelectPhysicalDevice(); + g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance); + IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE); // Select graphics queue family - { - uint32_t count; - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, nullptr); - VkQueueFamilyProperties* queues = (VkQueueFamilyProperties*)malloc(sizeof(VkQueueFamilyProperties) * count); - vkGetPhysicalDeviceQueueFamilyProperties(g_PhysicalDevice, &count, queues); - for (uint32_t i = 0; i < count; i++) - if (queues[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - g_QueueFamily = i; - break; - } - free(queues); - IM_ASSERT(g_QueueFamily != (uint32_t)-1); - } + g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice); + IM_ASSERT(g_QueueFamily != (uint32_t)-1); // Create Logical Device (with 1 queue) { @@ -257,7 +217,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode -#ifdef APP_UNLIMITED_FRAME_RATE +#ifdef APP_USE_UNLIMITED_FRAME_RATE VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; #else VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; @@ -387,7 +347,7 @@ int main(int, char**) //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+Vulkan Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); ImVector extensions; extensions.push_back("VK_KHR_surface"); @@ -400,7 +360,7 @@ int main(int, char**) VkWin32SurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.hwnd = hwnd; - createInfo.hinstance = GetModuleHandle(nullptr); + createInfo.hinstance = ::GetModuleHandle(nullptr); if (vkCreateWin32SurfaceKHR(g_Instance, &createInfo, nullptr, &surface) != VK_SUCCESS) { printf("Failed to create Vulkan surface.\n"); @@ -408,6 +368,7 @@ int main(int, char**) } // Show the window + // FIXME: Retrieve client size from window itself. ImGui_ImplVulkanH_Window* wd = &g_MainWindowData; SetupVulkanWindow(wd, surface, 1280, 800); ::ShowWindow(hwnd, SW_SHOWDEFAULT); @@ -525,7 +486,6 @@ int main(int, char**) // Rendering ImGui::Render(); - ImDrawData* draw_data = ImGui::GetDrawData(); const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); if (!is_minimized) @@ -539,10 +499,9 @@ int main(int, char**) } } + // Cleanup err = vkDeviceWaitIdle(g_Device); check_vk_result(err); - - // Cleanup ImGui_ImplVulkan_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index 3a856462a490..85f7451d4f61 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -35,7 +35,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_vulkan", "example_sdl3_vulkan\example_sdl3_vulkan.vcxproj", "{663A7E89-1E42-4222-921C-177F5B5910DF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "example_win32_vulkan\example_win32_vulkan.vcxproj", "{4CB8C22A-96F8-4D31-B747-FDAA6B742E47}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "example_win32_vulkan\example_win32_vulkan.vcxproj", "{0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -173,14 +173,14 @@ Global {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|Win32.Build.0 = Release|Win32 {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|x64.ActiveCfg = Release|x64 {663A7E89-1E42-4222-921C-177F5B5910DF}.Release|x64.Build.0 = Release|x64 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|Win32.ActiveCfg = Debug|Win32 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|Win32.Build.0 = Debug|Win32 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|x64.ActiveCfg = Debug|x64 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Debug|x64.Build.0 = Debug|x64 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|Win32.ActiveCfg = Release|Win32 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|Win32.Build.0 = Release|Win32 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|x64.ActiveCfg = Release|x64 - {4CB8C22A-96F8-4D31-B747-FDAA6B742E47}.Release|x64.Build.0 = Release|x64 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|Win32.ActiveCfg = Debug|Win32 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|Win32.Build.0 = Debug|Win32 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|x64.ActiveCfg = Debug|x64 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Debug|x64.Build.0 = Debug|x64 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|Win32.ActiveCfg = Release|Win32 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|Win32.Build.0 = Release|Win32 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|x64.ActiveCfg = Release|x64 + {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From af271e733039548d62eb7b56e94fd3672304f343 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 18:20:56 +0100 Subject: [PATCH 116/716] Backends: DX11: Expose vertex constant buffer in ImGui_ImplDX11_RenderState. DX9 and DX12 users can already alter the projection matrix (in undocumented ways, but possible) --- backends/imgui_impl_dx11.cpp | 45 ++++++++++++++++++------------------ backends/imgui_impl_dx11.h | 2 ++ docs/CHANGELOG.txt | 2 ++ 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index a2c67ec43f9e..bbd1633a2c95 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler. // 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. @@ -98,6 +99,27 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC vp.TopLeftX = vp.TopLeftY = 0; device_ctx->RSSetViewports(1, &vp); + // Setup orthographic projection matrix into our constant buffer + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + D3D11_MAPPED_SUBRESOURCE mapped_resource; + if (device_ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) == S_OK) + { + VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData; + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + float mvp[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.5f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, + }; + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); + device_ctx->Unmap(bd->pVertexConstantBuffer, 0); + } + // Setup shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; @@ -179,28 +201,6 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) device->Unmap(bd->pVB, 0); device->Unmap(bd->pIB, 0); - // Setup orthographic projection matrix into our constant buffer - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - { - D3D11_MAPPED_SUBRESOURCE mapped_resource; - if (device->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) - return; - VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData; - float L = draw_data->DisplayPos.x; - float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; - float T = draw_data->DisplayPos.y; - float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; - float mvp[4][4] = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.5f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, - }; - memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); - device->Unmap(bd->pVertexConstantBuffer, 0); - } - // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) struct BACKUP_DX11_STATE { @@ -255,6 +255,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) render_state.Device = bd->pd3dDevice; render_state.DeviceContext = bd->pd3dDeviceContext; render_state.SamplerDefault = bd->pFontSampler; + render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; platform_io.Renderer_RenderState = &render_state; // Render command lists diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 69ae493586fb..772c1b920c05 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -21,6 +21,7 @@ struct ID3D11Device; struct ID3D11DeviceContext; struct ID3D11SamplerState; +struct ID3D11Buffer; // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); @@ -40,6 +41,7 @@ struct ImGui_ImplDX11_RenderState ID3D11Device* Device; ID3D11DeviceContext* DeviceContext; ID3D11SamplerState* SamplerDefault; + ID3D11Buffer* VertexConstantBuffer; }; #endif // #ifndef IMGUI_DISABLE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 412ddabdac8c..4500f5a1f498 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,6 +72,8 @@ Other changes: platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] - Backends: Vulkan: Added a few more ImGui_ImplVulkanH_XXX helper functions primarily for the purpose of making our examples simpler. +- Backends: DX11: Expose vertex constant buffer in ImGui_ImplDX11_RenderState. + Reset projection matrix in ImDrawCallback_ResetRenderState handlers. (#6969, #5834, #7468, #3590) - Examples: Added Win32+Vulkan example for completeness. (#8180) [@jristic] From f04d3cbdaaf037e5f57bc39c0bd3f0d0c43b98fc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 18:28:01 +0100 Subject: [PATCH 117/716] Backends: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. (#6969, #5834, #7468, #3590) Amend e94f95d --- backends/imgui_impl_dx10.cpp | 56 ++++++++++++++++++++---------------- backends/imgui_impl_dx10.h | 12 ++++++++ backends/imgui_impl_dx11.cpp | 2 +- docs/CHANGELOG.txt | 1 + 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 15f0bb323f5d..89499af0cbaa 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-10-07: DirectX10: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). @@ -95,7 +96,28 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* vp.TopLeftX = vp.TopLeftY = 0; device->RSSetViewports(1, &vp); - // Bind shader and vertex buffers + // Setup orthographic projection matrix into our constant buffer + // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + void* mapped_resource; + if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) == S_OK) + { + VERTEX_CONSTANT_BUFFER_DX10* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX10*)mapped_resource; + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; + float mvp[4][4] = + { + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.5f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, + }; + memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); + bd->pVertexConstantBuffer->Unmap(); + } + + // Setup shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; device->IASetInputLayout(bd->pInputLayout); @@ -171,28 +193,6 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) bd->pVB->Unmap(); bd->pIB->Unmap(); - // Setup orthographic projection matrix into our constant buffer - // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - { - void* mapped_resource; - if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) - return; - VERTEX_CONSTANT_BUFFER_DX10* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX10*)mapped_resource; - float L = draw_data->DisplayPos.x; - float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; - float T = draw_data->DisplayPos.y; - float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; - float mvp[4][4] = - { - { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, - { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, - { 0.0f, 0.0f, 0.5f, 0.0f }, - { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, - }; - memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); - bd->pVertexConstantBuffer->Unmap(); - } - // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) struct BACKUP_DX10_STATE { @@ -236,6 +236,13 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) // Setup desired DX state ImGui_ImplDX10_SetupRenderState(draw_data, device); + // Setup render state structure (for callbacks and custom texture bindings) + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + ImGui_ImplDX10_RenderState render_state; + render_state.Device = bd->pd3dDevice; + render_state.SamplerDefault = bd->pFontSampler; + render_state.VertexConstantBuffer = bd->pVertexConstantBuffer; + platform_io.Renderer_RenderState = &render_state; // Render command lists // (Because we merged all buffers into a single one, we maintain our own offset into them) @@ -248,7 +255,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback) + if (pcmd->UserCallback != nullptr) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) @@ -278,6 +285,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } + platform_io.Renderer_RenderState = nullptr; // Restore modified DX state device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 29f339370f53..d9f29987d7ee 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -18,6 +18,8 @@ #ifndef IMGUI_DISABLE struct ID3D10Device; +struct ID3D10SamplerState; +struct ID3D10Buffer; // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device); @@ -29,4 +31,14 @@ IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); +// [BETA] Selected render state data shared with callbacks. +// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX10_RenderDrawData() call. +// (Please open an issue if you feel you need access to more data) +struct ImGui_ImplDX10_RenderState +{ + ID3D10Device* Device; + ID3D10SamplerState* SamplerDefault; + ID3D10Buffer* VertexConstantBuffer; +}; + #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index bbd1633a2c95..b38fece264b5 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -136,7 +136,7 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC device_ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. device_ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. - // Setup blend state + // Setup render state const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; device_ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); device_ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4500f5a1f498..81763b99c901 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -74,6 +74,7 @@ Other changes: primarily for the purpose of making our examples simpler. - Backends: DX11: Expose vertex constant buffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handlers. (#6969, #5834, #7468, #3590) +- Backends: DX10: Expose ImGui_ImplDX10_RenderState for completeness. (#6969, #5834, #7468, #3590) - Examples: Added Win32+Vulkan example for completeness. (#8180) [@jristic] From cec8ff1885deb4728cafca5b37bf532f68572e66 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 6 Jan 2025 18:41:17 +0100 Subject: [PATCH 118/716] Backends: Vulkan: Fixed building with using VK_NO_PROTOTYPES. (#8180) Broken by a2e2172 --- backends/imgui_impl_vulkan.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 1953288d92cf..de4c5a4aa7e8 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -164,6 +164,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySurfaceKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDestroySwapchainKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkDeviceWaitIdle) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkEnumeratePhysicalDevices) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkEndCommandBuffer) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFlushMappedMemoryRanges) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeCommandBuffers) \ @@ -171,7 +172,9 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceProperties) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceQueueFamilyProperties) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \ From 3115ae081591fe75b98747a7737eab065f2628f8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 27 Dec 2024 11:49:39 +0100 Subject: [PATCH 119/716] Demo: Font selector combo sets default focus. --- imgui_demo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 36d8f441584b..c9a21759d456 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7851,6 +7851,8 @@ void ImGui::ShowFontSelector(const char* label) ImGui::PushID((void*)font); if (ImGui::Selectable(font->GetDebugName(), font == font_current)) io.FontDefault = font; + if (font == font_current) + ImGui::SetItemDefaultFocus(); ImGui::PopID(); } ImGui::EndCombo(); From 0514332474fc3ffbb19e886de1b3b167e6aac521 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 11:44:00 +0100 Subject: [PATCH 120/716] Avoid clang/gcc warnings: -Wnontrivial-memaccess in backends. (#8295, #8129, #8135) --- backends/imgui_impl_dx12.h | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- misc/freetype/imgui_freetype.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 644c022fffbd..a57c1694d36e 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -43,7 +43,7 @@ struct ImGui_ImplDX12_InitInfo D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor; #endif - ImGui_ImplDX12_InitInfo() { memset(this, 0, sizeof(*this)); } + ImGui_ImplDX12_InitInfo() { memset((void*)this, 0, sizeof(*this)); } }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index de4c5a4aa7e8..4345f2b11554 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -225,7 +225,7 @@ struct ImGui_ImplVulkan_Texture VkImageView ImageView; VkDescriptorSet DescriptorSet; - ImGui_ImplVulkan_Texture() { memset(this, 0, sizeof(*this)); } + ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); } }; // Vulkan data diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index aeab6dfa0689..997bc4340bd5 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -169,7 +169,7 @@ namespace const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr); - FreeTypeFont() { memset(this, 0, sizeof(*this)); } + FreeTypeFont() { memset((void*)this, 0, sizeof(*this)); } ~FreeTypeFont() { CloseFont(); } // [Internals] From e6a7c7689f57038b2519fe43e55e3d57103ad0f7 Mon Sep 17 00:00:00 2001 From: Selim Sandal <49725809+selimsandal@users.noreply.github.com> Date: Wed, 8 Jan 2025 12:00:40 +0100 Subject: [PATCH 121/716] Backends: Metal: Fixed memory leaks. (#8276, #8166) --- backends/imgui_impl_metal.mm | 10 ++++++++-- docs/CHANGELOG.txt | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index edd7fa181e29..3ff905a60cef 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. // 2022-07-05: Metal: Add dispatch synchronization. // 2022-06-30: Metal: Use __bridge for ARC based systems. @@ -156,8 +157,11 @@ void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); IM_ASSERT(bd != nil && "Context or backend not initialized! Did you call ImGui_ImplMetal_Init()?"); +#ifdef IMGUI_IMPL_METAL_CPP + bd->SharedMetalContext.framebufferDescriptor = [[[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]autorelease]; +#else bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]; - +#endif if (bd->SharedMetalContext.depthStencilState == nil) ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device); } @@ -364,8 +368,10 @@ bool ImGui_ImplMetal_CreateDeviceObjects(id device) depthStencilDescriptor.depthWriteEnabled = NO; depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor]; +#ifdef IMGUI_IMPL_METAL_CPP + [depthStencilDescriptor release]; +#endif ImGui_ImplMetal_CreateFontsTexture(device); - return true; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 81763b99c901..a24d6ea4ea9f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,7 @@ Other changes: - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] +- Backends: Metal: Fixed leaks when using metal-cpp. (#8276, #8166) [@selimsandal] - Backends: Metal: Fixed resource leak when using multiple contexts. (#7419) [@anszom] - Backends: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] From bbbdc70f26b15db176a0b93f9dde3cd5f6d84d8c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 12:43:56 +0100 Subject: [PATCH 122/716] Refactor: moved FindBlockingModal() in its section. --- imgui.cpp | 96 ++++++++++++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3bb95bfcea05..00d66f857abf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3542,7 +3542,6 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) return "Unknown"; } - //----------------------------------------------------------------------------- // [SECTION] RENDER HELPERS // Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change, @@ -4252,7 +4251,6 @@ void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) hook.Callback(&g, &hook); } - //----------------------------------------------------------------------------- // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) //----------------------------------------------------------------------------- @@ -6957,42 +6955,6 @@ static void SetWindowActiveForSkipRefresh(ImGuiWindow* window) } } -// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) -// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. -// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. -// - WindowA // FindBlockingModal() returns Modal1 -// - WindowB // .. returns Modal1 -// - Modal1 // .. returns Modal2 -// - WindowC // .. returns Modal2 -// - WindowD // .. returns Modal2 -// - Modal2 // .. returns Modal2 -// - WindowE // .. returns NULL -// Notes: -// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. -// Only difference is here we check for ->Active/WasActive but it may be unnecessary. -ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (g.OpenPopupStack.Size <= 0) - return NULL; - - // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. - for (ImGuiPopupData& popup_data : g.OpenPopupStack) - { - ImGuiWindow* popup_window = popup_data.Window; - if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) - continue; - if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. - continue; - if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. - return popup_window; - if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal - continue; - return popup_window; // Place window right below first block modal - } - return NULL; -} - // Push a new Dear ImGui window to add widgets to. // - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair. // - Begin/End can be called multiple times during the frame with the same window name to append content. @@ -8276,14 +8238,6 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) return (ref_window == cur_window); } -// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) -// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. -// If you want a window to never be focused, you may use the e.g. NoInputs flag. -bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) -{ - return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); -} - float ImGui::GetWindowWidth() { ImGuiWindow* window = GImGui->CurrentWindow; @@ -10308,7 +10262,6 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own return true; } - //----------------------------------------------------------------------------- // [SECTION] ERROR CHECKING, STATE RECOVERY //----------------------------------------------------------------------------- @@ -11655,6 +11608,43 @@ ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal() return NULL; } + +// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) +// should be positioned behind that modal window, unless the window was created inside the modal begin-stack. +// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. +// - WindowA // FindBlockingModal() returns Modal1 +// - WindowB // .. returns Modal1 +// - Modal1 // .. returns Modal2 +// - WindowC // .. returns Modal2 +// - WindowD // .. returns Modal2 +// - Modal2 // .. returns Modal2 +// - WindowE // .. returns NULL +// Notes: +// - FindBlockingModal(NULL) == NULL is generally equivalent to GetTopMostPopupModal() == NULL. +// Only difference is here we check for ->Active/WasActive but it may be unnecessary. +ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.OpenPopupStack.Size <= 0) + return NULL; + + // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. + for (ImGuiPopupData& popup_data : g.OpenPopupStack) + { + ImGuiWindow* popup_window = popup_data.Window; + if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) + continue; + if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. + continue; + if (window == NULL) // FindBlockingModal(NULL) test for if FocusWindow(NULL) is naturally possible via a mouse click. + return popup_window; + if (IsWindowWithinBeginStackOf(window, popup_window)) // Window may be over modal + continue; + return popup_window; // Place window right below first block modal + } + return NULL; +} + void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags) { ImGuiContext& g = *GImGui; @@ -13524,6 +13514,14 @@ static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) return order; } +// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) +// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. +// If you want a window to never be focused, you may use the e.g. NoInputs flag. +bool ImGui::IsWindowNavFocusable(ImGuiWindow* window) +{ + return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus); +} + static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N) { ImGuiContext& g = *GImGui; @@ -13801,7 +13799,6 @@ void ImGui::NavUpdateWindowingOverlay() PopStyleVar(); } - //----------------------------------------------------------------------------- // [SECTION] DRAG AND DROP //----------------------------------------------------------------------------- @@ -14410,7 +14407,6 @@ void ImGui::LogButtons() LogToClipboard(); } - //----------------------------------------------------------------------------- // [SECTION] SETTINGS //----------------------------------------------------------------------------- @@ -14770,7 +14766,6 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl } } - //----------------------------------------------------------------------------- // [SECTION] LOCALIZATION //----------------------------------------------------------------------------- @@ -14782,7 +14777,6 @@ void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count) g.LocalizationTable[entries[n].Key] = entries[n].Text; } - //----------------------------------------------------------------------------- // [SECTION] VIEWPORTS, PLATFORM WINDOWS //----------------------------------------------------------------------------- From 2b8545684caea55032b48c7c62d493e7cf169e01 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 14:22:37 +0100 Subject: [PATCH 123/716] Refactor: moved Window Focus related functions to a dedicated section. --- imgui.cpp | 522 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 272 insertions(+), 250 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 00d66f857abf..5f898a389eac 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -85,6 +85,7 @@ CODE // [SECTION] SCROLLING // [SECTION] TOOLTIPS // [SECTION] POPUPS +// [SECTION] WINDOW FOCUS // [SECTION] KEYBOARD/GAMEPAD NAVIGATION // [SECTION] DRAG AND DROP // [SECTION] LOGGING/CAPTURING @@ -1202,6 +1203,10 @@ namespace ImGui // Item static void ItemHandleShortcut(ImGuiID id); +// Window Focus +static int FindWindowFocusIndex(ImGuiWindow* window); +static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags); + // Navigation static void NavUpdate(); static void NavUpdateWindowing(); @@ -1222,7 +1227,6 @@ static ImVec2 NavCalcPreferredRefPos(); static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window); static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window); static void NavRestoreLayer(ImGuiNavLayer layer); -static int FindWindowFocusIndex(ImGuiWindow* window); // Error Checking and Debug Tools static void ErrorCheckNewFrameSanityChecks(); @@ -6171,29 +6175,6 @@ static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settin window->Collapsed = settings->Collapsed; } -static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) -{ - ImGuiContext& g = *GImGui; - - const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0); - const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; - if ((just_created || child_flag_changed) && !new_is_explicit_child) - { - IM_ASSERT(!g.WindowsFocusOrder.contains(window)); - g.WindowsFocusOrder.push_back(window); - window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); - } - else if (!just_created && child_flag_changed && new_is_explicit_child) - { - IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); - for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) - g.WindowsFocusOrder[n]->FocusOrder--; - g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); - window->FocusOrder = -1; - } - window->IsExplicitChild = new_is_explicit_child; -} - static void InitOrLoadWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings) { // Initial window state with e.g. default/arbitrary window position @@ -7777,176 +7758,6 @@ void ImGui::End() SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); } -void ImGui::BringWindowToFocusFront(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(window == window->RootWindow); - - const int cur_order = window->FocusOrder; - IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); - if (g.WindowsFocusOrder.back() == window) - return; - - const int new_order = g.WindowsFocusOrder.Size - 1; - for (int n = cur_order; n < new_order; n++) - { - g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; - g.WindowsFocusOrder[n]->FocusOrder--; - IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); - } - g.WindowsFocusOrder[new_order] = window; - window->FocusOrder = (short)new_order; -} - -void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* current_front_window = g.Windows.back(); - if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better) - return; - for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window - if (g.Windows[i] == window) - { - memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); - g.Windows[g.Windows.Size - 1] = window; - break; - } -} - -void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - if (g.Windows[0] == window) - return; - for (int i = 0; i < g.Windows.Size; i++) - if (g.Windows[i] == window) - { - memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); - g.Windows[0] = window; - break; - } -} - -void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) -{ - IM_ASSERT(window != NULL && behind_window != NULL); - ImGuiContext& g = *GImGui; - window = window->RootWindow; - behind_window = behind_window->RootWindow; - int pos_wnd = FindWindowDisplayIndex(window); - int pos_beh = FindWindowDisplayIndex(behind_window); - if (pos_wnd < pos_beh) - { - size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); - memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); - g.Windows[pos_beh - 1] = window; - } - else - { - size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); - memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); - g.Windows[pos_beh] = window; - } -} - -int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - return g.Windows.index_from_ptr(g.Windows.find(window)); -} - -// Moving window to front of display and set focus (which happens to be back of our sorted list) -void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) -{ - ImGuiContext& g = *GImGui; - - // Modal check? - if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. - if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) - { - // This block would typically be reached in two situations: - // - API call to FocusWindow() with a window under a modal and ImGuiFocusRequestFlags_UnlessBelowModal flag. - // - User clicking on void or anything behind a modal while a modal is open (window == NULL) - IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); - if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) - BringWindowToDisplayBehind(window, blocking_modal); // Still bring right under modal. (FIXME: Could move in focus list too?) - ClosePopupsOverWindow(GetTopMostPopupModal(), false); // Note how we need to use GetTopMostPopupModal() aad NOT blocking_modal, to handle nested modals - return; - } - - // Find last focused child (if any) and focus it instead. - if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) - window = NavRestoreLastChildNavWindow(window); - - // Apply focus - if (g.NavWindow != window) - { - SetNavWindow(window); - if (window && g.NavHighlightItemUnderNav) - g.NavMousePosDirty = true; - g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId - g.NavLayer = ImGuiNavLayer_Main; - SetNavFocusScope(window ? window->NavRootFocusScopeId : 0); - g.NavIdIsAlive = false; - g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; - - // Close popups if any - ClosePopupsOverWindow(window, false); - } - - // Move the root window to the top of the pile - IM_ASSERT(window == NULL || window->RootWindow != NULL); - ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop - ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; - - // Steal active widgets. Some of the cases it triggers includes: - // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. - // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) - if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) - if (!g.ActiveIdNoClearOnFocusLoss) - ClearActiveID(); - - // Passing NULL allow to disable keyboard focus - if (!window) - return; - - // Bring to front - BringWindowToFocusFront(focus_front_window); - if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) - BringWindowToDisplayFront(display_front_window); -} - -void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) -{ - ImGuiContext& g = *GImGui; - IM_UNUSED(filter_viewport); // Unused in master branch. - int start_idx = g.WindowsFocusOrder.Size - 1; - if (under_this_window != NULL) - { - // Aim at root window behind us, if we are in a child window that's our own root (see #4640) - int offset = -1; - while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) - { - under_this_window = under_this_window->ParentWindow; - offset = 0; - } - start_idx = FindWindowFocusIndex(under_this_window) + offset; - } - for (int i = start_idx; i >= 0; i--) - { - // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. - ImGuiWindow* window = g.WindowsFocusOrder[i]; - if (window == ignore_window || !window->WasActive) - continue; - if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) - { - FocusWindow(window, flags); - return; - } - } - FocusWindow(NULL, flags); -} - // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. void ImGui::SetCurrentFont(ImFont* font) { @@ -8216,28 +8027,6 @@ bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags) return true; } -bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) -{ - ImGuiContext& g = *GImGui; - ImGuiWindow* ref_window = g.NavWindow; - ImGuiWindow* cur_window = g.CurrentWindow; - - if (ref_window == NULL) - return false; - if (flags & ImGuiFocusedFlags_AnyWindow) - return true; - - IM_ASSERT(cur_window); // Not inside a Begin()/End() - const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; - if (flags & ImGuiHoveredFlags_RootWindow) - cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); - - if (flags & ImGuiHoveredFlags_ChildWindows) - return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); - else - return (ref_window == cur_window); -} - float ImGui::GetWindowWidth() { ImGuiWindow* window = GImGui->CurrentWindow; @@ -8385,24 +8174,6 @@ void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond) SetWindowCollapsed(window, collapsed, cond); } -void ImGui::SetWindowFocus() -{ - FocusWindow(GImGui->CurrentWindow); -} - -void ImGui::SetWindowFocus(const char* name) -{ - if (name) - { - if (ImGuiWindow* window = FindWindowByName(name)) - FocusWindow(window); - } - else - { - FocusWindow(NULL); - } -} - void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot) { ImGuiContext& g = *GImGui; @@ -8460,12 +8231,6 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; } -void ImGui::SetNextWindowFocus() -{ - ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; -} - void ImGui::SetNextWindowBgAlpha(float alpha) { ImGuiContext& g = *GImGui; @@ -12148,6 +11913,273 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window) return window->Pos; } +//----------------------------------------------------------------------------- +// [SECTION] WINDOW FOCUS +//---------------------------------------------------------------------------- +// - SetWindowFocus() +// - SetNextWindowFocus() +// - IsWindowFocused() +// - UpdateWindowInFocusOrderList() [Internal] +// - BringWindowToFocusFront() [Internal] +// - BringWindowToDisplayFront() [Internal] +// - BringWindowToDisplayBack() [Internal] +// - BringWindowToDisplayBehind() [Internal] +// - FindWindowDisplayIndex() [Internal] +// - FocusWindow() [Internal] +// - FocusTopMostWindowUnderOne() [Internal] +//----------------------------------------------------------------------------- + +void ImGui::SetWindowFocus() +{ + FocusWindow(GImGui->CurrentWindow); +} + +void ImGui::SetWindowFocus(const char* name) +{ + if (name) + { + if (ImGuiWindow* window = FindWindowByName(name)) + FocusWindow(window); + } + else + { + FocusWindow(NULL); + } +} + +void ImGui::SetNextWindowFocus() +{ + ImGuiContext& g = *GImGui; + g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; +} + +// Similar to IsWindowHovered() +bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* ref_window = g.NavWindow; + ImGuiWindow* cur_window = g.CurrentWindow; + + if (ref_window == NULL) + return false; + if (flags & ImGuiFocusedFlags_AnyWindow) + return true; + + IM_ASSERT(cur_window); // Not inside a Begin()/End() + const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; + if (flags & ImGuiHoveredFlags_RootWindow) + cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); + + if (flags & ImGuiHoveredFlags_ChildWindows) + return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); + else + return (ref_window == cur_window); +} + +static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + int order = window->FocusOrder; + IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) + IM_ASSERT(g.WindowsFocusOrder[order] == window); + return order; +} + +static void ImGui::UpdateWindowInFocusOrderList(ImGuiWindow* window, bool just_created, ImGuiWindowFlags new_flags) +{ + ImGuiContext& g = *GImGui; + + const bool new_is_explicit_child = (new_flags & ImGuiWindowFlags_ChildWindow) != 0 && ((new_flags & ImGuiWindowFlags_Popup) == 0 || (new_flags & ImGuiWindowFlags_ChildMenu) != 0); + const bool child_flag_changed = new_is_explicit_child != window->IsExplicitChild; + if ((just_created || child_flag_changed) && !new_is_explicit_child) + { + IM_ASSERT(!g.WindowsFocusOrder.contains(window)); + g.WindowsFocusOrder.push_back(window); + window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1); + } + else if (!just_created && child_flag_changed && new_is_explicit_child) + { + IM_ASSERT(g.WindowsFocusOrder[window->FocusOrder] == window); + for (int n = window->FocusOrder + 1; n < g.WindowsFocusOrder.Size; n++) + g.WindowsFocusOrder[n]->FocusOrder--; + g.WindowsFocusOrder.erase(g.WindowsFocusOrder.Data + window->FocusOrder); + window->FocusOrder = -1; + } + window->IsExplicitChild = new_is_explicit_child; +} + +void ImGui::BringWindowToFocusFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(window == window->RootWindow); + + const int cur_order = window->FocusOrder; + IM_ASSERT(g.WindowsFocusOrder[cur_order] == window); + if (g.WindowsFocusOrder.back() == window) + return; + + const int new_order = g.WindowsFocusOrder.Size - 1; + for (int n = cur_order; n < new_order; n++) + { + g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1]; + g.WindowsFocusOrder[n]->FocusOrder--; + IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n); + } + g.WindowsFocusOrder[new_order] = window; + window->FocusOrder = (short)new_order; +} + +// Note technically focus related but rather adjacent and close to BringWindowToFocusFront() +void ImGui::BringWindowToDisplayFront(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* current_front_window = g.Windows.back(); + if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better) + return; + for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window + if (g.Windows[i] == window) + { + memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*)); + g.Windows[g.Windows.Size - 1] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBack(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + if (g.Windows[0] == window) + return; + for (int i = 0; i < g.Windows.Size; i++) + if (g.Windows[i] == window) + { + memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*)); + g.Windows[0] = window; + break; + } +} + +void ImGui::BringWindowToDisplayBehind(ImGuiWindow* window, ImGuiWindow* behind_window) +{ + IM_ASSERT(window != NULL && behind_window != NULL); + ImGuiContext& g = *GImGui; + window = window->RootWindow; + behind_window = behind_window->RootWindow; + int pos_wnd = FindWindowDisplayIndex(window); + int pos_beh = FindWindowDisplayIndex(behind_window); + if (pos_wnd < pos_beh) + { + size_t copy_bytes = (pos_beh - pos_wnd - 1) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_wnd], &g.Windows.Data[pos_wnd + 1], copy_bytes); + g.Windows[pos_beh - 1] = window; + } + else + { + size_t copy_bytes = (pos_wnd - pos_beh) * sizeof(ImGuiWindow*); + memmove(&g.Windows.Data[pos_beh + 1], &g.Windows.Data[pos_beh], copy_bytes); + g.Windows[pos_beh] = window; + } +} + +int ImGui::FindWindowDisplayIndex(ImGuiWindow* window) +{ + ImGuiContext& g = *GImGui; + return g.Windows.index_from_ptr(g.Windows.find(window)); +} + +// Moving window to front of display and set focus (which happens to be back of our sorted list) +void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags) +{ + ImGuiContext& g = *GImGui; + + // Modal check? + if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case. + if (ImGuiWindow* blocking_modal = FindBlockingModal(window)) + { + // This block would typically be reached in two situations: + // - API call to FocusWindow() with a window under a modal and ImGuiFocusRequestFlags_UnlessBelowModal flag. + // - User clicking on void or anything behind a modal while a modal is open (window == NULL) + IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "", blocking_modal->Name); + if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayBehind(window, blocking_modal); // Still bring right under modal. (FIXME: Could move in focus list too?) + ClosePopupsOverWindow(GetTopMostPopupModal(), false); // Note how we need to use GetTopMostPopupModal() aad NOT blocking_modal, to handle nested modals + return; + } + + // Find last focused child (if any) and focus it instead. + if ((flags & ImGuiFocusRequestFlags_RestoreFocusedChild) && window != NULL) + window = NavRestoreLastChildNavWindow(window); + + // Apply focus + if (g.NavWindow != window) + { + SetNavWindow(window); + if (window && g.NavHighlightItemUnderNav) + g.NavMousePosDirty = true; + g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId + g.NavLayer = ImGuiNavLayer_Main; + SetNavFocusScope(window ? window->NavRootFocusScopeId : 0); + g.NavIdIsAlive = false; + g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid; + + // Close popups if any + ClosePopupsOverWindow(window, false); + } + + // Move the root window to the top of the pile + IM_ASSERT(window == NULL || window->RootWindow != NULL); + ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop + ImGuiWindow* display_front_window = window ? window->RootWindow : NULL; + + // Steal active widgets. Some of the cases it triggers includes: + // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run. + // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId) + if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window) + if (!g.ActiveIdNoClearOnFocusLoss) + ClearActiveID(); + + // Passing NULL allow to disable keyboard focus + if (!window) + return; + + // Bring to front + BringWindowToFocusFront(focus_front_window); + if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0) + BringWindowToDisplayFront(display_front_window); +} + +void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window, ImGuiViewport* filter_viewport, ImGuiFocusRequestFlags flags) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(filter_viewport); // Unused in master branch. + int start_idx = g.WindowsFocusOrder.Size - 1; + if (under_this_window != NULL) + { + // Aim at root window behind us, if we are in a child window that's our own root (see #4640) + int offset = -1; + while (under_this_window->Flags & ImGuiWindowFlags_ChildWindow) + { + under_this_window = under_this_window->ParentWindow; + offset = 0; + } + start_idx = FindWindowFocusIndex(under_this_window) + offset; + } + for (int i = start_idx; i >= 0; i--) + { + // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user. + ImGuiWindow* window = g.WindowsFocusOrder[i]; + if (window == ignore_window || !window->WasActive) + continue; + if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) + { + FocusWindow(window, flags); + return; + } + } + FocusWindow(NULL, flags); +} + //----------------------------------------------------------------------------- // [SECTION] KEYBOARD/GAMEPAD NAVIGATION //----------------------------------------------------------------------------- @@ -13504,16 +13536,6 @@ static void ImGui::NavUpdateCreateWrappingRequest() NavMoveRequestForward(g.NavMoveDir, clip_dir, move_flags, g.NavMoveScrollFlags); } -static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) -{ - ImGuiContext& g = *GImGui; - IM_UNUSED(g); - int order = window->FocusOrder; - IM_ASSERT(window->RootWindow == window); // No child window (not testing _ChildWindow because of docking) - IM_ASSERT(g.WindowsFocusOrder[order] == window); - return order; -} - // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext) // Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically. // If you want a window to never be focused, you may use the e.g. NoInputs flag. From 1c67a3412e1540700494f4c0d76d389d0232606f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 14:55:51 +0100 Subject: [PATCH 124/716] BeginChild: also caller to manually set ImGuiNextWindowDataFlags_HasChildFlags / ChildFlags. (#8280) --- imgui.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5f898a389eac..ededc3d00247 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6049,9 +6049,12 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I } SetNextWindowSize(size); - // Forward child flags + // Forward child flags (we allow prior settings to merge but it'll only work for adding flags) + if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasChildFlags) + g.NextWindowData.ChildFlags |= child_flags; + else + g.NextWindowData.ChildFlags = child_flags; g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; - g.NextWindowData.ChildFlags = child_flags; // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. // FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround. From 90094a871a5379d78a1b38b8364e0bd2ee65f796 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 18:13:53 +0100 Subject: [PATCH 125/716] Fonts: Fixed miscalculation of Ellipsis ("...") character width when automatically created from a single comma character. --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a24d6ea4ea9f..89c4140b5df0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,8 @@ Other changes: windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) +- Fonts: Fixed miscalculation of Ellipsis ("...") character width when automatically + created from a single comma character, affecting some fonts/settings (not all). - Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 42bfb71625cf..9e155f592023 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3799,8 +3799,8 @@ void ImFont::BuildLookupTable() const ImFontGlyph* glyph = FindGlyph(dot_char); EllipsisChar = dot_char; EllipsisCharCount = 3; - EllipsisCharStep = (glyph->X1 - glyph->X0) + 1.0f; - EllipsisWidth = EllipsisCharStep * 3.0f - 1.0f; + EllipsisCharStep = (float)(int)(glyph->X1 - glyph->X0) + 1.0f; + EllipsisWidth = glyph->X0 + EllipsisCharStep * 3.0f - 1.0f; } } From c7983115e9f7bdee8bc76ec17612ef1a45bdc05e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 18:27:01 +0100 Subject: [PATCH 126/716] Fonts: Further tweaks for Ellipsis ("...") character width when automatically created from a single comma character: use AdvanceX as min. --- imgui_draw.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 9e155f592023..8baaf8b11767 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3796,11 +3796,11 @@ void ImFont::BuildLookupTable() } else if (dot_char != 0) { - const ImFontGlyph* glyph = FindGlyph(dot_char); + const ImFontGlyph* dot_glyph = FindGlyph(dot_char); EllipsisChar = dot_char; EllipsisCharCount = 3; - EllipsisCharStep = (float)(int)(glyph->X1 - glyph->X0) + 1.0f; - EllipsisWidth = glyph->X0 + EllipsisCharStep * 3.0f - 1.0f; + EllipsisCharStep = (float)(int)(dot_glyph->X1 - dot_glyph->X0) + 1.0f; + EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. } } From 940d9540f3f7efc9e79fdcba859a24162b383a6f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 15:28:48 +0100 Subject: [PATCH 127/716] Fixed MinGW builds uses UTF-8 friendly _wfopen(). (#8300) Amend bbd0a37bd, 40db2ca09 --- docs/CHANGELOG.txt | 1 + imgui.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 89c4140b5df0..00df8a746418 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,7 @@ Other changes: created from a single comma character, affecting some fonts/settings (not all). - Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] +- Misc: Fixed MinGW builds uses UTF-8 friendly _wfopen(). (#8300) - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] - Backends: Metal: Fixed leaks when using metal-cpp. (#8276, #8166) [@selimsandal] diff --git a/imgui.cpp b/imgui.cpp index ededc3d00247..bad766f030eb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2282,7 +2282,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImGuiID seed) ImFileHandle ImFileOpen(const char* filename, const char* mode) { -#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (defined(__MINGW32__) || (!defined(__CYGWIN__) && !defined(__GNUC__))) // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); From 8bbccf7a9779c45c15e201c18eb3971d40fc0e76 Mon Sep 17 00:00:00 2001 From: Delta <98419797+DeltaW0x@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:37:13 +0100 Subject: [PATCH 128/716] Backends: SDLGPU3: Added sdl_gpu backend. (#8163, #7998, #7988) +Squashed: Optimized shader source code encoding by ocornut (#8163, #7998, #7988) (squashed to avoid storing both in git history, 130 KB->62 KB) --- backends/imgui_impl_sdlgpu3.cpp | 630 ++++++++++++++++++ backends/imgui_impl_sdlgpu3.h | 46 ++ backends/imgui_impl_sdlgpu3_shaders.h | 372 +++++++++++ backends/sdlgpu3/build_instructions.txt | 36 + backends/sdlgpu3/shader.frag | 14 + backends/sdlgpu3/shader.vert | 22 + examples/example_sdl3_sdlgpu3/Makefile | 73 ++ examples/example_sdl3_sdlgpu3/build_win64.bat | 14 + .../example_sdl3_sdlgpu3.vcxproj | 189 ++++++ .../example_sdl3_sdlgpu3.vcxproj.filters | 60 ++ examples/example_sdl3_sdlgpu3/main.cpp | 210 ++++++ examples/imgui_examples.sln | 10 + 12 files changed, 1676 insertions(+) create mode 100644 backends/imgui_impl_sdlgpu3.cpp create mode 100644 backends/imgui_impl_sdlgpu3.h create mode 100644 backends/imgui_impl_sdlgpu3_shaders.h create mode 100644 backends/sdlgpu3/build_instructions.txt create mode 100644 backends/sdlgpu3/shader.frag create mode 100644 backends/sdlgpu3/shader.vert create mode 100644 examples/example_sdl3_sdlgpu3/Makefile create mode 100644 examples/example_sdl3_sdlgpu3/build_win64.bat create mode 100644 examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj create mode 100644 examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters create mode 100644 examples/example_sdl3_sdlgpu3/main.cpp diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp new file mode 100644 index 000000000000..31e899b77d92 --- /dev/null +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -0,0 +1,630 @@ +// dear imgui: Renderer Backend for SDL_Gpu +// This needs to be used along with the SDL3 Platform Backend + +// Implemented features: +// [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. +// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. +// - Unline other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. + +// CHANGELOG +// 2024-11-18: SDL_Gpu: Added the SDL_Gpu backend. + +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include "imgui_impl_sdlgpu3.h" +#include "imgui_impl_sdlgpu3_shaders.h" + +// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU_RenderDrawData() +struct ImGui_ImplSDLGPU_FrameData +{ + SDL_GPUBuffer* VertexBuffer = nullptr; + SDL_GPUBuffer* IndexBuffer = nullptr; + uint32_t VertexBufferSize = 0; + uint32_t IndexBufferSize = 0; +}; + +// SDL_Gpu Data +struct ImGui_ImplSDLGPU_Data +{ + ImGui_ImplSDLGPU_InitInfo GPUInitInfo; + + // Graphics pipeline & shaders + SDL_GPUShader* VertexShader = nullptr; + SDL_GPUShader* FragmentShader = nullptr; + SDL_GPUGraphicsPipeline* Pipeline = nullptr; + + // Font data + SDL_GPUSampler* FontSampler = nullptr; + SDL_GPUTexture* FontTexture = nullptr; + SDL_GPUTextureSamplerBinding FontBinding = {nullptr,nullptr}; + + // Frame data for main window + ImGui_ImplSDLGPU_FrameData MainWindowFrameData; +}; + +// Forward Declarations +static bool ImGui_ImplSDLGPU_CreateDeviceObjects(); +static void ImGui_ImplSDLGPU_DestroyDeviceObjects(); +static void ImGui_ImplSDLGPU_DestroyFrameData(); + +//----------------------------------------------------------------------------- +// FUNCTIONS +//----------------------------------------------------------------------------- + +// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts +// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. +// FIXME: multi-context support has never been tested. +static ImGui_ImplSDLGPU_Data* ImGui_ImplSDLGPU_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; +} + +static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer,uint32_t* old_size, uint32_t new_size,SDL_GPUBufferUsageFlags usage) +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + SDL_WaitForGPUIdle(v->GpuDevice); + SDL_ReleaseGPUBuffer(v->GpuDevice, *buffer); + + SDL_GPUBufferCreateInfo buffer_info = {}; + buffer_info.usage = usage; + buffer_info.size = new_size; + buffer_info.props = 0; + *buffer = SDL_CreateGPUBuffer(v->GpuDevice,&buffer_info); + *old_size = new_size; + IM_ASSERT(*buffer != nullptr && "Failed to create GPU Buffer, call SDL_GetError() for more information"); +} + +static void ImGui_ImplSDLGPU_SetupRenderState(ImDrawData* draw_data,SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer,SDL_GPURenderPass * render_pass, ImGui_ImplSDLGPU_FrameData* fd, uint32_t fb_width, uint32_t fb_height) +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + + // Bind graphics pipeline: + { + SDL_BindGPUGraphicsPipeline(render_pass,pipeline); + } + + // Bind Vertex And Index Buffers: + if (draw_data->TotalVtxCount > 0) + { + SDL_GPUBufferBinding vertex_buffer_binding = {}; + vertex_buffer_binding.buffer = fd->VertexBuffer; + vertex_buffer_binding.offset = 0; + SDL_GPUBufferBinding index_buffer_binding = {}; + index_buffer_binding.buffer = fd->IndexBuffer; + index_buffer_binding.offset = 0; + SDL_BindGPUVertexBuffers(render_pass,0,&vertex_buffer_binding,1); + SDL_BindGPUIndexBuffer(render_pass,&index_buffer_binding,sizeof(ImDrawIdx) == 2 ? SDL_GPU_INDEXELEMENTSIZE_16BIT : SDL_GPU_INDEXELEMENTSIZE_32BIT); + } + + // Setup viewport: + { + SDL_GPUViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.w = fb_width; + viewport.h = fb_height; + viewport.min_depth = 0.0f; + viewport.min_depth = 1.0f; + SDL_SetGPUViewport(render_pass,&viewport); + } + + // Setup scale and translation: + // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. + { + struct UBO{ + float scale[2]; + float translation[2]; + } ubo; + ubo.scale[0] = 2.0f / draw_data->DisplaySize.x; + ubo.scale[1] = 2.0f / draw_data->DisplaySize.y; + ubo.translation[0] = -1.0f - draw_data->DisplayPos.x * ubo.scale[0]; + ubo.translation[1] = -1.0f - draw_data->DisplayPos.y * ubo.scale[1]; + SDL_PushGPUVertexUniformData(command_buffer,0,&ubo,sizeof(UBO)); + } +} + +// SDL_GPU doesn't allow copy passes to occur while a render or compute pass is bound +// The only way to allow a user to supply their own RenderPass (to render to a texture instead of the window for example), +// is to split the upload part of ImGui_ImplSDLGPU_RenderDrawData to another function that needs to be called by the user before rendering +void Imgui_ImplSDLGPU_PrepareDrawData(ImDrawData* draw_data,SDL_GPUCommandBuffer* command_buffer) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if(fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0) + return; + + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU_FrameData* fd = &bd->MainWindowFrameData; + + uint32_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); + uint32_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); + + if(fd->VertexBuffer == nullptr || fd->VertexBufferSize < vertex_size) + CreateOrResizeBuffer(&fd->VertexBuffer,&fd->VertexBufferSize,vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX); + if (fd->IndexBuffer == nullptr || fd->IndexBufferSize < index_size) + CreateOrResizeBuffer(&fd->IndexBuffer,&fd->IndexBufferSize,index_size, SDL_GPU_BUFFERUSAGE_INDEX); + + SDL_GPUTransferBufferCreateInfo vertex_transferbuffer_info = {}; + vertex_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + vertex_transferbuffer_info.size = vertex_size; + SDL_GPUTransferBufferCreateInfo index_transferbuffer_info = {}; + index_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + index_transferbuffer_info.size = index_size; + + SDL_GPUTransferBuffer* vertex_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice,&vertex_transferbuffer_info); + IM_ASSERT(vertex_transferbuffer != nullptr && "Failed to create the vertex transfer buffer, call SDL_GetError() for more information"); + SDL_GPUTransferBuffer* index_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice,&index_transferbuffer_info); + IM_ASSERT(index_transferbuffer != nullptr && "Failed to create the index transfer buffer, call SDL_GetError() for more information"); + + ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->GpuDevice,vertex_transferbuffer,true); + ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->GpuDevice,index_transferbuffer,true); + for(int n = 0; n < draw_data->CmdListsCount; n++){ + const ImDrawList* draw_list = draw_data->CmdLists[n]; + memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); + memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); + vtx_dst += draw_list->VtxBuffer.Size; + idx_dst += draw_list->IdxBuffer.Size; + } + SDL_UnmapGPUTransferBuffer(v->GpuDevice,vertex_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->GpuDevice,index_transferbuffer); + + SDL_GPUTransferBufferLocation vertex_buffer_location = {}; + vertex_buffer_location.offset = 0; + vertex_buffer_location.transfer_buffer = vertex_transferbuffer; + SDL_GPUTransferBufferLocation index_buffer_location = {}; + index_buffer_location.offset = 0; + index_buffer_location.transfer_buffer = index_transferbuffer; + + SDL_GPUBufferRegion vertex_buffer_region = {}; + vertex_buffer_region.buffer = fd->VertexBuffer; + vertex_buffer_region.offset = 0; + vertex_buffer_region.size = vertex_size; + SDL_GPUBufferRegion index_buffer_region = {}; + index_buffer_region.buffer = fd->IndexBuffer; + index_buffer_region.offset = 0; + index_buffer_region.size = index_size; + + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(command_buffer); + SDL_UploadToGPUBuffer(copy_pass,&vertex_buffer_location,&vertex_buffer_region,true); + SDL_UploadToGPUBuffer(copy_pass,&index_buffer_location,&index_buffer_region,true); + SDL_EndGPUCopyPass(copy_pass); + SDL_ReleaseGPUTransferBuffer(v->GpuDevice, index_transferbuffer); + SDL_ReleaseGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer); +} + +void ImGui_ImplSDLGPU_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) +{ + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if(fb_width <= 0 || fb_height <= 0) + return; + + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_FrameData* fd = &bd->MainWindowFrameData; + + if (pipeline == nullptr) + pipeline = bd->Pipeline; + + ImGui_ImplSDLGPU_SetupRenderState(draw_data,pipeline,command_buffer,render_pass,fd,fb_width,fb_height); + + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists + // (Because we merged all buffers into a single one, we maintain our own offset into them) + int global_vtx_offset = 0; + int global_idx_offset = 0; + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* draw_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback != nullptr) + { + pcmd->UserCallback(draw_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + + // Clamp to viewport as SDL_SetGPUScissor() won't accept values that are off bounds + if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } + if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } + if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // Apply scissor/clipping rectangle + SDL_Rect scissor_rect = {}; + scissor_rect.x = (int)clip_min.x; + scissor_rect.y = (int)clip_min.y; + scissor_rect.w = (int)(clip_max.x - clip_min.x); + scissor_rect.h = (int)(clip_max.y - clip_min.y); + SDL_SetGPUScissor(render_pass,&scissor_rect); + + // Bind DescriptorSet with font or user texture + SDL_BindGPUFragmentSamplers(render_pass,0,(SDL_GPUTextureSamplerBinding*)pcmd->GetTexID(),1); + + // Draw + SDL_DrawGPUIndexedPrimitives(render_pass,pcmd->ElemCount,1,pcmd->IdxOffset + global_idx_offset,pcmd->VtxOffset + global_vtx_offset,0); + } + } + global_idx_offset += draw_list->IdxBuffer.Size; + global_vtx_offset += draw_list->VtxBuffer.Size; + } + + // Note: at this point both SDL_SetGPUViewport() and SDL_SetGPUScissor() have been called. + // Our last values will leak into user/application rendering if you forgot to call SDL_SetGPUViewport() and SDL_SetGPUScissor() yourself to explicitly set that state + // In theory we should aim to backup/restore those values but I am not sure this is possible. + // We perform a call to SDL_SetGPUScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644) + SDL_Rect scissor_rect {0,0,fb_width,fb_height}; + SDL_SetGPUScissor(render_pass,&scissor_rect); +} + +bool ImGui_ImplSDLGPU_CreateFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + // Destroy existing texture (if any) + if (bd->FontTexture) + { + SDL_WaitForGPUIdle(v->GpuDevice); + ImGui_ImplSDLGPU_DestroyFontsTexture(); + } + + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + uint32_t upload_size = width * height * 4 * sizeof(char); + + // Create the Image: + { + SDL_GPUTextureCreateInfo texture_info = {}; + texture_info.type = SDL_GPU_TEXTURETYPE_2D; + texture_info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + texture_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; + texture_info.width = width; + texture_info.height = height; + texture_info.layer_count_or_depth = 1; + texture_info.num_levels = 1; + texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1; + + bd->FontTexture = SDL_CreateGPUTexture(v->GpuDevice,&texture_info); + IM_ASSERT(bd->FontTexture && "Failed to create font texture, call SDL_GetError() for more info"); + } + + // Assign the texture to the TextureSamplerBinding + bd->FontBinding.texture = bd->FontTexture; + + // Create all the upload structures and upload: + { + SDL_GPUTransferBufferCreateInfo font_transferbuffer_info = {}; + font_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + font_transferbuffer_info.size = upload_size; + + SDL_GPUTransferBuffer* font_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice,&font_transferbuffer_info); + IM_ASSERT(font_transferbuffer != nullptr && "Failed to create font transfer buffer, call SDL_GetError() for more information"); + + void* texture_ptr = SDL_MapGPUTransferBuffer(v->GpuDevice,font_transferbuffer,false); + memcpy(texture_ptr,pixels,upload_size); + SDL_UnmapGPUTransferBuffer(v->GpuDevice,font_transferbuffer); + + SDL_GPUTextureTransferInfo font_transfer_info = {}; + font_transfer_info.offset = 0; + font_transfer_info.transfer_buffer = font_transferbuffer; + + SDL_GPUTextureRegion font_texture_region = {}; + font_texture_region.texture = bd->FontTexture; + font_texture_region.w = width; + font_texture_region.h = height; + font_texture_region.d = 1; + + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(v->GpuDevice); + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUTexture(copy_pass,&font_transfer_info,&font_texture_region,false); + SDL_EndGPUCopyPass(copy_pass); + SDL_SubmitGPUCommandBuffer(cmd); + SDL_ReleaseGPUTransferBuffer(v->GpuDevice, font_transferbuffer); + } + + // Store our identifier + io.Fonts->SetTexID((ImTextureID)&bd->FontBinding); + + return true; +} + +// You probably never need to call this, as it is called by ImGui_ImplSDLGPU_CreateFontsTexture() and ImGui_ImplSDLGPU_Shutdown(). +void ImGui_ImplSDLGPU_DestroyFontsTexture() +{ + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + if(bd->FontTexture) + { + SDL_ReleaseGPUTexture(v->GpuDevice,bd->FontTexture); + bd->FontBinding.texture = nullptr; + bd->FontTexture = nullptr; + } + + io.Fonts->SetTexID(0); +} + +static void Imgui_ImplSDLGPU_CreateShaders() +{ + // Create the shader modules + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + const char* driver = SDL_GetGPUDeviceDriver(v->GpuDevice); + + SDL_GPUShaderCreateInfo vertex_shader_info = {}; + vertex_shader_info.entrypoint = "main"; + vertex_shader_info.stage = SDL_GPU_SHADERSTAGE_VERTEX; + vertex_shader_info.num_uniform_buffers = 1; + vertex_shader_info.num_storage_buffers = 0; + vertex_shader_info.num_storage_textures = 0; + vertex_shader_info.num_samplers = 0; + + SDL_GPUShaderCreateInfo fragment_shader_info = {}; + fragment_shader_info.entrypoint = "main"; + fragment_shader_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT; + fragment_shader_info.num_samplers = 1; + fragment_shader_info.num_storage_buffers = 0; + fragment_shader_info.num_storage_textures = 0; + fragment_shader_info.num_uniform_buffers = 0; + + if(strcmp(driver,"vulkan") == 0) + { + vertex_shader_info.format = SDL_GPU_SHADERFORMAT_SPIRV; + vertex_shader_info.code = spirv_vertex; + vertex_shader_info.code_size = sizeof(spirv_vertex); + + fragment_shader_info.format = SDL_GPU_SHADERFORMAT_SPIRV; + fragment_shader_info.code = spirv_fragment; + fragment_shader_info.code_size = sizeof(spirv_fragment); + } + else if (strcmp(driver,"direct3d12") == 0) + { + vertex_shader_info.format = SDL_GPU_SHADERFORMAT_DXBC; + vertex_shader_info.code = dxbc_vertex; + vertex_shader_info.code_size = sizeof(dxbc_vertex); + + fragment_shader_info.format = SDL_GPU_SHADERFORMAT_DXBC; + fragment_shader_info.code = dxbc_fragment; + fragment_shader_info.code_size = sizeof(dxbc_fragment); + } +#ifdef __APPLE__ + else + { + vertex_shader_info.entrypoint = "main0"; + vertex_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB; + vertex_shader_info.code = metallib_vertex; + vertex_shader_info.code_size = sizeof(metallib_vertex); + + fragment_shader_info.entrypoint = "main0"; + fragment_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB; + fragment_shader_info.code = metallib_fragment; + fragment_shader_info.code_size = sizeof(metallib_fragment); + } +#endif + bd->VertexShader = SDL_CreateGPUShader(v->GpuDevice,&vertex_shader_info); + bd->FragmentShader = SDL_CreateGPUShader(v->GpuDevice,&fragment_shader_info); + + IM_ASSERT(bd->VertexShader != nullptr && "Failed to create vertex shader, call SDL_GetError() for more information"); + IM_ASSERT(bd->FragmentShader != nullptr && "Failed to create fragment shader, call SDL_GetError() for more information"); +} + +static void ImGui_ImplSDLGPU_CreateGraphicsPipeline() +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + Imgui_ImplSDLGPU_CreateShaders(); + + SDL_GPUVertexBufferDescription vertex_buffer_desc[1]; + vertex_buffer_desc[0].slot = 0; + vertex_buffer_desc[0].input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX; + vertex_buffer_desc[0].instance_step_rate = 0; + vertex_buffer_desc[0].pitch = sizeof(ImDrawVert); + + SDL_GPUVertexAttribute vertex_attributes[3]; + vertex_attributes[0].buffer_slot = 0; + vertex_attributes[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; + vertex_attributes[0].location = 0; + vertex_attributes[0].offset = offsetof(ImDrawVert,pos); + + vertex_attributes[1].buffer_slot = 0; + vertex_attributes[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2; + vertex_attributes[1].location = 1; + vertex_attributes[1].offset = offsetof(ImDrawVert, uv); + + vertex_attributes[2].buffer_slot = 0; + vertex_attributes[2].format = SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM; + vertex_attributes[2].location = 2; + vertex_attributes[2].offset = offsetof(ImDrawVert, col); + + SDL_GPUVertexInputState vertex_input_state = {}; + vertex_input_state.num_vertex_attributes = 3; + vertex_input_state.vertex_attributes = vertex_attributes; + vertex_input_state.num_vertex_buffers = 1; + vertex_input_state.vertex_buffer_descriptions = vertex_buffer_desc; + + SDL_GPURasterizerState rasterizer_state = {}; + rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL; + rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE; + rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE; + rasterizer_state.enable_depth_bias = false; + rasterizer_state.enable_depth_clip = false; + + SDL_GPUMultisampleState multisample_state = {}; + multisample_state.sample_count = v->MSAASamples; + multisample_state.enable_mask = false; + + SDL_GPUDepthStencilState depth_stencil_state = {}; + depth_stencil_state.enable_depth_test = false; + depth_stencil_state.enable_depth_write = false; + depth_stencil_state.enable_stencil_test = false; + + SDL_GPUColorTargetBlendState blend_state = {}; + blend_state.enable_blend = true; + blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA; + blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD; + blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE; + blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD; + blend_state.color_write_mask = SDL_GPU_COLORCOMPONENT_R | SDL_GPU_COLORCOMPONENT_G | SDL_GPU_COLORCOMPONENT_B | SDL_GPU_COLORCOMPONENT_A; + + SDL_GPUColorTargetDescription color_target_desc[1]; + color_target_desc[0].format = v->ColorTargetFormat; + color_target_desc[0].blend_state = blend_state; + + SDL_GPUGraphicsPipelineTargetInfo target_info = {}; + target_info.num_color_targets = 1; + target_info.color_target_descriptions = color_target_desc; + target_info.has_depth_stencil_target = false; + + SDL_GPUGraphicsPipelineCreateInfo pipeline_info = {}; + pipeline_info.vertex_shader = bd->VertexShader; + pipeline_info.fragment_shader = bd->FragmentShader; + pipeline_info.vertex_input_state = vertex_input_state; + pipeline_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; + pipeline_info.rasterizer_state = rasterizer_state; + pipeline_info.multisample_state = multisample_state; + pipeline_info.depth_stencil_state = depth_stencil_state; + pipeline_info.target_info = target_info; + + bd->Pipeline = SDL_CreateGPUGraphicsPipeline(v->GpuDevice,&pipeline_info); + IM_ASSERT(bd->Pipeline != nullptr && "Failed to create graphics pipeline, call SDL_GetError() for more information"); +} + +bool ImGui_ImplSDLGPU_CreateDeviceObjects() +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + if (!bd->FontSampler) + { + // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. + SDL_GPUSamplerCreateInfo sampler_info = {}; + sampler_info.min_filter = SDL_GPU_FILTER_LINEAR; + sampler_info.mag_filter = SDL_GPU_FILTER_LINEAR; + sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + sampler_info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + sampler_info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + sampler_info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + sampler_info.mip_lod_bias = 0.0f; + sampler_info.min_lod = -1000.0f; + sampler_info.max_lod = 1000.0f; + sampler_info.enable_anisotropy = true; + sampler_info.max_anisotropy = 1.0f; + sampler_info.enable_compare = false; + + bd->FontSampler = SDL_CreateGPUSampler(v->GpuDevice,&sampler_info); + bd->FontBinding.sampler = bd->FontSampler; + IM_ASSERT(bd->FontSampler != nullptr && "Failed to create font sampler, call SDL_GetError() for more information"); + } + + ImGui_ImplSDLGPU_CreateGraphicsPipeline(); + + return true; +} + +void ImGui_ImplSDLGPU_DestroyFrameData() +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + SDL_ReleaseGPUBuffer(v->GpuDevice,bd->MainWindowFrameData.VertexBuffer); + SDL_ReleaseGPUBuffer(v->GpuDevice,bd->MainWindowFrameData.IndexBuffer); + bd->MainWindowFrameData.VertexBuffer = nullptr; + bd->MainWindowFrameData.IndexBuffer = nullptr; + bd->MainWindowFrameData.VertexBufferSize = 0; + bd->MainWindowFrameData.IndexBufferSize = 0; +} + +void ImGui_ImplSDLGPU_DestroyDeviceObjects() +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + + ImGui_ImplSDLGPU_DestroyFrameData(); + ImGui_ImplSDLGPU_DestroyFontsTexture(); + + if(bd->VertexShader) { SDL_ReleaseGPUShader(v->GpuDevice,bd->VertexShader); bd->VertexShader = nullptr;} + if(bd->FragmentShader) { SDL_ReleaseGPUShader(v->GpuDevice,bd->FragmentShader); bd->FragmentShader = nullptr;} + if(bd->FontSampler) { SDL_ReleaseGPUSampler(v->GpuDevice, bd->FontSampler); bd->FontSampler = nullptr;} + if(bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->GpuDevice,bd->Pipeline); bd->Pipeline = nullptr;} +} + +bool ImGui_ImplSDLGPU_Init(ImGui_ImplSDLGPU_InitInfo* info) +{ + ImGuiIO& io = ImGui::GetIO(); + IMGUI_CHECKVERSION(); + IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); + + // Setup backend capabilities flags + ImGui_ImplSDLGPU_Data* bd = IM_NEW(ImGui_ImplSDLGPU_Data)(); + io.BackendRendererUserData = (void*)bd; + io.BackendRendererName = "imgui_impl_sdlgpu"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + + IM_ASSERT(info->GpuDevice != nullptr); + IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID); + + bd->GPUInitInfo = *info; + + ImGui_ImplSDLGPU_CreateDeviceObjects(); + + return true; +} + +void ImGui_ImplSDLGPU_Shutdown() +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + + ImGui_ImplSDLGPU_DestroyDeviceObjects(); + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + IM_DELETE(bd); +} + +void ImGui_ImplSDLGPU_NewFrame() +{ + ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?"); + + if(!bd->FontTexture) + ImGui_ImplSDLGPU_CreateFontsTexture(); +} + +#endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h new file mode 100644 index 000000000000..18d3001e400c --- /dev/null +++ b/backends/imgui_impl_sdlgpu3.h @@ -0,0 +1,46 @@ +// dear imgui: Renderer Backend for SDL_Gpu +// This needs to be used along with the SDL3 Platform Backend + +// Implemented features: +// [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. +// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. + +// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. +// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ + +// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. +// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. +// - Unline other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. + +#pragma once +#include "imgui.h" // IMGUI_IMPL_API +#ifndef IMGUI_DISABLE +#include + +// Initialization data, for ImGui_ImplSDLGPU_Init() +// - Remember to set ColorTargetFormat to the correct format. If you're rendering to the swapchain, call SDL_GetGPUSwapchainTextureFormat to query the right value +struct ImGui_ImplSDLGPU_InitInfo +{ + SDL_GPUDevice* GpuDevice = nullptr; + SDL_GPUTextureFormat ColorTargetFormat = SDL_GPU_TEXTUREFORMAT_INVALID; + SDL_GPUSampleCount MSAASamples = SDL_GPU_SAMPLECOUNT_1; +}; + +// Follow "Getting Started" link and check examples/ folder to learn about using backends! +IMGUI_IMPL_API bool ImGui_ImplSDLGPU_Init(ImGui_ImplSDLGPU_InitInfo* info); +IMGUI_IMPL_API void ImGui_ImplSDLGPU_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU_NewFrame(); +IMGUI_IMPL_API void Imgui_ImplSDLGPU_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); +IMGUI_IMPL_API void ImGui_ImplSDLGPU_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU_DestroyFontsTexture(); + +#endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3_shaders.h b/backends/imgui_impl_sdlgpu3_shaders.h new file mode 100644 index 000000000000..f792aa6abd77 --- /dev/null +++ b/backends/imgui_impl_sdlgpu3_shaders.h @@ -0,0 +1,372 @@ +#pragma once +#ifndef IMGUI_DISABLE +#include + +// Data exported using +// misc/fonts/binary_to_compressed_c.exe -u8 -nocompress filename symbolname >filename.h +// With some manual pasting. + +// Check sdlgpu3/ folder for the shaders' source code and instruction on how to build them +const uint8_t spirv_vertex[1732] = { + 3,2,35,7,0,0,1,0,11,0,13,0,55,0,0,0,0,0,0,0,17,0,2,0,1,0,0,0,11,0,6,0,1,0,0,0,71,76,83,76,46,115,116,100,46,52,53,48,0,0,0,0,14,0,3,0,0,0,0,0,1,0,0,0,15,0,10,0,0,0,0,0,4,0,0,0,109, + 97,105,110,0,0,0,0,11,0,0,0,15,0,0,0,21,0,0,0,30,0,0,0,31,0,0,0,3,0,3,0,2,0,0,0,194,1,0,0,4,0,10,0,71,76,95,71,79,79,71,76,69,95,99,112,112,95,115,116,121,108,101,95,108,105,110,101, + 95,100,105,114,101,99,116,105,118,101,0,0,4,0,8,0,71,76,95,71,79,79,71,76,69,95,105,110,99,108,117,100,101,95,100,105,114,101,99,116,105,118,101,0,5,0,4,0,4,0,0,0,109,97,105,110,0, + 0,0,0,5,0,3,0,9,0,0,0,0,0,0,0,6,0,5,0,9,0,0,0,0,0,0,0,67,111,108,111,114,0,0,0,6,0,4,0,9,0,0,0,1,0,0,0,85,86,0,0,5,0,3,0,11,0,0,0,79,117,116,0,5,0,4,0,15,0,0,0,97,67,111,108,111,114, + 0,0,5,0,3,0,21,0,0,0,97,85,86,0,5,0,6,0,28,0,0,0,103,108,95,80,101,114,86,101,114,116,101,120,0,0,0,0,6,0,6,0,28,0,0,0,0,0,0,0,103,108,95,80,111,115,105,116,105,111,110,0,6,0,7,0,28, + 0,0,0,1,0,0,0,103,108,95,80,111,105,110,116,83,105,122,101,0,0,0,0,6,0,7,0,28,0,0,0,2,0,0,0,103,108,95,67,108,105,112,68,105,115,116,97,110,99,101,0,6,0,7,0,28,0,0,0,3,0,0,0,103,108, + 95,67,117,108,108,68,105,115,116,97,110,99,101,0,5,0,3,0,30,0,0,0,0,0,0,0,5,0,4,0,31,0,0,0,97,80,111,115,0,0,0,0,5,0,6,0,33,0,0,0,117,80,117,115,104,67,111,110,115,116,97,110,116,0, + 0,0,6,0,5,0,33,0,0,0,0,0,0,0,117,83,99,97,108,101,0,0,6,0,6,0,33,0,0,0,1,0,0,0,117,84,114,97,110,115,108,97,116,101,0,0,5,0,3,0,35,0,0,0,112,99,0,0,71,0,4,0,11,0,0,0,30,0,0,0,0,0,0, + 0,71,0,4,0,15,0,0,0,30,0,0,0,2,0,0,0,71,0,4,0,21,0,0,0,30,0,0,0,1,0,0,0,71,0,3,0,28,0,0,0,2,0,0,0,72,0,5,0,28,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,72,0,5,0,28,0,0,0,1,0,0,0,11,0,0,0,1,0, + 0,0,72,0,5,0,28,0,0,0,2,0,0,0,11,0,0,0,3,0,0,0,72,0,5,0,28,0,0,0,3,0,0,0,11,0,0,0,4,0,0,0,71,0,4,0,31,0,0,0,30,0,0,0,0,0,0,0,71,0,3,0,33,0,0,0,2,0,0,0,72,0,5,0,33,0,0,0,0,0,0,0,35, + 0,0,0,0,0,0,0,72,0,5,0,33,0,0,0,1,0,0,0,35,0,0,0,8,0,0,0,71,0,4,0,35,0,0,0,33,0,0,0,0,0,0,0,71,0,4,0,35,0,0,0,34,0,0,0,1,0,0,0,19,0,2,0,2,0,0,0,33,0,3,0,3,0,0,0,2,0,0,0,22,0,3,0,6, + 0,0,0,32,0,0,0,23,0,4,0,7,0,0,0,6,0,0,0,4,0,0,0,23,0,4,0,8,0,0,0,6,0,0,0,2,0,0,0,30,0,4,0,9,0,0,0,7,0,0,0,8,0,0,0,32,0,4,0,10,0,0,0,3,0,0,0,9,0,0,0,59,0,4,0,10,0,0,0,11,0,0,0,3,0,0, + 0,21,0,4,0,12,0,0,0,32,0,0,0,1,0,0,0,43,0,4,0,12,0,0,0,13,0,0,0,0,0,0,0,32,0,4,0,14,0,0,0,1,0,0,0,7,0,0,0,59,0,4,0,14,0,0,0,15,0,0,0,1,0,0,0,32,0,4,0,17,0,0,0,3,0,0,0,7,0,0,0,43,0, + 4,0,12,0,0,0,19,0,0,0,1,0,0,0,32,0,4,0,20,0,0,0,1,0,0,0,8,0,0,0,59,0,4,0,20,0,0,0,21,0,0,0,1,0,0,0,32,0,4,0,23,0,0,0,3,0,0,0,8,0,0,0,21,0,4,0,25,0,0,0,32,0,0,0,0,0,0,0,43,0,4,0,25, + 0,0,0,26,0,0,0,1,0,0,0,28,0,4,0,27,0,0,0,6,0,0,0,26,0,0,0,30,0,6,0,28,0,0,0,7,0,0,0,6,0,0,0,27,0,0,0,27,0,0,0,32,0,4,0,29,0,0,0,3,0,0,0,28,0,0,0,59,0,4,0,29,0,0,0,30,0,0,0,3,0,0,0, + 59,0,4,0,20,0,0,0,31,0,0,0,1,0,0,0,30,0,4,0,33,0,0,0,8,0,0,0,8,0,0,0,32,0,4,0,34,0,0,0,2,0,0,0,33,0,0,0,59,0,4,0,34,0,0,0,35,0,0,0,2,0,0,0,32,0,4,0,36,0,0,0,2,0,0,0,8,0,0,0,43,0,4, + 0,6,0,0,0,43,0,0,0,0,0,0,0,43,0,4,0,6,0,0,0,44,0,0,0,0,0,128,63,43,0,4,0,6,0,0,0,49,0,0,0,0,0,128,191,32,0,4,0,50,0,0,0,3,0,0,0,6,0,0,0,54,0,5,0,2,0,0,0,4,0,0,0,0,0,0,0,3,0,0,0,248, + 0,2,0,5,0,0,0,61,0,4,0,7,0,0,0,16,0,0,0,15,0,0,0,65,0,5,0,17,0,0,0,18,0,0,0,11,0,0,0,13,0,0,0,62,0,3,0,18,0,0,0,16,0,0,0,61,0,4,0,8,0,0,0,22,0,0,0,21,0,0,0,65,0,5,0,23,0,0,0,24,0,0, + 0,11,0,0,0,19,0,0,0,62,0,3,0,24,0,0,0,22,0,0,0,61,0,4,0,8,0,0,0,32,0,0,0,31,0,0,0,65,0,5,0,36,0,0,0,37,0,0,0,35,0,0,0,13,0,0,0,61,0,4,0,8,0,0,0,38,0,0,0,37,0,0,0,133,0,5,0,8,0,0,0, + 39,0,0,0,32,0,0,0,38,0,0,0,65,0,5,0,36,0,0,0,40,0,0,0,35,0,0,0,19,0,0,0,61,0,4,0,8,0,0,0,41,0,0,0,40,0,0,0,129,0,5,0,8,0,0,0,42,0,0,0,39,0,0,0,41,0,0,0,81,0,5,0,6,0,0,0,45,0,0,0,42, + 0,0,0,0,0,0,0,81,0,5,0,6,0,0,0,46,0,0,0,42,0,0,0,1,0,0,0,80,0,7,0,7,0,0,0,47,0,0,0,45,0,0,0,46,0,0,0,43,0,0,0,44,0,0,0,65,0,5,0,17,0,0,0,48,0,0,0,30,0,0,0,13,0,0,0,62,0,3,0,48,0,0, + 0,47,0,0,0,65,0,6,0,50,0,0,0,51,0,0,0,30,0,0,0,13,0,0,0,26,0,0,0,61,0,4,0,6,0,0,0,52,0,0,0,51,0,0,0,133,0,5,0,6,0,0,0,53,0,0,0,52,0,0,0,49,0,0,0,65,0,6,0,50,0,0,0,54,0,0,0,30,0,0,0, + 13,0,0,0,26,0,0,0,62,0,3,0,54,0,0,0,53,0,0,0,253,0,1,0,56,0,1,0, +}; +const uint8_t spirv_fragment[844] = { + 3,2,35,7,0,0,1,0,11,0,13,0,30,0,0,0,0,0,0,0,17,0,2,0,1,0,0,0,11,0,6,0,1,0,0,0,71,76,83,76,46,115,116,100,46,52,53,48,0,0,0,0,14,0,3,0,0,0,0,0,1,0,0,0,15,0,7,0,4,0,0,0,4,0,0,0,109,97, + 105,110,0,0,0,0,9,0,0,0,13,0,0,0,16,0,3,0,4,0,0,0,7,0,0,0,3,0,3,0,2,0,0,0,194,1,0,0,4,0,10,0,71,76,95,71,79,79,71,76,69,95,99,112,112,95,115,116,121,108,101,95,108,105,110,101,95,100, + 105,114,101,99,116,105,118,101,0,0,4,0,8,0,71,76,95,71,79,79,71,76,69,95,105,110,99,108,117,100,101,95,100,105,114,101,99,116,105,118,101,0,5,0,4,0,4,0,0,0,109,97,105,110,0,0,0,0,5, + 0,4,0,9,0,0,0,102,67,111,108,111,114,0,0,5,0,3,0,11,0,0,0,0,0,0,0,6,0,5,0,11,0,0,0,0,0,0,0,67,111,108,111,114,0,0,0,6,0,4,0,11,0,0,0,1,0,0,0,85,86,0,0,5,0,3,0,13,0,0,0,73,110,0,0,5, + 0,5,0,22,0,0,0,115,84,101,120,116,117,114,101,0,0,0,0,71,0,4,0,9,0,0,0,30,0,0,0,0,0,0,0,71,0,4,0,13,0,0,0,30,0,0,0,0,0,0,0,71,0,4,0,22,0,0,0,33,0,0,0,0,0,0,0,71,0,4,0,22,0,0,0,34,0, + 0,0,2,0,0,0,19,0,2,0,2,0,0,0,33,0,3,0,3,0,0,0,2,0,0,0,22,0,3,0,6,0,0,0,32,0,0,0,23,0,4,0,7,0,0,0,6,0,0,0,4,0,0,0,32,0,4,0,8,0,0,0,3,0,0,0,7,0,0,0,59,0,4,0,8,0,0,0,9,0,0,0,3,0,0,0,23, + 0,4,0,10,0,0,0,6,0,0,0,2,0,0,0,30,0,4,0,11,0,0,0,7,0,0,0,10,0,0,0,32,0,4,0,12,0,0,0,1,0,0,0,11,0,0,0,59,0,4,0,12,0,0,0,13,0,0,0,1,0,0,0,21,0,4,0,14,0,0,0,32,0,0,0,1,0,0,0,43,0,4,0, + 14,0,0,0,15,0,0,0,0,0,0,0,32,0,4,0,16,0,0,0,1,0,0,0,7,0,0,0,25,0,9,0,19,0,0,0,6,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,27,0,3,0,20,0,0,0,19,0,0,0,32,0,4,0,21,0,0,0,0, + 0,0,0,20,0,0,0,59,0,4,0,21,0,0,0,22,0,0,0,0,0,0,0,43,0,4,0,14,0,0,0,24,0,0,0,1,0,0,0,32,0,4,0,25,0,0,0,1,0,0,0,10,0,0,0,54,0,5,0,2,0,0,0,4,0,0,0,0,0,0,0,3,0,0,0,248,0,2,0,5,0,0,0,65, + 0,5,0,16,0,0,0,17,0,0,0,13,0,0,0,15,0,0,0,61,0,4,0,7,0,0,0,18,0,0,0,17,0,0,0,61,0,4,0,20,0,0,0,23,0,0,0,22,0,0,0,65,0,5,0,25,0,0,0,26,0,0,0,13,0,0,0,24,0,0,0,61,0,4,0,10,0,0,0,27,0, + 0,0,26,0,0,0,87,0,5,0,7,0,0,0,28,0,0,0,23,0,0,0,27,0,0,0,133,0,5,0,7,0,0,0,29,0,0,0,18,0,0,0,28,0,0,0,62,0,3,0,9,0,0,0,29,0,0,0,253,0,1,0,56,0,1,0, +}; + +const uint8_t dxbc_vertex[1064] = { + 68,88,66,67,32,50,127,204,241,196,165,104,216,114,216,116,220,164,29,45,1,0,0,0,40,4,0,0,5,0,0,0,52,0,0,0,136,1,0,0,236,1,0,0,92,2,0,0,140,3,0,0,82,68,69,70,76,1,0,0,1,0,0,0,116,0, + 0,0,1,0,0,0,60,0,0,0,1,5,254,255,0,5,0,0,34,1,0,0,19,19,68,37,60,0,0,0,24,0,0,0,40,0,0,0,40,0,0,0,36,0,0,0,12,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, + 0,1,0,0,0,1,0,0,0,0,0,0,0,117,80,117,115,104,67,111,110,115,116,97,110,116,0,171,171,100,0,0,0,2,0,0,0,140,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,8,0,0,0,2,0,0,0,240,0,0, + 0,0,0,0,0,255,255,255,255,0,0,0,0,255,255,255,255,0,0,0,0,20,1,0,0,8,0,0,0,8,0,0,0,2,0,0,0,240,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,255,255,255,255,0,0,0,0,112,99,95,117,83,99,97, + 108,101,0,102,108,111,97,116,50,0,171,171,171,1,0,3,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,112,99,95,117,84,114,97,110,115,108,97,116,101,0,77,105,99,114, + 111,115,111,102,116,32,40,82,41,32,72,76,83,76,32,83,104,97,100,101,114,32,67,111,109,112,105,108,101,114,32,49,48,46,49,0,171,171,73,83,71,78,92,0,0,0,3,0,0,0,8,0,0,0,80,0,0,0,0,0, + 0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,3,0,0,80,0,0,0,1,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,3,3,0,0,80,0,0,0,2,0,0,0,0,0,0,0,3,0,0,0,2,0,0,0,15,15,0,0,84,69,88,67,79,79,82,68,0,171,171,171,79,83, + 71,78,104,0,0,0,3,0,0,0,8,0,0,0,80,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,15,0,0,0,80,0,0,0,1,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,3,12,0,0,89,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,2,0,0,0,15,0,0, + 0,84,69,88,67,79,79,82,68,0,83,86,95,80,111,115,105,116,105,111,110,0,171,171,171,83,72,69,88,40,1,0,0,81,0,1,0,74,0,0,0,106,8,0,1,89,0,0,7,70,142,48,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, + 0,0,1,0,0,0,95,0,0,3,50,16,16,0,0,0,0,0,95,0,0,3,50,16,16,0,1,0,0,0,95,0,0,3,242,16,16,0,2,0,0,0,101,0,0,3,242,32,16,0,0,0,0,0,101,0,0,3,50,32,16,0,1,0,0,0,103,0,0,4,242,32,16,0,2, + 0,0,0,1,0,0,0,104,0,0,2,1,0,0,0,50,0,0,13,50,0,16,0,0,0,0,0,70,16,16,0,0,0,0,0,70,128,48,0,0,0,0,0,0,0,0,0,0,0,0,0,230,138,48,0,0,0,0,0,0,0,0,0,0,0,0,0,54,0,0,6,34,32,16,0,2,0,0,0, + 26,0,16,128,65,0,0,0,0,0,0,0,54,0,0,5,242,32,16,0,0,0,0,0,70,30,16,0,2,0,0,0,54,0,0,5,18,32,16,0,2,0,0,0,10,0,16,0,0,0,0,0,54,0,0,8,194,32,16,0,2,0,0,0,2,64,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,128,63,54,0,0,5,50,32,16,0,1,0,0,0,70,16,16,0,1,0,0,0,62,0,0,1,83,84,65,84,148,0,0,0,7,0,0,0,1,0,0,0,0,0,0,0,6,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; +const uint8_t dxbc_fragment[744] = { + 68,88,66,67,235,219,43,109,38,151,39,223,98,41,193,28,215,98,67,110,1,0,0,0,232,2,0,0,5,0,0,0,52,0,0,0,12,1,0,0,88,1,0,0,140,1,0,0,76,2,0,0,82,68,69,70,208,0,0,0,0,0,0,0,0,0,0,0,2, + 0,0,0,60,0,0,0,1,5,255,255,0,5,0,0,167,0,0,0,19,19,68,37,60,0,0,0,24,0,0,0,40,0,0,0,40,0,0,0,36,0,0,0,12,0,0,0,0,0,0,0,140,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, + 0,0,2,0,0,0,0,0,0,0,158,0,0,0,2,0,0,0,5,0,0,0,4,0,0,0,255,255,255,255,0,0,0,0,1,0,0,0,12,0,0,0,2,0,0,0,0,0,0,0,95,115,84,101,120,116,117,114,101,95,115,97,109,112,108,101,114,0,115, + 84,101,120,116,117,114,101,0,77,105,99,114,111,115,111,102,116,32,40,82,41,32,72,76,83,76,32,83,104,97,100,101,114,32,67,111,109,112,105,108,101,114,32,49,48,46,49,0,171,73,83,71,78, + 68,0,0,0,2,0,0,0,8,0,0,0,56,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,15,15,0,0,56,0,0,0,1,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,3,3,0,0,84,69,88,67,79,79,82,68,0,171,171,171,79,83,71,78,44,0, + 0,0,1,0,0,0,8,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,15,0,0,0,83,86,95,84,97,114,103,101,116,0,171,171,83,72,69,88,184,0,0,0,81,0,0,0,46,0,0,0,106,8,0,1,90,0,0,6,70,110,48, + 0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,88,24,0,7,70,126,48,0,0,0,0,0,0,0,0,0,0,0,0,0,85,85,0,0,2,0,0,0,98,16,0,3,242,16,16,0,0,0,0,0,98,16,0,3,50,16,16,0,1,0,0,0,101,0,0,3,242,32,16,0,0, + 0,0,0,104,0,0,2,1,0,0,0,69,0,0,11,242,0,16,0,0,0,0,0,70,16,16,0,1,0,0,0,70,126,32,0,0,0,0,0,0,0,0,0,0,96,32,0,0,0,0,0,0,0,0,0,56,0,0,7,242,32,16,0,0,0,0,0,70,14,16,0,0,0,0,0,70,30, + 16,0,0,0,0,0,62,0,0,1,83,84,65,84,148,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +#ifdef __APPLE__ +#include +#if TARGET_OS_MAC +const uint8_t metallib_vertex[3892] = { + 77,84,76,66,1,128,2,0,7,0,0,129,14,0,0,0,52,15,0,0,0,0,0,0,88,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,219,0,0,0,0,0,0,0,49,0,0,0,0,0,0,0,12,1,0,0,0,0,0,0,8,0,0,0,0,0,0,0,20,1,0,0,0,0,0,0,32, + 14,0,0,0,0,0,0,1,0,0,0,123,0,0,0,78,65,77,69,6,0,109,97,105,110,48,0,84,89,80,69,1,0,0,72,65,83,72,32,0,62,81,190,157,8,240,236,158,164,213,65,62,170,226,96,136,231,243,238,160,100, + 26,13,254,254,64,19,129,180,3,149,75,77,68,83,90,8,0,32,14,0,0,0,0,0,0,79,70,70,84,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,69,82,83,8,0,2,0,6,0,3,0,1,0,69,78,68,84, + 69,78,68,84,45,0,0,0,86,65,84,84,24,0,3,0,97,80,111,115,0,0,128,97,85,86,0,1,128,97,67,111,108,111,114,0,2,128,86,65,84,89,5,0,3,0,4,4,6,69,78,68,84,4,0,0,0,69,78,68,84,222,192,23, + 11,0,0,0,0,20,0,0,0,8,14,0,0,255,255,255,255,66,67,192,222,53,20,0,0,3,0,0,0,98,12,48,36,128,16,5,200,20,0,0,0,33,12,0,0,74,3,0,0,11,2,33,0,2,0,0,0,22,0,0,0,7,129,35,145,65,200,4,73, + 6,16,50,57,146,1,132,12,37,5,8,25,30,4,139,98,128,16,69,2,66,146,11,66,132,16,50,20,56,8,24,75,10,50,66,136,72,112,196,33,35,68,18,135,140,16,65,146,2,100,200,8,177,20,32,67,70,136, + 32,201,1,50,66,132,24,42,40,42,144,49,124,176,92,145,32,196,200,0,0,0,137,32,0,0,24,0,0,0,50,34,8,9,32,98,70,0,33,43,36,152,16,33,37,36,152,16,25,39,12,133,164,144,96,66,100,92,32, + 36,100,130,224,153,1,24,70,32,128,97,4,1,184,67,72,32,37,77,17,37,76,62,149,82,210,193,57,141,52,1,205,148,4,145,65,4,66,48,197,136,68,145,13,4,204,17,128,129,10,228,28,1,40,12,34, + 8,194,48,2,145,140,0,0,0,0,0,81,24,0,0,100,0,0,0,27,246,35,248,255,255,255,255,1,48,5,192,15,0,56,0,254,0,144,0,10,232,3,34,28,224,1,30,228,225,29,240,161,13,204,161,30,220,97,28,218, + 192,28,224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,128,48,7,121,8,135,118,40,135,54,128,135,119,72,7,119,160,135,114,144,7,32,28,216,129,29,0,162,29,210,193,29,218,128,29, + 202,225,28,194,129,29,218,192,30,202,97,28,232,225,29,228,161,13,238,33,29,200,129,30,208,1,136,3,57,192,3,96,112,135,119,104,3,113,168,135,116,96,7,122,72,7,119,152,7,128,112,135, + 119,104,131,116,112,7,115,152,135,54,48,7,120,104,131,118,8,7,122,64,7,128,30,228,161,30,202,1,32,220,225,29,218,192,29,194,193,29,230,161,13,204,1,30,218,160,29,194,129,30,208,1,160, + 7,121,168,135,114,0,8,119,120,135,54,152,135,116,56,7,119,40,7,114,104,3,125,40,7,121,120,135,121,104,3,115,128,135,54,104,135,112,160,7,116,0,232,65,30,234,161,28,0,194,29,222,161, + 13,232,65,30,194,1,30,224,33,29,220,225,28,218,160,29,194,129,30,208,1,160,7,121,168,135,114,0,136,121,160,135,112,24,135,117,104,3,120,144,135,119,160,135,114,24,7,122,120,7,121,104, + 3,113,168,7,115,48,135,114,144,135,54,152,135,116,208,135,114,0,240,0,32,234,193,29,230,33,28,204,161,28,218,192,28,224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,96,195,24,8, + 4,176,0,164,0,84,65,128,4,105,0,13,225,144,14,242,208,6,226,80,15,230,96,14,229,32,15,109,224,14,239,208,6,225,192,14,233,16,14,243,0,0,0,73,24,0,0,1,0,0,0,19,132,64,0,19,176,112,72, + 7,121,176,3,58,104,131,112,128,7,120,96,135,114,104,131,118,8,135,113,120,135,121,192,135,56,160,3,55,128,3,55,128,131,13,183,81,14,109,0,15,122,96,7,116,160,7,118,64,7,122,96,7,116, + 208,6,233,16,7,122,128,7,122,128,7,109,144,14,120,160,7,120,160,7,120,208,6,233,16,7,118,160,7,113,96,7,122,16,7,118,208,6,233,48,7,114,160,7,115,32,7,122,48,7,114,208,6,233,96,7,116, + 160,7,118,64,7,122,96,7,116,208,6,230,48,7,114,160,7,115,32,7,122,48,7,114,208,6,230,96,7,116,160,7,118,64,7,122,96,7,116,208,6,246,16,7,118,160,7,113,96,7,122,16,7,118,208,6,246,32, + 7,116,160,7,115,32,7,122,48,7,114,208,6,246,48,7,114,160,7,115,32,7,122,48,7,114,208,6,246,64,7,120,160,7,118,64,7,122,96,7,116,208,6,246,96,7,116,160,7,118,64,7,122,96,7,116,208,6, + 246,144,7,118,160,7,113,32,7,120,160,7,113,32,7,120,208,6,246,16,7,114,128,7,122,16,7,114,128,7,122,16,7,114,128,7,109,96,15,113,144,7,114,160,7,114,80,7,118,160,7,114,80,7,118,208, + 6,246,32,7,117,96,7,122,32,7,117,96,7,122,32,7,117,96,7,109,96,15,117,16,7,114,160,7,117,16,7,114,160,7,117,16,7,114,208,6,246,16,7,112,32,7,116,160,7,113,0,7,114,64,7,122,16,7,112, + 32,7,116,208,6,238,128,7,122,16,7,118,160,7,115,32,7,26,33,12,89,48,0,210,208,67,42,160,48,0,0,8,0,0,0,4,0,0,0,0,0,10,64,98,131,64,81,166,1,0,128,44,16,0,11,0,0,0,50,30,152,16,25,17, + 76,144,140,9,38,71,198,4,67,202,34,40,129,66,40,135,242,41,64,129,130,40,144,98,24,1,40,3,218,17,0,210,177,132,39,0,0,0,177,24,0,0,165,0,0,0,51,8,128,28,196,225,28,102,20,1,61,136, + 67,56,132,195,140,66,128,7,121,120,7,115,152,113,12,230,0,15,237,16,14,244,128,14,51,12,66,30,194,193,29,206,161,28,102,48,5,61,136,67,56,132,131,27,204,3,61,200,67,61,140,3,61,204, + 120,140,116,112,7,123,8,7,121,72,135,112,112,7,122,112,3,118,120,135,112,32,135,25,204,17,14,236,144,14,225,48,15,110,48,15,227,240,14,240,80,14,51,16,196,29,222,33,28,216,33,29,194, + 97,30,102,48,137,59,188,131,59,208,67,57,180,3,60,188,131,60,132,3,59,204,240,20,118,96,7,123,104,7,55,104,135,114,104,7,55,128,135,112,144,135,112,96,7,118,40,7,118,248,5,118,120, + 135,119,128,135,95,8,135,113,24,135,114,152,135,121,152,129,44,238,240,14,238,224,14,245,192,14,236,48,3,98,200,161,28,228,161,28,204,161,28,228,161,28,220,97,28,202,33,28,196,129, + 29,202,97,6,214,144,67,57,200,67,57,152,67,57,200,67,57,184,195,56,148,67,56,136,3,59,148,195,47,188,131,60,252,130,59,212,3,59,176,195,12,199,105,135,112,88,135,114,112,131,116,104, + 7,120,96,135,116,24,135,116,160,135,25,206,83,15,238,0,15,242,80,14,228,144,14,227,64,15,225,32,14,236,80,14,51,32,40,29,220,193,30,194,65,30,210,33,28,220,129,30,220,224,28,228,225, + 29,234,1,30,102,24,81,56,176,67,58,156,131,59,204,80,36,118,96,7,123,104,7,55,96,135,119,120,7,120,152,81,76,244,144,15,240,80,14,51,30,106,30,202,97,28,232,33,29,222,193,29,126,1, + 30,228,161,28,204,33,29,240,97,6,84,133,131,56,204,195,59,176,67,61,208,67,57,252,194,60,228,67,59,136,195,59,176,195,140,197,10,135,121,152,135,119,24,135,116,8,7,122,40,7,114,152, + 129,92,227,16,14,236,192,14,229,80,14,243,48,35,193,210,65,30,228,225,23,216,225,29,222,1,30,102,72,25,59,176,131,61,180,131,27,132,195,56,140,67,57,204,195,60,184,193,57,200,195,59, + 212,3,60,204,72,180,113,8,7,118,96,7,113,8,135,113,88,135,25,219,198,14,236,96,15,237,224,6,240,32,15,229,48,15,229,32,15,246,80,14,110,16,14,227,48,14,229,48,15,243,224,6,233,224, + 14,228,80,14,248,48,35,226,236,97,28,194,129,29,216,225,23,236,33,29,230,33,29,196,33,29,216,33,29,232,33,31,102,32,157,59,188,67,61,184,3,57,148,131,57,204,88,188,112,112,7,119,120, + 7,122,8,7,122,72,135,119,112,135,25,206,135,14,229,16,14,240,16,14,236,192,14,239,48,14,243,144,14,244,80,14,51,40,48,8,135,116,144,7,55,48,135,122,112,135,113,160,135,116,120,7,119, + 248,133,115,144,135,119,168,7,120,152,7,0,0,0,0,121,32,0,0,26,1,0,0,114,30,72,32,67,136,12,25,9,114,50,72,32,35,129,140,145,145,209,68,160,16,40,100,60,49,50,66,142,144,33,163,152, + 6,100,208,82,0,0,0,139,210,88,216,6,109,80,28,20,27,71,6,209,18,25,76,178,24,6,179,64,18,49,24,202,131,68,148,161,68,87,35,0,0,0,0,83,68,75,32,86,101,114,115,105,111,110,119,99,104, + 97,114,95,115,105,122,101,102,114,97,109,101,45,112,111,105,110,116,101,114,97,105,114,46,109,97,120,95,100,101,118,105,99,101,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120, + 95,99,111,110,115,116,97,110,116,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,116,104,114,101,97,100,103,114,111,117,112,95,98,117,102,102,101,114,115,97,105,114,46,109, + 97,120,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,114,101,97,100,95,119,114,105,116,101,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,115,97,109, + 112,108,101,114,115,65,112,112,108,101,32,109,101,116,97,108,32,118,101,114,115,105,111,110,32,51,50,48,50,51,46,51,54,56,32,40,109,101,116,97,108,102,101,45,51,50,48,50,51,46,51,54, + 56,41,77,101,116,97,108,97,105,114,46,99,111,109,112,105,108,101,46,100,101,110,111,114,109,115,95,100,105,115,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,97,115, + 116,95,109,97,116,104,95,101,110,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,114,97,109,101,98,117,102,102,101,114,95,102,101,116,99,104,95,101,110,97,98,108,101, + 97,105,114,46,118,101,114,116,101,120,95,111,117,116,112,117,116,117,115,101,114,40,108,111,99,110,48,41,97,105,114,46,97,114,103,95,116,121,112,101,95,110,97,109,101,102,108,111,97, + 116,52,97,105,114,46,97,114,103,95,110,97,109,101,79,117,116,95,67,111,108,111,114,117,115,101,114,40,108,111,99,110,49,41,102,108,111,97,116,50,79,117,116,95,85,86,97,105,114,46,112, + 111,115,105,116,105,111,110,103,108,95,80,111,115,105,116,105,111,110,97,105,114,46,118,101,114,116,101,120,95,105,110,112,117,116,97,105,114,46,108,111,99,97,116,105,111,110,95,105, + 110,100,101,120,97,80,111,115,97,85,86,97,67,111,108,111,114,97,105,114,46,98,117,102,102,101,114,97,105,114,46,98,117,102,102,101,114,95,115,105,122,101,97,105,114,46,114,101,97,100, + 97,105,114,46,97,100,100,114,101,115,115,95,115,112,97,99,101,97,105,114,46,115,116,114,117,99,116,95,116,121,112,101,95,105,110,102,111,117,83,99,97,108,101,117,84,114,97,110,115, + 108,97,116,101,97,105,114,46,97,114,103,95,116,121,112,101,95,115,105,122,101,97,105,114,46,97,114,103,95,116,121,112,101,95,97,108,105,103,110,95,115,105,122,101,117,80,117,115,104, + 67,111,110,115,116,97,110,116,112,99,0,0,0,166,119,0,0,0,0,0,0,48,130,144,4,35,8,74,51,130,144,8,35,8,201,48,130,144,16,35,8,73,49,130,144,24,35,8,201,49,130,144,32,35,8,73,50,130, + 144,40,35,8,201,50,130,112,0,51,12,106,16,172,193,12,3,27,8,109,48,195,224,6,131,26,204,48,184,1,241,6,51,12,110,80,188,193,12,131,27,24,111,48,195,224,6,7,28,204,48,184,1,18,7,51, + 12,110,144,200,193,12,129,50,195,160,6,115,64,7,51,16,75,29,176,1,29,204,16,48,51,4,205,12,129,51,131,241,64,145,52,81,51,24,79,21,89,211,53,67,129,69,210,148,205,48,152,194,41,160, + 194,12,9,29,104,27,29,176,65,100,77,220,12,9,27,104,27,27,176,65,100,77,221,12,137,26,104,155,26,176,65,36,77,222,12,10,29,196,1,29,88,100,16,7,113,64,7,86,25,204,64,213,193,7,6,114, + 176,209,1,27,132,129,24,168,193,24,180,130,25,200,193,25,196,65,132,6,83,26,204,64,168,194,42,176,130,43,204,48,216,65,42,188,194,157,1,192,113,28,199,113,28,199,113,28,199,185,129, + 27,184,129,27,184,129,27,184,129,27,184,129,69,7,122,96,89,22,29,208,129,27,208,1,46,224,2,46,240,3,122,128,130,140,4,38,40,35,54,54,187,54,151,182,55,178,58,182,50,23,51,182,176,179, + 185,81,18,59,184,3,60,200,3,61,216,3,62,232,3,63,72,133,141,205,174,205,37,141,172,204,141,110,148,224,15,114,9,75,147,115,177,43,147,155,75,123,115,27,37,0,133,164,194,210,228,92, + 216,194,220,206,234,194,206,202,190,236,202,228,230,210,222,220,70,9,66,33,167,176,52,57,151,177,183,54,184,52,182,178,175,55,56,186,180,55,183,185,81,6,81,24,5,82,72,37,44,77,206, + 197,174,76,142,174,12,111,148,224,21,0,0,0,169,24,0,0,37,0,0,0,11,10,114,40,135,119,128,7,122,88,112,152,67,61,184,195,56,176,67,57,208,195,130,230,28,198,161,13,232,65,30,194,193, + 29,230,33,29,232,33,29,222,193,29,22,52,227,96,14,231,80,15,225,32,15,228,64,15,225,32,15,231,80,14,244,176,128,129,7,121,40,135,112,96,7,118,120,135,113,8,7,122,40,7,114,88,112,156, + 195,56,180,1,59,164,131,61,148,195,2,107,28,216,33,28,220,225,28,220,32,28,228,97,28,220,32,28,232,129,30,194,97,28,208,161,28,200,97,28,194,129,29,216,97,193,1,15,244,32,15,225,80, + 15,244,128,14,0,0,0,0,209,16,0,0,6,0,0,0,7,204,60,164,131,59,156,3,59,148,3,61,160,131,60,148,67,56,144,195,1,0,0,0,97,32,0,0,68,0,0,0,19,4,65,44,16,0,0,0,11,0,0,0,148,51,0,180,37, + 64,61,7,161,72,146,52,7,161,72,9,65,48,26,48,2,48,70,0,130,32,136,127,20,115,16,150,117,97,36,163,1,52,51,0,0,0,0,0,241,48,0,0,32,0,0,0,34,71,200,144,81,18,196,43,0,0,0,0,207,115,89, + 0,111,109,110,105,112,111,116,101,110,116,32,99,104,97,114,83,105,109,112,108,101,32,67,43,43,32,84,66,65,65,97,105,114,45,97,108,105,97,115,45,115,99,111,112,101,115,40,109,97,105, + 110,48,41,97,105,114,45,97,108,105,97,115,45,115,99,111,112,101,45,97,114,103,40,51,41,0,19,132,133,89,33,216,194,44,172,24,110,193,22,104,97,67,32,11,27,134,88,192,133,90,216,48,228, + 66,46,212,194,134,224,22,0,0,157,134,5,146,40,16,130,1,36,254,157,6,103,234,40,16,130,67,0,254,131,12,1,226,12,50,4,138,51,134,48,68,22,128,255,28,195,16,76,179,13,204,5,204,54,4,89, + 48,219,16,12,194,6,1,49,0,4,0,0,0,91,138,32,200,133,67,23,182,20,68,144,11,135,46,0,0,0,0,0,0,113,32,0,0,3,0,0,0,50,14,16,34,132,0,134,6,0,0,0,0,0,0,0,0,101,12,0,0,31,0,0,0,18,3,148, + 240,0,0,0,0,3,0,0,0,5,0,0,0,9,0,0,0,76,0,0,0,1,0,0,0,88,0,0,0,0,0,0,0,88,0,0,0,1,0,0,0,112,0,0,0,0,0,0,0,14,0,0,0,24,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,255,255,255,255,0,36,0,0,0,0,0,0,93,12,0,0,13,0,0,0,18,3,148,102,0,0,0,0,109,97,105,110,48,51,50,48,50,51,46,51,54,56,97,105,114,54, + 52,45,97,112,112,108,101,45,109,97,99,111,115,120,49,52,46,48,46,48,0,0,0,0,0,0,0,0,0,0, +}; +const uint8_t metallib_fragment[3787] = { + 77,84,76,66,1,128,2,0,7,0,0,129,14,0,0,0,203,14,0,0,0,0,0,0,88,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,219,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,227,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,235,0,0,0,0,0,0,0, + 224,13,0,0,0,0,0,0,1,0,0,0,123,0,0,0,78,65,77,69,6,0,109,97,105,110,48,0,84,89,80,69,1,0,1,72,65,83,72,32,0,201,103,233,140,10,95,185,107,79,93,85,82,78,218,248,8,95,184,8,139,191, + 155,174,56,51,95,203,135,255,117,44,62,77,68,83,90,8,0,224,13,0,0,0,0,0,0,79,70,70,84,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,69,82,83,8,0,2,0,6,0,3,0,1,0,69,78,68, + 84,69,78,68,84,4,0,0,0,69,78,68,84,4,0,0,0,69,78,68,84,222,192,23,11,0,0,0,0,20,0,0,0,196,13,0,0,255,255,255,255,66,67,192,222,53,20,0,0,3,0,0,0,98,12,48,36,128,16,5,200,20,0,0,0,33, + 12,0,0,44,3,0,0,11,2,33,0,2,0,0,0,22,0,0,0,7,129,35,145,65,200,4,73,6,16,50,57,146,1,132,12,37,5,8,25,30,4,139,98,128,20,69,2,66,146,11,66,164,16,50,20,56,8,24,75,10,50,82,136,72,112, + 196,33,35,68,18,135,140,16,65,146,2,100,200,8,177,20,32,67,70,136,32,201,1,50,82,132,24,42,40,42,144,49,124,176,92,145,32,197,200,0,0,0,137,32,0,0,31,0,0,0,50,34,72,9,32,98,70,0,33, + 43,36,152,20,33,37,36,152,20,25,39,12,133,164,144,96,82,100,92,32,36,101,130,128,154,1,24,70,32,128,27,132,97,4,1,64,74,154,34,74,152,252,127,34,174,137,138,136,223,30,254,105,140, + 0,24,68,32,2,140,164,41,162,132,201,255,37,128,121,22,34,250,167,49,2,96,16,193,16,76,33,194,40,135,208,28,1,114,132,160,230,8,130,57,2,48,24,70,16,26,163,172,114,6,115,12,128,70,111, + 32,64,5,218,8,0,0,81,24,0,0,105,0,0,0,27,246,35,248,255,255,255,255,1,104,3,96,13,0,83,0,252,0,144,128,10,232,3,34,28,224,1,30,228,225,29,240,161,13,204,161,30,220,97,28,218,192,28, + 224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,128,48,7,121,8,135,118,40,135,54,128,135,119,72,7,119,160,135,114,144,7,32,28,216,129,29,0,162,29,210,193,29,218,128,29,202,225, + 28,194,129,29,218,192,30,202,97,28,232,225,29,228,161,13,238,33,29,200,129,30,208,1,136,3,57,192,3,96,112,135,119,104,3,113,168,135,116,96,7,122,72,7,119,152,7,128,112,135,119,104, + 131,116,112,7,115,152,135,54,48,7,120,104,131,118,8,7,122,64,7,128,30,228,161,30,202,1,32,220,225,29,218,192,29,194,193,29,230,161,13,204,1,30,218,160,29,194,129,30,208,1,160,7,121, + 168,135,114,0,8,119,120,135,54,152,135,116,56,7,119,40,7,114,104,3,125,40,7,121,120,135,121,104,3,115,128,135,54,104,135,112,160,7,116,0,232,65,30,234,161,28,0,194,29,222,161,13,232, + 65,30,194,1,30,224,33,29,220,225,28,218,160,29,194,129,30,208,1,160,7,121,168,135,114,0,136,121,160,135,112,24,135,117,104,3,120,144,135,119,160,135,114,24,7,122,120,7,121,104,3,113, + 168,7,115,48,135,114,144,135,54,152,135,116,208,135,114,0,240,0,32,234,193,29,230,33,28,204,161,28,218,192,28,224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,96,131,33,12,192, + 2,84,27,140,129,0,22,160,218,0,17,255,255,255,255,63,0,109,0,172,1,96,10,128,31,0,18,80,1,125,176,193,40,2,96,1,170,13,134,33,0,11,80,109,96,142,255,255,255,255,31,128,54,0,214,0,144, + 128,10,232,3,0,73,24,0,0,4,0,0,0,19,134,64,24,38,12,68,97,76,24,142,194,0,0,0,0,19,176,112,72,7,121,176,3,58,104,131,112,128,7,120,96,135,114,104,131,118,8,135,113,120,135,121,192, + 135,56,160,3,55,128,3,55,128,131,13,183,81,14,109,0,15,122,96,7,116,160,7,118,64,7,122,96,7,116,208,6,233,16,7,122,128,7,122,128,7,109,144,14,120,160,7,120,160,7,120,208,6,233,16,7, + 118,160,7,113,96,7,122,16,7,118,208,6,233,48,7,114,160,7,115,32,7,122,48,7,114,208,6,233,96,7,116,160,7,118,64,7,122,96,7,116,208,6,230,48,7,114,160,7,115,32,7,122,48,7,114,208,6,230, + 96,7,116,160,7,118,64,7,122,96,7,116,208,6,246,16,7,118,160,7,113,96,7,122,16,7,118,208,6,246,32,7,116,160,7,115,32,7,122,48,7,114,208,6,246,48,7,114,160,7,115,32,7,122,48,7,114,208, + 6,246,64,7,120,160,7,118,64,7,122,96,7,116,208,6,246,96,7,116,160,7,118,64,7,122,96,7,116,208,6,246,144,7,118,160,7,113,32,7,120,160,7,113,32,7,120,208,6,246,16,7,114,128,7,122,16, + 7,114,128,7,122,16,7,114,128,7,109,96,15,113,144,7,114,160,7,114,80,7,118,160,7,114,80,7,118,208,6,246,32,7,117,96,7,122,32,7,117,96,7,122,32,7,117,96,7,109,96,15,117,16,7,114,160, + 7,117,16,7,114,160,7,117,16,7,114,208,6,246,16,7,112,32,7,116,160,7,113,0,7,114,64,7,122,16,7,112,32,7,116,208,6,238,128,7,122,16,7,118,160,7,115,32,7,26,33,12,89,48,0,210,208,67,42, + 160,64,0,0,8,0,0,0,4,0,0,0,0,0,10,96,72,85,108,15,16,0,2,0,0,128,0,0,0,0,0,64,1,72,108,16,40,234,50,0,0,144,5,2,0,0,0,10,0,0,0,50,30,152,16,25,17,76,144,140,9,38,71,198,4,67,106,69, + 80,2,133,80,14,229,83,128,2,5,81,32,197,48,2,80,6,36,199,18,158,0,0,177,24,0,0,165,0,0,0,51,8,128,28,196,225,28,102,20,1,61,136,67,56,132,195,140,66,128,7,121,120,7,115,152,113,12, + 230,0,15,237,16,14,244,128,14,51,12,66,30,194,193,29,206,161,28,102,48,5,61,136,67,56,132,131,27,204,3,61,200,67,61,140,3,61,204,120,140,116,112,7,123,8,7,121,72,135,112,112,7,122, + 112,3,118,120,135,112,32,135,25,204,17,14,236,144,14,225,48,15,110,48,15,227,240,14,240,80,14,51,16,196,29,222,33,28,216,33,29,194,97,30,102,48,137,59,188,131,59,208,67,57,180,3,60, + 188,131,60,132,3,59,204,240,20,118,96,7,123,104,7,55,104,135,114,104,7,55,128,135,112,144,135,112,96,7,118,40,7,118,248,5,118,120,135,119,128,135,95,8,135,113,24,135,114,152,135,121, + 152,129,44,238,240,14,238,224,14,245,192,14,236,48,3,98,200,161,28,228,161,28,204,161,28,228,161,28,220,97,28,202,33,28,196,129,29,202,97,6,214,144,67,57,200,67,57,152,67,57,200,67, + 57,184,195,56,148,67,56,136,3,59,148,195,47,188,131,60,252,130,59,212,3,59,176,195,12,199,105,135,112,88,135,114,112,131,116,104,7,120,96,135,116,24,135,116,160,135,25,206,83,15,238, + 0,15,242,80,14,228,144,14,227,64,15,225,32,14,236,80,14,51,32,40,29,220,193,30,194,65,30,210,33,28,220,129,30,220,224,28,228,225,29,234,1,30,102,24,81,56,176,67,58,156,131,59,204,80, + 36,118,96,7,123,104,7,55,96,135,119,120,7,120,152,81,76,244,144,15,240,80,14,51,30,106,30,202,97,28,232,33,29,222,193,29,126,1,30,228,161,28,204,33,29,240,97,6,84,133,131,56,204,195, + 59,176,67,61,208,67,57,252,194,60,228,67,59,136,195,59,176,195,140,197,10,135,121,152,135,119,24,135,116,8,7,122,40,7,114,152,129,92,227,16,14,236,192,14,229,80,14,243,48,35,193,210, + 65,30,228,225,23,216,225,29,222,1,30,102,72,25,59,176,131,61,180,131,27,132,195,56,140,67,57,204,195,60,184,193,57,200,195,59,212,3,60,204,72,180,113,8,7,118,96,7,113,8,135,113,88, + 135,25,219,198,14,236,96,15,237,224,6,240,32,15,229,48,15,229,32,15,246,80,14,110,16,14,227,48,14,229,48,15,243,224,6,233,224,14,228,80,14,248,48,35,226,236,97,28,194,129,29,216,225, + 23,236,33,29,230,33,29,196,33,29,216,33,29,232,33,31,102,32,157,59,188,67,61,184,3,57,148,131,57,204,88,188,112,112,7,119,120,7,122,8,7,122,72,135,119,112,135,25,206,135,14,229,16, + 14,240,16,14,236,192,14,239,48,14,243,144,14,244,80,14,51,40,48,8,135,116,144,7,55,48,135,122,112,135,113,160,135,116,120,7,119,248,133,115,144,135,119,168,7,120,152,7,0,0,0,0,121, + 32,0,0,252,0,0,0,114,30,72,32,67,136,12,25,9,114,50,72,32,35,129,140,145,145,209,68,160,16,40,100,60,49,50,66,142,144,33,163,56,6,220,41,1,0,0,0,139,210,88,216,6,109,80,28,20,27,71, + 6,81,100,48,134,180,40,15,178,24,197,34,41,24,178,28,13,83,68,75,32,86,101,114,115,105,111,110,119,99,104,97,114,95,115,105,122,101,102,114,97,109,101,45,112,111,105,110,116,101,114, + 97,105,114,46,109,97,120,95,100,101,118,105,99,101,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,99,111,110,115,116,97,110,116,95,98,117,102,102,101,114,115,97,105,114, + 46,109,97,120,95,116,104,114,101,97,100,103,114,111,117,112,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,114, + 101,97,100,95,119,114,105,116,101,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,115,97,109,112,108,101,114,115,65,112,112,108,101,32,109,101,116,97,108,32,118,101, + 114,115,105,111,110,32,51,50,48,50,51,46,51,54,56,32,40,109,101,116,97,108,102,101,45,51,50,48,50,51,46,51,54,56,41,77,101,116,97,108,97,105,114,46,99,111,109,112,105,108,101,46,100, + 101,110,111,114,109,115,95,100,105,115,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,97,115,116,95,109,97,116,104,95,101,110,97,98,108,101,97,105,114,46,99,111,109, + 112,105,108,101,46,102,114,97,109,101,98,117,102,102,101,114,95,102,101,116,99,104,95,101,110,97,98,108,101,97,105,114,46,114,101,110,100,101,114,95,116,97,114,103,101,116,97,105,114, + 46,97,114,103,95,116,121,112,101,95,110,97,109,101,102,108,111,97,116,52,97,105,114,46,97,114,103,95,110,97,109,101,102,67,111,108,111,114,97,105,114,46,102,114,97,103,109,101,110, + 116,95,105,110,112,117,116,117,115,101,114,40,108,111,99,110,48,41,97,105,114,46,99,101,110,116,101,114,97,105,114,46,112,101,114,115,112,101,99,116,105,118,101,73,110,95,67,111,108, + 111,114,117,115,101,114,40,108,111,99,110,49,41,102,108,111,97,116,50,73,110,95,85,86,97,105,114,46,116,101,120,116,117,114,101,97,105,114,46,108,111,99,97,116,105,111,110,95,105,110, + 100,101,120,97,105,114,46,115,97,109,112,108,101,116,101,120,116,117,114,101,50,100,60,102,108,111,97,116,44,32,115,97,109,112,108,101,62,115,84,101,120,116,117,114,101,97,105,114, + 46,115,97,109,112,108,101,114,115,97,109,112,108,101,114,115,84,101,120,116,117,114,101,83,109,112,108,114,0,198,96,0,0,0,0,0,0,48,130,208,8,35,8,82,51,130,208,12,35,8,13,49,130,208, + 20,35,8,141,49,130,208,28,35,8,13,50,130,208,36,35,8,141,50,130,208,44,35,8,13,51,130,144,0,51,12,100,16,148,193,12,131,25,8,103,48,195,128,6,3,25,204,48,160,1,145,6,51,12,104,80,164, + 193,12,3,26,24,105,48,195,128,6,135,26,204,48,160,1,178,6,51,12,104,144,176,193,12,129,50,195,64,6,109,224,6,51,16,203,27,152,129,27,204,16,48,51,4,205,12,129,51,195,241,184,129,27, + 64,145,52,205,16,128,194,12,137,27,80,149,117,65,145,132,205,144,152,1,149,89,23,164,73,219,12,10,25,112,157,27,152,129,7,125,18,24,204,144,188,65,24,116,110,96,6,144,24,72,99,48,3, + 33,10,163,64,10,165,48,195,0,7,161,96,10,71,6,0,199,113,28,199,113,28,199,113,28,231,6,110,224,6,110,224,6,110,224,6,110,224,6,22,29,232,129,101,89,166,192,177,2,43,144,131,58,128, + 130,140,4,38,40,35,54,54,187,54,151,182,55,178,58,182,50,23,51,182,176,179,185,81,18,56,136,3,57,152,3,58,168,3,59,184,3,60,72,133,141,205,174,205,37,141,172,204,141,110,148,32,15, + 114,9,75,147,115,177,43,147,155,75,123,115,27,37,208,131,164,194,210,228,92,216,194,220,206,234,194,206,202,190,236,202,228,230,210,222,220,70,9,246,32,167,176,52,57,151,177,183,54, + 184,52,182,178,175,55,56,186,180,55,183,185,81,6,62,232,3,63,72,38,44,77,206,197,76,46,236,172,173,204,141,110,148,192,20,0,0,0,0,169,24,0,0,37,0,0,0,11,10,114,40,135,119,128,7,122, + 88,112,152,67,61,184,195,56,176,67,57,208,195,130,230,28,198,161,13,232,65,30,194,193,29,230,33,29,232,33,29,222,193,29,22,52,227,96,14,231,80,15,225,32,15,228,64,15,225,32,15,231, + 80,14,244,176,128,129,7,121,40,135,112,96,7,118,120,135,113,8,7,122,40,7,114,88,112,156,195,56,180,1,59,164,131,61,148,195,2,107,28,216,33,28,220,225,28,220,32,28,228,97,28,220,32, + 28,232,129,30,194,97,28,208,161,28,200,97,28,194,129,29,216,97,193,1,15,244,32,15,225,80,15,244,128,14,0,0,0,0,209,16,0,0,6,0,0,0,7,204,60,164,131,59,156,3,59,148,3,61,160,131,60,148, + 67,56,144,195,1,0,0,0,97,32,0,0,49,0,0,0,19,4,65,44,16,0,0,0,4,0,0,0,196,106,96,4,128,220,8,0,129,17,0,18,51,0,0,0,241,48,0,0,28,0,0,0,34,71,200,144,81,14,196,42,0,0,0,0,23,134,1,0, + 97,105,114,45,97,108,105,97,115,45,115,99,111,112,101,115,40,109,97,105,110,48,41,97,105,114,45,97,108,105,97,115,45,115,99,111,112,101,45,115,97,109,112,108,101,114,115,97,105,114, + 45,97,108,105,97,115,45,115,99,111,112,101,45,116,101,120,116,117,114,101,115,0,43,132,85,64,133,21,3,43,172,66,42,172,24,90,97,21,84,97,131,208,10,172,0,0,35,6,205,16,130,96,240,88, + 135,129,20,3,33,8,204,104,66,0,96,176,136,255,108,3,17,0,27,4,196,0,0,0,2,0,0,0,91,6,224,104,5,0,0,0,0,0,0,0,113,32,0,0,3,0,0,0,50,14,16,34,132,0,251,5,0,0,0,0,0,0,0,0,101,12,0,0,37, + 0,0,0,18,3,148,40,1,0,0,0,3,0,0,0,32,0,0,0,9,0,0,0,76,0,0,0,1,0,0,0,88,0,0,0,0,0,0,0,88,0,0,0,2,0,0,0,136,0,0,0,0,0,0,0,41,0,0,0,24,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,136,0,0,0, + 0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,255,255,255,255,0,36,0,0,5,0,0,0,27,0,0,0,5,0,0,0,27,0,0,0,255,255,255,255,8,36,0,0,0,0,0,0,93,12,0,0,20,0,0,0,18,3, + 148,161,0,0,0,0,109,97,105,110,48,97,105,114,46,115,97,109,112,108,101,95,116,101,120,116,117,114,101,95,50,100,46,118,52,102,51,50,51,50,48,50,51,46,51,54,56,97,105,114,54,52,45,97, + 112,112,108,101,45,109,97,99,111,115,120,49,52,46,48,46,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; +#elif TARGET_OS_IPHONE +const uint8_t metallib_vertex[3876] = { + 77,84,76,66,1,0,2,0,7,0,0,130,18,0,1,0,36,15,0,0,0,0,0,0,88,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,219,0,0,0,0,0,0,0,49,0,0,0,0,0,0,0,12,1,0,0,0,0,0,0,8,0,0,0,0,0,0,0,20,1,0,0,0,0,0,0,16, + 14,0,0,0,0,0,0,1,0,0,0,123,0,0,0,78,65,77,69,6,0,109,97,105,110,48,0,84,89,80,69,1,0,0,72,65,83,72,32,0,240,54,230,217,232,66,102,78,35,5,77,235,101,252,229,192,148,96,126,162,111, + 77,253,247,211,52,17,198,182,137,68,244,77,68,83,90,8,0,16,14,0,0,0,0,0,0,79,70,70,84,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,69,82,83,8,0,2,0,7,0,3,0,2,0,69,78,68, + 84,69,78,68,84,45,0,0,0,86,65,84,84,24,0,3,0,97,80,111,115,0,0,128,97,85,86,0,1,128,97,67,111,108,111,114,0,2,128,86,65,84,89,5,0,3,0,4,4,6,69,78,68,84,4,0,0,0,69,78,68,84,222,192, + 23,11,0,0,0,0,20,0,0,0,252,13,0,0,255,255,255,255,66,67,192,222,53,20,0,0,3,0,0,0,98,12,48,36,128,16,5,200,20,0,0,0,33,12,0,0,72,3,0,0,11,2,33,0,2,0,0,0,22,0,0,0,7,129,35,145,65,200, + 4,73,6,16,50,57,146,1,132,12,37,5,8,25,30,4,139,98,128,16,69,2,66,146,11,66,132,16,50,20,56,8,24,75,10,50,66,136,72,112,196,33,35,68,18,135,140,16,65,146,2,100,200,8,177,20,32,67,70, + 136,32,201,1,50,66,132,24,42,40,42,144,49,124,176,92,145,32,196,200,0,0,0,137,32,0,0,24,0,0,0,50,34,8,9,32,98,70,0,33,43,36,152,16,33,37,36,152,16,25,39,12,133,164,144,96,66,100,92, + 32,36,100,130,224,153,1,24,70,32,128,97,4,1,184,67,72,32,37,77,17,37,76,62,149,82,210,193,57,141,52,1,205,148,4,145,65,4,66,48,197,136,68,145,13,4,204,17,128,129,10,228,28,1,40,12, + 34,8,194,48,2,145,140,0,0,0,0,0,81,24,0,0,100,0,0,0,27,246,35,248,255,255,255,255,1,48,5,192,15,0,56,0,254,0,144,0,10,232,3,34,28,224,1,30,228,225,29,240,161,13,204,161,30,220,97,28, + 218,192,28,224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,128,48,7,121,8,135,118,40,135,54,128,135,119,72,7,119,160,135,114,144,7,32,28,216,129,29,0,162,29,210,193,29,218,128, + 29,202,225,28,194,129,29,218,192,30,202,97,28,232,225,29,228,161,13,238,33,29,200,129,30,208,1,136,3,57,192,3,96,112,135,119,104,3,113,168,135,116,96,7,122,72,7,119,152,7,128,112,135, + 119,104,131,116,112,7,115,152,135,54,48,7,120,104,131,118,8,7,122,64,7,128,30,228,161,30,202,1,32,220,225,29,218,192,29,194,193,29,230,161,13,204,1,30,218,160,29,194,129,30,208,1,160, + 7,121,168,135,114,0,8,119,120,135,54,152,135,116,56,7,119,40,7,114,104,3,125,40,7,121,120,135,121,104,3,115,128,135,54,104,135,112,160,7,116,0,232,65,30,234,161,28,0,194,29,222,161, + 13,232,65,30,194,1,30,224,33,29,220,225,28,218,160,29,194,129,30,208,1,160,7,121,168,135,114,0,136,121,160,135,112,24,135,117,104,3,120,144,135,119,160,135,114,24,7,122,120,7,121,104, + 3,113,168,7,115,48,135,114,144,135,54,152,135,116,208,135,114,0,240,0,32,234,193,29,230,33,28,204,161,28,218,192,28,224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,96,195,24,8, + 4,176,0,164,0,84,65,128,4,105,0,13,225,144,14,242,208,6,226,80,15,230,96,14,229,32,15,109,224,14,239,208,6,225,192,14,233,16,14,243,0,0,0,73,24,0,0,1,0,0,0,19,132,64,0,19,170,112,72, + 7,121,176,3,58,104,131,112,128,7,120,96,135,114,104,131,116,120,135,121,136,3,60,112,131,56,112,3,56,216,112,27,229,208,6,240,160,7,118,64,7,122,96,7,116,160,7,118,64,7,109,144,14, + 113,160,7,120,160,7,120,208,6,233,128,7,122,128,7,122,128,7,109,144,14,113,96,7,122,16,7,118,160,7,113,96,7,109,144,14,115,32,7,122,48,7,114,160,7,115,32,7,109,144,14,118,64,7,122, + 96,7,116,160,7,118,64,7,109,96,14,115,32,7,122,48,7,114,160,7,115,32,7,109,96,14,118,64,7,122,96,7,116,160,7,118,64,7,109,96,15,113,96,7,122,16,7,118,160,7,113,96,7,109,96,15,114,64, + 7,122,48,7,114,160,7,115,32,7,109,96,15,115,32,7,122,48,7,114,160,7,115,32,7,109,96,15,116,128,7,122,96,7,116,160,7,118,64,7,109,96,15,118,64,7,122,96,7,116,160,7,118,64,7,109,96,15, + 121,96,7,122,16,7,114,128,7,122,16,7,114,128,7,109,96,15,113,32,7,120,160,7,113,32,7,120,160,7,113,32,7,120,208,6,246,16,7,121,32,7,122,32,7,117,96,7,122,32,7,117,96,7,109,96,15,114, + 80,7,118,160,7,114,80,7,118,160,7,114,80,7,118,208,6,246,80,7,113,32,7,122,80,7,113,32,7,122,80,7,113,32,7,109,96,15,113,0,7,114,64,7,122,16,7,112,32,7,116,160,7,113,0,7,114,64,7,109, + 224,14,120,160,7,113,96,7,122,48,7,114,160,17,194,144,5,3,32,13,61,164,2,10,3,0,128,0,0,0,64,0,0,0,0,0,160,0,36,54,8,20,85,26,0,0,200,2,1,0,11,0,0,0,50,30,152,16,25,17,76,144,140,9, + 38,71,198,4,67,202,34,40,129,66,40,135,242,41,64,129,130,40,144,17,128,50,160,29,1,32,29,75,144,2,0,0,0,0,177,24,0,0,165,0,0,0,51,8,128,28,196,225,28,102,20,1,61,136,67,56,132,195, + 140,66,128,7,121,120,7,115,152,113,12,230,0,15,237,16,14,244,128,14,51,12,66,30,194,193,29,206,161,28,102,48,5,61,136,67,56,132,131,27,204,3,61,200,67,61,140,3,61,204,120,140,116,112, + 7,123,8,7,121,72,135,112,112,7,122,112,3,118,120,135,112,32,135,25,204,17,14,236,144,14,225,48,15,110,48,15,227,240,14,240,80,14,51,16,196,29,222,33,28,216,33,29,194,97,30,102,48,137, + 59,188,131,59,208,67,57,180,3,60,188,131,60,132,3,59,204,240,20,118,96,7,123,104,7,55,104,135,114,104,7,55,128,135,112,144,135,112,96,7,118,40,7,118,248,5,118,120,135,119,128,135,95, + 8,135,113,24,135,114,152,135,121,152,129,44,238,240,14,238,224,14,245,192,14,236,48,3,98,200,161,28,228,161,28,204,161,28,228,161,28,220,97,28,202,33,28,196,129,29,202,97,6,214,144, + 67,57,200,67,57,152,67,57,200,67,57,184,195,56,148,67,56,136,3,59,148,195,47,188,131,60,252,130,59,212,3,59,176,195,12,199,105,135,112,88,135,114,112,131,116,104,7,120,96,135,116,24, + 135,116,160,135,25,206,83,15,238,0,15,242,80,14,228,144,14,227,64,15,225,32,14,236,80,14,51,32,40,29,220,193,30,194,65,30,210,33,28,220,129,30,220,224,28,228,225,29,234,1,30,102,24, + 81,56,176,67,58,156,131,59,204,80,36,118,96,7,123,104,7,55,96,135,119,120,7,120,152,81,76,244,144,15,240,80,14,51,30,106,30,202,97,28,232,33,29,222,193,29,126,1,30,228,161,28,204,33, + 29,240,97,6,84,133,131,56,204,195,59,176,67,61,208,67,57,252,194,60,228,67,59,136,195,59,176,195,140,197,10,135,121,152,135,119,24,135,116,8,7,122,40,7,114,152,129,92,227,16,14,236, + 192,14,229,80,14,243,48,35,193,210,65,30,228,225,23,216,225,29,222,1,30,102,72,25,59,176,131,61,180,131,27,132,195,56,140,67,57,204,195,60,184,193,57,200,195,59,212,3,60,204,72,180, + 113,8,7,118,96,7,113,8,135,113,88,135,25,219,198,14,236,96,15,237,224,6,240,32,15,229,48,15,229,32,15,246,80,14,110,16,14,227,48,14,229,48,15,243,224,6,233,224,14,228,80,14,248,48, + 35,226,236,97,28,194,129,29,216,225,23,236,33,29,230,33,29,196,33,29,216,33,29,232,33,31,102,32,157,59,188,67,61,184,3,57,148,131,57,204,88,188,112,112,7,119,120,7,122,8,7,122,72,135, + 119,112,135,25,206,135,14,229,16,14,240,16,14,236,192,14,239,48,14,243,144,14,244,80,14,51,40,48,8,135,116,144,7,55,48,135,122,112,135,113,160,135,116,120,7,119,248,133,115,144,135, + 119,168,7,120,152,7,0,0,0,0,121,32,0,0,25,1,0,0,114,30,72,32,67,136,12,25,9,114,50,72,32,35,129,140,145,145,209,68,160,16,40,100,60,49,50,66,142,144,33,163,152,6,100,208,82,0,0,0,139, + 210,88,216,6,109,80,28,20,27,71,6,209,18,25,76,178,24,6,179,64,18,49,24,202,131,68,148,161,68,87,35,0,0,0,0,83,68,75,32,86,101,114,115,105,111,110,119,99,104,97,114,95,115,105,122, + 101,102,114,97,109,101,45,112,111,105,110,116,101,114,97,105,114,46,109,97,120,95,100,101,118,105,99,101,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,99,111,110,115,116, + 97,110,116,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,116,104,114,101,97,100,103,114,111,117,112,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,116,101,120, + 116,117,114,101,115,97,105,114,46,109,97,120,95,114,101,97,100,95,119,114,105,116,101,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,115,97,109,112,108,101,114,115, + 65,112,112,108,101,32,109,101,116,97,108,32,118,101,114,115,105,111,110,32,51,50,48,50,51,46,51,54,56,32,40,109,101,116,97,108,102,101,45,51,50,48,50,51,46,51,54,56,41,77,101,116,97, + 108,97,105,114,46,99,111,109,112,105,108,101,46,100,101,110,111,114,109,115,95,100,105,115,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,97,115,116,95,109,97,116,104, + 95,101,110,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,114,97,109,101,98,117,102,102,101,114,95,102,101,116,99,104,95,101,110,97,98,108,101,97,105,114,46,118,101, + 114,116,101,120,95,111,117,116,112,117,116,117,115,101,114,40,108,111,99,110,48,41,97,105,114,46,97,114,103,95,116,121,112,101,95,110,97,109,101,102,108,111,97,116,52,97,105,114,46, + 97,114,103,95,110,97,109,101,79,117,116,95,67,111,108,111,114,117,115,101,114,40,108,111,99,110,49,41,102,108,111,97,116,50,79,117,116,95,85,86,97,105,114,46,112,111,115,105,116,105, + 111,110,103,108,95,80,111,115,105,116,105,111,110,97,105,114,46,118,101,114,116,101,120,95,105,110,112,117,116,97,105,114,46,108,111,99,97,116,105,111,110,95,105,110,100,101,120,97, + 80,111,115,97,85,86,97,67,111,108,111,114,97,105,114,46,98,117,102,102,101,114,97,105,114,46,98,117,102,102,101,114,95,115,105,122,101,97,105,114,46,114,101,97,100,97,105,114,46,97, + 100,100,114,101,115,115,95,115,112,97,99,101,97,105,114,46,115,116,114,117,99,116,95,116,121,112,101,95,105,110,102,111,117,83,99,97,108,101,117,84,114,97,110,115,108,97,116,101,97, + 105,114,46,97,114,103,95,116,121,112,101,95,115,105,122,101,97,105,114,46,97,114,103,95,116,121,112,101,95,97,108,105,103,110,95,115,105,122,101,117,80,117,115,104,67,111,110,115,116, + 97,110,116,112,99,0,0,0,230,117,0,0,0,0,0,0,48,130,144,4,35,8,10,51,130,144,8,35,8,201,48,130,144,16,35,8,73,49,130,144,24,35,8,201,49,130,144,32,35,8,73,50,130,144,40,35,8,7,48,195, + 160,6,193,26,204,48,176,129,208,6,51,12,110,48,168,193,12,131,27,16,111,48,195,224,6,197,27,204,48,184,129,241,6,51,12,110,112,192,193,12,131,27,32,113,48,195,224,6,137,28,204,16,40, + 51,12,106,224,6,115,48,3,177,208,129,26,204,193,12,1,51,67,208,204,16,56,51,24,15,20,73,19,53,131,241,84,145,53,93,51,20,88,36,77,217,12,67,41,152,194,41,204,144,204,129,182,205,1, + 27,68,214,196,205,144,176,129,182,177,1,27,68,214,212,205,144,168,129,182,169,1,27,68,210,228,205,160,204,65,28,204,129,69,6,113,16,7,115,96,149,193,12,20,29,124,96,32,7,219,28,176, + 65,24,136,129,26,140,1,43,152,129,28,156,65,28,68,104,48,165,193,12,68,42,168,194,42,180,194,12,67,29,160,130,43,156,25,0,28,199,113,28,199,113,28,199,113,110,224,6,110,224,6,110,224, + 6,110,224,6,110,96,209,129,30,88,150,69,7,116,224,6,116,128,11,184,128,11,252,128,30,160,32,35,129,9,202,136,141,205,174,205,165,237,141,172,142,173,204,197,140,45,236,108,110,148, + 164,14,236,224,14,240,32,15,244,96,15,248,160,15,82,97,99,179,107,115,73,35,43,115,163,27,37,240,131,92,194,210,228,92,236,202,228,230,210,222,220,70,9,254,32,169,176,52,57,23,182, + 48,183,179,186,176,179,178,47,187,50,185,185,180,55,183,81,2,80,200,41,44,77,206,101,236,173,13,46,141,173,236,235,13,142,46,237,205,109,110,148,33,20,68,97,20,82,9,75,147,115,177, + 43,147,163,43,195,27,37,112,5,0,0,0,169,24,0,0,37,0,0,0,11,10,114,40,135,119,128,7,122,88,112,152,67,61,184,195,56,176,67,57,208,195,130,230,28,198,161,13,232,65,30,194,193,29,230, + 33,29,232,33,29,222,193,29,22,52,227,96,14,231,80,15,225,32,15,228,64,15,225,32,15,231,80,14,244,176,128,129,7,121,40,135,112,96,7,118,120,135,113,8,7,122,40,7,114,88,112,156,195,56, + 180,1,59,164,131,61,148,195,2,107,28,216,33,28,220,225,28,220,32,28,228,97,28,220,32,28,232,129,30,194,97,28,208,161,28,200,97,28,194,129,29,216,97,193,1,15,244,32,15,225,80,15,244, + 128,14,0,0,0,0,209,16,0,0,6,0,0,0,7,204,60,164,131,59,156,3,59,148,3,61,160,131,60,148,67,56,144,195,1,0,0,0,97,32,0,0,68,0,0,0,19,4,65,44,16,0,0,0,11,0,0,0,148,51,0,197,64,91,2,212, + 115,16,73,20,69,115,16,73,36,17,4,163,1,35,0,99,4,32,8,130,248,71,49,7,97,89,23,70,50,26,64,51,3,0,0,0,241,48,0,0,32,0,0,0,34,71,200,144,81,18,196,43,0,0,0,0,207,115,89,0,111,109,110, + 105,112,111,116,101,110,116,32,99,104,97,114,83,105,109,112,108,101,32,67,43,43,32,84,66,65,65,97,105,114,45,97,108,105,97,115,45,115,99,111,112,101,115,40,109,97,105,110,48,41,97, + 105,114,45,97,108,105,97,115,45,115,99,111,112,101,45,97,114,103,40,51,41,0,19,132,101,89,33,212,130,44,172,24,108,161,22,102,97,67,16,11,27,6,88,184,5,90,216,48,224,2,46,208,194,134, + 192,22,0,0,157,6,38,154,40,16,130,65,36,254,157,134,135,234,40,16,130,67,0,254,131,12,1,226,12,50,4,138,51,134,48,68,22,128,255,28,195,16,76,179,13,12,6,204,54,4,90,48,219,16,12,194, + 6,1,49,0,4,0,0,0,91,138,32,192,133,35,23,182,20,68,128,11,71,46,0,0,0,0,0,0,113,32,0,0,3,0,0,0,50,14,16,34,132,0,132,6,0,0,0,0,0,0,0,0,101,12,0,0,31,0,0,0,18,3,148,240,0,0,0,0,3,0, + 0,0,5,0,0,0,9,0,0,0,76,0,0,0,1,0,0,0,88,0,0,0,0,0,0,0,88,0,0,0,1,0,0,0,112,0,0,0,0,0,0,0,14,0,0,0,21,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, + 0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,255,255,255,255,0,36,0,0,0,0,0,0,93,12,0,0,12,0,0,0,18,3,148,99,0,0,0,0,109,97,105,110,48,51,50,48,50,51,46,51,54,56,97,105,114,54,52,45,97,112,112, + 108,101,45,105,111,115,49,56,46,49,46,48,0,0,0,0,0, +}; +const uint8_t metallib_fragment[3771] = { + 77,84,76,66,1,0,2,0,7,0,0,130,18,0,1,0,187,14,0,0,0,0,0,0,88,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,219,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,227,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,235,0,0,0,0,0,0,0,208, + 13,0,0,0,0,0,0,1,0,0,0,123,0,0,0,78,65,77,69,6,0,109,97,105,110,48,0,84,89,80,69,1,0,1,72,65,83,72,32,0,167,26,51,31,140,153,203,226,66,149,243,47,185,58,96,202,28,176,71,121,86,159, + 244,234,235,69,155,58,121,67,241,212,77,68,83,90,8,0,208,13,0,0,0,0,0,0,79,70,70,84,24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,69,82,83,8,0,2,0,7,0,3,0,2,0,69,78,68,84, + 69,78,68,84,4,0,0,0,69,78,68,84,4,0,0,0,69,78,68,84,222,192,23,11,0,0,0,0,20,0,0,0,180,13,0,0,255,255,255,255,66,67,192,222,53,20,0,0,3,0,0,0,98,12,48,36,128,16,5,200,20,0,0,0,33,12, + 0,0,41,3,0,0,11,2,33,0,2,0,0,0,22,0,0,0,7,129,35,145,65,200,4,73,6,16,50,57,146,1,132,12,37,5,8,25,30,4,139,98,128,20,69,2,66,146,11,66,164,16,50,20,56,8,24,75,10,50,82,136,72,112, + 196,33,35,68,18,135,140,16,65,146,2,100,200,8,177,20,32,67,70,136,32,201,1,50,82,132,24,42,40,42,144,49,124,176,92,145,32,197,200,0,0,0,137,32,0,0,31,0,0,0,50,34,72,9,32,98,70,0,33, + 43,36,152,20,33,37,36,152,20,25,39,12,133,164,144,96,82,100,92,32,36,101,130,128,154,1,24,70,32,128,27,132,97,4,1,64,74,154,34,74,152,252,127,34,174,137,138,136,223,30,254,105,140, + 0,24,68,32,2,140,164,41,162,132,201,255,37,128,121,22,34,250,167,49,2,96,16,193,16,76,33,194,40,135,208,28,1,114,132,160,230,8,130,57,2,48,24,70,16,26,163,172,114,6,115,12,128,70,111, + 32,64,5,218,8,0,0,81,24,0,0,105,0,0,0,27,246,35,248,255,255,255,255,1,104,3,96,13,0,83,0,252,0,144,128,10,232,3,34,28,224,1,30,228,225,29,240,161,13,204,161,30,220,97,28,218,192,28, + 224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,128,48,7,121,8,135,118,40,135,54,128,135,119,72,7,119,160,135,114,144,7,32,28,216,129,29,0,162,29,210,193,29,218,128,29,202,225, + 28,194,129,29,218,192,30,202,97,28,232,225,29,228,161,13,238,33,29,200,129,30,208,1,136,3,57,192,3,96,112,135,119,104,3,113,168,135,116,96,7,122,72,7,119,152,7,128,112,135,119,104, + 131,116,112,7,115,152,135,54,48,7,120,104,131,118,8,7,122,64,7,128,30,228,161,30,202,1,32,220,225,29,218,192,29,194,193,29,230,161,13,204,1,30,218,160,29,194,129,30,208,1,160,7,121, + 168,135,114,0,8,119,120,135,54,152,135,116,56,7,119,40,7,114,104,3,125,40,7,121,120,135,121,104,3,115,128,135,54,104,135,112,160,7,116,0,232,65,30,234,161,28,0,194,29,222,161,13,232, + 65,30,194,1,30,224,33,29,220,225,28,218,160,29,194,129,30,208,1,160,7,121,168,135,114,0,136,121,160,135,112,24,135,117,104,3,120,144,135,119,160,135,114,24,7,122,120,7,121,104,3,113, + 168,7,115,48,135,114,144,135,54,152,135,116,208,135,114,0,240,0,32,234,193,29,230,33,28,204,161,28,218,192,28,224,161,13,218,33,28,232,1,29,0,122,144,135,122,40,7,96,131,33,12,192, + 2,84,27,140,129,0,22,160,218,0,17,255,255,255,255,63,0,109,0,172,1,96,10,128,31,0,18,80,1,125,176,193,40,2,96,1,170,13,134,33,0,11,80,109,96,142,255,255,255,255,31,128,54,0,214,0,144, + 128,10,232,3,0,73,24,0,0,4,0,0,0,19,134,64,24,38,12,68,97,76,24,142,194,0,0,0,0,19,170,112,72,7,121,176,3,58,104,131,112,128,7,120,96,135,114,104,131,116,120,135,121,136,3,60,112,131, + 56,112,3,56,216,112,27,229,208,6,240,160,7,118,64,7,122,96,7,116,160,7,118,64,7,109,144,14,113,160,7,120,160,7,120,208,6,233,128,7,122,128,7,122,128,7,109,144,14,113,96,7,122,16,7, + 118,160,7,113,96,7,109,144,14,115,32,7,122,48,7,114,160,7,115,32,7,109,144,14,118,64,7,122,96,7,116,160,7,118,64,7,109,96,14,115,32,7,122,48,7,114,160,7,115,32,7,109,96,14,118,64,7, + 122,96,7,116,160,7,118,64,7,109,96,15,113,96,7,122,16,7,118,160,7,113,96,7,109,96,15,114,64,7,122,48,7,114,160,7,115,32,7,109,96,15,115,32,7,122,48,7,114,160,7,115,32,7,109,96,15,116, + 128,7,122,96,7,116,160,7,118,64,7,109,96,15,118,64,7,122,96,7,116,160,7,118,64,7,109,96,15,121,96,7,122,16,7,114,128,7,122,16,7,114,128,7,109,96,15,113,32,7,120,160,7,113,32,7,120, + 160,7,113,32,7,120,208,6,246,16,7,121,32,7,122,32,7,117,96,7,122,32,7,117,96,7,109,96,15,114,80,7,118,160,7,114,80,7,118,160,7,114,80,7,118,208,6,246,80,7,113,32,7,122,80,7,113,32, + 7,122,80,7,113,32,7,109,96,15,113,0,7,114,64,7,122,16,7,112,32,7,116,160,7,113,0,7,114,64,7,109,224,14,120,160,7,113,96,7,122,48,7,114,160,17,194,144,5,3,32,13,61,164,2,10,4,0,128, + 0,0,0,64,0,0,0,0,0,160,0,134,84,197,246,0,1,32,0,0,0,8,0,0,0,0,0,20,128,196,6,129,162,43,3,0,0,89,32,10,0,0,0,50,30,152,16,25,17,76,144,140,9,38,71,198,4,67,106,69,80,2,133,80,14,229, + 83,128,2,5,81,32,35,0,101,64,114,44,65,10,0,0,0,177,24,0,0,165,0,0,0,51,8,128,28,196,225,28,102,20,1,61,136,67,56,132,195,140,66,128,7,121,120,7,115,152,113,12,230,0,15,237,16,14,244, + 128,14,51,12,66,30,194,193,29,206,161,28,102,48,5,61,136,67,56,132,131,27,204,3,61,200,67,61,140,3,61,204,120,140,116,112,7,123,8,7,121,72,135,112,112,7,122,112,3,118,120,135,112,32, + 135,25,204,17,14,236,144,14,225,48,15,110,48,15,227,240,14,240,80,14,51,16,196,29,222,33,28,216,33,29,194,97,30,102,48,137,59,188,131,59,208,67,57,180,3,60,188,131,60,132,3,59,204, + 240,20,118,96,7,123,104,7,55,104,135,114,104,7,55,128,135,112,144,135,112,96,7,118,40,7,118,248,5,118,120,135,119,128,135,95,8,135,113,24,135,114,152,135,121,152,129,44,238,240,14, + 238,224,14,245,192,14,236,48,3,98,200,161,28,228,161,28,204,161,28,228,161,28,220,97,28,202,33,28,196,129,29,202,97,6,214,144,67,57,200,67,57,152,67,57,200,67,57,184,195,56,148,67, + 56,136,3,59,148,195,47,188,131,60,252,130,59,212,3,59,176,195,12,199,105,135,112,88,135,114,112,131,116,104,7,120,96,135,116,24,135,116,160,135,25,206,83,15,238,0,15,242,80,14,228, + 144,14,227,64,15,225,32,14,236,80,14,51,32,40,29,220,193,30,194,65,30,210,33,28,220,129,30,220,224,28,228,225,29,234,1,30,102,24,81,56,176,67,58,156,131,59,204,80,36,118,96,7,123,104, + 7,55,96,135,119,120,7,120,152,81,76,244,144,15,240,80,14,51,30,106,30,202,97,28,232,33,29,222,193,29,126,1,30,228,161,28,204,33,29,240,97,6,84,133,131,56,204,195,59,176,67,61,208,67, + 57,252,194,60,228,67,59,136,195,59,176,195,140,197,10,135,121,152,135,119,24,135,116,8,7,122,40,7,114,152,129,92,227,16,14,236,192,14,229,80,14,243,48,35,193,210,65,30,228,225,23,216, + 225,29,222,1,30,102,72,25,59,176,131,61,180,131,27,132,195,56,140,67,57,204,195,60,184,193,57,200,195,59,212,3,60,204,72,180,113,8,7,118,96,7,113,8,135,113,88,135,25,219,198,14,236, + 96,15,237,224,6,240,32,15,229,48,15,229,32,15,246,80,14,110,16,14,227,48,14,229,48,15,243,224,6,233,224,14,228,80,14,248,48,35,226,236,97,28,194,129,29,216,225,23,236,33,29,230,33, + 29,196,33,29,216,33,29,232,33,31,102,32,157,59,188,67,61,184,3,57,148,131,57,204,88,188,112,112,7,119,120,7,122,8,7,122,72,135,119,112,135,25,206,135,14,229,16,14,240,16,14,236,192, + 14,239,48,14,243,144,14,244,80,14,51,40,48,8,135,116,144,7,55,48,135,122,112,135,113,160,135,116,120,7,119,248,133,115,144,135,119,168,7,120,152,7,0,0,0,0,121,32,0,0,251,0,0,0,114, + 30,72,32,67,136,12,25,9,114,50,72,32,35,129,140,145,145,209,68,160,16,40,100,60,49,50,66,142,144,33,163,56,6,220,41,1,0,0,0,139,210,88,216,6,109,80,28,20,27,71,6,81,100,48,134,180, + 40,15,178,24,197,34,41,24,178,28,13,83,68,75,32,86,101,114,115,105,111,110,119,99,104,97,114,95,115,105,122,101,102,114,97,109,101,45,112,111,105,110,116,101,114,97,105,114,46,109, + 97,120,95,100,101,118,105,99,101,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,99,111,110,115,116,97,110,116,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,116, + 104,114,101,97,100,103,114,111,117,112,95,98,117,102,102,101,114,115,97,105,114,46,109,97,120,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,114,101,97,100,95,119,114, + 105,116,101,95,116,101,120,116,117,114,101,115,97,105,114,46,109,97,120,95,115,97,109,112,108,101,114,115,65,112,112,108,101,32,109,101,116,97,108,32,118,101,114,115,105,111,110,32, + 51,50,48,50,51,46,51,54,56,32,40,109,101,116,97,108,102,101,45,51,50,48,50,51,46,51,54,56,41,77,101,116,97,108,97,105,114,46,99,111,109,112,105,108,101,46,100,101,110,111,114,109,115, + 95,100,105,115,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,97,115,116,95,109,97,116,104,95,101,110,97,98,108,101,97,105,114,46,99,111,109,112,105,108,101,46,102,114, + 97,109,101,98,117,102,102,101,114,95,102,101,116,99,104,95,101,110,97,98,108,101,97,105,114,46,114,101,110,100,101,114,95,116,97,114,103,101,116,97,105,114,46,97,114,103,95,116,121, + 112,101,95,110,97,109,101,102,108,111,97,116,52,97,105,114,46,97,114,103,95,110,97,109,101,102,67,111,108,111,114,97,105,114,46,102,114,97,103,109,101,110,116,95,105,110,112,117,116, + 117,115,101,114,40,108,111,99,110,48,41,97,105,114,46,99,101,110,116,101,114,97,105,114,46,112,101,114,115,112,101,99,116,105,118,101,73,110,95,67,111,108,111,114,117,115,101,114,40, + 108,111,99,110,49,41,102,108,111,97,116,50,73,110,95,85,86,97,105,114,46,116,101,120,116,117,114,101,97,105,114,46,108,111,99,97,116,105,111,110,95,105,110,100,101,120,97,105,114,46, + 115,97,109,112,108,101,116,101,120,116,117,114,101,50,100,60,102,108,111,97,116,44,32,115,97,109,112,108,101,62,115,84,101,120,116,117,114,101,97,105,114,46,115,97,109,112,108,101, + 114,115,97,109,112,108,101,114,115,84,101,120,116,117,114,101,83,109,112,108,114,0,6,95,0,0,0,0,0,0,48,130,208,8,35,8,18,51,130,208,12,35,8,13,49,130,208,20,35,8,141,49,130,208,28, + 35,8,13,50,130,208,36,35,8,141,50,130,208,44,35,8,9,48,195,64,6,65,25,204,48,152,129,112,6,51,12,104,48,144,193,12,3,26,16,105,48,195,128,6,69,26,204,48,160,129,145,6,51,12,104,112, + 168,193,12,3,26,32,107,48,195,128,6,9,27,204,16,40,51,12,100,128,6,109,48,3,177,184,1,25,180,193,12,1,51,67,208,204,16,56,51,28,79,27,180,1,20,73,211,12,193,31,204,144,180,1,85,89, + 23,20,73,216,12,137,25,80,153,117,65,154,180,205,160,144,1,215,181,129,25,120,208,39,129,193,12,137,27,132,65,215,6,102,0,137,129,52,6,51,16,161,32,10,163,64,10,51,12,111,0,10,165, + 112,99,0,112,28,199,113,28,199,113,28,199,185,129,27,184,129,27,184,129,27,184,129,27,184,129,69,7,122,96,89,150,41,112,172,192,10,228,160,14,160,32,35,129,9,202,136,141,205,174,205, + 165,237,141,172,142,173,204,197,140,45,236,108,110,148,228,13,224,32,14,228,96,14,232,160,14,236,224,14,82,97,99,179,107,115,73,35,43,115,163,27,37,192,131,92,194,210,228,92,236,202, + 228,230,210,222,220,70,9,242,32,169,176,52,57,23,182,48,183,179,186,176,179,178,47,187,50,185,185,180,55,183,81,2,61,200,41,44,77,206,101,236,173,13,46,141,173,236,235,13,142,46,237, + 205,109,110,148,97,15,248,160,15,146,9,75,147,115,49,147,11,59,107,43,115,163,27,37,40,5,0,0,0,0,169,24,0,0,37,0,0,0,11,10,114,40,135,119,128,7,122,88,112,152,67,61,184,195,56,176, + 67,57,208,195,130,230,28,198,161,13,232,65,30,194,193,29,230,33,29,232,33,29,222,193,29,22,52,227,96,14,231,80,15,225,32,15,228,64,15,225,32,15,231,80,14,244,176,128,129,7,121,40,135, + 112,96,7,118,120,135,113,8,7,122,40,7,114,88,112,156,195,56,180,1,59,164,131,61,148,195,2,107,28,216,33,28,220,225,28,220,32,28,228,97,28,220,32,28,232,129,30,194,97,28,208,161,28, + 200,97,28,194,129,29,216,97,193,1,15,244,32,15,225,80,15,244,128,14,0,0,0,0,209,16,0,0,6,0,0,0,7,204,60,164,131,59,156,3,59,148,3,61,160,131,60,148,67,56,144,195,1,0,0,0,97,32,0,0, + 49,0,0,0,19,4,65,44,16,0,0,0,4,0,0,0,196,106,96,4,128,220,8,0,129,17,0,18,51,0,0,0,241,48,0,0,28,0,0,0,34,71,200,144,81,14,196,42,0,0,0,0,23,134,1,0,97,105,114,45,97,108,105,97,115, + 45,115,99,111,112,101,115,40,109,97,105,110,48,41,97,105,114,45,97,108,105,97,115,45,115,99,111,112,101,45,115,97,109,112,108,101,114,115,97,105,114,45,97,108,105,97,115,45,115,99, + 111,112,101,45,116,101,120,116,117,114,101,115,0,43,4,85,56,133,21,195,42,168,2,42,172,24,88,65,21,82,97,131,192,10,171,0,0,35,6,205,16,130,96,240,84,135,129,20,3,33,8,204,104,66,0, + 96,176,136,255,108,3,17,0,27,4,196,0,0,0,2,0,0,0,91,6,224,96,5,0,0,0,0,0,0,0,113,32,0,0,3,0,0,0,50,14,16,34,132,0,248,5,0,0,0,0,0,0,0,0,101,12,0,0,37,0,0,0,18,3,148,40,1,0,0,0,3,0, + 0,0,32,0,0,0,9,0,0,0,76,0,0,0,1,0,0,0,88,0,0,0,0,0,0,0,88,0,0,0,2,0,0,0,136,0,0,0,0,0,0,0,41,0,0,0,21,0,0,0,0,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, + 0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,255,255,255,255,0,36,0,0,5,0,0,0,27,0,0,0,5,0,0,0,27,0,0,0,255,255,255,255,8,36,0,0,0,0,0,0,93,12,0,0,19,0,0,0,18,3,148,126,0,0,0,0,109,97,105,110, + 48,97,105,114,46,115,97,109,112,108,101,95,116,101,120,116,117,114,101,95,50,100,46,118,52,102,51,50,51,50,48,50,51,46,51,54,56,97,105,114,54,52,45,97,112,112,108,101,45,105,111,115, + 49,56,46,49,46,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; +#elif TARGET_IPHONE_SIMULATOR +#error "SDL_GPU does not support the iphone simulator" +#endif +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/backends/sdlgpu3/build_instructions.txt b/backends/sdlgpu3/build_instructions.txt new file mode 100644 index 000000000000..751dc97a4e0b --- /dev/null +++ b/backends/sdlgpu3/build_instructions.txt @@ -0,0 +1,36 @@ +1) Compile the raw shader files to SPIRV: + + glslc -o vertex.spv -c shader.vert + glslc -o fragment.spv -c shader.frag + + +2) Build SDL_shadercross (https://github.com/libsdl-org/SDL_shadercross) + + +3-A) Compiling for the Vulkan Driver: + + Nothing to do, you just need the previous vertex.spv/fragment.spv, proceed to step 4 + + +3-B) Compiling for the DirectX 12 Driver: + + ./shadercross vertex.spv -s SPIRV -d DXBC -t vertex -e main -o vertex.dxbc + ./shadercross fragment.spv -s SPIRV -d DXBC -t fragment -e main -o fragment.dxbc + + Proceed to step 4 + + +3-C) Compiling for Metal (On windows you'll need the Metal Developer Tools for Windows, on linux you might use wine, but I never tested it): + + ./shadercross vertex.spv -s SPIRV -d MSL -t vertex -e main -o vertex.metal + ./shadercross fragment.spv -s SPIRV -d MSL -t fragment -e main -o fragment.metal + + xcrun -sdk macosx metal -o vertex.ir -c vertex.metal + xcrun -sdk macosx metal -o fragment.ir -c fragment.metal + xcrun -sdk macosx metallib -o vertex.metallib -c vertex.ir + xcrun -sdk macosx metallib -o fragment.metallib -c fragment.ir + + Proceed to step 4 + + +4) Either find a way to load the shader bytecode from file, or use a tool like https://notisrac.github.io/FileToCArray/ to convert the file to a uint8_t array \ No newline at end of file diff --git a/backends/sdlgpu3/shader.frag b/backends/sdlgpu3/shader.frag new file mode 100644 index 000000000000..2de1f76a3b23 --- /dev/null +++ b/backends/sdlgpu3/shader.frag @@ -0,0 +1,14 @@ +#version 450 core +layout(location = 0) out vec4 fColor; + +layout(set=2, binding=0) uniform sampler2D sTexture; + +layout(location = 0) in struct { + vec4 Color; + vec2 UV; +} In; + +void main() +{ + fColor = In.Color * texture(sTexture, In.UV.st); +} \ No newline at end of file diff --git a/backends/sdlgpu3/shader.vert b/backends/sdlgpu3/shader.vert new file mode 100644 index 000000000000..3363da8b2a7b --- /dev/null +++ b/backends/sdlgpu3/shader.vert @@ -0,0 +1,22 @@ +#version 450 core +layout(location = 0) in vec2 aPos; +layout(location = 1) in vec2 aUV; +layout(location = 2) in vec4 aColor; + +layout(set=1,binding=0) uniform UBO { + vec2 uScale; + vec2 uTranslate; +} ubo; + +layout(location = 0) out struct { + vec4 Color; + vec2 UV; +} Out; + +void main() +{ + Out.Color = aColor; + Out.UV = aUV; + gl_Position = vec4(aPos * ubo.uScale + ubo.uTranslate, 0, 1); + gl_Position.y *= -1.0f; +} \ No newline at end of file diff --git a/examples/example_sdl3_sdlgpu3/Makefile b/examples/example_sdl3_sdlgpu3/Makefile new file mode 100644 index 000000000000..f6239e0fa845 --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/Makefile @@ -0,0 +1,73 @@ +# +# Cross Platform Makefile +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X +# +# You will need SDL3 (http://www.libsdl.org) which is still unreleased/unpackaged. + +#CXX = g++ +#CXX = clang++ + +EXE = example_sdl3_sdlgpu3 +IMGUI_DIR = ../.. +SOURCES = main.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlgpu3.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) +UNAME_S := $(shell uname -s) + +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = + + +##--------------------------------------------------------------------- +## BUILD FLAGS PER PLATFORM +##--------------------------------------------------------------------- + +ifeq ($(UNAME_S), Linux) #LINUX + ECHO_MESSAGE = "Linux" + LIBS += -ldl `pkg-config sdl3 --libs` + + CXXFLAGS += `pkg-config sdl3 --cflags` + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(UNAME_S), Darwin) #APPLE + ECHO_MESSAGE = "Mac OS X" + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo `pkg-config --libs sdl3` + LIBS += -L/usr/local/lib -L/opt/local/lib + + CXXFLAGS += `pkg-config sdl3 --cflags` + CXXFLAGS += -I/usr/local/include -I/opt/local/include + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(OS), Windows_NT) + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -limm32 `pkg-config --static --libs sdl3` + + CXXFLAGS += `pkg-config --cflags sdl3` + CFLAGS = $(CXXFLAGS) +endif + +##--------------------------------------------------------------------- +## BUILD RULES +##--------------------------------------------------------------------- + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +all: $(EXE) + @echo Build complete for $(ECHO_MESSAGE) + +$(EXE): $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +clean: + rm -f $(EXE) $(OBJS) diff --git a/examples/example_sdl3_sdlgpu3/build_win64.bat b/examples/example_sdl3_sdlgpu3/build_win64.bat new file mode 100644 index 000000000000..ad7a2d603ae7 --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/build_win64.bat @@ -0,0 +1,14 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars64.bat or vcvarsall.bat to setup command-line compiler. + +@set OUT_EXE=example_sdl3_sdlgpu3 +@set INCLUDES=/I..\.. /I..\..\backends /I%SDL3_DIR%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_sdlgpu3.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:%SDL3_DIR%\lib\x64 SDL3.lib shell32.lib + +@set OUT_DIR=Debug +mkdir %OUT_DIR% +cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console + +@set OUT_DIR=Release +@REM mkdir %OUT_DIR% +@REM cl /nologo /Zi /MD /utf-8 /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj new file mode 100644 index 000000000000..3d034f52c0a5 --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {c22cb6f8-39a5-4dda-90ed-4aca4e81e1e5} + example_sdl3_sdlgpu3 + 8.1 + + + + Application + true + MultiByte + v140 + + + Application + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + + + + + + + + + + + + + + + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + + Level4 + Disabled + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + _MBCS;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + %SDL3_DIR%\lib\x86;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + Disabled + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + _MBCS;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + %SDL3_DIR%\lib\x64;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + false + _MBCS;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + true + true + %SDL3_DIR%\lib\x86;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + + + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + false + _MBCS;%(PreprocessorDefinitions) + /utf-8 %(AdditionalOptions) + + + true + true + true + %SDL3_DIR%\lib\x64;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters new file mode 100644 index 000000000000..4710b550cc0f --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters @@ -0,0 +1,60 @@ + + + + + sources + + + sources + + + sources + + + imgui + + + imgui + + + imgui + + + imgui + + + imgui + + + + + sources + + + sources + + + sources + + + imgui + + + imgui + + + imgui + + + + + + + + {9044ef92-2afa-42f2-92df-ac473c7c32b3} + + + {ef84458b-039a-4902-8455-4e33df5a8578} + + + \ No newline at end of file diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp new file mode 100644 index 000000000000..6c29962dd0b8 --- /dev/null +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -0,0 +1,210 @@ +// Dear ImGui: standalone example application for SDL_Gpu + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +// Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. +// - Unline other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. + +#include "imgui.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_sdlgpu3.h" +#include // printf, fprintf +#include // abort +#include + + +// This example doesn't compile with Emscripten yet! Awaiting SDL3 support. +#ifdef __EMSCRIPTEN__ +#include "../libs/emscripten/emscripten_mainloop_stub.h" +#endif + +// Main code +int main(int, char**) +{ + // Setup SDL + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD) != 0) + { + printf("Error: SDL_Init(): %s\n", SDL_GetError()); + return -1; + } + + // Create SDL window graphics context + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDLGpu example", 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); + if (window == nullptr) + { + printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); + return -1; + } + + // Create SDL Gpu Device + SDL_GPUDevice* gpuDevice = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB,true,nullptr); + if (gpuDevice == nullptr) + { + printf("Error: SDL_CreateGPUDevice(): %s\n", SDL_GetError()); + return -1; + } + + // Claim window for GPU Device + if (!SDL_ClaimWindowForGPUDevice(gpuDevice, window)) + { + printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError()); + return -1; + } + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplSDL3_InitForOther(window); + ImGui_ImplSDLGPU_InitInfo init_info = {}; + init_info.GpuDevice = gpuDevice; + init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(gpuDevice, window); + init_info.MSAASamples = SDL_GPU_SAMPLECOUNT_1; + ImGui_ImplSDLGPU_Init(&init_info); + + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. + // - Read 'docs/FONTS.md' for more instructions and details. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //io.Fonts->AddFontDefault(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //IM_ASSERT(font != nullptr); + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop + bool done = false; + while (!done) + { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. + // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL3_ProcessEvent(&event); + if (event.type == SDL_EVENT_QUIT) + done = true; + if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) + done = true; + } + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } + + // Start the Dear ImGui frame + ImGui_ImplSDLGPU_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); + + // Acquire a GPU command buffer + SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(gpuDevice); + + //Acquire a swapchain texture + SDL_GPUTexture* swapchain_texture; + SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); + + if (swapchain_texture != nullptr && !is_minimized) + { + // !!! THIS IS MANDATORY !!! + // Call Imgui_ImplSDLGPU_PrepareDrawData to upload the vertex/index buffer + Imgui_ImplSDLGPU_PrepareDrawData(draw_data, command_buffer); + + // Setup and start a render pass + SDL_GPUColorTargetInfo target_info = {}; + target_info.texture = swapchain_texture; + target_info.clear_color = SDL_FColor{ clear_color.x,clear_color.y,clear_color.z,clear_color.w }; + target_info.load_op = SDL_GPU_LOADOP_CLEAR; + target_info.store_op = SDL_GPU_STOREOP_STORE; + target_info.mip_level = 0; + target_info.layer_or_depth_plane = 0; + target_info.cycle = false; + SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &target_info, 1, nullptr); + /// Render ImGui + ImGui_ImplSDLGPU_RenderDrawData(draw_data, command_buffer, render_pass); + SDL_EndGPURenderPass(render_pass); + } + // Submit the command buffer + SDL_SubmitGPUCommandBuffer(command_buffer); + } + // Cleanup + SDL_WaitForGPUIdle(gpuDevice); + ImGui_ImplSDL3_Shutdown(); + ImGui_ImplSDLGPU_Shutdown(); + ImGui::DestroyContext(); + SDL_ReleaseWindowFromGPUDevice(gpuDevice, window); + SDL_DestroyGPUDevice(gpuDevice); + SDL_DestroyWindow(window); + SDL_Quit(); + return 0; +} diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index 85f7451d4f61..cf1c5ad50f63 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -37,6 +37,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_vulkan", "exam EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "example_win32_vulkan\example_win32_vulkan.vcxproj", "{0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlgpu3", "example_sdl3_sdlgpu3\example_sdl3_sdlgpu3.vcxproj", "{C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -181,6 +183,14 @@ Global {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|Win32.Build.0 = Release|Win32 {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|x64.ActiveCfg = Release|x64 {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}.Release|x64.Build.0 = Release|x64 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|Win32.ActiveCfg = Debug|Win32 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|Win32.Build.0 = Debug|Win32 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|x64.ActiveCfg = Debug|x64 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Debug|x64.Build.0 = Debug|x64 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|Win32.ActiveCfg = Release|Win32 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|Win32.Build.0 = Release|Win32 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|x64.ActiveCfg = Release|x64 + {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From e79984927266f9b44302b2b43e70cf674513cffd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 16:08:14 +0100 Subject: [PATCH 129/716] Backends: SDLGPU3: Added sdl_gpu backend (amends). (#8163, #7998, #7988) --- backends/imgui_impl_sdlgpu3.cpp | 301 ++++++++++++------------ backends/imgui_impl_sdlgpu3.h | 18 +- backends/sdlgpu3/build_instructions.txt | 6 +- backends/sdlgpu3/shader.frag | 5 +- backends/sdlgpu3/shader.vert | 8 +- backends/vulkan/build_instructions.txt | 4 + docs/CHANGELOG.txt | 1 + docs/EXAMPLES.md | 24 +- docs/README.md | 2 +- examples/example_sdl3_sdlgpu3/main.cpp | 53 +++-- 10 files changed, 221 insertions(+), 201 deletions(-) create mode 100644 backends/vulkan/build_instructions.txt diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 31e899b77d92..e681efdc39ab 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -1,4 +1,4 @@ -// dear imgui: Renderer Backend for SDL_Gpu +// dear imgui: Renderer Backend for SDL_GPU // This needs to be used along with the SDL3 Platform Backend // Implemented features: @@ -17,19 +17,19 @@ // - Introduction, links and more at the top of imgui.cpp // Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. -// - Unline other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// - Unlike other backends, the user must call the function Imgui_ImplSDLGPU3_PrepareDrawData() BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU3_RenderDrawData. // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG -// 2024-11-18: SDL_Gpu: Added the SDL_Gpu backend. +// 2025-01-09: SDL_Gpu: Added the SDL_GPU3 backend. #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_sdlgpu3.h" #include "imgui_impl_sdlgpu3_shaders.h" -// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU_RenderDrawData() -struct ImGui_ImplSDLGPU_FrameData +// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU3_RenderDrawData() +struct ImGui_ImplSDLGPU3_FrameData { SDL_GPUBuffer* VertexBuffer = nullptr; SDL_GPUBuffer* IndexBuffer = nullptr; @@ -37,10 +37,10 @@ struct ImGui_ImplSDLGPU_FrameData uint32_t IndexBufferSize = 0; }; -// SDL_Gpu Data -struct ImGui_ImplSDLGPU_Data +// SDL_GPU Data +struct ImGui_ImplSDLGPU3_Data { - ImGui_ImplSDLGPU_InitInfo GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo GPUInitInfo; // Graphics pipeline & shaders SDL_GPUShader* VertexShader = nullptr; @@ -50,16 +50,16 @@ struct ImGui_ImplSDLGPU_Data // Font data SDL_GPUSampler* FontSampler = nullptr; SDL_GPUTexture* FontTexture = nullptr; - SDL_GPUTextureSamplerBinding FontBinding = {nullptr,nullptr}; + SDL_GPUTextureSamplerBinding FontBinding = { nullptr, nullptr }; // Frame data for main window - ImGui_ImplSDLGPU_FrameData MainWindowFrameData; + ImGui_ImplSDLGPU3_FrameData MainWindowFrameData; }; // Forward Declarations -static bool ImGui_ImplSDLGPU_CreateDeviceObjects(); -static void ImGui_ImplSDLGPU_DestroyDeviceObjects(); -static void ImGui_ImplSDLGPU_DestroyFrameData(); +static bool ImGui_ImplSDLGPU3_CreateDeviceObjects(); +static void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); +static void ImGui_ImplSDLGPU3_DestroyFrameData(); //----------------------------------------------------------------------------- // FUNCTIONS @@ -68,38 +68,19 @@ static void ImGui_ImplSDLGPU_DestroyFrameData(); // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. // FIXME: multi-context support has never been tested. -static ImGui_ImplSDLGPU_Data* ImGui_ImplSDLGPU_GetBackendData() +static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData() { - return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; + return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } -static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer,uint32_t* old_size, uint32_t new_size,SDL_GPUBufferUsageFlags usage) +static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass * render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height) { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + //ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - SDL_WaitForGPUIdle(v->GpuDevice); - SDL_ReleaseGPUBuffer(v->GpuDevice, *buffer); - - SDL_GPUBufferCreateInfo buffer_info = {}; - buffer_info.usage = usage; - buffer_info.size = new_size; - buffer_info.props = 0; - *buffer = SDL_CreateGPUBuffer(v->GpuDevice,&buffer_info); - *old_size = new_size; - IM_ASSERT(*buffer != nullptr && "Failed to create GPU Buffer, call SDL_GetError() for more information"); -} - -static void ImGui_ImplSDLGPU_SetupRenderState(ImDrawData* draw_data,SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer,SDL_GPURenderPass * render_pass, ImGui_ImplSDLGPU_FrameData* fd, uint32_t fb_width, uint32_t fb_height) -{ - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - - // Bind graphics pipeline: - { - SDL_BindGPUGraphicsPipeline(render_pass,pipeline); - } + // Bind graphics pipeline + SDL_BindGPUGraphicsPipeline(render_pass,pipeline); - // Bind Vertex And Index Buffers: + // Bind Vertex And Index Buffers if (draw_data->TotalVtxCount > 0) { SDL_GPUBufferBinding vertex_buffer_binding = {}; @@ -112,56 +93,66 @@ static void ImGui_ImplSDLGPU_SetupRenderState(ImDrawData* draw_data,SDL_GPUGraph SDL_BindGPUIndexBuffer(render_pass,&index_buffer_binding,sizeof(ImDrawIdx) == 2 ? SDL_GPU_INDEXELEMENTSIZE_16BIT : SDL_GPU_INDEXELEMENTSIZE_32BIT); } - // Setup viewport: - { - SDL_GPUViewport viewport = {}; - viewport.x = 0; - viewport.y = 0; - viewport.w = fb_width; - viewport.h = fb_height; - viewport.min_depth = 0.0f; - viewport.min_depth = 1.0f; - SDL_SetGPUViewport(render_pass,&viewport); - } - - // Setup scale and translation: + // Setup viewport + SDL_GPUViewport viewport = {}; + viewport.x = 0; + viewport.y = 0; + viewport.w = (float)fb_width; + viewport.h = (float)fb_height; + viewport.min_depth = 0.0f; + viewport.min_depth = 1.0f; + SDL_SetGPUViewport(render_pass,&viewport); + + // Setup scale and translation // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - { - struct UBO{ - float scale[2]; - float translation[2]; - } ubo; - ubo.scale[0] = 2.0f / draw_data->DisplaySize.x; - ubo.scale[1] = 2.0f / draw_data->DisplaySize.y; - ubo.translation[0] = -1.0f - draw_data->DisplayPos.x * ubo.scale[0]; - ubo.translation[1] = -1.0f - draw_data->DisplayPos.y * ubo.scale[1]; - SDL_PushGPUVertexUniformData(command_buffer,0,&ubo,sizeof(UBO)); - } + struct UBO { float scale[2]; float translation[2]; } ubo; + ubo.scale[0] = 2.0f / draw_data->DisplaySize.x; + ubo.scale[1] = 2.0f / draw_data->DisplaySize.y; + ubo.translation[0] = -1.0f - draw_data->DisplayPos.x * ubo.scale[0]; + ubo.translation[1] = -1.0f - draw_data->DisplayPos.y * ubo.scale[1]; + SDL_PushGPUVertexUniformData(command_buffer, 0, &ubo, sizeof(UBO)); } -// SDL_GPU doesn't allow copy passes to occur while a render or compute pass is bound +static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer, uint32_t* old_size, uint32_t new_size, SDL_GPUBufferUsageFlags usage) +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + + SDL_WaitForGPUIdle(v->GpuDevice); + SDL_ReleaseGPUBuffer(v->GpuDevice, *buffer); + + SDL_GPUBufferCreateInfo buffer_info = {}; + buffer_info.usage = usage; + buffer_info.size = new_size; + buffer_info.props = 0; + *buffer = SDL_CreateGPUBuffer(v->GpuDevice, &buffer_info); + *old_size = new_size; + IM_ASSERT(*buffer != nullptr && "Failed to create GPU Buffer, call SDL_GetError() for more information"); +} + +// SDL_GPU doesn't allow copy passes to occur while a render or compute pass is bound! // The only way to allow a user to supply their own RenderPass (to render to a texture instead of the window for example), -// is to split the upload part of ImGui_ImplSDLGPU_RenderDrawData to another function that needs to be called by the user before rendering -void Imgui_ImplSDLGPU_PrepareDrawData(ImDrawData* draw_data,SDL_GPUCommandBuffer* command_buffer) +// is to split the upload part of ImGui_ImplSDLGPU3_RenderDrawData() to another function that needs to be called by the user before rendering. +void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if(fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0) + if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0) return; - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; - ImGui_ImplSDLGPU_FrameData* fd = &bd->MainWindowFrameData; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData; uint32_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); uint32_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); - - if(fd->VertexBuffer == nullptr || fd->VertexBufferSize < vertex_size) - CreateOrResizeBuffer(&fd->VertexBuffer,&fd->VertexBufferSize,vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX); + if (fd->VertexBuffer == nullptr || fd->VertexBufferSize < vertex_size) + CreateOrResizeBuffer(&fd->VertexBuffer, &fd->VertexBufferSize, vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX); if (fd->IndexBuffer == nullptr || fd->IndexBufferSize < index_size) - CreateOrResizeBuffer(&fd->IndexBuffer,&fd->IndexBufferSize,index_size, SDL_GPU_BUFFERUSAGE_INDEX); + CreateOrResizeBuffer(&fd->IndexBuffer, &fd->IndexBufferSize, index_size, SDL_GPU_BUFFERUSAGE_INDEX); + // FIXME: It feels like more code could be shared there. SDL_GPUTransferBufferCreateInfo vertex_transferbuffer_info = {}; vertex_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; vertex_transferbuffer_info.size = vertex_size; @@ -169,22 +160,23 @@ void Imgui_ImplSDLGPU_PrepareDrawData(ImDrawData* draw_data,SDL_GPUCommandBuffer index_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; index_transferbuffer_info.size = index_size; - SDL_GPUTransferBuffer* vertex_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice,&vertex_transferbuffer_info); + SDL_GPUTransferBuffer* vertex_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice, &vertex_transferbuffer_info); IM_ASSERT(vertex_transferbuffer != nullptr && "Failed to create the vertex transfer buffer, call SDL_GetError() for more information"); - SDL_GPUTransferBuffer* index_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice,&index_transferbuffer_info); + SDL_GPUTransferBuffer* index_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice, &index_transferbuffer_info); IM_ASSERT(index_transferbuffer != nullptr && "Failed to create the index transfer buffer, call SDL_GetError() for more information"); - ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->GpuDevice,vertex_transferbuffer,true); - ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->GpuDevice,index_transferbuffer,true); - for(int n = 0; n < draw_data->CmdListsCount; n++){ + ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer, true); + ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->GpuDevice, index_transferbuffer, true); + for (int n = 0; n < draw_data->CmdListsCount; n++) + { const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; idx_dst += draw_list->IdxBuffer.Size; } - SDL_UnmapGPUTransferBuffer(v->GpuDevice,vertex_transferbuffer); - SDL_UnmapGPUTransferBuffer(v->GpuDevice,index_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->GpuDevice, index_transferbuffer); SDL_GPUTransferBufferLocation vertex_buffer_location = {}; vertex_buffer_location.offset = 0; @@ -197,34 +189,35 @@ void Imgui_ImplSDLGPU_PrepareDrawData(ImDrawData* draw_data,SDL_GPUCommandBuffer vertex_buffer_region.buffer = fd->VertexBuffer; vertex_buffer_region.offset = 0; vertex_buffer_region.size = vertex_size; + SDL_GPUBufferRegion index_buffer_region = {}; index_buffer_region.buffer = fd->IndexBuffer; index_buffer_region.offset = 0; index_buffer_region.size = index_size; SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(command_buffer); - SDL_UploadToGPUBuffer(copy_pass,&vertex_buffer_location,&vertex_buffer_region,true); - SDL_UploadToGPUBuffer(copy_pass,&index_buffer_location,&index_buffer_region,true); + SDL_UploadToGPUBuffer(copy_pass, &vertex_buffer_location, &vertex_buffer_region,true); + SDL_UploadToGPUBuffer(copy_pass, &index_buffer_location, &index_buffer_region,true); SDL_EndGPUCopyPass(copy_pass); SDL_ReleaseGPUTransferBuffer(v->GpuDevice, index_transferbuffer); SDL_ReleaseGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer); } -void ImGui_ImplSDLGPU_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) +void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if(fb_width <= 0 || fb_height <= 0) + if (fb_width <= 0 || fb_height <= 0) return; - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_FrameData* fd = &bd->MainWindowFrameData; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData; if (pipeline == nullptr) pipeline = bd->Pipeline; - ImGui_ImplSDLGPU_SetupRenderState(draw_data,pipeline,command_buffer,render_pass,fd,fb_width,fb_height); + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports @@ -267,10 +260,10 @@ void ImGui_ImplSDLGPU_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer SDL_SetGPUScissor(render_pass,&scissor_rect); // Bind DescriptorSet with font or user texture - SDL_BindGPUFragmentSamplers(render_pass,0,(SDL_GPUTextureSamplerBinding*)pcmd->GetTexID(),1); + SDL_BindGPUFragmentSamplers(render_pass, 0, (SDL_GPUTextureSamplerBinding*)pcmd->GetTexID(), 1); // Draw - SDL_DrawGPUIndexedPrimitives(render_pass,pcmd->ElemCount,1,pcmd->IdxOffset + global_idx_offset,pcmd->VtxOffset + global_vtx_offset,0); + SDL_DrawGPUIndexedPrimitives(render_pass, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0); } } global_idx_offset += draw_list->IdxBuffer.Size; @@ -281,21 +274,21 @@ void ImGui_ImplSDLGPU_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer // Our last values will leak into user/application rendering if you forgot to call SDL_SetGPUViewport() and SDL_SetGPUScissor() yourself to explicitly set that state // In theory we should aim to backup/restore those values but I am not sure this is possible. // We perform a call to SDL_SetGPUScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644) - SDL_Rect scissor_rect {0,0,fb_width,fb_height}; - SDL_SetGPUScissor(render_pass,&scissor_rect); + SDL_Rect scissor_rect { 0, 0, fb_width, fb_height }; + SDL_SetGPUScissor(render_pass, &scissor_rect); } -bool ImGui_ImplSDLGPU_CreateFontsTexture() +bool ImGui_ImplSDLGPU3_CreateFontsTexture() { ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; // Destroy existing texture (if any) if (bd->FontTexture) { SDL_WaitForGPUIdle(v->GpuDevice); - ImGui_ImplSDLGPU_DestroyFontsTexture(); + ImGui_ImplSDLGPU3_DestroyFontsTexture(); } unsigned char* pixels; @@ -315,7 +308,7 @@ bool ImGui_ImplSDLGPU_CreateFontsTexture() texture_info.num_levels = 1; texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1; - bd->FontTexture = SDL_CreateGPUTexture(v->GpuDevice,&texture_info); + bd->FontTexture = SDL_CreateGPUTexture(v->GpuDevice, &texture_info); IM_ASSERT(bd->FontTexture && "Failed to create font texture, call SDL_GetError() for more info"); } @@ -328,12 +321,12 @@ bool ImGui_ImplSDLGPU_CreateFontsTexture() font_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; font_transferbuffer_info.size = upload_size; - SDL_GPUTransferBuffer* font_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice,&font_transferbuffer_info); + SDL_GPUTransferBuffer* font_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice, &font_transferbuffer_info); IM_ASSERT(font_transferbuffer != nullptr && "Failed to create font transfer buffer, call SDL_GetError() for more information"); - void* texture_ptr = SDL_MapGPUTransferBuffer(v->GpuDevice,font_transferbuffer,false); - memcpy(texture_ptr,pixels,upload_size); - SDL_UnmapGPUTransferBuffer(v->GpuDevice,font_transferbuffer); + void* texture_ptr = SDL_MapGPUTransferBuffer(v->GpuDevice, font_transferbuffer, false); + memcpy(texture_ptr, pixels, upload_size); + SDL_UnmapGPUTransferBuffer(v->GpuDevice, font_transferbuffer); SDL_GPUTextureTransferInfo font_transfer_info = {}; font_transfer_info.offset = 0; @@ -347,7 +340,7 @@ bool ImGui_ImplSDLGPU_CreateFontsTexture() SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(v->GpuDevice); SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); - SDL_UploadToGPUTexture(copy_pass,&font_transfer_info,&font_texture_region,false); + SDL_UploadToGPUTexture(copy_pass, &font_transfer_info, &font_texture_region, false); SDL_EndGPUCopyPass(copy_pass); SDL_SubmitGPUCommandBuffer(cmd); SDL_ReleaseGPUTransferBuffer(v->GpuDevice, font_transferbuffer); @@ -359,28 +352,26 @@ bool ImGui_ImplSDLGPU_CreateFontsTexture() return true; } -// You probably never need to call this, as it is called by ImGui_ImplSDLGPU_CreateFontsTexture() and ImGui_ImplSDLGPU_Shutdown(). -void ImGui_ImplSDLGPU_DestroyFontsTexture() +// You probably never need to call this, as it is called by ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_Shutdown(). +void ImGui_ImplSDLGPU3_DestroyFontsTexture() { ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; - - if(bd->FontTexture) + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + if (bd->FontTexture) { - SDL_ReleaseGPUTexture(v->GpuDevice,bd->FontTexture); + SDL_ReleaseGPUTexture(v->GpuDevice, bd->FontTexture); bd->FontBinding.texture = nullptr; bd->FontTexture = nullptr; } - io.Fonts->SetTexID(0); } -static void Imgui_ImplSDLGPU_CreateShaders() +static void Imgui_ImplSDLGPU3_CreateShaders() { // Create the shader modules - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; const char* driver = SDL_GetGPUDeviceDriver(v->GpuDevice); @@ -400,22 +391,20 @@ static void Imgui_ImplSDLGPU_CreateShaders() fragment_shader_info.num_storage_textures = 0; fragment_shader_info.num_uniform_buffers = 0; - if(strcmp(driver,"vulkan") == 0) + if (strcmp(driver, "vulkan") == 0) { vertex_shader_info.format = SDL_GPU_SHADERFORMAT_SPIRV; vertex_shader_info.code = spirv_vertex; vertex_shader_info.code_size = sizeof(spirv_vertex); - fragment_shader_info.format = SDL_GPU_SHADERFORMAT_SPIRV; fragment_shader_info.code = spirv_fragment; fragment_shader_info.code_size = sizeof(spirv_fragment); } - else if (strcmp(driver,"direct3d12") == 0) + else if (strcmp(driver, "direct3d12") == 0) { vertex_shader_info.format = SDL_GPU_SHADERFORMAT_DXBC; vertex_shader_info.code = dxbc_vertex; vertex_shader_info.code_size = sizeof(dxbc_vertex); - fragment_shader_info.format = SDL_GPU_SHADERFORMAT_DXBC; fragment_shader_info.code = dxbc_fragment; fragment_shader_info.code_size = sizeof(dxbc_fragment); @@ -427,25 +416,23 @@ static void Imgui_ImplSDLGPU_CreateShaders() vertex_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB; vertex_shader_info.code = metallib_vertex; vertex_shader_info.code_size = sizeof(metallib_vertex); - fragment_shader_info.entrypoint = "main0"; fragment_shader_info.format = SDL_GPU_SHADERFORMAT_METALLIB; fragment_shader_info.code = metallib_fragment; fragment_shader_info.code_size = sizeof(metallib_fragment); } #endif - bd->VertexShader = SDL_CreateGPUShader(v->GpuDevice,&vertex_shader_info); - bd->FragmentShader = SDL_CreateGPUShader(v->GpuDevice,&fragment_shader_info); - + bd->VertexShader = SDL_CreateGPUShader(v->GpuDevice, &vertex_shader_info); + bd->FragmentShader = SDL_CreateGPUShader(v->GpuDevice, &fragment_shader_info); IM_ASSERT(bd->VertexShader != nullptr && "Failed to create vertex shader, call SDL_GetError() for more information"); IM_ASSERT(bd->FragmentShader != nullptr && "Failed to create fragment shader, call SDL_GetError() for more information"); } -static void ImGui_ImplSDLGPU_CreateGraphicsPipeline() +static void ImGui_ImplSDLGPU3_CreateGraphicsPipeline() { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; - Imgui_ImplSDLGPU_CreateShaders(); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + Imgui_ImplSDLGPU3_CreateShaders(); SDL_GPUVertexBufferDescription vertex_buffer_desc[1]; vertex_buffer_desc[0].slot = 0; @@ -520,14 +507,14 @@ static void ImGui_ImplSDLGPU_CreateGraphicsPipeline() pipeline_info.depth_stencil_state = depth_stencil_state; pipeline_info.target_info = target_info; - bd->Pipeline = SDL_CreateGPUGraphicsPipeline(v->GpuDevice,&pipeline_info); + bd->Pipeline = SDL_CreateGPUGraphicsPipeline(v->GpuDevice, &pipeline_info); IM_ASSERT(bd->Pipeline != nullptr && "Failed to create graphics pipeline, call SDL_GetError() for more information"); } -bool ImGui_ImplSDLGPU_CreateDeviceObjects() +bool ImGui_ImplSDLGPU3_CreateDeviceObjects() { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; if (!bd->FontSampler) { @@ -546,53 +533,53 @@ bool ImGui_ImplSDLGPU_CreateDeviceObjects() sampler_info.max_anisotropy = 1.0f; sampler_info.enable_compare = false; - bd->FontSampler = SDL_CreateGPUSampler(v->GpuDevice,&sampler_info); + bd->FontSampler = SDL_CreateGPUSampler(v->GpuDevice, &sampler_info); bd->FontBinding.sampler = bd->FontSampler; IM_ASSERT(bd->FontSampler != nullptr && "Failed to create font sampler, call SDL_GetError() for more information"); } - ImGui_ImplSDLGPU_CreateGraphicsPipeline(); + ImGui_ImplSDLGPU3_CreateGraphicsPipeline(); return true; } -void ImGui_ImplSDLGPU_DestroyFrameData() +void ImGui_ImplSDLGPU3_DestroyFrameData() { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; - SDL_ReleaseGPUBuffer(v->GpuDevice,bd->MainWindowFrameData.VertexBuffer); - SDL_ReleaseGPUBuffer(v->GpuDevice,bd->MainWindowFrameData.IndexBuffer); + SDL_ReleaseGPUBuffer(v->GpuDevice, bd->MainWindowFrameData.VertexBuffer); + SDL_ReleaseGPUBuffer(v->GpuDevice, bd->MainWindowFrameData.IndexBuffer); bd->MainWindowFrameData.VertexBuffer = nullptr; bd->MainWindowFrameData.IndexBuffer = nullptr; bd->MainWindowFrameData.VertexBufferSize = 0; bd->MainWindowFrameData.IndexBufferSize = 0; } -void ImGui_ImplSDLGPU_DestroyDeviceObjects() +void ImGui_ImplSDLGPU3_DestroyDeviceObjects() { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - ImGui_ImplSDLGPU_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; - ImGui_ImplSDLGPU_DestroyFrameData(); - ImGui_ImplSDLGPU_DestroyFontsTexture(); + ImGui_ImplSDLGPU3_DestroyFrameData(); + ImGui_ImplSDLGPU3_DestroyFontsTexture(); - if(bd->VertexShader) { SDL_ReleaseGPUShader(v->GpuDevice,bd->VertexShader); bd->VertexShader = nullptr;} - if(bd->FragmentShader) { SDL_ReleaseGPUShader(v->GpuDevice,bd->FragmentShader); bd->FragmentShader = nullptr;} - if(bd->FontSampler) { SDL_ReleaseGPUSampler(v->GpuDevice, bd->FontSampler); bd->FontSampler = nullptr;} - if(bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->GpuDevice,bd->Pipeline); bd->Pipeline = nullptr;} + if (bd->VertexShader) { SDL_ReleaseGPUShader(v->GpuDevice, bd->VertexShader); bd->VertexShader = nullptr;} + if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->GpuDevice, bd->FragmentShader); bd->FragmentShader = nullptr;} + if (bd->FontSampler) { SDL_ReleaseGPUSampler(v->GpuDevice, bd->FontSampler); bd->FontSampler = nullptr;} + if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->GpuDevice, bd->Pipeline); bd->Pipeline = nullptr;} } -bool ImGui_ImplSDLGPU_Init(ImGui_ImplSDLGPU_InitInfo* info) +bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) { ImGuiIO& io = ImGui::GetIO(); IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); // Setup backend capabilities flags - ImGui_ImplSDLGPU_Data* bd = IM_NEW(ImGui_ImplSDLGPU_Data)(); + ImGui_ImplSDLGPU3_Data* bd = IM_NEW(ImGui_ImplSDLGPU3_Data)(); io.BackendRendererUserData = (void*)bd; - io.BackendRendererName = "imgui_impl_sdlgpu"; + io.BackendRendererName = "imgui_impl_sdlgpu3"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. IM_ASSERT(info->GpuDevice != nullptr); @@ -600,31 +587,31 @@ bool ImGui_ImplSDLGPU_Init(ImGui_ImplSDLGPU_InitInfo* info) bd->GPUInitInfo = *info; - ImGui_ImplSDLGPU_CreateDeviceObjects(); + ImGui_ImplSDLGPU3_CreateDeviceObjects(); return true; } -void ImGui_ImplSDLGPU_Shutdown() +void ImGui_ImplSDLGPU3_Shutdown() { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLGPU_DestroyDeviceObjects(); + ImGui_ImplSDLGPU3_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; IM_DELETE(bd); } -void ImGui_ImplSDLGPU_NewFrame() +void ImGui_ImplSDLGPU3_NewFrame() { - ImGui_ImplSDLGPU_Data* bd = ImGui_ImplSDLGPU_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?"); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLGPU3_Init()?"); - if(!bd->FontTexture) - ImGui_ImplSDLGPU_CreateFontsTexture(); + if (!bd->FontTexture) + ImGui_ImplSDLGPU3_CreateFontsTexture(); } #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 18d3001e400c..ff9c751c8660 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -1,4 +1,4 @@ -// dear imgui: Renderer Backend for SDL_Gpu +// dear imgui: Renderer Backend for SDL_GPU // This needs to be used along with the SDL3 Platform Backend // Implemented features: @@ -27,7 +27,7 @@ // Initialization data, for ImGui_ImplSDLGPU_Init() // - Remember to set ColorTargetFormat to the correct format. If you're rendering to the swapchain, call SDL_GetGPUSwapchainTextureFormat to query the right value -struct ImGui_ImplSDLGPU_InitInfo +struct ImGui_ImplSDLGPU3_InitInfo { SDL_GPUDevice* GpuDevice = nullptr; SDL_GPUTextureFormat ColorTargetFormat = SDL_GPU_TEXTUREFORMAT_INVALID; @@ -35,12 +35,12 @@ struct ImGui_ImplSDLGPU_InitInfo }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplSDLGPU_Init(ImGui_ImplSDLGPU_InitInfo* info); -IMGUI_IMPL_API void ImGui_ImplSDLGPU_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplSDLGPU_NewFrame(); -IMGUI_IMPL_API void Imgui_ImplSDLGPU_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); -IMGUI_IMPL_API void ImGui_ImplSDLGPU_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); -IMGUI_IMPL_API bool ImGui_ImplSDLGPU_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLGPU_DestroyFontsTexture(); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_NewFrame(); +IMGUI_IMPL_API void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyFontsTexture(); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/sdlgpu3/build_instructions.txt b/backends/sdlgpu3/build_instructions.txt index 751dc97a4e0b..25f4a5d28318 100644 --- a/backends/sdlgpu3/build_instructions.txt +++ b/backends/sdlgpu3/build_instructions.txt @@ -1,3 +1,7 @@ + +Instructions to rebuild imgui_impl_sdlgpu3_shaders.h +(You don't need to copy this folder if you are using the backend as-is) + 1) Compile the raw shader files to SPIRV: glslc -o vertex.spv -c shader.vert @@ -33,4 +37,4 @@ Proceed to step 4 -4) Either find a way to load the shader bytecode from file, or use a tool like https://notisrac.github.io/FileToCArray/ to convert the file to a uint8_t array \ No newline at end of file +4) Use a tool like https://notisrac.github.io/FileToCArray/ or misc/fonts/binary_to_compressed_c.cpp in imgui repository to convert the file to a uint8_t array. diff --git a/backends/sdlgpu3/shader.frag b/backends/sdlgpu3/shader.frag index 2de1f76a3b23..ab9ce184e0fa 100644 --- a/backends/sdlgpu3/shader.frag +++ b/backends/sdlgpu3/shader.frag @@ -3,7 +3,8 @@ layout(location = 0) out vec4 fColor; layout(set=2, binding=0) uniform sampler2D sTexture; -layout(location = 0) in struct { +layout(location = 0) in struct +{ vec4 Color; vec2 UV; } In; @@ -11,4 +12,4 @@ layout(location = 0) in struct { void main() { fColor = In.Color * texture(sTexture, In.UV.st); -} \ No newline at end of file +} diff --git a/backends/sdlgpu3/shader.vert b/backends/sdlgpu3/shader.vert index 3363da8b2a7b..3a85a9038192 100644 --- a/backends/sdlgpu3/shader.vert +++ b/backends/sdlgpu3/shader.vert @@ -3,12 +3,14 @@ layout(location = 0) in vec2 aPos; layout(location = 1) in vec2 aUV; layout(location = 2) in vec4 aColor; -layout(set=1,binding=0) uniform UBO { +layout(set=1,binding=0) uniform UBO +{ vec2 uScale; vec2 uTranslate; } ubo; -layout(location = 0) out struct { +layout(location = 0) out struct +{ vec4 Color; vec2 UV; } Out; @@ -19,4 +21,4 @@ void main() Out.UV = aUV; gl_Position = vec4(aPos * ubo.uScale + ubo.uTranslate, 0, 1); gl_Position.y *= -1.0f; -} \ No newline at end of file +} diff --git a/backends/vulkan/build_instructions.txt b/backends/vulkan/build_instructions.txt new file mode 100644 index 000000000000..1f028d96f53e --- /dev/null +++ b/backends/vulkan/build_instructions.txt @@ -0,0 +1,4 @@ + +Script to rebuild shaders stored inside imgui_impl_vulkan.h +(You don't need to copy this folder if you are using the backend as-is) + diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 00df8a746418..80b95681037c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,6 +68,7 @@ Other changes: - Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Misc: Fixed MinGW builds uses UTF-8 friendly _wfopen(). (#8300) +- Backends: SDL_GPU for SDL3: Added backend for SDL_GPU! (#8163, #7998, #7988) [@DeltaW0x]. - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] - Backends: Metal: Fixed leaks when using metal-cpp. (#8276, #8166) [@selimsandal] diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 224beb1c16a0..0df73059bda2 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -139,8 +139,8 @@ This support building with Emscripten and targeting WebGL.
Prefer using that if you are using modern GL or WebGL in your application. [example_sdl2_sdlrenderer2/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_sdlrenderer2/)
-SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL2 (most graphics backends are supported underneath)
-= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlrenderer.cpp
+SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL2 example.
+= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlrenderer2.cpp
This requires SDL 2.0.18+ (released November 2021)
[example_sdl2_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_vulkan/)
@@ -149,6 +149,26 @@ SDL2 (Win32, Mac, Linux, etc.) + Vulkan example.
This is quite long and tedious, because: Vulkan.
For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. +[example_sdl3_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_opengl3/)
+SDL3 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example.
+= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_opengl3.cpp
+This uses more modern GL calls and custom shaders.
+This support building with Emscripten and targeting WebGL.
+ +[example_sdl3_sdlgpu3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_sdlgpu3/)
+SDL3 (Win32, Mac, Linux, etc.) + SDL_GPU for SDL3 example.
+= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_sdlrenderer3.cpp
+ +[example_sdl3_sdlrenderer3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_sdlrenderer3/)
+SDL3 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL3 example.
+= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_sdlrenderer3.cpp
+ +[example_sdl3_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_vulkan/)
+SDL3 (Win32, Mac, Linux, etc.) + Vulkan example.
+= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_vulkan.cpp
+This is quite long and tedious, because: Vulkan.
+For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. + [example_win32_directx9/](https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx9/)
DirectX9 example, Windows only.
= main.cpp + imgui_impl_win32.cpp + imgui_impl_dx9.cpp diff --git a/docs/README.md b/docs/README.md index 388d8eac63af..9b437311af12 100644 --- a/docs/README.md +++ b/docs/README.md @@ -123,7 +123,7 @@ On most platforms and when using C++, **you should be able to use a combination Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles, which is essentially what Backends are doing. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that: setting up a window and using backends. If you follow the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide it should in theory takes you less than an hour to integrate Dear ImGui. **Make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** Officially maintained backends/bindings (in repository): -- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_Renderer, Vulkan, WebGPU. +- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU. - Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android. - Frameworks: Allegro5, Emscripten. diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 6c29962dd0b8..353c10857809 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for SDL_Gpu +// Dear ImGui: standalone example application for SDL3 + SDL_GPU // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq @@ -17,7 +17,6 @@ #include // abort #include - // This example doesn't compile with Emscripten yet! Awaiting SDL3 support. #ifdef __EMSCRIPTEN__ #include "../libs/emscripten/emscripten_mainloop_stub.h" @@ -34,23 +33,23 @@ int main(int, char**) } // Create SDL window graphics context - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDLGpu example", 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); return -1; } - // Create SDL Gpu Device - SDL_GPUDevice* gpuDevice = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB,true,nullptr); - if (gpuDevice == nullptr) + // Create GPU Device + SDL_GPUDevice* gpu_device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB,true,nullptr); + if (gpu_device == nullptr) { printf("Error: SDL_CreateGPUDevice(): %s\n", SDL_GetError()); return -1; } // Claim window for GPU Device - if (!SDL_ClaimWindowForGPUDevice(gpuDevice, window)) + if (!SDL_ClaimWindowForGPUDevice(gpu_device, window)) { printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError()); return -1; @@ -69,11 +68,11 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForOther(window); - ImGui_ImplSDLGPU_InitInfo init_info = {}; - init_info.GpuDevice = gpuDevice; - init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(gpuDevice, window); + ImGui_ImplSDLGPU3_InitInfo init_info = {}; + init_info.GpuDevice = gpu_device; + init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(gpu_device, window); init_info.MSAASamples = SDL_GPU_SAMPLECOUNT_1; - ImGui_ImplSDLGPU_Init(&init_info); + ImGui_ImplSDLGPU3_Init(&init_info); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. @@ -119,9 +118,9 @@ int main(int, char**) SDL_Delay(10); continue; } - + // Start the Dear ImGui frame - ImGui_ImplSDLGPU_NewFrame(); + ImGui_ImplSDLGPU3_NewFrame(); ImGui_ImplSDL3_NewFrame(); ImGui::NewFrame(); @@ -167,18 +166,15 @@ int main(int, char**) ImDrawData* draw_data = ImGui::GetDrawData(); const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f); - // Acquire a GPU command buffer - SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(gpuDevice); + SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(gpu_device); // Acquire a GPU command buffer - //Acquire a swapchain texture SDL_GPUTexture* swapchain_texture; - SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); + SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); // Acquire a swapchain texture if (swapchain_texture != nullptr && !is_minimized) { - // !!! THIS IS MANDATORY !!! - // Call Imgui_ImplSDLGPU_PrepareDrawData to upload the vertex/index buffer - Imgui_ImplSDLGPU_PrepareDrawData(draw_data, command_buffer); + // This is mandatory: call Imgui_ImplSDLGPU3_PrepareDrawData() to upload the vertex/index buffer! + Imgui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer); // Setup and start a render pass SDL_GPUColorTargetInfo target_info = {}; @@ -190,21 +186,26 @@ int main(int, char**) target_info.layer_or_depth_plane = 0; target_info.cycle = false; SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &target_info, 1, nullptr); - /// Render ImGui - ImGui_ImplSDLGPU_RenderDrawData(draw_data, command_buffer, render_pass); + + // Render ImGui + ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass); + SDL_EndGPURenderPass(render_pass); } + // Submit the command buffer SDL_SubmitGPUCommandBuffer(command_buffer); } // Cleanup - SDL_WaitForGPUIdle(gpuDevice); + SDL_WaitForGPUIdle(gpu_device); ImGui_ImplSDL3_Shutdown(); - ImGui_ImplSDLGPU_Shutdown(); + ImGui_ImplSDLGPU3_Shutdown(); ImGui::DestroyContext(); - SDL_ReleaseWindowFromGPUDevice(gpuDevice, window); - SDL_DestroyGPUDevice(gpuDevice); + + SDL_ReleaseWindowFromGPUDevice(gpu_device, window); + SDL_DestroyGPUDevice(gpu_device); SDL_DestroyWindow(window); SDL_Quit(); + return 0; } From 596e09770d351fad21adbfa7b4f88383c6da1440 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 17:07:53 +0100 Subject: [PATCH 130/716] Backends: SDL3: Added ImGui_ImplSDL3_InitForSDLGPU() for consistency. (#8163, #7998, #7988) --- backends/imgui_impl_sdl3.cpp | 5 +++++ backends/imgui_impl_sdl3.h | 1 + docs/CHANGELOG.txt | 2 ++ examples/example_sdl3_sdlgpu3/main.cpp | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index a167c74cd617..c3935b2abd56 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -531,6 +531,11 @@ bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere return ImGui_ImplSDL3_Init(window, renderer, nullptr); } +bool ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window) +{ + return ImGui_ImplSDL3_Init(window, nullptr, nullptr); +} + bool ImGui_ImplSDL3_InitForOther(SDL_Window* window) { return ImGui_ImplSDL3_Init(window, nullptr, nullptr); diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 0d906a65cd32..ff0e2aed3dd5 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -35,6 +35,7 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); +IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window); IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame(); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 80b95681037c..56ad9b8d00f7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,8 @@ Other changes: - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Misc: Fixed MinGW builds uses UTF-8 friendly _wfopen(). (#8300) - Backends: SDL_GPU for SDL3: Added backend for SDL_GPU! (#8163, #7998, #7988) [@DeltaW0x]. +- Backends: SDL3: Added ImGui_ImplSDL3_InitForSDLGPU() for consistency, even + though it is currently not doing anything particular. (#8163, #7998, #7988) - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). [@Helodity] - Backends: Metal: Fixed leaks when using metal-cpp. (#8276, #8166) [@selimsandal] diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 353c10857809..f025c537dea0 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -67,7 +67,7 @@ int main(int, char**) //ImGui::StyleColorsLight(); // Setup Platform/Renderer backends - ImGui_ImplSDL3_InitForOther(window); + ImGui_ImplSDL3_InitForSDLGPU(window); ImGui_ImplSDLGPU3_InitInfo init_info = {}; init_info.GpuDevice = gpu_device; init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(gpu_device, window); From e7fb97208a876a2c57143e9cda0372d878c6abe9 Mon Sep 17 00:00:00 2001 From: Daniel Walz Date: Thu, 9 Jan 2025 23:12:07 +0100 Subject: [PATCH 131/716] Backends: Metal: Added missing IM_UNUSED (#8302) --- backends/imgui_impl_metal.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 3ff905a60cef..1e0c47f52b51 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -143,6 +143,7 @@ bool ImGui_ImplMetal_Init(id device) void ImGui_ImplMetal_Shutdown() { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); + IM_UNUSED(bd); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGui_ImplMetal_DestroyDeviceObjects(); ImGui_ImplMetal_DestroyBackendData(); From 0b8ff4b2382d4bbd5c168b1a5373f86ea3145957 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 23:15:59 +0100 Subject: [PATCH 132/716] Backends, Examples: Vulkan: add IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE. use in descriptor pools sizes. (#6642) --- backends/imgui_impl_vulkan.cpp | 4 +++- backends/imgui_impl_vulkan.h | 6 ++++-- docs/CHANGELOG.txt | 4 ++++ examples/example_glfw_vulkan/main.cpp | 9 +++++---- examples/example_sdl2_vulkan/main.cpp | 9 +++++---- examples/example_sdl3_vulkan/main.cpp | 9 +++++---- examples/example_win32_vulkan/main.cpp | 9 +++++---- 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 4345f2b11554..940ea2d79b15 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-09: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in descriptor pool. (#6642) // 2025-01-06: Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. // 2024-12-11: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) // 2024-11-27: Vulkan: Make user-provided descriptor pool optional. As a convenience, when setting init_info->DescriptorPoolSize the backend will create one itself. (#8172, #4867) @@ -1022,8 +1023,9 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - if (v->DescriptorPoolSize) + if (v->DescriptorPoolSize != 0) { + IM_ASSERT(v->DescriptorPoolSize > IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE); VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 5621acbddb64..3bd9948647c3 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -61,14 +61,16 @@ #define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #endif +// Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). +// It is expected that as early as Q1 2025 the backend will use a few more descriptors. Use this value + number of desired calls to ImGui_ImplVulkan_AddTexture(). +#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (1) // Minimum per atlas + // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] // - About descriptor pool: // - A VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // and must contain a pool size large enough to hold a small number of VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptors. // - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you. -// - Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). -// - It is expected that as early as Q1 2025 the backend will use a few more descriptors, so aim at 10 + number of desierd calls to ImGui_ImplVulkan_AddTexture(). // - About dynamic rendering: // - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. struct ImGui_ImplVulkan_InitInfo diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 56ad9b8d00f7..1b713e17f151 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -79,6 +79,10 @@ Other changes: platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) [@Zer0xFF] - Backends: Vulkan: Added a few more ImGui_ImplVulkanH_XXX helper functions primarily for the purpose of making our examples simpler. +- Backends: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify + how many image sampler descriptors are expected to be available in the provided + descriptor pool. Current backend needs 1 but it is expected that by end of Q1 2025 + this number will grow (will staying a very small number). (#6642) - Backends: DX11: Expose vertex constant buffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handlers. (#6969, #5834, #7468, #3590) - Backends: DX10: Expose ImGui_ImplDX10_RenderState for completeness. (#6969, #5834, #7468, #3590) diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 9f8dced2f18d..b61dcaae0088 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -189,17 +189,18 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool - // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) - // If you wish to load e.g. additional textures you may need to alter pools sizes. + // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1; + pool_info.maxSets = 0; + for (VkDescriptorPoolSize& pool_size : pool_sizes) + pool_info.maxSets += pool_size.descriptorCount; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index fafa8ea42a76..b82ed0b7ace8 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -177,17 +177,18 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool - // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) - // If you wish to load e.g. additional textures you may need to alter pools sizes. + // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1; + pool_info.maxSets = 0; + for (VkDescriptorPoolSize& pool_size : pool_sizes) + pool_info.maxSets += pool_size.descriptorCount; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 569eaeffb871..e36f87194ead 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -182,17 +182,18 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool - // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) - // If you wish to load e.g. additional textures you may need to alter pools sizes. + // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1; + pool_info.maxSets = 0; + for (VkDescriptorPoolSize& pool_size : pool_sizes) + pool_info.maxSets += pool_size.descriptorCount; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 3fabf7a2dec5..c6c138695a13 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -178,17 +178,18 @@ static void SetupVulkan(ImVector instance_extensions) } // Create Descriptor Pool - // The example only requires a single combined image sampler descriptor for the font image and only uses one descriptor set (for that) - // If you wish to load e.g. additional textures you may need to alter pools sizes. + // If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets. { VkDescriptorPoolSize pool_sizes[] = { - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE }, }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - pool_info.maxSets = 1; + pool_info.maxSets = 0; + for (VkDescriptorPoolSize& pool_size : pool_sizes) + pool_info.maxSets += pool_size.descriptorCount; pool_info.poolSizeCount = (uint32_t)IM_ARRAYSIZE(pool_sizes); pool_info.pPoolSizes = pool_sizes; err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool); From 1d962820d8b972d93a4627afc3cb4c09837c298c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 12 Jan 2025 15:11:30 +0100 Subject: [PATCH 133/716] Error Handling: Turned common EndTable() and other TableXXX functions fail cases into recoverable errors. (#1651, #8314) --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 45 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1b713e17f151..bf9f209c4647 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - Error Handling: Fixed bugs recovering from within a table that created a child window, and from nested child windows. (#1651) +- Error Handling: Turned common EndTable() and other TableXXX functions + fail cases into a recoverable error. (#1651, #8314) - InputText: Fixed a bug where character replacements performed from a callback were not applied when pasting from clipbard. (#8229) - InputText: Fixed issue when activating a ReadOnly field when the underlying diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 1ab9c703ec5d..ec25bf906022 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1337,7 +1337,11 @@ void ImGui::EndTable() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && "Only call EndTable() if BeginTable() returns true!"); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "EndTable() call should only be done while in BeginTable() scope!"); + return; + } // This assert would be very useful to catch a common error... unfortunately it would probably trigger in some // cases, and for consistency user may sometimes output empty tables (and still benefit from e.g. outer border) @@ -1560,8 +1564,12 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); - IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!"); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } + IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); if (table->DeclColumnsCount >= table->ColumnsCount) { @@ -1634,7 +1642,11 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit @@ -1711,9 +1723,11 @@ void ImGui::TableSetColumnEnabled(int column_n, bool enabled) { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL); - if (!table) + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); return; + } IM_ASSERT(table->Flags & ImGuiTableFlags_Hideable); // See comments above if (column_n < 0) column_n = table->CurrentColumn; @@ -3034,7 +3048,11 @@ void ImGui::TableHeadersRow() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } // Call layout if not already done. This is automatically done by TableNextRow: we do it here _only_ to make // it easier to debug-step in TableUpdateLayout(). Your own version of this function doesn't need this. @@ -3079,7 +3097,12 @@ void ImGui::TableHeader(const char* label) return; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && "Need to call TableHeader() after BeginTable()!"); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } + IM_ASSERT(table->CurrentColumn != -1); const int column_n = table->CurrentColumn; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -3254,7 +3277,11 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ImGuiTable* table = g.CurrentTable; ImGuiWindow* window = g.CurrentWindow; ImDrawList* draw_list = window->DrawList; - IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } IM_ASSERT(table->CurrentRow == -1 && "Must be first row"); if (max_label_width == 0.0f) From a28ffa81c4a8e244e2682587285a63e3d0f2c67e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 13:26:15 +0100 Subject: [PATCH 134/716] Docs: added more references to IsKeyDown(), InFlags. (#8317) --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 2 +- imgui_internal.h | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bf9f209c4647..9c1b280b3da4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -153,11 +153,12 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking changes: - Commented out pre-1.87 IO system (equivalent to using IMGUI_DISABLE_OBSOLETE_KEYIO or IMGUI_DISABLE_OBSOLETE_FUNCTIONS before). - - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). + - io.KeyMap[] and io.KeysDown[] are removed (obsoleted February 2022). Use IsKeyDown() instead. - io.NavInputs[] and ImGuiNavInput are removed (obsoleted July 2022). - Pre-1.87 backends are not supported: - backends need to call io.AddKeyEvent(), io.AddMouseEvent() instead of writing to io.KeysDown[], io.MouseDown[] fields. - backends need to call io.AddKeyAnalogEvent() for gamepad values instead of writing to io.NavInputs[] fields. + - you can use IsKeyDown() instead of reading from io.KeysDown[]. - For more references: - read 1.87 and 1.88 part of API BREAKING CHANGES in imgui.cpp or read Changelog for 1.87 and 1.88. - read https://github.com/ocornut/imgui/issues/4921 @@ -2390,6 +2391,7 @@ Breaking Changes: - For all calls to IO new functions, the Dear ImGui context should be bound/current. - Reworked IO keyboard input API: (#4921, #2625, #3724) [@thedmd, @ocornut] - Added io.AddKeyEvent() function, obsoleting writing directly to io.KeyMap[], io.KeysDown[] arrays. + - You can use IsKeyDown() instead of reading from io.KeysDown[]. - For keyboard modifiers, you can call io.AddKeyEvent() with ImGuiKey_ModXXX values, obsoleting writing directly to io.KeyCtrl, io.KeyShift etc. - Added io.SetKeyEventNativeData() function (optional) to pass native and old legacy indices. diff --git a/imgui.cpp b/imgui.cpp index bad766f030eb..c676172effd3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -647,7 +647,7 @@ CODE - Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only] note: for all calls to IO new functions, the Dear ImGui context should be bound/current. read https://github.com/ocornut/imgui/issues/4921 for details. - - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. + - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(), ImGui::IsKeyDown(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX) - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX) - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes). diff --git a/imgui_internal.h b/imgui_internal.h index 850136b0db2a..9ff2b6d3e0fd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1247,11 +1247,11 @@ struct ImGuiNextItemData struct ImGuiLastItemData { ImGuiID ID; - ImGuiItemFlags ItemFlags; // See ImGuiItemFlags_ + ImGuiItemFlags ItemFlags; // See ImGuiItemFlags_ (called 'InFlags' before v1.91.4). ImGuiItemStatusFlags StatusFlags; // See ImGuiItemStatusFlags_ ImRect Rect; // Full rectangle ImRect NavRect; // Navigation scoring rectangle (not displayed) - // Rarely used fields are not explicitly cleared, only valid when the corresponding ImGuiItemStatusFlags ar set. + // Rarely used fields are not explicitly cleared, only valid when the corresponding ImGuiItemStatusFlags are set. ImRect DisplayRect; // Display rectangle. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) is set. ImRect ClipRect; // Clip rectangle at the time of submitting item. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasClipRect) is set.. ImGuiKeyChord Shortcut; // Shortcut at the time of submitting item. ONLY VALID IF (StatusFlags & ImGuiItemStatusFlags_HasShortcut) is set.. From a604d4f717bb99a704fcb17d29a6f0dbac78c060 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 10 Jan 2025 17:08:09 +0100 Subject: [PATCH 135/716] Fixed IsItemDeactivated(), IsItemDeactivatedAfterEdit() to work when interrupted before/after the active id is submitted. (#5184, #5904, #6766, #8303, #8004) --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 40 ++++++++++++++++++++++++---------------- imgui.h | 2 +- imgui_internal.h | 16 ++++++++++++---- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9c1b280b3da4..1f1eb05a96fd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,15 @@ Breaking changes: Other changes: +- Fixed issues with IsItemDeactivated() and IsItemDeactivatedAfterEdit() not + emitting a reliable signal when an item is deactivated externally: e.g. + via an explicit clear of focus, clear of active id, opening of modal etc. + (#5184, #5904, #6766, #8303, #8004) + - It used to work when the interruption happened in the frame before the + active item as submitted, but not after. It should work in both cases now. + - While this is not specific to a certain widgets, typically it would + mostly be noticeable on InputText() because it keeps ActiveId for a + longer time while allowing other interaction to happen. - Error Handling: Fixed bugs recovering from within a table that created a child window, and from nested child windows. (#1651) - Error Handling: Turned common EndTable() and other TableXXX functions diff --git a/imgui.cpp b/imgui.cpp index c676172effd3..6b9f47164400 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3930,9 +3930,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) ActiveIdSource = ImGuiInputSource_None; ActiveIdMouseButton = -1; ActiveIdPreviousFrame = 0; - ActiveIdPreviousFrameIsAlive = false; - ActiveIdPreviousFrameHasBeenEditedBefore = false; - ActiveIdPreviousFrameWindow = NULL; + memset(&DeactivatedItemData, 0, sizeof(DeactivatedItemData)); memset(&ActiveIdValueOnActivation, 0, sizeof(ActiveIdValueOnActivation)); LastActiveId = 0; LastActiveIdTimer = 0.0f; @@ -4175,7 +4173,7 @@ void ImGui::Shutdown() g.WindowsById.Clear(); g.NavWindow = NULL; g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL; - g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL; + g.ActiveIdWindow = NULL; g.MovingWindow = NULL; g.KeysRoutingTable.Clear(); @@ -4359,6 +4357,13 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window) g.MovingWindow = NULL; } + // Store deactivate data + ImGuiDeactivatedItemData* deactivated_data = &g.DeactivatedItemData; + deactivated_data->ID = g.ActiveId; + deactivated_data->ElapseFrame = (g.LastItemData.ID == g.ActiveId) ? g.FrameCount : g.FrameCount + 1; // FIXME: OK to use LastItemData? + deactivated_data->HasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; + deactivated_data->IsAlive = (g.ActiveIdIsAlive == g.ActiveId); + // This could be written in a more general way (e.g associate a hook to ActiveId), // but since this is currently quite an exception we'll leave it as is. // One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveID() @@ -5189,11 +5194,8 @@ void ImGui::NewFrame() g.ActiveIdTimer += g.IO.DeltaTime; g.LastActiveIdTimer += g.IO.DeltaTime; g.ActiveIdPreviousFrame = g.ActiveId; - g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow; - g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore; g.ActiveIdIsAlive = 0; g.ActiveIdHasBeenEditedThisFrame = false; - g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdIsJustActivated = false; if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) g.TempInputId = 0; @@ -5202,6 +5204,9 @@ void ImGui::NewFrame() g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingAllKeyboardKeys = false; } + if (g.DeactivatedItemData.ElapseFrame < g.FrameCount) + g.DeactivatedItemData.ID = 0; + g.DeactivatedItemData.IsAlive = false; // Record when we have been stationary as this state is preserved while over same item. // FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values. @@ -5833,13 +5838,13 @@ bool ImGui::IsItemDeactivated() ImGuiContext& g = *GImGui; if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDeactivated) return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Deactivated) != 0; - return (g.ActiveIdPreviousFrame == g.LastItemData.ID && g.ActiveIdPreviousFrame != 0 && g.ActiveId != g.LastItemData.ID); + return (g.DeactivatedItemData.ID == g.LastItemData.ID && g.LastItemData.ID != 0 && g.DeactivatedItemData.ElapseFrame >= g.FrameCount); } bool ImGui::IsItemDeactivatedAfterEdit() { ImGuiContext& g = *GImGui; - return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore)); + return IsItemDeactivated() && g.DeactivatedItemData.HasBeenEditedBefore; } // == (GetItemID() == GetFocusID() && GetFocusID() != 0) @@ -10443,8 +10448,8 @@ void ImGui::KeepAliveID(ImGuiID id) ImGuiContext& g = *GImGui; if (g.ActiveId == id) g.ActiveIdIsAlive = id; - if (g.ActiveIdPreviousFrame == id) - g.ActiveIdPreviousFrameIsAlive = true; + if (g.DeactivatedItemData.ID == id) + g.DeactivatedItemData.IsAlive = true; } // Declare item bounding box for clipping and interaction. @@ -10529,6 +10534,9 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // window->DrawList->AddRect(g.LastItemData.NavRect.Min, g.LastItemData.NavRect.Max, IM_COL32(255,255,0,255)); // [DEBUG] #endif + if (id != 0 && g.DeactivatedItemData.ID == id) + g.DeactivatedItemData.ElapseFrame = g.FrameCount; + // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them) if (is_rect_visible) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Visible; @@ -10888,7 +10896,7 @@ void ImGui::BeginGroup() group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive; group_data.BackupHoveredIdIsAlive = g.HoveredId != 0; group_data.BackupIsSameLine = window->DC.IsSameLine; - group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive; + group_data.BackupDeactivatedIdIsAlive = g.DeactivatedItemData.IsAlive; group_data.EmitItem = true; window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x; @@ -10939,11 +10947,11 @@ void ImGui::EndGroup() // Also if you grep for LastItemId you'll notice it is only used in that context. // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.) const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId; - const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true); + const bool group_contains_deactivated_id = (group_data.BackupDeactivatedIdIsAlive == false) && (g.DeactivatedItemData.IsAlive == true); if (group_contains_curr_active_id) g.LastItemData.ID = g.ActiveId; - else if (group_contains_prev_active_id) - g.LastItemData.ID = g.ActiveIdPreviousFrame; + else if (group_contains_deactivated_id) + g.LastItemData.ID = g.DeactivatedItemData.ID; g.LastItemData.Rect = group_bb; // Forward Hovered flag @@ -10957,7 +10965,7 @@ void ImGui::EndGroup() // Forward Deactivated flag g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDeactivated; - if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame) + if (group_contains_deactivated_id) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Deactivated; g.GroupStack.pop_back(); diff --git a/imgui.h b/imgui.h index 0f7a99862432..5a3a7af6569e 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19164 +#define IMGUI_VERSION_NUM 19165 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 9ff2b6d3e0fd..bb5a5677460e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -140,6 +140,7 @@ struct ImGuiContext; // Main Dear ImGui context struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum) struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum +struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function. struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup() struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box @@ -1070,7 +1071,7 @@ struct IMGUI_API ImGuiGroupData ImVec2 BackupCurrLineSize; float BackupCurrLineTextBaseOffset; ImGuiID BackupActiveIdIsAlive; - bool BackupActiveIdPreviousFrameIsAlive; + bool BackupDeactivatedIdIsAlive; bool BackupHoveredIdIsAlive; bool BackupIsSameLine; bool EmitItem; @@ -1314,6 +1315,15 @@ struct ImGuiPtrOrIndex ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; } }; +// Data used by IsItemDeactivated()/IsItemDeactivatedAfterEdit() functions +struct ImGuiDeactivatedItemData +{ + ImGuiID ID; + int ElapseFrame; + bool HasBeenEditedBefore; + bool IsAlive; +}; + //----------------------------------------------------------------------------- // [SECTION] Popup support //----------------------------------------------------------------------------- @@ -2106,9 +2116,7 @@ struct ImGuiContext ImGuiWindow* ActiveIdWindow; ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad ImGuiID ActiveIdPreviousFrame; - bool ActiveIdPreviousFrameIsAlive; - bool ActiveIdPreviousFrameHasBeenEditedBefore; - ImGuiWindow* ActiveIdPreviousFrameWindow; + ImGuiDeactivatedItemData DeactivatedItemData; ImGuiDataTypeStorage ActiveIdValueOnActivation; // Backup of initial value at the time of activation. ONLY SET BY SPECIFIC WIDGETS: DragXXX and SliderXXX. ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation. float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation. From 00f12b9a09d2a39831eb8dfc4f75f11460768a6e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 15:22:45 +0100 Subject: [PATCH 136/716] InputText: Fixed not calling CallbackEdit on revert/clear with Escape key. (#8273) + rework comments. Seems like there is no reason to not run that path. Amend ancient 9501cd99, f3ab5e625 --- docs/CHANGELOG.txt | 2 ++ imgui.h | 4 ++-- imgui_widgets.cpp | 14 ++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1f1eb05a96fd..5753d10dba16 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,8 @@ Other changes: value is being modified. (#8242) - InputText: Added sanity check to detect some cases of passing a non zero-terminated input buffer. +- InputText: Fixed not calling CallbackEdit on revert/clear with Escape key, + although IsItemEdited() was behaving correctly. (#8273) - Tables: Fixed TableAngledHeadersRow() creating an infinite horizontal scrolling region when the table is hosted in a viewport with negative coordinates. diff --git a/imgui.h b/imgui.h index 5a3a7af6569e..a89a6c621a23 100644 --- a/imgui.h +++ b/imgui.h @@ -1182,7 +1182,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_CallbackAlways = 1 << 20, // Callback on each iteration. User code may query cursor position, modify text buffer. ImGuiInputTextFlags_CallbackCharFilter = 1 << 21, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard. ImGuiInputTextFlags_CallbackResize = 1 << 22, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) - ImGuiInputTextFlags_CallbackEdit = 1 << 23, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) + ImGuiInputTextFlags_CallbackEdit = 1 << 23, // Callback on any edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. // Obsolete names //ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior @@ -2442,7 +2442,7 @@ struct ImGuiIO // Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used. // The callback function should return 0 by default. // Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details) -// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) +// - ImGuiInputTextFlags_CallbackEdit: Callback on buffer edit. Note that InputText() already returns true on edit + you can always use IsItemEdited(). The callback is useful to manipulate the underlying buffer while focus is active. // - ImGuiInputTextFlags_CallbackAlways: Callback on each iteration // - ImGuiInputTextFlags_CallbackCompletion: Callback on pressing TAB // - ImGuiInputTextFlags_CallbackHistory: Callback on pressing Up/Down arrows diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 854f09634bd0..725f6de2aca7 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4977,19 +4977,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } } - // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer - // before clearing ActiveId, even though strictly speaking it wasn't modified on this frame. - // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. - // This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage + // FIXME-OPT: We always reapply the live buffer back to the input buffer before clearing ActiveId, + // even though strictly speaking it wasn't modified on this frame. Should mark dirty state from the stb_textedit callbacks. + // If we do that, need to ensure that as special case, 'validated == true' also writes back. + // This also allows the user to use InputText() without maintaining any user-side storage. // (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object // unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize). - const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); + const bool apply_edit_back_to_user_buffer = true;// !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0); if (apply_edit_back_to_user_buffer) { - // Apply new value immediately - copy modified buffer back + // Apply current edited text immediately. // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer - // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect. - // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks. // User callback if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0) From 32cea853317c6ee1dbfb4f08925b410956366ed7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 15:51:39 +0100 Subject: [PATCH 137/716] Debug Tools: Item Picker: Always available in menu. Tweak Demo Debug Options. (#2673, #1651) --- docs/CHANGELOG.txt | 3 +++ imgui_demo.cpp | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5753d10dba16..8d3ced68e2df 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other changes: a child window, and from nested child windows. (#1651) - Error Handling: Turned common EndTable() and other TableXXX functions fail cases into a recoverable error. (#1651, #8314) +- Error Handling: Exposed some options in Demo->Tools->Debug Options. (#1651) - InputText: Fixed a bug where character replacements performed from a callback were not applied when pasting from clipbard. (#8229) - InputText: Fixed issue when activating a ReadOnly field when the underlying @@ -76,6 +77,8 @@ Other changes: windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) +- Debug Tools: Item Picker: Always available regardless of value of + io.ConfigDebugIsDebuggerPresent. (#2673) - Fonts: Fixed miscalculation of Ellipsis ("...") character width when automatically created from a single comma character, affecting some fonts/settings (not all). - Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c9a21759d456..7bb15d737bee 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -743,19 +743,27 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) #else const bool has_debug_tools = false; #endif + if (ImGui::BeginMenu("Debug Options")) + { + ImGui::BeginDisabled(!has_debug_tools); + ImGui::Checkbox("Highlight ID Conflicts", &io.ConfigDebugHighlightIdConflicts); + ImGui::EndDisabled(); + ImGui::Checkbox("Assert on error recovery", &io.ConfigErrorRecoveryEnableAssert); + ImGui::TextDisabled("(see Demo->Configuration for details & more)"); + ImGui::EndMenu(); + } + ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); bool is_debugger_present = io.ConfigDebugIsDebuggerPresent; - if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present)) + if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools))// && is_debugger_present)) ImGui::DebugStartItemPicker(); if (!is_debugger_present) - ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools."); + ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable some extra features to avoid casual users crashing the application."); ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor); ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout); - ImGui::SeparatorText("Debug Options"); - ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools); ImGui::EndMenu(); } ImGui::EndMenuBar(); From 6fb7d442559a4540d3bbbe70d9dfc4a04d60109b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 16:46:29 +0100 Subject: [PATCH 138/716] Backends: SDL2/SDL3: Comments. (#7672, #7670) --- backends/imgui_impl_sdl2.cpp | 2 ++ backends/imgui_impl_sdl3.cpp | 3 ++- imgui_demo.cpp | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index e937b5496654..0aaf9830a9c5 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -399,6 +399,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr) return false; ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod); + //IMGUI_DEBUG_LOG("SDL_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n", + // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index c3935b2abd56..b8e4dec5ea84 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -375,8 +375,9 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) { if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == nullptr) return false; - //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%d: key=%d, scancode=%d, mod=%X\n", (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP", event->key.key, event->key.scancode, event->key.mod); ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod); + //IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n", + // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod); ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode); io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN)); io.SetKeyEventNativeData(key, event->key.key, event->key.scancode, event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7bb15d737bee..4bc70fe425e0 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -743,6 +743,7 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) #else const bool has_debug_tools = false; #endif + ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); if (ImGui::BeginMenu("Debug Options")) { ImGui::BeginDisabled(!has_debug_tools); @@ -752,8 +753,6 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) ImGui::TextDisabled("(see Demo->Configuration for details & more)"); ImGui::EndMenu(); } - - ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools); ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools); ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools); bool is_debugger_present = io.ConfigDebugIsDebuggerPresent; From 290e402a0206e9c0fb6868f60a007e4f93273d13 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 18:55:09 +0100 Subject: [PATCH 139/716] TreeNode, Tables: added ImGuiTreeNodeFlags_LabelSpanAllColumns. (#8318, #3565) --- docs/CHANGELOG.txt | 4 ++++ imgui.h | 7 ++++--- imgui_demo.cpp | 2 ++ imgui_widgets.cpp | 10 +++++++--- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8d3ced68e2df..8e2a9419a06c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -70,6 +70,10 @@ Other changes: coordinates. - Tables, MultiSelect: Fixed an issue where column width may be mismeasured when calling BeginMultiSelect() while inside a table. (#8250) +- TreeNode, Tables: Added ImGuiTreeNodeFlags_LabelSpanAllColumns to make + the label (not only the frame) also spans all columns. This can be useful + for table rows where you know nothing else is submitted. (#8318, #3565) + Obviously best used with ImGuiTableFlags_NoBordersInBodyUntilResize. - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) diff --git a/imgui.h b/imgui.h index a89a6c621a23..8e2821643162 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19165 +#define IMGUI_VERSION_NUM 19166 #define IMGUI_HAS_TABLE /* @@ -1206,9 +1206,10 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode. ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area). ImGuiTreeNodeFlags_SpanTextWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. - ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (text will still fit in current column) - ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 15, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) + ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (label will still fit in current column) + ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 17, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4bc70fe425e0..548ce1b05d56 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6363,6 +6363,8 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_LabelSpanAllColumns); + ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns"); HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns."); if (ImGui::BeginTable("3ways", 3, flags)) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 725f6de2aca7..44fe25f1aa5c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6532,6 +6532,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // We vertically grow up to current line height up the typical widget height. const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2); const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (g.CurrentTable != NULL); + const bool span_all_columns_label = (flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) != 0 && (g.CurrentTable != NULL); ImRect frame_bb; frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; frame_bb.Min.y = window->DC.CursorPos.y; @@ -6557,7 +6558,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l bool is_open = TreeNodeUpdateNextOpen(storage_id, flags); bool is_visible; - if (span_all_columns) + if (span_all_columns || span_all_columns_label) { // Modify ClipRect for the ItemAdd(), faster than doing a PushColumnsBackground/PushTableBackgroundChannel for every Selectable.. const float backup_clip_rect_min_x = window->ClipRect.Min.x; @@ -6598,7 +6599,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return is_open; } - if (span_all_columns) + if (span_all_columns || span_all_columns_label) { TablePushBackgroundChannel(); g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasClipRect; @@ -6751,7 +6752,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l LogSetNextTextDecoration(">", NULL); } - if (span_all_columns) + if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); // Label @@ -6759,6 +6760,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); else RenderText(text_pos, label, label_end, false); + + if (span_all_columns_label) + TablePopBackgroundChannel(); } if (store_tree_node_stack_data && is_open) From c5f60942bdd9f1fb0ae61f3d82510b0c05c16191 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 19:18:05 +0100 Subject: [PATCH 140/716] Demo: tweak demo for ImGuiTreeNodeFlags_LabelSpanAllColumns. (#8318, #3565) --- imgui_demo.cpp | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 548ce1b05d56..cc8afe388813 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -6357,17 +6357,17 @@ static void ShowDemoWindowTables() IMGUI_DEMO_MARKER("Tables/Tree view"); if (ImGui::TreeNode("Tree view")) { - static ImGuiTableFlags flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; + static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; - static ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAllColumns; - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags, ImGuiTreeNodeFlags_SpanTextWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_SpanAllColumns); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags, ImGuiTreeNodeFlags_LabelSpanAllColumns); + static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanTextWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_LabelSpanAllColumns); ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns"); HelpMarker("See \"Columns flags\" section to configure how indentation is applied to individual columns."); - if (ImGui::BeginTable("3ways", 3, flags)) + if (ImGui::BeginTable("3ways", 3, table_flags)) { // The first column will use the default _WidthStretch when ScrollX is Off and _WidthFixed when ScrollX is On ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_NoHide); @@ -6388,13 +6388,21 @@ static void ShowDemoWindowTables() ImGui::TableNextRow(); ImGui::TableNextColumn(); const bool is_folder = (node->ChildCount > 0); + + ImGuiTreeNodeFlags node_flags = tree_node_flags_base; + if (node != &all_nodes[0]) + node_flags &= ~ImGuiTreeNodeFlags_LabelSpanAllColumns; // Only demonstrate this on the root node. + if (is_folder) { - bool open = ImGui::TreeNodeEx(node->Name, tree_node_flags); - ImGui::TableNextColumn(); - ImGui::TextDisabled("--"); - ImGui::TableNextColumn(); - ImGui::TextUnformatted(node->Type); + bool open = ImGui::TreeNodeEx(node->Name, node_flags); + if ((node_flags & ImGuiTreeNodeFlags_LabelSpanAllColumns) == 0) + { + ImGui::TableNextColumn(); + ImGui::TextDisabled("--"); + ImGui::TableNextColumn(); + ImGui::TextUnformatted(node->Type); + } if (open) { for (int child_n = 0; child_n < node->ChildCount; child_n++) @@ -6404,7 +6412,7 @@ static void ShowDemoWindowTables() } else { - ImGui::TreeNodeEx(node->Name, tree_node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen); + ImGui::TreeNodeEx(node->Name, node_flags | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen); ImGui::TableNextColumn(); ImGui::Text("%d", node->Size); ImGui::TableNextColumn(); @@ -6414,7 +6422,7 @@ static void ShowDemoWindowTables() }; static const MyTreeNode nodes[] = { - { "Root", "Folder", -1, 1, 3 }, // 0 + { "Root with Long Name", "Folder", -1, 1, 3 }, // 0 { "Music", "Folder", -1, 4, 2 }, // 1 { "Textures", "Folder", -1, 6, 3 }, // 2 { "desktop.ini", "System file", 1024, -1,-1 }, // 3 From c38c18c1a072d2f31a15722c81393f0585cef9e7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 19:39:57 +0100 Subject: [PATCH 141/716] Avoid using 1<<31 for ImGuiWindowFlags_NavFlattened as it seems to confuse some binding generators. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 8e2821643162..c71e7521f635 100644 --- a/imgui.h +++ b/imgui.h @@ -1099,8 +1099,8 @@ enum ImGuiWindowFlags_ // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiWindowFlags_NavFlattened = 1 << 29, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call. - ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call. #endif }; From 21902e2f53602ff85e4f23fe4d974864997f4648 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 19:51:15 +0100 Subject: [PATCH 142/716] Backends: SDL_GPU: fixed SDL_GPUViewport initialisation. (#8163, #7998, #7988) Probably harmless. Amend 8bbccf7 --- backends/imgui_impl_sdlgpu3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index e681efdc39ab..7eb5eeb08fc0 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -100,7 +100,7 @@ static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGra viewport.w = (float)fb_width; viewport.h = (float)fb_height; viewport.min_depth = 0.0f; - viewport.min_depth = 1.0f; + viewport.max_depth = 1.0f; SDL_SetGPUViewport(render_pass,&viewport); // Setup scale and translation From 9f8481a842e45c6490a36818841cc8e34ca003c4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 14 Jan 2025 13:14:50 +0100 Subject: [PATCH 143/716] (Breaking) TreeNode: renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth. (#6937) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 1 + imgui.h | 5 +++-- imgui_demo.cpp | 8 ++++---- imgui_widgets.cpp | 4 ++-- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8e2a9419a06c..5e581d0bdc8b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,9 @@ HOW TO UPDATE? Breaking changes: +- TreeNode: renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth + for consistency with other names. Kept redirection enum (will obsolete). (#6937) + Other changes: - Fixed issues with IsItemDeactivated() and IsItemDeactivatedAfterEdit() not diff --git a/imgui.cpp b/imgui.cpp index 6b9f47164400..c0540d697982 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/01/14 (1.91.7) - renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth for consistency with other names. Kept redirection enum (will obsolete). (#6937) - 2024/11/27 (1.91.6) - changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. As a result, old .ini data may be partially lost (docking and tables information particularly). Because some users have crafted and storing .ini data as a way to workaround limitations of the docking API, we are providing a '#define IMGUI_USE_LEGACY_CRC32_ADLER' compile-time option to keep using old CRC32 tables if you cannot afford invalidating old .ini data. diff --git a/imgui.h b/imgui.h index c71e7521f635..44c1027ec031 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19166 +#define IMGUI_VERSION_NUM 19167 #define IMGUI_HAS_TABLE /* @@ -1205,7 +1205,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node. ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode. ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area). - ImGuiTreeNodeFlags_SpanTextWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. + ImGuiTreeNodeFlags_SpanLabelWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text. ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (label will still fit in current column) ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible @@ -1214,6 +1214,7 @@ enum ImGuiTreeNodeFlags_ #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 + ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth,// Renamed in 1.90.7 #endif }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index cc8afe388813..0cb45a508b23 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1122,7 +1122,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &base_flags, ImGuiTreeNodeFlags_SpanTextWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); @@ -1159,9 +1159,9 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Text("This is a drag and drop source"); ImGui::EndDragDropSource(); } - if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth)) + if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) { - // Item 2 has an additional inline button to help demonstrate SpanTextWidth. + // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. ImGui::SameLine(); if (ImGui::SmallButton("button")) {} } @@ -6361,7 +6361,7 @@ static void ShowDemoWindowTables() static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns; ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanTextWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanTextWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_LabelSpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_LabelSpanAllColumns); ImGui::SameLine(); HelpMarker("Useful if you know that you aren't displaying contents in other columns"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 44fe25f1aa5c..7fc082df3f9e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6536,7 +6536,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l ImRect frame_bb; frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x; frame_bb.Min.y = window->DC.CursorPos.y; - frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanTextWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x; + frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : (flags & ImGuiTreeNodeFlags_SpanLabelWidth) ? window->DC.CursorPos.x + text_width + padding.x : window->WorkRect.Max.x; frame_bb.Max.y = window->DC.CursorPos.y + frame_height; if (display_frame) { @@ -6550,7 +6550,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing ImRect interact_bb = frame_bb; - if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanTextWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) + if ((flags & (ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanLabelWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0) interact_bb.Max.x = frame_bb.Min.x + text_width + (label_size.x > 0.0f ? style.ItemSpacing.x * 2.0f : 0.0f); // Compute open and multi-select states before ItemAdd() as it clear NextItem data. From 5c1d2d1e4c562a2ed3efbc64476e703a655b45fd Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 14 Jan 2025 13:16:43 +0100 Subject: [PATCH 144/716] Version 1.91.7 --- docs/CHANGELOG.txt | 22 ++++++++++++---------- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5e581d0bdc8b..462de35fb3df 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,9 +36,11 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.7 WIP (In Progress) + VERSION 1.91.7 (Released 2025-01-14) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.7 + Breaking changes: - TreeNode: renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth @@ -59,9 +61,9 @@ Other changes: a child window, and from nested child windows. (#1651) - Error Handling: Turned common EndTable() and other TableXXX functions fail cases into a recoverable error. (#1651, #8314) -- Error Handling: Exposed some options in Demo->Tools->Debug Options. (#1651) +- Error Handling: Basic error handling options in Demo->Tools->Debug Options. (#1651) - InputText: Fixed a bug where character replacements performed from a callback - were not applied when pasting from clipbard. (#8229) + were not applied when pasting from clipboard. (#8229) - InputText: Fixed issue when activating a ReadOnly field when the underlying value is being modified. (#8242) - InputText: Added sanity check to detect some cases of passing a non @@ -70,12 +72,12 @@ Other changes: although IsItemEdited() was behaving correctly. (#8273) - Tables: Fixed TableAngledHeadersRow() creating an infinite horizontal scrolling region when the table is hosted in a viewport with negative - coordinates. + coordinates (left of primary monitor, with multi-viewports enabled). - Tables, MultiSelect: Fixed an issue where column width may be mismeasured when calling BeginMultiSelect() while inside a table. (#8250) - TreeNode, Tables: Added ImGuiTreeNodeFlags_LabelSpanAllColumns to make - the label (not only the frame) also spans all columns. This can be useful - for table rows where you know nothing else is submitted. (#8318, #3565) + the label (not only the highlight/frame) also spans all columns. This is + useful for table rows where you know nothing else is submitted. (#8318, #3565) Obviously best used with ImGuiTableFlags_NoBordersInBodyUntilResize. - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed @@ -84,13 +86,13 @@ Other changes: windows with the ImGuiWindowFlags_NoNavInputs flag. (#8231) - Debug Tools: Debug Log: hovering 0xXXXXXXXX values in log is allowed even if a popup is blocking mouse access to the debug log window. (#5855) -- Debug Tools: Item Picker: Always available regardless of value of - io.ConfigDebugIsDebuggerPresent. (#2673) +- Debug Tools: Item Picker: Always available in Tools menu regardless of value + of io.ConfigDebugIsDebuggerPresent. (#2673) - Fonts: Fixed miscalculation of Ellipsis ("...") character width when automatically created from a single comma character, affecting some fonts/settings (not all). - Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] -- Misc: Fixed MinGW builds uses UTF-8 friendly _wfopen(). (#8300) +- Misc: Fixed MinGW builds not using UTF-8 friendly _wfopen(). (#8300) - Backends: SDL_GPU for SDL3: Added backend for SDL_GPU! (#8163, #7998, #7988) [@DeltaW0x]. - Backends: SDL3: Added ImGui_ImplSDL3_InitForSDLGPU() for consistency, even though it is currently not doing anything particular. (#8163, #7998, #7988) @@ -105,7 +107,7 @@ Other changes: - Backends: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in the provided descriptor pool. Current backend needs 1 but it is expected that by end of Q1 2025 - this number will grow (will staying a very small number). (#6642) + this number will grow (will stay a small number). (#6642) - Backends: DX11: Expose vertex constant buffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handlers. (#6969, #5834, #7468, #3590) - Backends: DX10: Expose ImGui_ImplDX10_RenderState for completeness. (#6969, #5834, #7468, #3590) diff --git a/imgui.cpp b/imgui.cpp index c0540d697982..63dbd1fe8ae4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 44c1027ec031..0f7bdbbc6bfb 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.7 WIP" -#define IMGUI_VERSION_NUM 19167 +#define IMGUI_VERSION "1.91.7" +#define IMGUI_VERSION_NUM 19170 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0cb45a508b23..d0e41f370cf2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8baaf8b11767..344eae9e8a40 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index bb5a5677460e..f3f915d7ead2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index ec25bf906022..efef5ff74347 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7fc082df3f9e..dd27400cd156 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 WIP +// dear imgui, v1.91.7 // (widgets code) /* From c59a2267d0977d7261a78c884ccf7735345c4060 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 11:58:47 +0100 Subject: [PATCH 145/716] Version 1.91.8 WIP --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 462de35fb3df..373dcd1082b2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.91.8 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.91.7 (Released 2025-01-14) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 63dbd1fe8ae4..678ff2e522f0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 0f7bdbbc6bfb..cd7c925930ae 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.7" -#define IMGUI_VERSION_NUM 19170 +#define IMGUI_VERSION "1.91.8 WIP" +#define IMGUI_VERSION_NUM 19171 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d0e41f370cf2..26c246db68a9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 344eae9e8a40..e8c445dd30b3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index f3f915d7ead2..9db5fde5e2f8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index efef5ff74347..e0df575c440c 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dd27400cd156..71a5c5b9a00e 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.7 +// dear imgui, v1.91.8 WIP // (widgets code) /* From 100075f2be6a16d6569f6c591c2a908394f414eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 12:05:33 +0100 Subject: [PATCH 146/716] Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. + minor tweaks to faciliate branch merging. --- backends/imgui_impl_dx12.cpp | 53 ++++++++++++++++-------------------- docs/CHANGELOG.txt | 3 ++ imgui.cpp | 1 + 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 24fdb7aa0025..6f17f587aff9 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -19,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. // 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. // 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). // 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple. @@ -64,6 +65,8 @@ struct ImGui_ImplDX12_Texture ID3D12Resource* pTextureResource; D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle; D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle; + + ImGui_ImplDX12_Texture() { memset((void*)this, 0, sizeof(*this)); } }; struct ImGui_ImplDX12_Data @@ -180,8 +183,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; - // FIXME: I'm assuming that this only gets called once per frame! - // If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator. + // FIXME: We are assuming that this only gets called once per frame! ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); bd->frameIndex = bd->frameIndex + 1; ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight]; @@ -352,11 +354,11 @@ static void ImGui_ImplDX12_CreateFontsTexture() bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture)); - UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); - UINT uploadSize = height * uploadPitch; + UINT upload_pitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); + UINT upload_size = height * upload_pitch; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Alignment = 0; - desc.Width = uploadSize; + desc.Width = upload_size; desc.Height = 1; desc.DepthOrArraySize = 1; desc.MipLevels = 1; @@ -376,26 +378,28 @@ static void ImGui_ImplDX12_CreateFontsTexture() IM_ASSERT(SUCCEEDED(hr)); void* mapped = nullptr; - D3D12_RANGE range = { 0, uploadSize }; + D3D12_RANGE range = { 0, upload_size }; hr = uploadBuffer->Map(0, &range, &mapped); IM_ASSERT(SUCCEEDED(hr)); for (int y = 0; y < height; y++) - memcpy((void*) ((uintptr_t) mapped + y * uploadPitch), pixels + y * width * 4, width * 4); + memcpy((void*) ((uintptr_t) mapped + y * upload_pitch), pixels + y * width * 4, width * 4); uploadBuffer->Unmap(0, &range); D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; - srcLocation.pResource = uploadBuffer; - srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srcLocation.PlacedFootprint.Footprint.Width = width; - srcLocation.PlacedFootprint.Footprint.Height = height; - srcLocation.PlacedFootprint.Footprint.Depth = 1; - srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch; - D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; - dstLocation.pResource = pTexture; - dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dstLocation.SubresourceIndex = 0; + { + srcLocation.pResource = uploadBuffer; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srcLocation.PlacedFootprint.Footprint.Width = width; + srcLocation.PlacedFootprint.Footprint.Height = height; + srcLocation.PlacedFootprint.Footprint.Depth = 1; + srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch; + + dstLocation.pResource = pTexture; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.SubresourceIndex = 0; + } D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; @@ -412,15 +416,6 @@ static void ImGui_ImplDX12_CreateFontsTexture() HANDLE event = ::CreateEvent(0, 0, 0, 0); IM_ASSERT(event != nullptr); - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.NodeMask = 1; - - ID3D12CommandQueue* cmdQueue = nullptr; - hr = bd->pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue)); - IM_ASSERT(SUCCEEDED(hr)); - ID3D12CommandAllocator* cmdAlloc = nullptr; hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); IM_ASSERT(SUCCEEDED(hr)); @@ -435,6 +430,7 @@ static void ImGui_ImplDX12_CreateFontsTexture() hr = cmdList->Close(); IM_ASSERT(SUCCEEDED(hr)); + ID3D12CommandQueue* cmdQueue = bd->InitInfo.CommandQueue; cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList); hr = cmdQueue->Signal(fence, 1); IM_ASSERT(SUCCEEDED(hr)); @@ -444,7 +440,6 @@ static void ImGui_ImplDX12_CreateFontsTexture() cmdList->Release(); cmdAlloc->Release(); - cmdQueue->Release(); ::CloseHandle(event); fence->Release(); uploadBuffer->Release(); @@ -707,11 +702,11 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (!bd || !bd->pd3dDevice) return; - ImGuiIO& io = ImGui::GetIO(); SafeRelease(bd->pRootSignature); SafeRelease(bd->pPipelineState); // Free SRV descriptor used by texture + ImGuiIO& io = ImGui::GetIO(); ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); SafeRelease(font_tex->pTextureResource); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 373dcd1082b2..7b0f545ee9a8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Backends: DirectX12: Texture upload use the command queue provided in + ImGui_ImplDX12_InitInfo instead of creating its own. + ----------------------------------------------------------------------- VERSION 1.91.7 (Released 2025-01-14) diff --git a/imgui.cpp b/imgui.cpp index 678ff2e522f0..009a9abf1f16 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5086,6 +5086,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() } // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. +// FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! static void SetupDrawListSharedData() { ImGuiContext& g = *GImGui; From 8a9de84cd0130110ce6d1411558a8d59d7169ae3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 13:47:52 +0100 Subject: [PATCH 147/716] FontAtlas: reduced baked IM_DRAWLIST_TEX_LINES_WIDTH_MAX from 63 to 32. (#3245) --- docs/CHANGELOG.txt | 1 + imgui.h | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7b0f545ee9a8..0ca9af5a249a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,7 @@ Breaking changes: Other changes: +- ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) - Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. diff --git a/imgui.h b/imgui.h index cd7c925930ae..d4c8edb365fd 100644 --- a/imgui.h +++ b/imgui.h @@ -2923,7 +2923,7 @@ struct ImGuiSelectionExternalStorage // The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking. #ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX -#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (63) +#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) #endif // ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] @@ -2997,7 +2997,6 @@ struct ImDrawChannel ImVector _IdxBuffer; }; - // Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. // This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call. struct ImDrawListSplitter From 0e21bde77b0647b872cc4e571b3c05f54d2e556e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 13:58:38 +0100 Subject: [PATCH 148/716] Misc shallow merge to reduce diff in other branches. --- backends/imgui_impl_dx10.cpp | 2 +- backends/imgui_impl_opengl2.cpp | 12 +++++++++++- imgui.h | 8 +++++--- imgui_internal.h | 8 ++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 89499af0cbaa..5471eef5311c 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -47,7 +47,7 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif -// DirectX data +// DirectX10 data struct ImGui_ImplDX10_Data { ID3D10Device* pd3dDevice; diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 767731fb39ea..2a255be4c7f7 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -69,6 +69,16 @@ #include #endif +// [Debugging] +//#define IMGUI_IMPL_OPENGL_DEBUG +#ifdef IMGUI_IMPL_OPENGL_DEBUG +#include +#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check +#else +#define GL_CALL(_CALL) _CALL // Call without error check +#endif + +// OpenGL data struct ImGui_ImplOpenGL2_Data { GLuint FontTexture; @@ -155,7 +165,7 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. - glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); + GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height)); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); diff --git a/imgui.h b/imgui.h index d4c8edb365fd..b9a4fe1581b0 100644 --- a/imgui.h +++ b/imgui.h @@ -158,7 +158,7 @@ typedef unsigned int ImU32; // 32-bit unsigned integer (often used to st typedef signed long long ImS64; // 64-bit signed integer typedef unsigned long long ImU64; // 64-bit unsigned integer -// Forward declarations +// Forward declarations: ImDrawList, ImFontAtlas layer struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit() struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback) struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix. @@ -173,6 +173,8 @@ struct ImFontConfig; // Configuration data when adding a font or struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) + +// Forward declarations: ImGui layer struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h) struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO) struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use) @@ -3374,7 +3376,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters //------------------------------------------- - // [BETA] Custom Rectangles/Glyphs API + // [ALPHA] Custom Rectangles/Glyphs API //------------------------------------------- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. @@ -3400,11 +3402,11 @@ struct ImFontAtlas ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). - bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. + bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. bool TexReady; // Set when texture was built matching current font input bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight diff --git a/imgui_internal.h b/imgui_internal.h index 9db5fde5e2f8..12d8f7a51b7a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -130,10 +130,17 @@ Index of this file: // [SECTION] Forward declarations //----------------------------------------------------------------------------- +// Utilities +// (other types which are not forwarded declared are: ImBitArray<>, ImSpan<>, ImSpanAllocator<>, ImPool<>, ImChunkStream<>) struct ImBitVector; // Store 1-bit per value struct ImRect; // An axis-aligned rectangle (2 points) +struct ImGuiTextIndex; // Maintain a line index for a text buffer. + +// ImDrawList/ImFontAtlas struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances + +// ImGui struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others) struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it struct ImGuiContext; // Main Dear ImGui context @@ -736,6 +743,7 @@ struct ImGuiTextIndex // Helper: ImGuiStorage IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key); + //----------------------------------------------------------------------------- // [SECTION] ImDrawList support //----------------------------------------------------------------------------- From 6684984c49bf2975b2f1e257daf0cd216d55f1e8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 15:13:05 +0100 Subject: [PATCH 149/716] Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. --- docs/CHANGELOG.txt | 2 ++ examples/example_win32_directx12/main.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0ca9af5a249a..27e447ec30e4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -44,6 +44,8 @@ Breaking changes: Other changes: - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) +- Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in + provided example, to reduce latency. - Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 392ba18aab14..5b1a7af370bf 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -23,8 +23,8 @@ #endif // Config for example app -static const int APP_NUM_FRAMES_IN_FLIGHT = 3; -static const int APP_NUM_BACK_BUFFERS = 3; +static const int APP_NUM_FRAMES_IN_FLIGHT = 2; +static const int APP_NUM_BACK_BUFFERS = 2; static const int APP_SRV_HEAP_SIZE = 64; struct FrameContext From 8ebf22d3c11ee89840d43f415cb48c947908a927 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 16:10:47 +0100 Subject: [PATCH 150/716] Backends: Vulkan: use ImVector<> for simplicity. --- backends/imgui_impl_vulkan.cpp | 32 +++++++++++++------------------- backends/imgui_impl_vulkan.h | 4 ++-- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 940ea2d79b15..f4bd50694d22 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -216,7 +216,7 @@ struct ImGui_ImplVulkan_WindowRenderBuffers { uint32_t Index; uint32_t Count; - ImGui_ImplVulkan_FrameRenderBuffers* FrameRenderBuffers; + ImVector FrameRenderBuffers; }; struct ImGui_ImplVulkan_Texture @@ -501,12 +501,12 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Allocate array to store enough vertex/index buffers ImGui_ImplVulkan_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers; - if (wrb->FrameRenderBuffers == nullptr) + if (wrb->FrameRenderBuffers.Size == 0) { wrb->Index = 0; wrb->Count = v->ImageCount; - wrb->FrameRenderBuffers = (ImGui_ImplVulkan_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); - memset((void*)wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); + wrb->FrameRenderBuffers.resize(wrb->Count); + memset((void*)wrb->FrameRenderBuffers.Data, 0, wrb->FrameRenderBuffers.size_in_bytes()); } IM_ASSERT(wrb->Count == v->ImageCount); wrb->Index = (wrb->Index + 1) % wrb->Count; @@ -1250,8 +1250,7 @@ void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulk { for (uint32_t n = 0; n < buffers->Count; n++) ImGui_ImplVulkan_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator); - IM_FREE(buffers->FrameRenderBuffers); - buffers->FrameRenderBuffers = nullptr; + buffers->FrameRenderBuffers.clear(); buffers->Index = 0; buffers->Count = 0; } @@ -1460,10 +1459,8 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); for (uint32_t i = 0; i < wd->SemaphoreCount; i++) ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - IM_FREE(wd->Frames); - IM_FREE(wd->FrameSemaphores); - wd->Frames = nullptr; - wd->FrameSemaphores = nullptr; + wd->Frames.clear(); + wd->FrameSemaphores.clear(); wd->ImageCount = 0; if (wd->RenderPass) vkDestroyRenderPass(device, wd->RenderPass, allocator); @@ -1518,12 +1515,11 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers); check_vk_result(err); - IM_ASSERT(wd->Frames == nullptr && wd->FrameSemaphores == nullptr); wd->SemaphoreCount = wd->ImageCount + 1; - wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount); - wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->SemaphoreCount); - memset((void*)wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); - memset((void*)wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->SemaphoreCount); + wd->Frames.resize(wd->ImageCount); + wd->FrameSemaphores.resize(wd->SemaphoreCount); + memset(wd->Frames.Data, 0, wd->Frames.size_in_bytes()); + memset(wd->FrameSemaphores.Data, 0, wd->FrameSemaphores.size_in_bytes()); for (uint32_t i = 0; i < wd->ImageCount; i++) wd->Frames[i].Backbuffer = backbuffers[i]; } @@ -1633,10 +1629,8 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); for (uint32_t i = 0; i < wd->SemaphoreCount; i++) ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - IM_FREE(wd->Frames); - IM_FREE(wd->FrameSemaphores); - wd->Frames = nullptr; - wd->FrameSemaphores = nullptr; + wd->Frames.clear(); + wd->FrameSemaphores.clear(); vkDestroyPipeline(device, wd->Pipeline, allocator); vkDestroyRenderPass(device, wd->RenderPass, allocator); vkDestroySwapchainKHR(device, wd->Swapchain, allocator); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 3bd9948647c3..6f4839c1301b 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -207,8 +207,8 @@ struct ImGui_ImplVulkanH_Window uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) - ImGui_ImplVulkanH_Frame* Frames; - ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores; + ImVector Frames; + ImVector FrameSemaphores; ImGui_ImplVulkanH_Window() { From 0f33d7185fefb5351858e288eb28da698867d461 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 17:25:44 +0100 Subject: [PATCH 151/716] Examples: Vulkan: vkAcquireNextImageKHR() and vkQueuePresentKHR() returning VK_SUBOPTIMAL_KHR keeps moving forward. (#7825, #7831) --- docs/CHANGELOG.txt | 2 ++ examples/example_glfw_vulkan/main.cpp | 18 ++++++++---------- examples/example_sdl2_vulkan/main.cpp | 18 ++++++++---------- examples/example_sdl3_vulkan/main.cpp | 18 ++++++++---------- examples/example_win32_vulkan/main.cpp | 18 ++++++++---------- 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 27e447ec30e4..429785637549 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,8 @@ Other changes: - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. +- Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by + vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister] - Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index b61dcaae0088..31da972dfcf0 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -61,7 +61,7 @@ static void glfw_error_callback(int error, const char* description) } static void check_vk_result(VkResult err) { - if (err == 0) + if (err == VK_SUCCESS) return; fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); if (err < 0) @@ -263,17 +263,15 @@ static void CleanupVulkanWindow() static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) { - VkResult err; - VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; { @@ -342,11 +340,11 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) info.pImageIndices = &wd->FrameIndex; VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index b82ed0b7ace8..0d7a4586e0c8 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -49,7 +49,7 @@ static bool g_SwapChainRebuild = false; static void check_vk_result(VkResult err) { - if (err == 0) + if (err == VK_SUCCESS) return; fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); if (err < 0) @@ -251,17 +251,15 @@ static void CleanupVulkanWindow() static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) { - VkResult err; - VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; { @@ -330,11 +328,11 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) info.pImageIndices = &wd->FrameIndex; VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index e36f87194ead..81f0581e97a9 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -54,7 +54,7 @@ static bool g_SwapChainRebuild = false; static void check_vk_result(VkResult err) { - if (err == 0) + if (err == VK_SUCCESS) return; fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); if (err < 0) @@ -256,17 +256,15 @@ static void CleanupVulkanWindow() static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) { - VkResult err; - VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; { @@ -335,11 +333,11 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) info.pImageIndices = &wd->FrameIndex; VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index c6c138695a13..f337d8e7de5a 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -50,7 +50,7 @@ static bool g_SwapChainRebuild = false; static void check_vk_result(VkResult err) { - if (err == 0) + if (err == VK_SUCCESS) return; fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err); if (err < 0) @@ -252,17 +252,15 @@ static void CleanupVulkanWindow() static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data) { - VkResult err; - VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore; VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore; - err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); + VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; { @@ -331,11 +329,11 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) info.pImageIndices = &wd->FrameIndex; VkResult err = vkQueuePresentKHR(g_Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - { g_SwapChainRebuild = true; + if (err == VK_ERROR_OUT_OF_DATE_KHR) return; - } - check_vk_result(err); + if (err != VK_SUBOPTIMAL_KHR) + check_vk_result(err); wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } From b4a5d1dc531254d7079c3bebdc564fa5817c3be7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 12:42:54 +0100 Subject: [PATCH 152/716] Backends: SDLGPU3: Rename GpuDevice->Device. Expose ImGui_ImplSDLGPU3_CreateDeviceObjects(), ImGui_ImplSDLGPU3_DestroyDeviceObjects(). Misc renaming. (#8163, #7998, #7988) --- backends/imgui_impl_sdlgpu3.cpp | 127 ++++++++++++------------- backends/imgui_impl_sdlgpu3.h | 19 ++-- docs/CHANGELOG.txt | 7 +- examples/example_sdl3_sdlgpu3/main.cpp | 2 +- 4 files changed, 80 insertions(+), 75 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 7eb5eeb08fc0..b508e091aa31 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -21,13 +21,16 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG -// 2025-01-09: SDL_Gpu: Added the SDL_GPU3 backend. +// 2025-01-16: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device. +// 2025-01-09: SDL_GPU: Added the SDL_GPU3 backend. #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_sdlgpu3.h" #include "imgui_impl_sdlgpu3_shaders.h" +// SDL_GPU Data + // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU3_RenderDrawData() struct ImGui_ImplSDLGPU3_FrameData { @@ -37,10 +40,9 @@ struct ImGui_ImplSDLGPU3_FrameData uint32_t IndexBufferSize = 0; }; -// SDL_GPU Data struct ImGui_ImplSDLGPU3_Data { - ImGui_ImplSDLGPU3_InitInfo GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo InitInfo; // Graphics pipeline & shaders SDL_GPUShader* VertexShader = nullptr; @@ -57,8 +59,6 @@ struct ImGui_ImplSDLGPU3_Data }; // Forward Declarations -static bool ImGui_ImplSDLGPU3_CreateDeviceObjects(); -static void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); static void ImGui_ImplSDLGPU3_DestroyFrameData(); //----------------------------------------------------------------------------- @@ -116,16 +116,16 @@ static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGra static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer, uint32_t* old_size, uint32_t new_size, SDL_GPUBufferUsageFlags usage) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - SDL_WaitForGPUIdle(v->GpuDevice); - SDL_ReleaseGPUBuffer(v->GpuDevice, *buffer); + SDL_WaitForGPUIdle(v->Device); + SDL_ReleaseGPUBuffer(v->Device, *buffer); SDL_GPUBufferCreateInfo buffer_info = {}; buffer_info.usage = usage; buffer_info.size = new_size; buffer_info.props = 0; - *buffer = SDL_CreateGPUBuffer(v->GpuDevice, &buffer_info); + *buffer = SDL_CreateGPUBuffer(v->Device, &buffer_info); *old_size = new_size; IM_ASSERT(*buffer != nullptr && "Failed to create GPU Buffer, call SDL_GetError() for more information"); } @@ -142,7 +142,7 @@ void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff return; ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData; uint32_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); @@ -160,13 +160,13 @@ void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff index_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; index_transferbuffer_info.size = index_size; - SDL_GPUTransferBuffer* vertex_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice, &vertex_transferbuffer_info); + SDL_GPUTransferBuffer* vertex_transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &vertex_transferbuffer_info); IM_ASSERT(vertex_transferbuffer != nullptr && "Failed to create the vertex transfer buffer, call SDL_GetError() for more information"); - SDL_GPUTransferBuffer* index_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice, &index_transferbuffer_info); + SDL_GPUTransferBuffer* index_transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &index_transferbuffer_info); IM_ASSERT(index_transferbuffer != nullptr && "Failed to create the index transfer buffer, call SDL_GetError() for more information"); - ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer, true); - ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->GpuDevice, index_transferbuffer, true); + ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->Device, vertex_transferbuffer, true); + ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->Device, index_transferbuffer, true); for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* draw_list = draw_data->CmdLists[n]; @@ -175,8 +175,8 @@ void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff vtx_dst += draw_list->VtxBuffer.Size; idx_dst += draw_list->IdxBuffer.Size; } - SDL_UnmapGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer); - SDL_UnmapGPUTransferBuffer(v->GpuDevice, index_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->Device, vertex_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->Device, index_transferbuffer); SDL_GPUTransferBufferLocation vertex_buffer_location = {}; vertex_buffer_location.offset = 0; @@ -199,8 +199,8 @@ void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff SDL_UploadToGPUBuffer(copy_pass, &vertex_buffer_location, &vertex_buffer_region,true); SDL_UploadToGPUBuffer(copy_pass, &index_buffer_location, &index_buffer_region,true); SDL_EndGPUCopyPass(copy_pass); - SDL_ReleaseGPUTransferBuffer(v->GpuDevice, index_transferbuffer); - SDL_ReleaseGPUTransferBuffer(v->GpuDevice, vertex_transferbuffer); + SDL_ReleaseGPUTransferBuffer(v->Device, index_transferbuffer); + SDL_ReleaseGPUTransferBuffer(v->Device, vertex_transferbuffer); } void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) @@ -278,16 +278,16 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe SDL_SetGPUScissor(render_pass, &scissor_rect); } -bool ImGui_ImplSDLGPU3_CreateFontsTexture() +void ImGui_ImplSDLGPU3_CreateFontsTexture() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; // Destroy existing texture (if any) if (bd->FontTexture) { - SDL_WaitForGPUIdle(v->GpuDevice); + SDL_WaitForGPUIdle(v->Device); ImGui_ImplSDLGPU3_DestroyFontsTexture(); } @@ -308,7 +308,7 @@ bool ImGui_ImplSDLGPU3_CreateFontsTexture() texture_info.num_levels = 1; texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1; - bd->FontTexture = SDL_CreateGPUTexture(v->GpuDevice, &texture_info); + bd->FontTexture = SDL_CreateGPUTexture(v->Device, &texture_info); IM_ASSERT(bd->FontTexture && "Failed to create font texture, call SDL_GetError() for more info"); } @@ -317,39 +317,37 @@ bool ImGui_ImplSDLGPU3_CreateFontsTexture() // Create all the upload structures and upload: { - SDL_GPUTransferBufferCreateInfo font_transferbuffer_info = {}; - font_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - font_transferbuffer_info.size = upload_size; + SDL_GPUTransferBufferCreateInfo transferbuffer_info = {}; + transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + transferbuffer_info.size = upload_size; - SDL_GPUTransferBuffer* font_transferbuffer = SDL_CreateGPUTransferBuffer(v->GpuDevice, &font_transferbuffer_info); - IM_ASSERT(font_transferbuffer != nullptr && "Failed to create font transfer buffer, call SDL_GetError() for more information"); + SDL_GPUTransferBuffer* transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &transferbuffer_info); + IM_ASSERT(transferbuffer != nullptr && "Failed to create font transfer buffer, call SDL_GetError() for more information"); - void* texture_ptr = SDL_MapGPUTransferBuffer(v->GpuDevice, font_transferbuffer, false); + void* texture_ptr = SDL_MapGPUTransferBuffer(v->Device, transferbuffer, false); memcpy(texture_ptr, pixels, upload_size); - SDL_UnmapGPUTransferBuffer(v->GpuDevice, font_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->Device, transferbuffer); - SDL_GPUTextureTransferInfo font_transfer_info = {}; - font_transfer_info.offset = 0; - font_transfer_info.transfer_buffer = font_transferbuffer; + SDL_GPUTextureTransferInfo transfer_info = {}; + transfer_info.offset = 0; + transfer_info.transfer_buffer = transferbuffer; - SDL_GPUTextureRegion font_texture_region = {}; - font_texture_region.texture = bd->FontTexture; - font_texture_region.w = width; - font_texture_region.h = height; - font_texture_region.d = 1; + SDL_GPUTextureRegion texture_region = {}; + texture_region.texture = bd->FontTexture; + texture_region.w = width; + texture_region.h = height; + texture_region.d = 1; - SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(v->GpuDevice); + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(v->Device); SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); - SDL_UploadToGPUTexture(copy_pass, &font_transfer_info, &font_texture_region, false); + SDL_UploadToGPUTexture(copy_pass, &transfer_info, &texture_region, false); SDL_EndGPUCopyPass(copy_pass); SDL_SubmitGPUCommandBuffer(cmd); - SDL_ReleaseGPUTransferBuffer(v->GpuDevice, font_transferbuffer); + SDL_ReleaseGPUTransferBuffer(v->Device, transferbuffer); } // Store our identifier io.Fonts->SetTexID((ImTextureID)&bd->FontBinding); - - return true; } // You probably never need to call this, as it is called by ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_Shutdown(). @@ -357,10 +355,10 @@ void ImGui_ImplSDLGPU3_DestroyFontsTexture() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; if (bd->FontTexture) { - SDL_ReleaseGPUTexture(v->GpuDevice, bd->FontTexture); + SDL_ReleaseGPUTexture(v->Device, bd->FontTexture); bd->FontBinding.texture = nullptr; bd->FontTexture = nullptr; } @@ -371,9 +369,9 @@ static void Imgui_ImplSDLGPU3_CreateShaders() { // Create the shader modules ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - const char* driver = SDL_GetGPUDeviceDriver(v->GpuDevice); + const char* driver = SDL_GetGPUDeviceDriver(v->Device); SDL_GPUShaderCreateInfo vertex_shader_info = {}; vertex_shader_info.entrypoint = "main"; @@ -422,8 +420,8 @@ static void Imgui_ImplSDLGPU3_CreateShaders() fragment_shader_info.code_size = sizeof(metallib_fragment); } #endif - bd->VertexShader = SDL_CreateGPUShader(v->GpuDevice, &vertex_shader_info); - bd->FragmentShader = SDL_CreateGPUShader(v->GpuDevice, &fragment_shader_info); + bd->VertexShader = SDL_CreateGPUShader(v->Device, &vertex_shader_info); + bd->FragmentShader = SDL_CreateGPUShader(v->Device, &fragment_shader_info); IM_ASSERT(bd->VertexShader != nullptr && "Failed to create vertex shader, call SDL_GetError() for more information"); IM_ASSERT(bd->FragmentShader != nullptr && "Failed to create fragment shader, call SDL_GetError() for more information"); } @@ -431,7 +429,7 @@ static void Imgui_ImplSDLGPU3_CreateShaders() static void ImGui_ImplSDLGPU3_CreateGraphicsPipeline() { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; Imgui_ImplSDLGPU3_CreateShaders(); SDL_GPUVertexBufferDescription vertex_buffer_desc[1]; @@ -507,14 +505,14 @@ static void ImGui_ImplSDLGPU3_CreateGraphicsPipeline() pipeline_info.depth_stencil_state = depth_stencil_state; pipeline_info.target_info = target_info; - bd->Pipeline = SDL_CreateGPUGraphicsPipeline(v->GpuDevice, &pipeline_info); + bd->Pipeline = SDL_CreateGPUGraphicsPipeline(v->Device, &pipeline_info); IM_ASSERT(bd->Pipeline != nullptr && "Failed to create graphics pipeline, call SDL_GetError() for more information"); } -bool ImGui_ImplSDLGPU3_CreateDeviceObjects() +void ImGui_ImplSDLGPU3_CreateDeviceObjects() { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; if (!bd->FontSampler) { @@ -533,23 +531,22 @@ bool ImGui_ImplSDLGPU3_CreateDeviceObjects() sampler_info.max_anisotropy = 1.0f; sampler_info.enable_compare = false; - bd->FontSampler = SDL_CreateGPUSampler(v->GpuDevice, &sampler_info); + bd->FontSampler = SDL_CreateGPUSampler(v->Device, &sampler_info); bd->FontBinding.sampler = bd->FontSampler; IM_ASSERT(bd->FontSampler != nullptr && "Failed to create font sampler, call SDL_GetError() for more information"); } ImGui_ImplSDLGPU3_CreateGraphicsPipeline(); - - return true; + ImGui_ImplSDLGPU3_CreateFontsTexture(); } void ImGui_ImplSDLGPU3_DestroyFrameData() { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - SDL_ReleaseGPUBuffer(v->GpuDevice, bd->MainWindowFrameData.VertexBuffer); - SDL_ReleaseGPUBuffer(v->GpuDevice, bd->MainWindowFrameData.IndexBuffer); + SDL_ReleaseGPUBuffer(v->Device, bd->MainWindowFrameData.VertexBuffer); + SDL_ReleaseGPUBuffer(v->Device, bd->MainWindowFrameData.IndexBuffer); bd->MainWindowFrameData.VertexBuffer = nullptr; bd->MainWindowFrameData.IndexBuffer = nullptr; bd->MainWindowFrameData.VertexBufferSize = 0; @@ -559,15 +556,15 @@ void ImGui_ImplSDLGPU3_DestroyFrameData() void ImGui_ImplSDLGPU3_DestroyDeviceObjects() { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->GPUInitInfo; + ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; ImGui_ImplSDLGPU3_DestroyFrameData(); ImGui_ImplSDLGPU3_DestroyFontsTexture(); - if (bd->VertexShader) { SDL_ReleaseGPUShader(v->GpuDevice, bd->VertexShader); bd->VertexShader = nullptr;} - if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->GpuDevice, bd->FragmentShader); bd->FragmentShader = nullptr;} - if (bd->FontSampler) { SDL_ReleaseGPUSampler(v->GpuDevice, bd->FontSampler); bd->FontSampler = nullptr;} - if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->GpuDevice, bd->Pipeline); bd->Pipeline = nullptr;} + if (bd->VertexShader) { SDL_ReleaseGPUShader(v->Device, bd->VertexShader); bd->VertexShader = nullptr;} + if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->Device, bd->FragmentShader); bd->FragmentShader = nullptr;} + if (bd->FontSampler) { SDL_ReleaseGPUSampler(v->Device, bd->FontSampler); bd->FontSampler = nullptr;} + if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr;} } bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) @@ -582,10 +579,10 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) io.BackendRendererName = "imgui_impl_sdlgpu3"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - IM_ASSERT(info->GpuDevice != nullptr); + IM_ASSERT(info->Device != nullptr); IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID); - bd->GPUInitInfo = *info; + bd->InitInfo = *info; ImGui_ImplSDLGPU3_CreateDeviceObjects(); diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index ff9c751c8660..865139e26a0f 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -29,18 +29,21 @@ // - Remember to set ColorTargetFormat to the correct format. If you're rendering to the swapchain, call SDL_GetGPUSwapchainTextureFormat to query the right value struct ImGui_ImplSDLGPU3_InitInfo { - SDL_GPUDevice* GpuDevice = nullptr; + SDL_GPUDevice* Device = nullptr; SDL_GPUTextureFormat ColorTargetFormat = SDL_GPU_TEXTUREFORMAT_INVALID; SDL_GPUSampleCount MSAASamples = SDL_GPU_SAMPLECOUNT_1; }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info); -IMGUI_IMPL_API void ImGui_ImplSDLGPU3_Shutdown(); -IMGUI_IMPL_API void ImGui_ImplSDLGPU3_NewFrame(); -IMGUI_IMPL_API void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); -IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); -IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyFontsTexture(); +IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_Shutdown(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_NewFrame(); +IMGUI_IMPL_API void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); + +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateFontsTexture(); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyFontsTexture(); #endif // #ifndef IMGUI_DISABLE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 429785637549..f04436ac0687 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,9 @@ HOW TO UPDATE? Breaking changes: +- Backends: SDLGPU3: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device + for consistency. (#8163, #7998, #7988) + Other changes: - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) @@ -48,6 +51,8 @@ Other changes: provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister] +- Backends: SDLGPU3: Exposed ImGui_ImplSDLGPU3_CreateDeviceObjects()/_DestroyDeviceObjects(). + Removed return value from ImGui_ImplSDLGPU3_CreateFontsTexture(). (#8163, #7998, #7988) - Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. @@ -110,7 +115,7 @@ Other changes: - Demo: Added label edition to Property Editor demo + fix an ID issue. (#8266) [@moritz-h] - Misc: Fixed misc/cpp/imgui_stdlib.h/.cpp not supporting IMGUI_DISABLE. (#8294) [@juur] - Misc: Fixed MinGW builds not using UTF-8 friendly _wfopen(). (#8300) -- Backends: SDL_GPU for SDL3: Added backend for SDL_GPU! (#8163, #7998, #7988) [@DeltaW0x]. +- Backends: SDLGPU3 for SDL3: Added backend for SDL_GPU! (#8163, #7998, #7988) [@DeltaW0x]. - Backends: SDL3: Added ImGui_ImplSDL3_InitForSDLGPU() for consistency, even though it is currently not doing anything particular. (#8163, #7998, #7988) - Backends: Allegro5: Avoid calling al_set_mouse_cursor() repeatedly since it appears diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index f025c537dea0..1077639e7fea 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -69,7 +69,7 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForSDLGPU(window); ImGui_ImplSDLGPU3_InitInfo init_info = {}; - init_info.GpuDevice = gpu_device; + init_info.Device = gpu_device; init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(gpu_device, window); init_info.MSAASamples = SDL_GPU_SAMPLECOUNT_1; ImGui_ImplSDLGPU3_Init(&init_info); From 007735737a4f1895fc9e578ce5420874d6875bd9 Mon Sep 17 00:00:00 2001 From: Diego Mateos Date: Thu, 16 Jan 2025 17:10:26 +0100 Subject: [PATCH 153/716] Ignore vscode artifacts (#8324) --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f632636e0fdd..15a908273eae 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,9 @@ examples/example_sdl2_opengl3/web/* .idea cmake-build-* +## VS code artifacts +.vscode + ## Unix executables from our example Makefiles examples/example_glfw_metal/example_glfw_metal examples/example_glfw_opengl2/example_glfw_opengl2 From 4c64ba16c54823e77a719d6b599e824f066f5f92 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 17:42:00 +0100 Subject: [PATCH 154/716] imgui_freetype: fixed issue where glyph advances would incorrectly be snapped to pixels. --- docs/CHANGELOG.txt | 4 ++++ misc/freetype/imgui_freetype.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f04436ac0687..f543799f0c8d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,10 @@ Breaking changes: Other changes: - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) +- imgui_freetype: fixed issue where glyph advances would incorrectly be + snapped to pixels. Effectively it would only be noticeable when hinting + is disabled with ImGuiFreeTypeBuilderFlags_NoHinting, as hinting itself + snaps glyph advances. - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 997bc4340bd5..421fdba63436 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -104,6 +104,9 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_ // Code //------------------------------------------------------------------------- +#define FT_CEIL(X) (((X + 63) & -64) / 64) // From SDL_ttf: Handy routines for converting from fixed point +#define FT_SCALEFACTOR 64.0f + namespace { // Glyph metrics: @@ -182,9 +185,6 @@ namespace float InvRasterizationDensity; }; - // From SDL_ttf: Handy routines for converting from fixed point - #define FT_CEIL(X) (((X + 63) & -64) / 64) - bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags) { FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); @@ -316,7 +316,7 @@ namespace out_glyph_info->Height = (int)ft_bitmap->rows; out_glyph_info->OffsetX = Face->glyph->bitmap_left; out_glyph_info->OffsetY = -Face->glyph->bitmap_top; - out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x); + out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR; out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); return ft_bitmap; From b7c27c5333bca2d9b7958b3a12a1438ab18d20d7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 19:07:09 +0100 Subject: [PATCH 155/716] Windows: legacy SetWindowFontScale() is properly inherited by nested child windows. (#2701, #8138, #1018) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 5 ++++- imgui.h | 2 +- imgui_internal.h | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f543799f0c8d..c69c017d9961 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,9 @@ Other changes: snapped to pixels. Effectively it would only be noticeable when hinting is disabled with ImGuiFreeTypeBuilderFlags_NoHinting, as hinting itself snaps glyph advances. +- Windows: legacy SetWindowFontScale() is properly inherited by nested child + windows. Note that an upcoming major release should make this obsolete, + but in the meanwhile it works better now. (#2701, #8138, #1018) - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/imgui.cpp b/imgui.cpp index 009a9abf1f16..613bef69a528 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4276,7 +4276,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); LastFrameActive = -1; LastTimeActive = -1.0f; - FontWindowScale = 1.0f; + FontWindowScale = FontWindowScaleParents = 1.0f; SettingsOffset = -1; DrawList = &DrawListInst; DrawList->_OwnerName = Name; @@ -7037,6 +7037,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // There's little point to expose a flag to set this: because the interesting cases won't be using parent_window_in_stack, // e.g. linking a tool window in a standalone viewport to a document window, regardless of their Begin() stack parenting. (#6798) window->ParentWindowForFocusRoute = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window_in_stack : NULL; + + // Inherent SetWindowFontScale() from parent until we fix this system... + window->FontWindowScaleParents = parent_window ? parent_window->FontWindowScaleParents * parent_window->FontWindowScale : 1.0f; } // Add to focus scope stack diff --git a/imgui.h b/imgui.h index b9a4fe1581b0..b111407e2fae 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.8 WIP" -#define IMGUI_VERSION_NUM 19171 +#define IMGUI_VERSION_NUM 19172 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 12d8f7a51b7a..b98aafca8668 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2551,6 +2551,7 @@ struct IMGUI_API ImGuiWindow ImGuiStorage StateStorage; ImVector ColumnsStorage; float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() + float FontWindowScaleParents; int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) @@ -2585,7 +2586,7 @@ struct IMGUI_API ImGuiWindow // We don't use g.FontSize because the window may be != g.CurrentWindow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; } + float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); } }; From f2262eb81aa2a86f8acc9d9ef5996f6a14429d4d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 19:46:54 +0100 Subject: [PATCH 156/716] Windows: latch FontRefSize at time of Begin(), consistent with e.g. TitleBarHeight, and to avoid calling CalcFontSize() on non-current window. --- imgui.cpp | 14 ++++++++------ imgui_internal.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 613bef69a528..7c08e6e87d4b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4276,6 +4276,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX); LastFrameActive = -1; LastTimeActive = -1.0f; + FontRefSize = 0.0f; FontWindowScale = FontWindowScaleParents = 1.0f; SettingsOffset = -1; DrawList = &DrawListInst; @@ -7201,6 +7202,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y; window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontSize + g.Style.FramePadding.y * 2.0f; window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0f : 0.0f; + window->FontRefSize = g.FontSize; // Lock this to discourage calling window->CalcFontSize() outside of current window. // Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible. // Those flags will be altered further down in the function depending on more conditions. @@ -9649,7 +9651,7 @@ void ImGui::UpdateMouseWheel() { LockWheelingWindow(window, wheel.x); float max_step = window->InnerRect.GetWidth() * 0.67f; - float scroll_step = ImTrunc(ImMin(2 * window->CalcFontSize(), max_step)); + float scroll_step = ImTrunc(ImMin(2 * window->FontRefSize, max_step)); SetScrollX(window, window->Scroll.x - wheel.x * scroll_step); g.WheelingWindowScrolledFrame = g.FrameCount; } @@ -9657,7 +9659,7 @@ void ImGui::UpdateMouseWheel() { LockWheelingWindow(window, wheel.y); float max_step = window->InnerRect.GetHeight() * 0.67f; - float scroll_step = ImTrunc(ImMin(5 * window->CalcFontSize(), max_step)); + float scroll_step = ImTrunc(ImMin(5 * window->FontRefSize, max_step)); SetScrollY(window, window->Scroll.y - wheel.y * scroll_step); g.WheelingWindowScrolledFrame = g.FrameCount; } @@ -12987,7 +12989,7 @@ static void ImGui::NavUpdate() { // *Fallback* manual-scroll with Nav directional keys when window has no navigable item ImGuiWindow* window = g.NavWindow; - const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. + const float scroll_speed = IM_ROUND(window->FontRefSize * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported. const ImGuiDir move_dir = g.NavMoveDir; if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY && move_dir != ImGuiDir_None) { @@ -13177,8 +13179,8 @@ void ImGui::NavUpdateCreateMoveRequest() if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer])) { IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n"); - float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f); - float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item + float pad_x = ImMin(inner_rect_rel.GetWidth(), window->FontRefSize * 0.5f); + float pad_y = ImMin(inner_rect_rel.GetHeight(), window->FontRefSize * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX; inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +FLT_MAX; inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -FLT_MAX; @@ -13436,7 +13438,7 @@ static float ImGui::NavUpdatePageUpPageDown() else { ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; - const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); + const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->FontRefSize * 1.0f + nav_rect_rel.GetHeight()); float nav_scoring_rect_offset_y = 0.0f; if (IsKeyPressed(ImGuiKey_PageUp, true)) { diff --git a/imgui_internal.h b/imgui_internal.h index b98aafca8668..736031d32e4d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2552,6 +2552,7 @@ struct IMGUI_API ImGuiWindow ImVector ColumnsStorage; float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() float FontWindowScaleParents; + float FontRefSize; // This is a copy of window->CalcFontSize() at the time of Begin(), trying to phase out CalcFontSize() especially as it may be called on non-current window. int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) From 487d7f9a296cec2af496b64f6eb9d939fc8fae33 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 22:30:43 +0100 Subject: [PATCH 157/716] Font: Internals: make used page maps smaller. Since it's extremely rarely used and for iterations only. ~34->16 bytes with ImWchar32. --- imgui.cpp | 4 ++-- imgui.h | 2 +- imgui_draw.cpp | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7c08e6e87d4b..b326c444dc24 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16177,9 +16177,9 @@ void ImGui::DebugNodeFont(ImFont* font) // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) - if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095)) + if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191)) { - base += 4096 - 256; + base += 8192 - 256; continue; } diff --git a/imgui.h b/imgui.h index b111407e2fae..bcf0ac403e3d 100644 --- a/imgui.h +++ b/imgui.h @@ -3461,7 +3461,7 @@ struct ImFont float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) - ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e8c445dd30b3..67a993de54c6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3689,7 +3689,7 @@ ImFont::ImFont() Scale = 1.0f; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; - memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); + memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); } ImFont::~ImFont() @@ -3709,7 +3709,7 @@ void ImFont::ClearOutputData() DirtyLookupTables = true; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; - memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); + memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); } static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) @@ -3732,7 +3732,7 @@ void ImFont::BuildLookupTable() IndexAdvanceX.clear(); IndexLookup.clear(); DirtyLookupTables = false; - memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap)); + memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); GrowIndex(max_codepoint + 1); for (int i = 0; i < Glyphs.Size; i++) { @@ -3741,8 +3741,8 @@ void ImFont::BuildLookupTable() IndexLookup[codepoint] = (ImWchar)i; // Mark 4K page as used - const int page_n = codepoint / 4096; - Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + const int page_n = codepoint / 8192; + Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); } // Create a glyph to handle TAB @@ -3804,15 +3804,15 @@ void ImFont::BuildLookupTable() } } -// API is designed this way to avoid exposing the 4K page size +// API is designed this way to avoid exposing the 8K page size // e.g. use with IsGlyphRangeUnused(0, 255) bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) { - unsigned int page_begin = (c_begin / 4096); - unsigned int page_last = (c_last / 4096); + unsigned int page_begin = (c_begin / 8192); + unsigned int page_last = (c_last / 8192); for (unsigned int page_n = page_begin; page_n <= page_last; page_n++) - if ((page_n >> 3) < sizeof(Used4kPagesMap)) - if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7))) + if ((page_n >> 3) < sizeof(Used8kPagesMap)) + if (Used8kPagesMap[page_n >> 3] & (1 << (page_n & 7))) return false; return true; } From dd89a3741b1d05ab0997d80bfe0377070251d300 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 17 Jan 2025 17:11:22 +0100 Subject: [PATCH 158/716] Backends: Vulkan: sharing duplicate code. (#5446, #8326) --- backends/imgui_impl_vulkan.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f4bd50694d22..2bd40f624aed 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1079,6 +1079,15 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; } } +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) +{ + // Manually load those two (see #5446) + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); +} +#endif + bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { // Load function pointers @@ -1094,9 +1103,7 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch #undef IMGUI_VULKAN_FUNC_LOAD #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - // Manually load those two (see #5446) - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); + ImGui_ImplVulkan_LoadDynamicRenderingFunctions(loader_func, user_data); #endif #else IM_UNUSED(loader_func); @@ -1115,8 +1122,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) { #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #ifndef IMGUI_IMPL_VULKAN_USE_LOADER - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdBeginRenderingKHR")); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(vkGetInstanceProcAddr(info->Instance, "vkCmdEndRenderingKHR")); + ImGui_ImplVulkan_LoadDynamicRenderingFunctions([](const char* function_name, void* user_data) { return vkGetInstanceProcAddr((VkInstance)user_data, function_name); }, (void*)info->Instance); #endif IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR != nullptr); IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR != nullptr); From d7454de80a2d51cee6601d275c441987e7aebb5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 17 Jan 2025 18:09:28 +0100 Subject: [PATCH 159/716] Font: minor tweak to struct alignment. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index bcf0ac403e3d..b42fa06371a0 100644 --- a/imgui.h +++ b/imgui.h @@ -3457,10 +3457,10 @@ struct ImFont ImWchar FallbackChar; // 2-4 // out // = FFFD/'?' // Character used if a glyph isn't found. float EllipsisWidth; // 4 // out // Width float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 - bool DirtyLookupTables; // 1 // out // float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + bool DirtyLookupTables; // 1 // out // ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. // Methods From 80c9cd1f6e4ec84034f918de21aba3953dfa9893 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 18 Jan 2025 16:43:17 +0100 Subject: [PATCH 160/716] Font: reduce unnecessary padding in ImFontConfig struct too. --- imgui.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui.h b/imgui.h index b42fa06371a0..82903424a886 100644 --- a/imgui.h +++ b/imgui.h @@ -3233,26 +3233,27 @@ struct ImDrawData // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) //----------------------------------------------------------------------------- +// A font input/source (we may rename this to ImFontSource in the future) struct ImFontConfig { void* FontData; // // TTF/OTF data int FontDataSize; // // TTF/OTF data size bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. + bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. int FontNo; // 0 // Index of font within TTF/OTF file - float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. - bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs - bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered. - ImWchar EllipsisChar; // 0 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. + ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] char Name[40]; // Name (strictly to ease debugging) From aa23f3801b7414989093abf7388144bc4dfd221c Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Fri, 17 Jan 2025 19:18:05 -0300 Subject: [PATCH 161/716] Backends: SDL_Renderer2/3: Use endian-dependent RGBA32 texture format, to match SDL_Color. (#8327) --- backends/imgui_impl_sdlrenderer2.cpp | 3 ++- backends/imgui_impl_sdlrenderer3.cpp | 3 ++- docs/CHANGELOG.txt | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 6d0ee564f1b3..fcc6d5dd3e39 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -21,6 +21,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. // 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. // 2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3. @@ -228,7 +229,7 @@ bool ImGui_ImplSDLRenderer2_CreateFontsTexture() // Upload texture to graphics system // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height); + bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); if (bd->FontTexture == nullptr) { SDL_Log("error creating texture"); diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 1bcf7a228b0a..0cede09be733 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -23,6 +23,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. // 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer3_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-07-01: Update for SDL3 api changes: SDL_RenderGeometryRaw() uint32 version was removed (SDL#9009). // 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. @@ -247,7 +248,7 @@ bool ImGui_ImplSDLRenderer3_CreateFontsTexture() // Upload texture to graphics system // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height); + bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); if (bd->FontTexture == nullptr) { SDL_Log("error creating texture"); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c69c017d9961..f2812a66197b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,6 +60,8 @@ Other changes: vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister] - Backends: SDLGPU3: Exposed ImGui_ImplSDLGPU3_CreateDeviceObjects()/_DestroyDeviceObjects(). Removed return value from ImGui_ImplSDLGPU3_CreateFontsTexture(). (#8163, #7998, #7988) +- Backends: SDL_Renderer2/3: Use endian-dependent RGBA32 texture format, to match + SDL_Color. (#8327) [@dkosmari] - Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. From aa1b4ea861173109a64eef644243f632f388d567 Mon Sep 17 00:00:00 2001 From: Julian Rachele Date: Sun, 19 Jan 2025 16:30:15 -0500 Subject: [PATCH 162/716] Backends: OSX: Remove notification observer when shutting down. (#8331) --- backends/imgui_impl_osx.mm | 2 ++ docs/CHANGELOG.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index c2a5f6378a45..92c26418f8f6 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -29,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-20: Removed notification observer when shutting down. (#8331) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn @@ -497,6 +498,7 @@ void ImGui_ImplOSX_Shutdown() ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); + [[NSNotificationCenter defaultCenter] removeObserver:bd->Observer]; bd->Observer = nullptr; if (bd->Monitor != nullptr) { diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f2812a66197b..c81fc8df0a7c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,7 @@ Other changes: SDL_Color. (#8327) [@dkosmari] - Backends: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. +- Backends: OSX: Removed notification observer when shutting down. (#8331) [@jrachele] ----------------------------------------------------------------------- From 8b0af7fddcba41d2c091b6752451ed9082af777e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Jan 2025 14:30:40 +0100 Subject: [PATCH 163/716] Backends: SDL: update comments regarding API stability, regarding SDL_GPU and SDL_Renderer. --- backends/imgui_impl_sdl3.cpp | 6 ++---- backends/imgui_impl_sdl3.h | 6 ++---- backends/imgui_impl_sdlrenderer2.cpp | 12 +++++++----- backends/imgui_impl_sdlrenderer2.h | 12 +++++++----- backends/imgui_impl_sdlrenderer3.cpp | 18 +++++++++--------- backends/imgui_impl_sdlrenderer3.h | 18 +++++++++--------- 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index b8e4dec5ea84..eb0eef89f5a5 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -1,9 +1,7 @@ -// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*) -// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) +// dear imgui: Platform Backend for SDL3 +// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..) // (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) - // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index ff0e2aed3dd5..5b8973738201 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -1,9 +1,7 @@ -// dear imgui: Platform Backend for SDL3 (*EXPERIMENTAL*) -// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) +// dear imgui: Platform Backend for SDL3 +// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..) // (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.) -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) - // Implemented features: // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index fcc6d5dd3e39..8245854c262c 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -1,11 +1,13 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL2 // (Requires: SDL 2.0.17+) -// Note how SDL_Renderer is an _optional_ component of SDL2. -// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. -// If your application will want to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and -// it might be difficult to step out of those boundaries. +// Note that SDL_Renderer is an _optional_ component of SDL2, which IMHO is now largely obsolete. +// For a multi-platform app consider using other technologies: +// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. You will need to update to SDL3. +// - SDL2+DirectX, SDL2+OpenGL, SDL2+Vulkan: combine SDL with dedicated renderers. +// If your application wants to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user +// and it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index 7aed18d21809..a0337d314753 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -1,11 +1,13 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL2 // (Requires: SDL 2.0.17+) -// Note how SDL_Renderer is an _optional_ component of SDL2. -// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. -// If your application will want to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and -// it might be difficult to step out of those boundaries. +// Note that SDL_Renderer is an _optional_ component of SDL2, which IMHO is now largely obsolete. +// For a multi-platform app consider using other technologies: +// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. You will need to update to SDL3. +// - SDL2+DirectX, SDL2+OpenGL, SDL2+Vulkan: combine SDL with dedicated renderers. +// If your application wants to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user +// and it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 0cede09be733..99253d9643fd 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -1,13 +1,13 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL3 -// (Requires: SDL 3.0.0+) - -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) - -// Note how SDL_Renderer is an _optional_ component of SDL3. -// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. -// If your application will want to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and -// it might be difficult to step out of those boundaries. +// (Requires: SDL 3.1.8+) + +// Note that SDL_Renderer is an _optional_ component of SDL3, which IMHO is now largely obsolete. +// For a multi-platform app consider using other technologies: +// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. +// - SDL3+DirectX, SDL3+OpenGL, SDL3+Vulkan: combine SDL with dedicated renderers. +// If your application wants to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user +// and it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 3a7a51ee545e..3473bcc77e00 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -1,13 +1,13 @@ // dear imgui: Renderer Backend for SDL_Renderer for SDL3 -// (Requires: SDL 3.0.0+) - -// (**IMPORTANT: SDL 3.0.0 is NOT YET RELEASED AND CURRENTLY HAS A FAST CHANGING API. THIS CODE BREAKS OFTEN AS SDL3 CHANGES.**) - -// Note how SDL_Renderer is an _optional_ component of SDL3. -// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX. -// If your application will want to render any non trivial amount of graphics other than UI, -// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and -// it might be difficult to step out of those boundaries. +// (Requires: SDL 3.1.8+) + +// Note that SDL_Renderer is an _optional_ component of SDL3, which IMHO is now largely obsolete. +// For a multi-platform app consider using other technologies: +// - SDL3+SDL_GPU: SDL_GPU is SDL3 new graphics abstraction API. +// - SDL3+DirectX, SDL3+OpenGL, SDL3+Vulkan: combine SDL with dedicated renderers. +// If your application wants to render any non trivial amount of graphics other than UI, +// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user +// and it might be difficult to step out of those boundaries. // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! From 4c2e7bb03557dd28f0a6b6809c3466485cc4c3df Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Jan 2025 15:24:46 +0100 Subject: [PATCH 164/716] Backends: SDL2,SDL3: removed assert preventing using ImGui_ImplSDL2_SetGamepadMode()/ImGui_ImplSDL3_SetGamepadMode() with ImGui_ImplSDL2_GamepadMode_Manual/ImGui_ImplSDL3_GamepadMode_Manual and an empty array. (#8329) --- backends/imgui_impl_sdl2.cpp | 3 ++- backends/imgui_impl_sdl3.cpp | 3 ++- docs/CHANGELOG.txt | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 0aaf9830a9c5..a27962a316bb 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f. // 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: @@ -665,7 +666,7 @@ void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_ ImGui_ImplSDL2_CloseGamepads(); if (mode == ImGui_ImplSDL2_GamepadMode_Manual) { - IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); + IM_ASSERT(manual_gamepads_array != nullptr || manual_gamepads_count <= 0); for (int n = 0; n < manual_gamepads_count; n++) bd->Gamepads.push_back(manual_gamepads_array[n]); } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index eb0eef89f5a5..d5de5443e244 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten. // 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: @@ -635,7 +636,7 @@ void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad* ImGui_ImplSDL3_CloseGamepads(); if (mode == ImGui_ImplSDL3_GamepadMode_Manual) { - IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); + IM_ASSERT(manual_gamepads_array != nullptr || manual_gamepads_count <= 0); for (int n = 0; n < manual_gamepads_count; n++) bd->Gamepads.push_back(manual_gamepads_array[n]); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c81fc8df0a7c..17f62c386f66 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,10 @@ Other changes: provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by vkAcquireNextImageKHR() or vkQueuePresentKHR(). (#7825, #7831) [@NostraMagister] +- Backends: SDL2: removed assert preventing using ImGui_ImplSDL2_SetGamepadMode() + with ImGui_ImplSDL2_GamepadMode_Manual and an empty array. (#8329) +- Backends: SDL3: removed assert preventing using ImGui_ImplSDL3_SetGamepadMode() + with ImGui_ImplSDL3_GamepadMode_Manual and an empty array. (#8329) - Backends: SDLGPU3: Exposed ImGui_ImplSDLGPU3_CreateDeviceObjects()/_DestroyDeviceObjects(). Removed return value from ImGui_ImplSDLGPU3_CreateFontsTexture(). (#8163, #7998, #7988) - Backends: SDL_Renderer2/3: Use endian-dependent RGBA32 texture format, to match From e8779a67b1498ba345dc139a2b2303b17408e14b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Jan 2025 17:55:09 +0100 Subject: [PATCH 165/716] Font: direct AddText()/RenderText() calls don't need to call strlen() if below clipping region. Unlikely to meaningful affect anyone but still.. --- imgui_draw.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 67a993de54c6..97342b35b7e2 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1669,8 +1669,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 // Accept null ranges if (text_begin == text_end || text_begin[0] == 0) return; - if (text_end == NULL) - text_end = text_begin + strlen(text_begin); + // No need to strlen() here: font->RenderText() will do it and may early out. // Pull default font/size from the shared ImDrawListSharedData instance if (font == NULL) @@ -1693,7 +1692,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end) { - AddText(NULL, 0.0f, pos, col, text_begin, text_end); + AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end); } void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) @@ -4125,15 +4124,15 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) { - if (!text_end) - text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. - // Align to be pixel perfect float x = IM_TRUNC(pos.x); float y = IM_TRUNC(pos.y); if (y > clip_rect.w) return; + if (!text_end) + text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + const float scale = size / FontSize; const float line_height = FontSize * scale; const float origin_x = x; From 7ae7c9079038050a3c19d6e768d183301d8a303c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Jan 2025 13:55:44 +0100 Subject: [PATCH 166/716] Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. (#8334) --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 4 ++-- imgui_demo.cpp | 2 +- imgui_widgets.cpp | 20 +++++++++++++++----- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 17f62c386f66..ccb4882da23a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,10 @@ Other changes: - Windows: legacy SetWindowFontScale() is properly inherited by nested child windows. Note that an upcoming major release should make this obsolete, but in the meanwhile it works better now. (#2701, #8138, #1018) +- Tabs, Style: reworked selected overline rendering to better accommodate + for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), + increased default rounding (style.TabRounding). (#8334) [@Kian738, @ocornut] + styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/imgui.cpp b/imgui.cpp index b326c444dc24..f448ab90d21e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1334,11 +1334,11 @@ ImGuiStyle::ImGuiStyle() GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. - TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. + TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. - TabBarOverlineSize = 2.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar. + TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar. TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees). TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 26c246db68a9..e41c0ac5c500 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7966,7 +7966,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); - ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f"); + ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); ImGui::SeparatorText("Rounding"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 71a5c5b9a00e..4f58c4cd2332 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -10150,11 +10150,21 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, TabItemBackground(display_draw_list, bb, flags, tab_col); if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) { - float x_offset = IM_TRUNC(0.4f * style.TabRounding); - if (x_offset < 2.0f * g.CurrentDpiScale) - x_offset = 0.0f; - float y_offset = 1.0f * g.CurrentDpiScale; - display_draw_list->AddLine(bb.GetTL() + ImVec2(x_offset, y_offset), bb.GetTR() + ImVec2(-x_offset, y_offset), GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline), style.TabBarOverlineSize); + // Might be moved to TabItemBackground() ? + ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale); + ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale); + ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); + if (style.TabRounding > 0.0f) + { + float rounding = style.TabRounding; + display_draw_list->PathArcToFast(tl + ImVec2(+rounding, +rounding), rounding, 7, 9); + display_draw_list->PathArcToFast(tr + ImVec2(-rounding, +rounding), rounding, 9, 11); + display_draw_list->PathStroke(overline_col, 0, style.TabBarOverlineSize); + } + else + { + display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize); + } } RenderNavCursor(bb, id); From 2af26b75d13e6f2be97c53d2d3ebf17b1b18a150 Mon Sep 17 00:00:00 2001 From: David Maas Date: Tue, 21 Jan 2025 14:25:39 +0100 Subject: [PATCH 167/716] ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] ImAlphaBlendColors() was broken by ImLerp() change. (cd6c83c) --- docs/CHANGELOG.txt | 1 + imgui_internal.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ccb4882da23a..c7f26c3b7617 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,7 @@ Other changes: - Windows: legacy SetWindowFontScale() is properly inherited by nested child windows. Note that an upcoming major release should make this obsolete, but in the meanwhile it works better now. (#2701, #8138, #1018) +- ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] - Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), increased default rounding (style.TabRounding). (#8334) [@Kian738, @ocornut] diff --git a/imgui_internal.h b/imgui_internal.h index 736031d32e4d..33a6ec8b0bc5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -469,7 +469,7 @@ static inline double ImRsqrt(double x) { return 1.0 / sqrt(x); } template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } -template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * (T)t); } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } template static inline T ImAddClampOverflow(T a, T b, T mn, T mx) { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; } template static inline T ImSubClampOverflow(T a, T b, T mn, T mx) { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; } From bf13442c7cf4a082466dae31d50981ec103a7af7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 21 Jan 2025 14:59:29 +0100 Subject: [PATCH 168/716] Moved ImGuiColorEditFlags_AlphaPreview/ImGuiColorEditFlags_AlphaPreviewHalf flags. Demo: reorganized some of color edit/picker demo section. --- imgui.h | 4 ++-- imgui_demo.cpp | 65 +++++++++++++++++++++++++------------------------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/imgui.h b/imgui.h index 82903424a886..2306667cf9dc 100644 --- a/imgui.h +++ b/imgui.h @@ -1752,11 +1752,11 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) + ImGuiColorEditFlags_AlphaPreview = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 12, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. // User Options (right-click on widget to change some of them). ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. - ImGuiColorEditFlags_AlphaPreview = 1 << 17, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. - ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. ImGuiColorEditFlags_HDR = 1 << 19, // // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well). ImGuiColorEditFlags_DisplayRGB = 1 << 20, // [Display] // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex. ImGuiColorEditFlags_DisplayHSV = 1 << 21, // [Display] // " diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e41c0ac5c500..5100356b38a9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2117,19 +2117,15 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) if (ImGui::TreeNode("Color/Picker Widgets")) { static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); + static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_AlphaPreview; - static bool alpha_preview = true; - static bool alpha_half_preview = false; - static bool drag_and_drop = true; - static bool options_menu = true; - static bool hdr = false; ImGui::SeparatorText("Options"); - ImGui::Checkbox("With Alpha Preview", &alpha_preview); - ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview); - ImGui::Checkbox("With Drag and Drop", &drag_and_drop); - ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); - ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); - ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreview", &base_flags, ImGuiColorEditFlags_AlphaPreview); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); + ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); ImGui::SeparatorText("Inline color editor"); @@ -2137,15 +2133,15 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); HelpMarker( "Click on the color square to open a color picker.\n" "CTRL+click on individual component to input value.\n"); - ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags); + ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); ImGui::Text("Color widget HSV with Alpha:"); - ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags); + ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); ImGui::Text("Color widget with Float Display:"); - ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags); + ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); ImGui::Text("Color button with Picker:"); @@ -2153,7 +2149,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " "be used for the tooltip and picker popup."); - ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags); + ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); ImGui::Text("Color button with Custom Picker Popup:"); @@ -2173,7 +2169,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) } static ImVec4 backup_color; - bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags); + bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags); ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); open_popup |= ImGui::Button("Palette"); if (open_popup) @@ -2185,7 +2181,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) { ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); ImGui::Separator(); - ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); ImGui::SameLine(); ImGui::BeginGroup(); // Lock X position @@ -2227,40 +2223,42 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Text("Color button only:"); static bool no_border = false; ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); - ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); ImGui::SeparatorText("Color picker"); - static bool alpha = true; - static bool alpha_bar = true; - static bool side_preview = true; + static bool ref_color = false; static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); - static int display_mode = 0; static int picker_mode = 0; - ImGui::Checkbox("With Alpha", &alpha); - ImGui::Checkbox("With Alpha Bar", &alpha_bar); - ImGui::Checkbox("With Side Preview", &side_preview); - if (side_preview) + static int display_mode = 0; + static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar; + + ImGui::PushID("Color picker"); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview); + if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview) { ImGui::SameLine(); ImGui::Checkbox("With Ref Color", &ref_color); if (ref_color) { ImGui::SameLine(); - ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags); + ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags); } } - ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0"); + + ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); + ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); + + ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0"); ImGui::SameLine(); HelpMarker( "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); - ImGui::SameLine(); HelpMarker("When not specified explicitly (Auto/Current mode), user can right-click the picker to change mode."); - ImGuiColorEditFlags flags = misc_flags; - if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4() - if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar; - if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview; + + ImGuiColorEditFlags flags = base_flags | color_picker_flags; if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays @@ -2289,6 +2287,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); ImGui::SetNextItemWidth(w); ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + ImGui::PopID(); // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! From 3e6bdc2242ca2e29346b380f76212e64e480a146 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 10:22:31 +0100 Subject: [PATCH 169/716] Examples: SDL3+SDL_GPU: use SDL_GPU_PRESENTMODE_MAILBOX swapchain parameters. --- examples/example_sdl3_sdlgpu3/main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 1077639e7fea..dbc7759ba5d5 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -7,7 +7,7 @@ // - Introduction, links and more at the top of imgui.cpp // Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. -// - Unline other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// - Unlike other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData() BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. #include "imgui.h" @@ -54,6 +54,7 @@ int main(int, char**) printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError()); return -1; } + SDL_SetGPUSwapchainParameters(gpu_device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_MAILBOX); // Setup Dear ImGui context IMGUI_CHECKVERSION(); @@ -140,7 +141,7 @@ int main(int, char**) ImGui::Checkbox("Another Window", &show_another_window); ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + ImGui::ColorEdit4("clear color", (float*)&clear_color); // Edit 3 floats representing a color if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) counter++; @@ -179,7 +180,7 @@ int main(int, char**) // Setup and start a render pass SDL_GPUColorTargetInfo target_info = {}; target_info.texture = swapchain_texture; - target_info.clear_color = SDL_FColor{ clear_color.x,clear_color.y,clear_color.z,clear_color.w }; + target_info.clear_color = SDL_FColor { clear_color.x, clear_color.y, clear_color.z, clear_color.w }; target_info.load_op = SDL_GPU_LOADOP_CLEAR; target_info.store_op = SDL_GPU_STOREOP_STORE; target_info.mip_level = 0; @@ -196,6 +197,7 @@ int main(int, char**) // Submit the command buffer SDL_SubmitGPUCommandBuffer(command_buffer); } + // Cleanup SDL_WaitForGPUIdle(gpu_device); ImGui_ImplSDL3_Shutdown(); From d17e9fc107ef561743e335aaa62641fcd8ce1952 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 10:32:09 +0100 Subject: [PATCH 170/716] Backends: SDL_GPU: shallow tweaks + disable anisotropy in sampler. Examples: SDL+Vulkan: Fixed incorrect defines. --- backends/imgui_impl_sdlgpu3.cpp | 13 +++++++------ examples/example_sdl2_vulkan/main.cpp | 2 +- examples/example_sdl3_vulkan/main.cpp | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index b508e091aa31..74b966227ddd 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -89,8 +89,8 @@ static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGra SDL_GPUBufferBinding index_buffer_binding = {}; index_buffer_binding.buffer = fd->IndexBuffer; index_buffer_binding.offset = 0; - SDL_BindGPUVertexBuffers(render_pass,0,&vertex_buffer_binding,1); - SDL_BindGPUIndexBuffer(render_pass,&index_buffer_binding,sizeof(ImDrawIdx) == 2 ? SDL_GPU_INDEXELEMENTSIZE_16BIT : SDL_GPU_INDEXELEMENTSIZE_32BIT); + SDL_BindGPUVertexBuffers(render_pass,0, &vertex_buffer_binding, 1); + SDL_BindGPUIndexBuffer(render_pass, &index_buffer_binding, sizeof(ImDrawIdx) == 2 ? SDL_GPU_INDEXELEMENTSIZE_16BIT : SDL_GPU_INDEXELEMENTSIZE_32BIT); } // Setup viewport @@ -101,7 +101,7 @@ static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGra viewport.h = (float)fb_height; viewport.min_depth = 0.0f; viewport.max_depth = 1.0f; - SDL_SetGPUViewport(render_pass,&viewport); + SDL_SetGPUViewport(render_pass, &viewport); // Setup scale and translation // Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. @@ -118,6 +118,7 @@ static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer, uint32_t* old_size, uin ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; + // Even though this is fairly rarely called. SDL_WaitForGPUIdle(v->Device); SDL_ReleaseGPUBuffer(v->Device, *buffer); @@ -196,8 +197,8 @@ void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff index_buffer_region.size = index_size; SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(command_buffer); - SDL_UploadToGPUBuffer(copy_pass, &vertex_buffer_location, &vertex_buffer_region,true); - SDL_UploadToGPUBuffer(copy_pass, &index_buffer_location, &index_buffer_region,true); + SDL_UploadToGPUBuffer(copy_pass, &vertex_buffer_location, &vertex_buffer_region, true); + SDL_UploadToGPUBuffer(copy_pass, &index_buffer_location, &index_buffer_region, true); SDL_EndGPUCopyPass(copy_pass); SDL_ReleaseGPUTransferBuffer(v->Device, index_transferbuffer); SDL_ReleaseGPUTransferBuffer(v->Device, vertex_transferbuffer); @@ -527,7 +528,7 @@ void ImGui_ImplSDLGPU3_CreateDeviceObjects() sampler_info.mip_lod_bias = 0.0f; sampler_info.min_lod = -1000.0f; sampler_info.max_lod = 1000.0f; - sampler_info.enable_anisotropy = true; + sampler_info.enable_anisotropy = false; sampler_info.max_anisotropy = 1.0f; sampler_info.enable_compare = false; diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 0d7a4586e0c8..c0282f9328f7 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -217,7 +217,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode -#ifdef APP_UNLIMITED_FRAME_RATE +#ifdef APP_USE_UNLIMITED_FRAME_RATE VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; #else VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 81f0581e97a9..52544c34229a 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -222,7 +222,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode -#ifdef APP_UNLIMITED_FRAME_RATE +#ifdef APP_USE_UNLIMITED_FRAME_RATE VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; #else VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; From fdca6c08adbd71f711261e28f4d75124c14d1cc5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 11:28:47 +0100 Subject: [PATCH 171/716] Inputs: added IsMouseReleasedWithDelay() helper. (#8337, #8320) --- docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 13 +++++++++++++ imgui.h | 2 ++ imgui_demo.cpp | 2 ++ 4 files changed, 23 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c7f26c3b7617..3cce5f1c3efa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,12 @@ Other changes: snapped to pixels. Effectively it would only be noticeable when hinting is disabled with ImGuiFreeTypeBuilderFlags_NoHinting, as hinting itself snaps glyph advances. +- Inputs: added IsMouseReleasedWithDelay() helper. (#8337, #8320) + Use if you absolutely need to distinguish single-click from double-clicks + by introducing a delay. This is a very rarely used UI idiom, but some apps + use this: e.g. MS Explorer single-click on an icon triggers a rename. + Generally use with 'delay >= io.MouseDoubleClickTime' + combine with a + 'io.MouseClickedLastCount == 1' check. - Windows: legacy SetWindowFontScale() is properly inherited by nested child windows. Note that an upcoming major release should make this obsolete, but in the meanwhile it works better now. (#2701, #8138, #1018) diff --git a/imgui.cpp b/imgui.cpp index f448ab90d21e..90639578e652 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9210,6 +9210,17 @@ bool ImGui::IsMouseReleased(ImGuiMouseButton button, ImGuiID owner_id) return g.IO.MouseReleased[button] && TestKeyOwner(MouseButtonToKey(button), owner_id); // Should be same as IsKeyReleased(MouseButtonToKey(button), owner_id) } +// Use if you absolutely need to distinguish single-click from double-click by introducing a delay. +// Generally use with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount == 1' test. +// This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename. +bool ImGui::IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); + const float time_since_release = (float)(g.Time - g.IO.MouseReleasedTime[button]); + return !IsMouseDown(button) && (time_since_release - g.IO.DeltaTime < delay) && (time_since_release >= delay); +} + bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button) { ImGuiContext& g = *GImGui; @@ -9483,6 +9494,8 @@ static void ImGui::UpdateMouseInputs() io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f; io.MouseClickedCount[i] = 0; // Will be filled below io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0f; + if (io.MouseReleased[i]) + io.MouseReleasedTime[i] = g.Time; io.MouseDownDurationPrev[i] = io.MouseDownDuration[i]; io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0.0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f; if (io.MouseClicked[i]) diff --git a/imgui.h b/imgui.h index 2306667cf9dc..e27c3a3d1056 100644 --- a/imgui.h +++ b/imgui.h @@ -1011,6 +1011,7 @@ namespace ImGui IMGUI_API bool IsMouseClicked(ImGuiMouseButton button, bool repeat = false); // did mouse button clicked? (went from !Down to Down). Same as GetMouseClickedCount() == 1. IMGUI_API bool IsMouseReleased(ImGuiMouseButton button); // did mouse button released? (went from Down to !Down) IMGUI_API bool IsMouseDoubleClicked(ImGuiMouseButton button); // did mouse button double-clicked? Same as GetMouseClickedCount() == 2. (note that a double-click will also report IsMouseClicked() == true) + IMGUI_API bool IsMouseReleasedWithDelay(ImGuiMouseButton button, float delay); // delayed mouse release (use very sparingly!). Generally used with 'delay >= io.MouseDoubleClickTime' + combined with a 'io.MouseClickedLastCount==1' test. This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single click on an icon to rename. IMGUI_API int GetMouseClickedCount(ImGuiMouseButton button); // return the number of successive mouse-clicks at the time where a click happen (otherwise 0). IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block. IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available @@ -2405,6 +2406,7 @@ struct ImGuiIO ImU16 MouseClickedCount[5]; // == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down ImU16 MouseClickedLastCount[5]; // Count successive number of clicks. Stays valid after mouse release. Reset after another click is done. bool MouseReleased[5]; // Mouse button went from Down to !Down + double MouseReleasedTime[5]; // Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click). bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5100356b38a9..9f6264a5d279 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7407,6 +7407,8 @@ static void ShowDemoWindowInputs() ImGui::Text("Mouse down:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); } ImGui::Text("Mouse wheel: %.1f", io.MouseWheel); + ImGui::Text("Mouse clicked count:"); + for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseClickedCount[i] > 0) { ImGui::SameLine(); ImGui::Text("b%d: %d", i, io.MouseClickedCount[i]); } // We iterate both legacy native range and named ImGuiKey ranges. This is a little unusual/odd but this allows // displaying the data for old/new backends. From 6906ac979e51ca9b2b60f3d820dd43f8f689884c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 12:12:07 +0100 Subject: [PATCH 172/716] ColorEdit, ColorPicker: (Breaking) redesigned how alpha is displayed in the preview square. (#8335, #1578, #346) Added ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg. Removed ImGuiColorEditFlags_AlphaPreview. --- docs/CHANGELOG.txt | 8 ++++++++ imgui.cpp | 3 +++ imgui.h | 16 +++++++++++++--- imgui_demo.cpp | 11 ++++++----- imgui_widgets.cpp | 22 +++++++++++++--------- 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3cce5f1c3efa..f0aeebbb34cf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,14 @@ HOW TO UPDATE? Breaking changes: +- ColorEdit, ColorPicker: redesigned how alpha is displayed in the preview square. (#8335, #1578, #346) + - Removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. + - Prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. + - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. + - The new flags may be combined better and allow finer controls: + - ImGuiColorEditFlags_AlphaOpaque: disable alpha in the preview, but alpha value still editable. + - ImGuiColorEditFlags_AlphaNoBg: disable rendering a checkerboard background behind transparent color. + - ImGuiColorEditFlags_AlphaPreviewHalf: display half opaque / half transparent preview. - Backends: SDLGPU3: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device for consistency. (#8163, #7998, #7988) diff --git a/imgui.cpp b/imgui.cpp index 90639578e652..0b988f2b47ec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,9 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. + prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. + the new flags (ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg + existing ImGuiColorEditFlags_AlphaPreviewHalf) may be combined better and allow finer controls: - 2025/01/14 (1.91.7) - renamed ImGuiTreeNodeFlags_SpanTextWidth to ImGuiTreeNodeFlags_SpanLabelWidth for consistency with other names. Kept redirection enum (will obsolete). (#6937) - 2024/11/27 (1.91.6) - changed CRC32 table from CRC32-adler to CRC32c polynomial in order to be compatible with the result of SSE 4.2 instructions. As a result, old .ini data may be partially lost (docking and tables information particularly). diff --git a/imgui.h b/imgui.h index e27c3a3d1056..d42a932c296f 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.8 WIP" -#define IMGUI_VERSION_NUM 19172 +#define IMGUI_VERSION_NUM 19173 #define IMGUI_HAS_TABLE /* @@ -1753,8 +1753,14 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_NoSidePreview = 1 << 8, // // ColorPicker: disable bigger color preview on right side of the picker, use small color square preview instead. ImGuiColorEditFlags_NoDragDrop = 1 << 9, // // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source. ImGuiColorEditFlags_NoBorder = 1 << 10, // // ColorButton: disable border (which is enforced by default) - ImGuiColorEditFlags_AlphaPreview = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque. - ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 12, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque. + + // Alpha preview + // - Prior to 1.91.8 (2025/01/21): alpha was made opaque in the preview by default using old name ImGuiColorEditFlags_AlphaPreview. + // - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. + // - The new flags may be combined better and allow finer controls. + ImGuiColorEditFlags_AlphaOpaque = 1 << 11, // // ColorEdit, ColorPicker, ColorButton: disable alpha in the preview,. Contrary to _NoAlpha it may still be edited when calling ColorEdit4()/ColorPicker4(). For ColorButton() this does the same as _NoAlpha. + ImGuiColorEditFlags_AlphaNoBg = 1 << 12, // // ColorEdit, ColorPicker, ColorButton: disable rendering a checkerboard background behind transparent color. + ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 13, // // ColorEdit, ColorPicker, ColorButton: display half opaque / half transparent preview. // User Options (right-click on widget to change some of them). ImGuiColorEditFlags_AlphaBar = 1 << 16, // // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker. @@ -1774,12 +1780,16 @@ enum ImGuiColorEditFlags_ ImGuiColorEditFlags_DefaultOptions_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar, // [Internal] Masks + ImGuiColorEditFlags_AlphaMask_ = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque | ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf, ImGuiColorEditFlags_DisplayMask_ = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex, ImGuiColorEditFlags_DataTypeMask_ = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float, ImGuiColorEditFlags_PickerMask_ = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar, ImGuiColorEditFlags_InputMask_ = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV, // Obsolete names +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiColorEditFlags_AlphaPreview = 0, // [Removed in 1.91.8] This is the default now. Will display a checkerboard unless ImGuiColorEditFlags_AlphaNoBg is set. +#endif //ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69] }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9f6264a5d279..43344f3fc543 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2117,11 +2117,12 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) if (ImGui::TreeNode("Color/Picker Widgets")) { static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); - static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_AlphaPreview; + static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None; ImGui::SeparatorText("Options"); ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreview", &base_flags, ImGuiColorEditFlags_AlphaPreview); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg); ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf); ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop); ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); @@ -8047,9 +8048,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) filter.Draw("Filter colors", ImGui::GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; - if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); - if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_AlphaPreview)) { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine(); - if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); + if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } ImGui::SameLine(); + if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); + if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); HelpMarker( "In the color list:\n" "Left-click on color square to open color picker,\n" diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 4f58c4cd2332..e0fec9122b4d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5902,7 +5902,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoLabel)) Text("Current"); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoTooltip; ColorButton("##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)); if (ref_col != NULL) { @@ -5942,7 +5942,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl if ((flags & ImGuiColorEditFlags_NoInputs) == 0) { PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x); - ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf; + ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaMask_ | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview; ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker; if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0) if (ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB)) @@ -6118,8 +6118,8 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held); - if (flags & ImGuiColorEditFlags_NoAlpha) - flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf); + if (flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaOpaque)) + flags &= ~(ImGuiColorEditFlags_AlphaNoBg | ImGuiColorEditFlags_AlphaPreviewHalf); ImVec4 col_rgb = col; if (flags & ImGuiColorEditFlags_InputHSV) @@ -6138,14 +6138,17 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f) { float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f); - RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); + if ((flags & ImGuiColorEditFlags_AlphaNoBg) == 0) + RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight); + else + window->DrawList->AddRectFilled(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), rounding, ImDrawFlags_RoundCornersRight); window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft); } else { // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha - ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha; - if (col_source.w < 1.0f) + ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaOpaque) ? col_rgb_without_alpha : col_rgb; + if (col_source.w < 1.0f && (flags & ImGuiColorEditFlags_AlphaNoBg) == 0) RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding); else window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding); @@ -6175,7 +6178,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl // Tooltip if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)); + ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_)); return pressed; } @@ -6216,7 +6219,8 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2); ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]); int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]); - ColorButton("##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz); + ImGuiColorEditFlags flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_AlphaMask_; + ColorButton("##preview", cf, (flags & flags_to_forward) | ImGuiColorEditFlags_NoTooltip, sz); SameLine(); if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_)) { From 71da34c48cf70f1f553a7a8b4edfbb0babdcfbef Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 16:56:18 +0100 Subject: [PATCH 173/716] Debug Tools: Tweaked font preview + indent "Glyphs" block. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 99 +++++++++++++++++++++++++--------------------- 2 files changed, 55 insertions(+), 45 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f0aeebbb34cf..ab01011c7616 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -73,6 +73,7 @@ Other changes: for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), increased default rounding (style.TabRounding). (#8334) [@Kian738, @ocornut] styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). +- Debug Tools: Tweaked font preview. - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/imgui.cpp b/imgui.cpp index 0b988f2b47ec..0fe7c820935c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16147,18 +16147,24 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co // [DEBUG] Display details for a single font, called by ShowStyleEditor(). void ImGui::DebugNodeFont(ImFont* font) { - bool opened = TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)", + bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)", font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); - SameLine(); - if (SmallButton("Set as default")) - GetIO().FontDefault = font; - if (!opened) - return; // Display preview text + if (!opened) + Indent(); + Indent(); PushFont(font); Text("The quick brown fox jumps over the lazy dog"); PopFont(); + if (!opened) + { + Unindent(); + Unindent(); + return; + } + if (SmallButton("Set as default")) + GetIO().FontDefault = font; // Display details SetNextItemWidth(GetFontSize() * 8); @@ -16182,57 +16188,60 @@ void ImGui::DebugNodeFont(ImFont* font) config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); // Display all glyphs of the fonts in separate pages of 256 characters - if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { - ImDrawList* draw_list = GetWindowDrawList(); - const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); - const float cell_size = font->FontSize * 1; - const float cell_spacing = GetStyle().ItemSpacing.y; - for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { - // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) - // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT - // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) - if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191)) + ImDrawList* draw_list = GetWindowDrawList(); + const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); + const float cell_size = font->FontSize * 1; + const float cell_spacing = GetStyle().ItemSpacing.y; + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) { - base += 8192 - 256; - continue; - } - - int count = 0; - for (unsigned int n = 0; n < 256; n++) - if (font->FindGlyphNoFallback((ImWchar)(base + n))) - count++; - if (count <= 0) - continue; - if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) - continue; + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191)) + { + base += 8192 - 256; + continue; + } - // Draw a 16x16 grid of glyphs - ImVec2 base_pos = GetCursorScreenPos(); - for (unsigned int n = 0; n < 256; n++) - { - // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions - // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. - ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); - ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); - draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); - if (!glyph) + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (font->FindGlyphNoFallback((ImWchar)(base + n))) + count++; + if (count <= 0) + continue; + if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) continue; - font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); - if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + + // Draw a 16x16 grid of glyphs + ImVec2 base_pos = GetCursorScreenPos(); + for (unsigned int n = 0; n < 256; n++) { - DebugNodeFontGlyph(font, glyph); - EndTooltip(); + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (!glyph) + continue; + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + { + DebugNodeFontGlyph(font, glyph); + EndTooltip(); + } } + Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + TreePop(); } - Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); TreePop(); } - TreePop(); } TreePop(); + Unindent(); } void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph) From 10199341b1d5c193a9f2748fdeeeac2e57ce354e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Jan 2025 11:31:32 +0100 Subject: [PATCH 174/716] ImFontAtlas: made calling ClearFonts() call ClearInputData(). (#8174, #6556, #6336, #4723) --- docs/CHANGELOG.txt | 4 +++- imgui.h | 2 +- imgui_draw.cpp | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ab01011c7616..f0021b2ab49c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,7 +54,6 @@ Breaking changes: Other changes: -- ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) - imgui_freetype: fixed issue where glyph advances would incorrectly be snapped to pixels. Effectively it would only be noticeable when hinting is disabled with ImGuiFreeTypeBuilderFlags_NoHinting, as hinting itself @@ -74,6 +73,9 @@ Other changes: increased default rounding (style.TabRounding). (#8334) [@Kian738, @ocornut] styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). - Debug Tools: Tweaked font preview. +- ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) +- ImFontAtlas: made calling ClearFonts() call ClearInputData(), as calling + one without the other is never correct. (#8174, #6556, #6336, #4723) - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/imgui.h b/imgui.h index d42a932c296f..48910ea753e0 100644 --- a/imgui.h +++ b/imgui.h @@ -3355,8 +3355,8 @@ struct ImFontAtlas IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearFonts(); // Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. - IMGUI_API void ClearFonts(); // Clear output font data (glyphs storage, UV coordinates). IMGUI_API void Clear(); // Clear all input and output. // Build atlas, retrieve pixel data. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 97342b35b7e2..eb5cfd51b539 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2520,6 +2520,7 @@ void ImFontAtlas::ClearTexData() void ImFontAtlas::ClearFonts() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + ClearInputData(); Fonts.clear_delete(); TexReady = false; } From 9bc5b0406d36508a3167b0a069f3f18987f838e6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 14:39:07 +0100 Subject: [PATCH 175/716] Windows, Style: Fixed small rendering issues with menu bar, resize grip and scrollbar when using thick border sizes. (#8267, #7887) Amend e.g. 742b5f4c. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 14 ++++++++------ imgui_widgets.cpp | 10 ++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f0021b2ab49c..c6e9d26f3577 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -67,6 +67,8 @@ Other changes: - Windows: legacy SetWindowFontScale() is properly inherited by nested child windows. Note that an upcoming major release should make this obsolete, but in the meanwhile it works better now. (#2701, #8138, #1018) +- Windows, Style: Fixed small rendering issues with menu bar, resize grip and + scrollbar when using thick border sizes. (#8267, #7887) - ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] - Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), diff --git a/imgui.cpp b/imgui.cpp index 0fe7c820935c..ac91f490baef 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6712,7 +6712,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window) if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) { float y = window->Pos.y + window->TitleBarHeight - 1; - window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), border_col, g.Style.FrameBorderSize); + window->DrawList->AddLine(ImVec2(window->Pos.x + border_size * 0.5f, y), ImVec2(window->Pos.x + window->Size.x - border_size * 0.5f, y), border_col, g.Style.FrameBorderSize); } } @@ -6772,9 +6772,10 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar { ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. - window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); + window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); + float window_border_size = window->WindowBorderSize; if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) - window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); + window->DrawList->AddLine(menu_bar_rect.GetBL() + ImVec2(window_border_size * 0.5f, 0.0f), menu_bar_rect.GetBR() - ImVec2(window_border_size * 0.5f, 0.0f), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } // Scrollbars @@ -6793,9 +6794,10 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar continue; const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n]; const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size))); - window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size))); - window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12); + const float border_inner = IM_ROUND(window_border_size * 0.5f); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(border_inner, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, border_inner))); + window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, border_inner) : ImVec2(border_inner, resize_grip_draw_size))); + window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + border_inner), corner.y + grip.InnerDir.y * (window_rounding + border_inner)), window_rounding, grip.AngleMin12, grip.AngleMax12); window->DrawList->PathFillConvex(col); } } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e0fec9122b4d..9ce939fd39e3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -911,13 +911,14 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) { const ImRect outer_rect = window->Rect(); const ImRect inner_rect = window->InnerRect; - const float border_size = window->WindowBorderSize; const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) IM_ASSERT(scrollbar_size > 0.0f); + const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f); + const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(GImGui->Style.FrameBorderSize * 0.5f) : 0.0f; if (axis == ImGuiAxis_X) - return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); + return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); else - return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); + return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y + border_top, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size); } void ImGui::Scrollbar(ImGuiAxis axis) @@ -8630,8 +8631,9 @@ bool ImGui::BeginMenuBar() // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. + const float border_top = ImMax(window->WindowBorderSize * 0.5f - window->TitleBarHeight, 0.0f); ImRect bar_rect = window->MenuBarRect(); - ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y)); + ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize * 0.5f), IM_ROUND(bar_rect.Min.y + border_top), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize * 0.5f))), IM_ROUND(bar_rect.Max.y)); clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); From bbf957875bbca8fb8b459997fba571eba964f4d2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 14:43:16 +0100 Subject: [PATCH 176/716] Amend 9bc5b04 to avoid using GImGui mid-function. --- imgui_widgets.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9ce939fd39e3..1bd19fe7cff2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -909,12 +909,13 @@ ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis) // Return scrollbar rectangle, must only be called for corresponding axis if window->ScrollbarX/Y is set. ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) { + ImGuiContext& g = *GImGui; const ImRect outer_rect = window->Rect(); const ImRect inner_rect = window->InnerRect; const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) IM_ASSERT(scrollbar_size > 0.0f); const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f); - const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(GImGui->Style.FrameBorderSize * 0.5f) : 0.0f; + const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f; if (axis == ImGuiAxis_X) return ImRect(inner_rect.Min.x + border_size, ImMax(outer_rect.Min.y + border_size, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size); else From ed7551c1d4443b92513337fd6653f0fac8268da9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 14:59:37 +0100 Subject: [PATCH 177/716] Selectable: Fixed horizontal label alignment when combined with using ImGuiSelectableFlags_SpanAllColumns. (#8338) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 9 +++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c6e9d26f3577..eac83b090236 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -139,6 +139,8 @@ Other changes: the label (not only the highlight/frame) also spans all columns. This is useful for table rows where you know nothing else is submitted. (#8318, #3565) Obviously best used with ImGuiTableFlags_NoBordersInBodyUntilResize. +- Selectable: Fixed horizontal label alignment when combined with using + ImGuiSelectableFlags_SpanAllColumns. (#8338) - Drags: Added ImGuiSliderFlags_NoSpeedTweaks flag to disable keyboard modifiers altering the tweak speed. Useful if you want to alter tweak speed yourself based on your own logic. (#8223) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1bd19fe7cff2..ad4820827630 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6943,13 +6943,9 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth)) size.x = ImMax(label_size.x, max_x - min_x); - // Text stays at the submission position, but bounding box may be extended on both sides - const ImVec2 text_min = pos; - const ImVec2 text_max(min_x + size.x, pos.y + size.y); - // Selectables are meant to be tightly packed together with no click-gap, so we extend their box to cover spacing between selectable. // FIXME: Not part of layout so not included in clipper calculation, but ItemSize currently doesn't allow offsetting CursorPos. - ImRect bb(min_x, pos.y, text_max.x, text_max.y); + ImRect bb(min_x, pos.y, min_x + size.x, pos.y + size.y); if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) { const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x; @@ -7085,8 +7081,9 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl PopColumnsBackground(); } + // Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns. if (is_visible) - RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb); + RenderTextClipped(pos, ImVec2(window->WorkRect.Max.x, pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb); // Automatically close popups if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) From 53244aaac72f3986dd29d79c2aecb2cc2cdf58f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 15:00:21 +0100 Subject: [PATCH 178/716] Amend 9bc5b04 with a shadowed variable warning fix. --- imgui.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index ac91f490baef..5468951d7549 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6773,7 +6773,6 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImRect menu_bar_rect = window->MenuBarRect(); menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them. window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawFlags_RoundCornersTop); - float window_border_size = window->WindowBorderSize; if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y) window->DrawList->AddLine(menu_bar_rect.GetBL() + ImVec2(window_border_size * 0.5f, 0.0f), menu_bar_rect.GetBR() - ImVec2(window_border_size * 0.5f, 0.0f), GetColorU32(ImGuiCol_Border), style.FrameBorderSize); } From 9eafb7bbfb7b281029056f042514a76a9b17bc5a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 16:54:59 +0100 Subject: [PATCH 179/716] ImFont: IndexLookup[] table hold 16-bit values even in ImWchar32 mode. --- docs/CHANGELOG.txt | 3 +++ imgui.h | 2 +- imgui_draw.cpp | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index eac83b090236..d9a95e3c103a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -78,6 +78,9 @@ Other changes: - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) - ImFontAtlas: made calling ClearFonts() call ClearInputData(), as calling one without the other is never correct. (#8174, #6556, #6336, #4723) +- ImFont: IndexLookup[] table hold 16-bit values even in ImWchar32 mode, + as it accounts for number of glyphs in same font. This is favorable to + CalcTextSize() calls touching less memory. - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/imgui.h b/imgui.h index 48910ea753e0..8c6082d9ea06 100644 --- a/imgui.h +++ b/imgui.h @@ -3456,7 +3456,7 @@ struct ImFont float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) - ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. + ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // // All glyphs. const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index eb5cfd51b539..1a30b9a9b256 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3738,7 +3738,7 @@ void ImFont::BuildLookupTable() { int codepoint = (int)Glyphs[i].Codepoint; IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; - IndexLookup[codepoint] = (ImWchar)i; + IndexLookup[codepoint] = (ImU16)i; // Mark 4K page as used const int page_n = codepoint / 8192; @@ -3756,7 +3756,7 @@ void ImFont::BuildLookupTable() tab_glyph.Codepoint = '\t'; tab_glyph.AdvanceX *= IM_TABSIZE; IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; - IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1); + IndexLookup[(int)tab_glyph.Codepoint] = (ImU16)(Glyphs.Size - 1); } // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) @@ -3829,7 +3829,7 @@ void ImFont::GrowIndex(int new_size) if (new_size <= IndexLookup.Size) return; IndexAdvanceX.resize(new_size, -1.0f); - IndexLookup.resize(new_size, (ImWchar)-1); + IndexLookup.resize(new_size, (ImU16)-1); } // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. @@ -3872,6 +3872,7 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa glyph.U1 = u1; glyph.V1 = v1; glyph.AdvanceX = advance_x; + IM_ASSERT(Glyphs.Size < 0xFFFF); // IndexLookup[] hold 16-bit values and -1 is reserved. // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. @@ -3885,13 +3886,13 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. unsigned int index_size = (unsigned int)IndexLookup.Size; - if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists + if (dst < index_size && IndexLookup.Data[dst] == (ImU16)-1 && !overwrite_dst) // 'dst' already exists return; if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op return; GrowIndex(dst + 1); - IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1; + IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImU16)-1; IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; } @@ -3900,8 +3901,8 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) { if (c >= (size_t)IndexLookup.Size) return FallbackGlyph; - const ImWchar i = IndexLookup.Data[c]; - if (i == (ImWchar)-1) + const ImU16 i = IndexLookup.Data[c]; + if (i == (ImU16)-1) return FallbackGlyph; return &Glyphs.Data[i]; } @@ -3910,8 +3911,8 @@ const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) { if (c >= (size_t)IndexLookup.Size) return NULL; - const ImWchar i = IndexLookup.Data[c]; - if (i == (ImWchar)-1) + const ImU16 i = IndexLookup.Data[c]; + if (i == (ImU16)-1) return NULL; return &Glyphs.Data[i]; } From 4211fdc70bac319543d4fedac1d6d42c9f1a94a5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 15:44:51 +0100 Subject: [PATCH 180/716] ImFont: compact comments in header section. --- imgui.h | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/imgui.h b/imgui.h index 8c6082d9ea06..ba763da86cd7 100644 --- a/imgui.h +++ b/imgui.h @@ -3451,28 +3451,28 @@ struct ImFontAtlas struct ImFont { // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize) - ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). + ImVector IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX - float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) + float FontSize; // 4 // in // Height of characters/line, set during loading (don't change after loading) // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) - ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. - ImVector Glyphs; // 12-16 // out // // All glyphs. + ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. + ImVector Glyphs; // 12-16 // out // All glyphs. const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) // [Internal] Members: Cold ~32/40 bytes // Conceptually ConfigData[] is the list of font sources merged to create this font. - ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into - const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances - short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. + ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into + const ImFontConfig* ConfigData; // 4-8 // in // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances + short ConfigDataCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. short EllipsisCharCount; // 1 // out // 1 or 3 - ImWchar EllipsisChar; // 2-4 // out // = '...'/'.'// Character used for ellipsis rendering. - ImWchar FallbackChar; // 2-4 // out // = FFFD/'?' // Character used if a glyph isn't found. - float EllipsisWidth; // 4 // out // Width - float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 - float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() - float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) - int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). + ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') + float EllipsisWidth; // 4 // out // Total ellipsis Width + float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 + float Scale; // 4 // in // Base font scale (1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) bool DirtyLookupTables; // 1 // out // ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. @@ -3481,9 +3481,9 @@ struct ImFont IMGUI_API ~ImFont(); IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c); IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c); - float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } - bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + bool IsLoaded() const { return ContainerAtlas != NULL; } + const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. From 8a1613a382f81d321355efe47698a34520fe2c8a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 19:27:50 +0100 Subject: [PATCH 181/716] Fonts: OversampleH/OversampleV value defaults to 0 for automatic selection. --- docs/CHANGELOG.txt | 10 +++++++--- docs/FONTS.md | 2 -- imgui.cpp | 10 +++++++--- imgui.h | 4 ++-- imgui_draw.cpp | 30 ++++++++++++++++++++---------- imgui_internal.h | 1 + misc/freetype/imgui_freetype.cpp | 2 +- 7 files changed, 38 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d9a95e3c103a..3e0080ac3d47 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,11 +76,15 @@ Other changes: styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). - Debug Tools: Tweaked font preview. - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) -- ImFontAtlas: made calling ClearFonts() call ClearInputData(), as calling - one without the other is never correct. (#8174, #6556, #6336, #4723) -- ImFont: IndexLookup[] table hold 16-bit values even in ImWchar32 mode, +- Fonts: IndexLookup[] table hold 16-bit values even in ImWchar32 mode, as it accounts for number of glyphs in same font. This is favorable to CalcTextSize() calls touching less memory. +- Fonts: OversampleH/OversampleV defaults to 0 for automatic selection. + - OversampleH == 0 --> use 1 or 2 depending on font size and use of PixelSnapH. + - OversampleV == 0 --> always use 1. + This also +- ImFontAtlas: made calling ClearFonts() call ClearInputData(), as calling + one without the other is never correct. (#8174, #6556, #6336, #4723) - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in provided example, to reduce latency. - Examples: Vulkan: better handle VK_SUBOPTIMAL_KHR being returned by diff --git a/docs/FONTS.md b/docs/FONTS.md index c451af61c0ba..e36afdf817d0 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -110,8 +110,6 @@ ImGui::PopFont(); **For advanced options create a ImFontConfig structure and pass it to the AddFont() function (it will be copied internally):** ```cpp ImFontConfig config; -config.OversampleH = 2; -config.OversampleV = 1; config.GlyphExtraSpacing.x = 1.0f; ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); ``` diff --git a/imgui.cpp b/imgui.cpp index 5468951d7549..3764b5663c03 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16184,9 +16184,13 @@ void ImGui::DebugNodeFont(ImFont* font) Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) if (font->ConfigData) - if (const ImFontConfig* cfg = &font->ConfigData[config_i]) - BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", - config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + { + const ImFontConfig* cfg = &font->ConfigData[config_i]; + int oversample_h, oversample_v; + ImFontAtlasBuildGetOversampleFactors(cfg, &oversample_h, &oversample_v); + BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", + config_i, cfg->Name, cfg->OversampleH, oversample_h, cfg->OversampleV, oversample_v, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + } // Display all glyphs of the fonts in separate pages of 256 characters { diff --git a/imgui.h b/imgui.h index ba763da86cd7..8e240b390ead 100644 --- a/imgui.h +++ b/imgui.h @@ -3254,8 +3254,8 @@ struct ImFontConfig bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. int FontNo; // 0 // Index of font within TTF/OTF file - int OversampleH; // 2 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. + int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1a30b9a9b256..c7f8044c64f9 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2374,8 +2374,8 @@ ImFontConfig::ImFontConfig() { memset(this, 0, sizeof(*this)); FontDataOwnedByAtlas = true; - OversampleH = 2; - OversampleV = 1; + OversampleH = 0; // Auto == 1 or 2 depending on size + OversampleV = 0; // Auto == 1 GlyphMaxAdvanceX = FLT_MAX; RasterizerMultiply = 1.0f; RasterizerDensity = 1.0f; @@ -2573,8 +2573,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); - IM_ASSERT(font_cfg->OversampleH > 0 && font_cfg->OversampleV > 0 && "Is ImFontConfig struct correctly initialized?"); - IM_ASSERT(font_cfg->RasterizerDensity > 0.0f); + IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); // Create new font if (!font_cfg->MergeMode) @@ -2858,6 +2857,13 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out->push_back((int)(((it - it_begin) << 5) + bit_n)); } +void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v) +{ + // Automatically disable horizontal oversampling over size 32 + *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 32.0f || cfg->PixelSnapH) ? 1 : 2; + *out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1; +} + static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { IM_ASSERT(atlas->ConfigData.Size > 0); @@ -2985,15 +2991,19 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) buf_rects_out_n += src_tmp.GlyphsCount; buf_packedchars_out_n += src_tmp.GlyphsCount; - // Convert our ranges in the format stb_truetype wants + // Automatic selection of oversampling parameters ImFontConfig& cfg = atlas->ConfigData[src_i]; + int oversample_h, oversample_v; + ImFontAtlasBuildGetOversampleFactors(&cfg, &oversample_h, &oversample_v); + + // Convert our ranges in the format stb_truetype wants src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity; src_tmp.PackRange.first_unicode_codepoint_in_range = 0; src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; - src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH; - src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV; + src_tmp.PackRange.h_oversample = (unsigned char)oversample_h; + src_tmp.PackRange.v_oversample = (unsigned char)oversample_v; // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity); @@ -3002,9 +3012,9 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) int x0, y0, x1, y1; const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); IM_ASSERT(glyph_index_in_font != 0); - stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1); - src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + cfg.OversampleH - 1); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + cfg.OversampleV - 1); + stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * oversample_h, scale * oversample_v, 0, 0, &x0, &y0, &x1, &y1); + src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + oversample_h - 1); + src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + oversample_v - 1); total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; } } diff --git a/imgui_internal.h b/imgui_internal.h index 33a6ec8b0bc5..e78659adc369 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3571,6 +3571,7 @@ IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); +IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v); //----------------------------------------------------------------------------- // [SECTION] Test Engine specific hooks (imgui_test_engine) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 421fdba63436..029991bbdec3 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -33,7 +33,7 @@ // - For correct results you need to be using sRGB and convert to linear space in the pixel shader output. // - The default dear imgui styles will be impacted by this change (alpha values will need tweaking). -// FIXME: cfg.OversampleH, OversampleV are not supported (but perhaps not so necessary with this rasterizer). +// FIXME: cfg.OversampleH, OversampleV are not supported, but generally not necessary with this rasterizer because Hinting makes everything look better. #include "imgui.h" #ifndef IMGUI_DISABLE From afb6e9a879cbac8346601a5b4984e3991c30cc8f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 20:03:04 +0100 Subject: [PATCH 182/716] Fonts: OversampleH auto-selection uses 36 as heuristic for now. --- imgui_draw.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c7f8044c64f9..f00a68361935 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2859,8 +2859,8 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v) { - // Automatically disable horizontal oversampling over size 32 - *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 32.0f || cfg->PixelSnapH) ? 1 : 2; + // Automatically disable horizontal oversampling over size 36 + *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2; *out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1; } From 96e3b147f0ad8a0b70e818d6d845aa7956e8e7b2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 25 Jan 2025 01:14:46 +0100 Subject: [PATCH 183/716] Fixed build with IMGUI_ENABLE_FREETYPE (#8346) --- imgui_draw.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f00a68361935..4b59d6775867 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2819,6 +2819,13 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig *data = table[*data]; } +void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v) +{ + // Automatically disable horizontal oversampling over size 36 + *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2; + *out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1; +} + #ifdef IMGUI_ENABLE_STB_TRUETYPE // Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) // (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) @@ -2857,13 +2864,6 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out->push_back((int)(((it - it_begin) << 5) + bit_n)); } -void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v) -{ - // Automatically disable horizontal oversampling over size 36 - *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2; - *out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1; -} - static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { IM_ASSERT(atlas->ConfigData.Size > 0); From 5a28f188ff0f502e63336f2993235308ea775267 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jan 2025 12:27:10 +0100 Subject: [PATCH 184/716] Fixed parameter names to SetLastItemData() to align with current names. --- imgui.cpp | 6 +++--- imgui_internal.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3764b5663c03..9416757c8b2f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4695,12 +4695,12 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id) // This is also inlined in ItemAdd() // Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set g.LastItemData.DisplayRect. -void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags item_flags, const ImRect& item_rect) +void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect) { ImGuiContext& g = *GImGui; g.LastItemData.ID = item_id; - g.LastItemData.ItemFlags = in_flags; - g.LastItemData.StatusFlags = item_flags; + g.LastItemData.ItemFlags = item_flags; + g.LastItemData.StatusFlags = status_flags; g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; } diff --git a/imgui_internal.h b/imgui_internal.h index e78659adc369..a8cd3719e31b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3095,7 +3095,7 @@ namespace ImGui IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags); IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); - IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); + IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); IMGUI_API void PushMultiItemsWidths(int components, float width_full); From 134fbe12451c4538c17a7730c1fa30663372e06e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jan 2025 12:39:44 +0100 Subject: [PATCH 185/716] Windows: Fixed IsItemXXXX() functions not working on append-version of EndChild(). (#8350) Also made some of the fields accessible after BeginChild() to match Begin() logic. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 28 ++++++++++++++++++++++------ imgui_internal.h | 1 + 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3e0080ac3d47..e9952a080948 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,8 @@ Other changes: but in the meanwhile it works better now. (#2701, #8138, #1018) - Windows, Style: Fixed small rendering issues with menu bar, resize grip and scrollbar when using thick border sizes. (#8267, #7887) +- Windows: Fixed IsItemXXXX() functions not working on append-version of EndChild(). (#8350) + Also made some of the fields accessible after BeginChild() to match Begin() logic. - ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] - Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), diff --git a/imgui.cpp b/imgui.cpp index 9416757c8b2f..7afea92bcb2a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1256,6 +1256,7 @@ static void RenderWindowTitleBarContents(ImGuiWindow* window, const static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgrounds(); static void SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect); +static void SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect); // Viewports const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbitrary constant instead of e.g. ImHashStr("ViewportDefault", 0); so it's easier to spot in the debugger. The exact value doesn't matter. @@ -4704,6 +4705,18 @@ void ImGui::SetLastItemData(ImGuiID item_id, ImGuiItemFlags item_flags, ImGuiIte g.LastItemData.Rect = g.LastItemData.NavRect = item_rect; } +static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect) +{ + ImGuiContext& g = *GImGui; + SetLastItemData(window->MoveId, g.CurrentItemFlags, window->DC.WindowItemStatusFlags, rect); +} + +static void ImGui::SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect) +{ + ImGuiContext& g = *GImGui; + SetLastItemData(window->ChildId, g.CurrentItemFlags, window->DC.WindowItemStatusFlags, rect); +} + float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) { if (wrap_pos_x < 0.0f) @@ -6157,7 +6170,14 @@ void ImGui::EndChild() } if (g.HoveredWindow == child_window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; + child_window->DC.WindowItemStatusFlags = g.LastItemData.StatusFlags; + //SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); // Not needed, effectively done by ItemAdd() } + else + { + SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); + } + g.WithinEndChildID = backup_within_end_child_id; g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } @@ -7612,6 +7632,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin(). // This is useful to allow creating context menus on title bar only, etc. + window->DC.WindowItemStatusFlags = ImGuiItemStatusFlags_None; + window->DC.WindowItemStatusFlags |= IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0; SetLastItemDataForWindow(window, title_bar_rect); // [DEBUG] @@ -7717,12 +7739,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) return !window->SkipItems; } -static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& rect) -{ - ImGuiContext& g = *GImGui; - SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect(rect.Min, rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, rect); -} - void ImGui::End() { ImGuiContext& g = *GImGui; diff --git a/imgui_internal.h b/imgui_internal.h index a8cd3719e31b..b7b81c2e2676 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2456,6 +2456,7 @@ struct IMGUI_API ImGuiWindowTempData ImGuiLayoutType LayoutType; ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() ImU32 ModalDimBgColor; + ImGuiItemStatusFlags WindowItemStatusFlags; // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. From a05d547ae88c228a392153bbee6a1fa88abc926e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jan 2025 14:39:26 +0100 Subject: [PATCH 186/716] Windows: separating WindowItemStatusFlags from ChildItemStatusFlag, because IsItemXXX _after_ BeginChild()>Begin() shouldn't return last status emitted by e.g. EndChild() As IsItemXXX() after is specced as returning title bar data we don't want to lock ourselves up from adding them to child window (e.g. MDI idea using windows to host child windows). --- imgui.cpp | 4 ++-- imgui_internal.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7afea92bcb2a..e4c2f2a2edc2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4714,7 +4714,7 @@ static void ImGui::SetLastItemDataForWindow(ImGuiWindow* window, const ImRect& r static void ImGui::SetLastItemDataForChildWindowItem(ImGuiWindow* window, const ImRect& rect) { ImGuiContext& g = *GImGui; - SetLastItemData(window->ChildId, g.CurrentItemFlags, window->DC.WindowItemStatusFlags, rect); + SetLastItemData(window->ChildId, g.CurrentItemFlags, window->DC.ChildItemStatusFlags, rect); } float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x) @@ -6170,7 +6170,7 @@ void ImGui::EndChild() } if (g.HoveredWindow == child_window) g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow; - child_window->DC.WindowItemStatusFlags = g.LastItemData.StatusFlags; + child_window->DC.ChildItemStatusFlags = g.LastItemData.StatusFlags; //SetLastItemDataForChildWindowItem(child_window, child_window->Rect()); // Not needed, effectively done by ItemAdd() } else diff --git a/imgui_internal.h b/imgui_internal.h index b7b81c2e2676..2922993b3784 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2457,6 +2457,7 @@ struct IMGUI_API ImGuiWindowTempData ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin() ImU32 ModalDimBgColor; ImGuiItemStatusFlags WindowItemStatusFlags; + ImGuiItemStatusFlags ChildItemStatusFlags; // Local parameters stacks // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. From 9c4948a4d1a24237a63546de2e79e331bb5722b4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jan 2025 15:41:24 +0100 Subject: [PATCH 187/716] TabBar: Internals: added TabItemSpacing(). (#8349, #3291) --- imgui_internal.h | 3 ++ imgui_widgets.cpp | 118 ++++++++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 47 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 2922993b3784..0b19c63e3085 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2612,6 +2612,8 @@ enum ImGuiTabItemFlagsPrivate_ ImGuiTabItemFlags_SectionMask_ = ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing, ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout) ImGuiTabItemFlags_Button = 1 << 21, // Used by TabItemButton, change the tab item behavior to mimic a button + ImGuiTabItemFlags_Invisible = 1 << 22, // To reserve space e.g. with ImGuiTabItemFlags_Leading + //ImGuiTabItemFlags_Unsorted = 1 << 23, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. }; // Storage for one active tab item (sizeof() 40 bytes) @@ -3378,6 +3380,7 @@ namespace ImGui IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos); IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar); IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window); + IMGUI_API void TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width); IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker); IMGUI_API ImVec2 TabItemCalcSize(ImGuiWindow* window); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ad4820827630..22f73866063c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -9925,7 +9925,7 @@ bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags f IM_ASSERT_USER_ERROR(tab_bar, "Needs to be called between BeginTabBar() and EndTabBar()!"); return false; } - IM_ASSERT(!(flags & ImGuiTabItemFlags_Button)); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! + IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0); // BeginTabItem() Can't be used with button flags, use TabItemButton() instead! bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL); if (ret && !(flags & ImGuiTabItemFlags_NoPushId)) @@ -9971,6 +9971,23 @@ bool ImGui::TabItemButton(const char* label, ImGuiTabItemFlags flags) return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL); } +void ImGui::TabItemSpacing(const char* str_id, ImGuiTabItemFlags flags, float width) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window->SkipItems) + return; + + ImGuiTabBar* tab_bar = g.CurrentTabBar; + if (tab_bar == NULL) + { + IM_ASSERT_USER_ERROR(tab_bar != NULL, "Needs to be called between BeginTabBar() and EndTabBar()!"); + return; + } + SetNextItemWidth(width); + TabItemEx(tab_bar, str_id, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder | ImGuiTabItemFlags_Invisible, NULL); +} + bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window) { // Layout whole tab bar if not already done @@ -10116,8 +10133,11 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap); if (g.DragDropActive) button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; - bool hovered, held; - bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); + bool hovered, held, pressed; + if (flags & ImGuiTabItemFlags_Invisible) + hovered = held = pressed = false; + else + pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags); if (pressed && !is_tab_button) TabBarQueueFocus(tab_bar, tab); @@ -10149,46 +10169,59 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, #endif // Render tab shape - ImDrawList* display_draw_list = window->DrawList; - const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); - TabItemBackground(display_draw_list, bb, flags, tab_col); - if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) - { - // Might be moved to TabItemBackground() ? - ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale); - ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale); - ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); - if (style.TabRounding > 0.0f) - { - float rounding = style.TabRounding; - display_draw_list->PathArcToFast(tl + ImVec2(+rounding, +rounding), rounding, 7, 9); - display_draw_list->PathArcToFast(tr + ImVec2(-rounding, +rounding), rounding, 9, 11); - display_draw_list->PathStroke(overline_col, 0, style.TabBarOverlineSize); - } - else + const bool is_visible = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible) && !(flags & ImGuiTabItemFlags_Invisible); + if (is_visible) + { + ImDrawList* display_draw_list = window->DrawList; + const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabSelected : ImGuiCol_TabDimmedSelected) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabDimmed)); + TabItemBackground(display_draw_list, bb, flags, tab_col); + if (tab_contents_visible && (tab_bar->Flags & ImGuiTabBarFlags_DrawSelectedOverline) && style.TabBarOverlineSize > 0.0f) { - display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize); + // Might be moved to TabItemBackground() ? + ImVec2 tl = bb.GetTL() + ImVec2(0, 1.0f * g.CurrentDpiScale); + ImVec2 tr = bb.GetTR() + ImVec2(0, 1.0f * g.CurrentDpiScale); + ImU32 overline_col = GetColorU32(tab_bar_focused ? ImGuiCol_TabSelectedOverline : ImGuiCol_TabDimmedSelectedOverline); + if (style.TabRounding > 0.0f) + { + float rounding = style.TabRounding; + display_draw_list->PathArcToFast(tl + ImVec2(+rounding, +rounding), rounding, 7, 9); + display_draw_list->PathArcToFast(tr + ImVec2(-rounding, +rounding), rounding, 9, 11); + display_draw_list->PathStroke(overline_col, 0, style.TabBarOverlineSize); + } + else + { + display_draw_list->AddLine(tl - ImVec2(0.5f, 0.5f), tr - ImVec2(0.5f, 0.5f), overline_col, style.TabBarOverlineSize); + } } - } - RenderNavCursor(bb, id); + RenderNavCursor(bb, id); - // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. - const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); - if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) - TabBarQueueFocus(tab_bar, tab); + // Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget. + const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup); + if (tab_bar->SelectedTabId != tab->ID && hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button) + TabBarQueueFocus(tab_bar, tab); - if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) - flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; + if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton) + flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; - // Render tab label, process close button - const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; - bool just_closed; - bool text_clipped; - TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); - if (just_closed && p_open != NULL) - { - *p_open = false; - TabBarCloseTab(tab_bar, tab); + // Render tab label, process close button + const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, id) : 0; + bool just_closed; + bool text_clipped; + TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped); + if (just_closed && p_open != NULL) + { + *p_open = false; + TabBarCloseTab(tab_bar, tab); + } + + // Tooltip + // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) + // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) + // FIXME: This is a mess. + // FIXME: We may want disabled tab to still display the tooltip? + if (text_clipped && g.HoveredId == id && !held) + if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) + SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); } // Restore main window position so user can draw there @@ -10196,15 +10229,6 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, PopClipRect(); window->DC.CursorPos = backup_main_cursor_pos; - // Tooltip - // (Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer-> seems ok) - // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) - // FIXME: This is a mess. - // FIXME: We may want disabled tab to still display the tooltip? - if (text_clipped && g.HoveredId == id && !held) - if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) - SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); - IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected if (is_tab_button) return pressed; From ea0da0bf4736692cff7dd28eeba6ae3c95daf1aa Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jan 2025 18:04:44 +0100 Subject: [PATCH 188/716] Extracted PushPasswordFont() out of InputText code. --- imgui_internal.h | 1 + imgui_widgets.cpp | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 0b19c63e3085..667c4ea1fab6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3018,6 +3018,7 @@ namespace ImGui // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } + IMGUI_API void PushPasswordFont(); inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 22f73866063c..e37a2fb45b76 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4246,6 +4246,23 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons BufTextLen += new_text_len; } +void ImGui::PushPasswordFont() +{ + ImGuiContext& g = *GImGui; + ImFont* in_font = g.Font; + ImFont* out_font = &g.InputTextPasswordFont; + const ImFontGlyph* glyph = in_font->FindGlyph('*'); + out_font->FontSize = in_font->FontSize; + out_font->Scale = in_font->Scale; + out_font->Ascent = in_font->Ascent; + out_font->Descent = in_font->Descent; + out_font->ContainerAtlas = in_font->ContainerAtlas; + out_font->FallbackGlyph = glyph; + out_font->FallbackAdvanceX = glyph->AdvanceX; + IM_ASSERT(out_font->Glyphs.Size == 0 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0); + PushFont(out_font); +} + // Return false to discard a character. static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard) { @@ -4656,19 +4673,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Password pushes a temporary font with only a fallback glyph if (is_password && !is_displaying_hint) - { - const ImFontGlyph* glyph = g.Font->FindGlyph('*'); - ImFont* password_font = &g.InputTextPasswordFont; - password_font->FontSize = g.Font->FontSize; - password_font->Scale = g.Font->Scale; - password_font->Ascent = g.Font->Ascent; - password_font->Descent = g.Font->Descent; - password_font->ContainerAtlas = g.Font->ContainerAtlas; - password_font->FallbackGlyph = glyph; - password_font->FallbackAdvanceX = glyph->AdvanceX; - IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty()); - PushFont(password_font); - } + PushPasswordFont(); // Process mouse inputs and character inputs if (g.ActiveId == id) From 4230e98720357c5e770e3a078a9e4d09f0923279 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 Jan 2025 14:39:00 +0100 Subject: [PATCH 189/716] Error Handling, Debug Log: IMGUI_DEBUG_LOG_ERROR() doesn't need the extra variable. Amend 236006152 --- imgui_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 667c4ea1fab6..ea6479ec317c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -229,7 +229,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif // Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam. -#define IMGUI_DEBUG_LOG_ERROR(...) do { ImGuiContext& g2 = *GImGui; if (g2.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g2.DebugLogSkippedErrors++; } while (0) +#define IMGUI_DEBUG_LOG_ERROR(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g.DebugLogSkippedErrors++; } while (0) #define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) From dfd1bc3c5b35ed9d4203b39e1bdf43d60a061b74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jan 2025 19:05:18 +0100 Subject: [PATCH 190/716] Tables, Menus: Fixed using BeginTable() in menu layer (any menu bar). (#8355) --- docs/CHANGELOG.txt | 3 +++ imgui_internal.h | 1 + imgui_tables.cpp | 8 +++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e9952a080948..be448d16f355 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,9 @@ Other changes: scrollbar when using thick border sizes. (#8267, #7887) - Windows: Fixed IsItemXXXX() functions not working on append-version of EndChild(). (#8350) Also made some of the fields accessible after BeginChild() to match Begin() logic. +- Tables, Menus: Fixed using BeginTable() in menu layer (any menu bar). (#8355) + It previously overrode the current layer back to main layer, which caused an issue + with MainMenuBar attempted to release focus when leaving the menu layer. - ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] - Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), diff --git a/imgui_internal.h b/imgui_internal.h index ea6479ec317c..d4154dabaae2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2877,6 +2877,7 @@ struct IMGUI_API ImGuiTable ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; + ImS8 NavLayer; // ImGuiNavLayer at the time of BeginTable(). bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). bool IsInitializing; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e0df575c440c..d5e952d8f9a1 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -374,6 +374,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->ColumnsCount = columns_count; table->IsLayoutLocked = false; table->InnerWidth = inner_width; + table->NavLayer = (ImS8)outer_window->DC.NavLayerCurrent; temp_data->UserOuterSize = outer_size; // Instance data (for instance 0, TableID == TableInstanceID) @@ -1050,7 +1051,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) const int column_n = table->DisplayOrderToIndex[order_n]; ImGuiTableColumn* column = &table->Columns[column_n]; - column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main); // Use Count NOT request so Header line changes layer when frozen + // Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen + column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : table->NavLayer); if (offset_x_frozen && table->FreezeColumnsCount == visible_n) { @@ -1493,7 +1495,7 @@ void ImGui::EndTable() if (inner_window != outer_window) { short backup_nav_layers_active_mask = inner_window->DC.NavLayersActiveMask; - inner_window->DC.NavLayersActiveMask |= 1 << ImGuiNavLayer_Main; // So empty table don't appear to navigate differently. + inner_window->DC.NavLayersActiveMask |= 1 << table->NavLayer; // So empty table don't appear to navigate differently. g.CurrentTable = NULL; // To avoid error recovery recursing EndChild(); g.CurrentTable = table; @@ -2032,7 +2034,7 @@ void ImGui::TableEndRow(ImGuiTable* table) if (unfreeze_rows_request) { for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - table->Columns[column_n].NavLayerCurrent = ImGuiNavLayer_Main; + table->Columns[column_n].NavLayerCurrent = table->NavLayer; const float y0 = ImMax(table->RowPosY2 + 1, table->InnerClipRect.Min.y); table_instance->LastFrozenHeight = y0 - table->OuterRect.Min.y; From a71191515ac29725ee2aa94b6f5d59cc9ffa108c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jan 2025 19:07:28 +0100 Subject: [PATCH 191/716] EndMainMenuBar doesn't attempt to restore focus when there's an active id. (#8355) I don't have a specific issue in mind but it seems sane to add that test. --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e37a2fb45b76..f772f309c84d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8769,7 +8769,7 @@ void ImGui::EndMainMenuBar() // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window // FIXME: With this strategy we won't be able to restore a NULL focus. ImGuiContext& g = *GImGui; - if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest) + if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest && g.ActiveId == 0) FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); End(); From dabc99018915a534d11d22abc65a6f4d6898d2d4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jan 2025 19:59:41 +0100 Subject: [PATCH 192/716] Rename internal id for standardizing naming convention. "##menubar" -> "##MenuBar", "###NavWindowingList" -> "###NavWindowingOverlay" "###NavUpdateWindowing" one should have zero side effect on anyone. --- imgui.cpp | 6 +++--- imgui.h | 2 +- imgui_widgets.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e4c2f2a2edc2..5223ed76c892 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13649,7 +13649,7 @@ static void ImGui::NavUpdateWindowing() // Start CTRL+Tab or Square+L/R window selection // (g.ConfigNavWindowingKeyNext/g.ConfigNavWindowingKeyPrev defaults are ImGuiMod_Ctrl|ImGuiKey_Tab and ImGuiMod_Ctrl|ImGuiMod_Shift|ImGuiKey_Tab) - const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing"); + const ImGuiID owner_id = ImHashStr("##NavUpdateWindowing"); const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); @@ -13849,12 +13849,12 @@ void ImGui::NavUpdateWindowingOverlay() return; if (g.NavWindowingListWindow == NULL) - g.NavWindowingListWindow = FindWindowByName("###NavWindowingList"); + g.NavWindowingListWindow = FindWindowByName("##NavWindowingOverlay"); const ImGuiViewport* viewport = GetMainViewport(); SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); - Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); + Begin("##NavWindowingOverlay", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings); if (g.ContextName[0] != 0) SeparatorText(g.ContextName); for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--) diff --git a/imgui.h b/imgui.h index 8e240b390ead..7d2f333349a4 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.8 WIP" -#define IMGUI_VERSION_NUM 19173 +#define IMGUI_VERSION_NUM 19174 #define IMGUI_HAS_TABLE /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f772f309c84d..dccb7a5356da 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8630,7 +8630,7 @@ bool ImGui::BeginMenuBar() IM_ASSERT(!window->DC.MenuBarAppending); BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore - PushID("##menubar"); + PushID("##MenuBar"); // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect. // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy. From c0308da665dd1553955ba340a82e0b969631c1ad Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 29 Jan 2025 20:13:22 +0100 Subject: [PATCH 193/716] Fixed zealous GCC warning. (#8355) Amend dfd1bc3 --- imgui_tables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index d5e952d8f9a1..5411e8a1b818 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1052,7 +1052,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) ImGuiTableColumn* column = &table->Columns[column_n]; // Initial nav layer: using FreezeRowsCount, NOT FreezeRowsRequest, so Header line changes layer when frozen - column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : table->NavLayer); + column->NavLayerCurrent = (ImS8)(table->FreezeRowsCount > 0 ? ImGuiNavLayer_Menu : (ImGuiNavLayer)table->NavLayer); if (offset_x_frozen && table->FreezeColumnsCount == visible_n) { From fa178f42350598f853f2ec36b5aeb231e0e08c75 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 30 Jan 2025 14:30:14 +0100 Subject: [PATCH 194/716] Error Handling: Recovery from missing EndMenuBar() call. (#1651) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 5 +++++ imgui_widgets.cpp | 9 +++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index be448d16f355..99333efdabe3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,7 @@ Other changes: scrollbar when using thick border sizes. (#8267, #7887) - Windows: Fixed IsItemXXXX() functions not working on append-version of EndChild(). (#8350) Also made some of the fields accessible after BeginChild() to match Begin() logic. +- Error Handling: Recovery from missing EndMenuBar() call. (#1651) - Tables, Menus: Fixed using BeginTable() in menu layer (any menu bar). (#8355) It previously overrode the current layer back to main layer, which caused an issue with MainMenuBar attempted to release focus when leaving the menu layer. diff --git a/imgui.cpp b/imgui.cpp index 5223ed76c892..dffd37b45f08 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10301,6 +10301,11 @@ void ImGui::ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryStat IM_ASSERT_USER_ERROR(0, "Missing EndMultiSelect()"); EndMultiSelect(); } + if (window->DC.MenuBarAppending) //-V1044 + { + IM_ASSERT_USER_ERROR(0, "Missing EndMenuBar()"); + EndMenuBar(); + } while (window->DC.TreeDepth > state_in->SizeOfTreeStack) //-V1044 { IM_ASSERT_USER_ERROR(0, "Missing TreePop()"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index dccb7a5356da..9335da9fd0d3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8657,6 +8657,10 @@ void ImGui::EndMenuBar() return; ImGuiContext& g = *GImGui; + IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" + IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); + IM_ASSERT(window->DC.MenuBarAppending); + // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings. if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu)) { @@ -8683,9 +8687,6 @@ void ImGui::EndMenuBar() } } - IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" - IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar); - IM_ASSERT(window->DC.MenuBarAppending); PopClipRect(); PopID(); window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos. @@ -8764,11 +8765,11 @@ bool ImGui::BeginMainMenuBar() void ImGui::EndMainMenuBar() { + ImGuiContext& g = *GImGui; EndMenuBar(); // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window // FIXME: With this strategy we won't be able to restore a NULL focus. - ImGuiContext& g = *GImGui; if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest && g.ActiveId == 0) FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild); From ae6cfd32a0372f5ac4bec3ae304e78746d7fca23 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 30 Jan 2025 14:34:05 +0100 Subject: [PATCH 195/716] Tables, Menus: Fixed tables or child windows submitted inside BeginMainMenuBar() being unable to save their settings. (#8356) Amend error handling (fa178f4) to avoid us setting ImGuiWindowFlags_NoSavedSettings on the wrong window. --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 99333efdabe3..c07fcf766af7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -75,6 +75,8 @@ Other changes: - Tables, Menus: Fixed using BeginTable() in menu layer (any menu bar). (#8355) It previously overrode the current layer back to main layer, which caused an issue with MainMenuBar attempted to release focus when leaving the menu layer. +- Tables, Menus: Fixed tables or child windows submitted inside BeginMainMenuBar() + being unable to save their settings, as the main menu bar uses _NoSavedSettings. (#8356) - ColorEdit, ColorPicker: Fixed alpha preview broken in 1.91.7. (#8336, #8241). [@PathogenDavid] - Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9335da9fd0d3..0981b447e033 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8755,18 +8755,29 @@ bool ImGui::BeginMainMenuBar() float height = GetFrameHeight(); bool is_open = BeginViewportSideBar("##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags); g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f); - - if (is_open) - BeginMenuBar(); - else + if (!is_open) + { End(); + return false; + } + + // Temporarily disable _NoSavedSettings, in the off-chance that tables or child windows submitted within the menu-bar may want to use settings. (#8356) + g.CurrentWindow->Flags &= ~ImGuiWindowFlags_NoSavedSettings; + BeginMenuBar(); return is_open; } void ImGui::EndMainMenuBar() { ImGuiContext& g = *GImGui; + if (!g.CurrentWindow->DC.MenuBarAppending) + { + IM_ASSERT_USER_ERROR(0, "Calling EndMainMenuBar() not from a menu-bar!"); // Not technically testing that it is the main menu bar + return; + } + EndMenuBar(); + g.CurrentWindow->Flags |= ImGuiWindowFlags_NoSavedSettings; // Restore _NoSavedSettings (#8356) // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window // FIXME: With this strategy we won't be able to restore a NULL focus. From e6c5296f30a5111fa1dc926d2c15abd0f809fbb1 Mon Sep 17 00:00:00 2001 From: Konstantin Podsvirov Date: Fri, 31 Jan 2025 16:11:33 +0300 Subject: [PATCH 196/716] Examples: SDL3: Fix for Emscripten platform (#8363) --- examples/example_sdl3_opengl3/main.cpp | 1 - examples/example_sdl3_sdlrenderer3/main.cpp | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 5520a7da9293..8cd54bd4ef68 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -18,7 +18,6 @@ #include #endif -// This example doesn't compile with Emscripten yet! Awaiting SDL3 support. #ifdef __EMSCRIPTEN__ #include "../libs/emscripten/emscripten_mainloop_stub.h" #endif diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 4b9b86e9bd5a..483350fcb47a 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -21,6 +21,10 @@ #include #endif +#ifdef __EMSCRIPTEN__ +#include "../libs/emscripten/emscripten_mainloop_stub.h" +#endif + // Main code int main(int, char**) { From dbb5eeaadffb6a3ba6a60de1290312e5802dba5a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 Jan 2025 15:57:48 +0100 Subject: [PATCH 197/716] Version 1.91.8 --- docs/CHANGELOG.txt | 11 ++++++----- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 15 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c07fcf766af7..eaedb9c1be0c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,12 +36,15 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.8 WIP (In Progress) + VERSION 1.91.8 (Released 2025-01-31) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.8 + Breaking changes: -- ColorEdit, ColorPicker: redesigned how alpha is displayed in the preview square. (#8335, #1578, #346) +- ColorEdit, ColorPicker: redesigned how alpha is displayed in the preview + square. (#8335, #1578, #346) - Removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. - Prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. - We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. @@ -63,7 +66,7 @@ Other changes: by introducing a delay. This is a very rarely used UI idiom, but some apps use this: e.g. MS Explorer single-click on an icon triggers a rename. Generally use with 'delay >= io.MouseDoubleClickTime' + combine with a - 'io.MouseClickedLastCount == 1' check. + 'GetMouseClickedCount() == 1' check. - Windows: legacy SetWindowFontScale() is properly inherited by nested child windows. Note that an upcoming major release should make this obsolete, but in the meanwhile it works better now. (#2701, #8138, #1018) @@ -81,7 +84,6 @@ Other changes: - Tabs, Style: reworked selected overline rendering to better accommodate for rounded tabs. Reduced default thickness (style.TabBarOverlineSize), increased default rounding (style.TabRounding). (#8334) [@Kian738, @ocornut] - styles as the current look is not right (but ImGuiCol_TabSelectedOverline stays the same). - Debug Tools: Tweaked font preview. - ImDrawList: texture baked storage for thick line reduced from ~64x64 to ~32x32. (#3245) - Fonts: IndexLookup[] table hold 16-bit values even in ImWchar32 mode, @@ -90,7 +92,6 @@ Other changes: - Fonts: OversampleH/OversampleV defaults to 0 for automatic selection. - OversampleH == 0 --> use 1 or 2 depending on font size and use of PixelSnapH. - OversampleV == 0 --> always use 1. - This also - ImFontAtlas: made calling ClearFonts() call ClearInputData(), as calling one without the other is never correct. (#8174, #6556, #6336, #4723) - Examples: DirectX12: Reduced number of frame in flight from 3 to 2 in diff --git a/imgui.cpp b/imgui.cpp index dffd37b45f08..5ca57dfc65b3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 7d2f333349a4..7b037a584027 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.8 WIP" -#define IMGUI_VERSION_NUM 19174 +#define IMGUI_VERSION "1.91.8" +#define IMGUI_VERSION_NUM 19180 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 43344f3fc543..03ce4710adc8 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4b59d6775867..e426f0e5dc67 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index d4154dabaae2..af52d0feae3c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5411e8a1b818..e7a3b8e8d191 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0981b447e033..1e4297fcbd67 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 WIP +// dear imgui, v1.91.8 // (widgets code) /* From e2a99b57605982c50f2df4fefaf0767aadde9cd8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 Jan 2025 18:26:52 +0100 Subject: [PATCH 198/716] Internals: renamed GetIOEx() to GetIO(). Added GetPlatformIO() explicit context variant. --- imgui.cpp | 9 ++++++++- imgui_internal.h | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5ca57dfc65b3..7d4da45501d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4814,7 +4814,7 @@ ImGuiIO& ImGui::GetIO() } // This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856) -ImGuiIO& ImGui::GetIOEx(ImGuiContext* ctx) +ImGuiIO& ImGui::GetIO(ImGuiContext* ctx) { IM_ASSERT(ctx != NULL); return ctx->IO; @@ -4826,6 +4826,13 @@ ImGuiPlatformIO& ImGui::GetPlatformIO() return GImGui->PlatformIO; } +// This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856) +ImGuiPlatformIO& ImGui::GetPlatformIO(ImGuiContext* ctx) +{ + IM_ASSERT(ctx != NULL; + return ctx->PlatformIO; +} + // Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame() ImDrawData* ImGui::GetDrawData() { diff --git a/imgui_internal.h b/imgui_internal.h index af52d0feae3c..2d2ea02df323 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2980,7 +2980,8 @@ namespace ImGui // If this ever crashes because g.CurrentWindow is NULL, it means that either: // - ImGui::NewFrame() has never been called, which is illegal. // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal. - IMGUI_API ImGuiIO& GetIOEx(ImGuiContext* ctx); + IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx); + IMGUI_API ImGuiPlatformIO& GetPlatformIO(ImGuiContext* ctx); inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; } inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; } IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id); From e4db4e423d78bce7e6c050f1f0710b3b635a9871 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 Jan 2025 19:50:18 +0100 Subject: [PATCH 199/716] Internals: renamed GetIOEx() to GetIO(). Added GetPlatformIO() explicit context variant. - OOPS --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 7d4da45501d0..88f5088515af 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4829,7 +4829,7 @@ ImGuiPlatformIO& ImGui::GetPlatformIO() // This variant exists to facilitate backends experimenting with multi-threaded parallel context. (#8069, #6293, #5856) ImGuiPlatformIO& ImGui::GetPlatformIO(ImGuiContext* ctx) { - IM_ASSERT(ctx != NULL; + IM_ASSERT(ctx != NULL); return ctx->PlatformIO; } From f820bf7cd4bd92cfbe5bbd3bab51e7cb81442e53 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 12:33:40 +0100 Subject: [PATCH 200/716] Version 1.91.9 WIP --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index eaedb9c1be0c..296c4202d393 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.91.9 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.91.8 (Released 2025-01-31) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 88f5088515af..09c5175a3967 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 7b037a584027..9b1a8323dfc7 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.8" -#define IMGUI_VERSION_NUM 19180 +#define IMGUI_VERSION "1.91.9 WIP" +#define IMGUI_VERSION_NUM 19181 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 03ce4710adc8..530ed6cc41bc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e426f0e5dc67..3fa5adae1701 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 2d2ea02df323..d59c19c601a3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e7a3b8e8d191..71d1e7d8be3b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1e4297fcbd67..1ddaf71be402 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.8 +// dear imgui, v1.91.9 WIP // (widgets code) /* From 626533999502662a9f507b34d9ae0d8579d55a95 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 14:01:48 +0100 Subject: [PATCH 201/716] Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), RadioButton(), Selectable(). (#8370) Item is already made inactive at the time of calling MarkItemEdited(). Fix a604d4f71 --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 296c4202d393..10dc36bb884b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), Selectable(). (#8370) + Regression from 2025/01/13. + ----------------------------------------------------------------------- VERSION 1.91.8 (Released 2025-01-31) diff --git a/imgui.cpp b/imgui.cpp index 09c5175a3967..5f0ca9d81242 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4440,8 +4440,11 @@ void ImGui::MarkItemEdited(ImGuiID id) return; if (g.ActiveId == id || g.ActiveId == 0) { + // FIXME: Can't we fully rely on LastItemData yet? g.ActiveIdHasBeenEditedThisFrame = true; g.ActiveIdHasBeenEditedBefore = true; + if (g.DeactivatedItemData.ID == id) + g.DeactivatedItemData.HasBeenEditedBefore = true; } // We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343) From 204cebc8fc5678c446037f232945bde58003fa76 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 14:21:53 +0100 Subject: [PATCH 202/716] Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] --- backends/imgui_impl_metal.mm | 4 ++-- docs/CHANGELOG.txt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 1e0c47f52b51..5df9176a095e 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -311,11 +311,11 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c indexBufferOffset += (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx); } - __block MetalContext* sharedMetalContext = bd->SharedMetalContext; + MetalContext* sharedMetalContext = bd->SharedMetalContext; [commandBuffer addCompletedHandler:^(id) { dispatch_async(dispatch_get_main_queue(), ^{ - @synchronized(bd->SharedMetalContext.bufferCache) + @synchronized(sharedMetalContext.bufferCache) { [sharedMetalContext.bufferCache addObject:vertexBuffer]; [sharedMetalContext.bufferCache addObject:indexBuffer]; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 10dc36bb884b..935d453ab604 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,9 +43,9 @@ Breaking changes: Other changes: -- Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), Selectable(). (#8370) - Regression from 2025/01/13. - +- Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), + RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) +- Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] ----------------------------------------------------------------------- VERSION 1.91.8 (Released 2025-01-31) From 5dd84082ab333453e50f08ba4dc9ebf0d8860254 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 15:11:03 +0100 Subject: [PATCH 203/716] InputTextWithHint(): Fixed buffer overflow when user callback modifies the buffer contents in a way that alters hint visibility. (#8368) --- backends/imgui_impl_metal.mm | 1 + docs/CHANGELOG.txt | 3 +++ imgui.cpp | 1 + imgui_widgets.cpp | 14 +++++++++++++- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 5df9176a095e..1cd2308d144d 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-03: Metal: Crash fix. (#8367) // 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. // 2022-07-05: Metal: Add dispatch synchronization. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 935d453ab604..e472ffcf2f94 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,9 @@ Other changes: - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) +- InputTextWithHint(): Fixed buffer-overflow (luckily often with no visible effect) + when a user callback modified the buffer contents in a way that altered the + visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 5f0ca9d81242..8f99608b24dd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2012,6 +2012,7 @@ const char* ImStreolRange(const char* str, const char* str_end) const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line { + IM_ASSERT_PARANOID(buf_mid_line >= buf_begin && buf_mid_line <= buf_begin + strlen(buf_begin)); while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') buf_mid_line--; return buf_mid_line; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1ddaf71be402..be015a6f44ff 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4669,7 +4669,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Select the buffer to render. const bool buf_display_from_state = (render_cursor || render_selection || g.ActiveId == id) && !is_readonly && state; - const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); // Password pushes a temporary font with only a fallback glyph if (is_password && !is_displaying_hint) @@ -5151,6 +5151,18 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const int buf_display_max_length = 2 * 1024 * 1024; const char* buf_display = buf_display_from_state ? state->TextA.Data : buf; //-V595 const char* buf_display_end = NULL; // We have specialized paths below for setting the length + + // Display hint when contents is empty + // At this point we need to handle the possibility that a callback could have modified the underlying buffer (#8368) + const bool new_is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0); + if (new_is_displaying_hint != is_displaying_hint) + { + if (is_password && !is_displaying_hint) + PopFont(); + is_displaying_hint = new_is_displaying_hint; + if (is_password && !is_displaying_hint) + PushPasswordFont(); + } if (is_displaying_hint) { buf_display = hint; From da0ba9e2fef6a60bae033580499a74e2764ce635 Mon Sep 17 00:00:00 2001 From: PhantomCloak Date: Sun, 2 Feb 2025 19:25:09 +0300 Subject: [PATCH 204/716] Backends: WebGPU: add type alias for dawn WGPUProgrammableStageDescriptor -> WGPUComputeState. (#8369) --- backends/imgui_impl_wgpu.cpp | 6 ++++++ docs/CHANGELOG.txt | 2 ++ 2 files changed, 8 insertions(+) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 2f34c0e0b345..84de56df2057 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -58,6 +58,12 @@ #include #include +#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +// Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413) +// Using type alias until WGPU adopts the same naming convention (#8369) +using WGPUProgrammableStageDescriptor = WGPUComputeState; +#endif + // Dear ImGui prototypes from imgui_internal.h extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0); #define MEMALIGN(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align (copied from IM_ALIGN() macro). diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e472ffcf2f94..bf40370200f4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,8 @@ Other changes: when a user callback modified the buffer contents in a way that altered the visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] +- Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. + [@PhantomCloak] (#8369) ----------------------------------------------------------------------- VERSION 1.91.8 (Released 2025-01-31) From de962e83d0095a0676a42da184cad8e4066669a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 17:50:12 +0100 Subject: [PATCH 205/716] ImFont: remove SetGlyphVisible() Which was never marked public. Added by d284a6cff. (#2149, #515) Making room by removing stuff that are inconvenient to implement in our scaling system. If you were using this function please post an issue to report it. --- imgui.h | 1 - imgui_draw.cpp | 12 ++++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index 9b1a8323dfc7..f80e9d255f28 100644 --- a/imgui.h +++ b/imgui.h @@ -3498,7 +3498,6 @@ struct ImFont IMGUI_API void GrowIndex(int new_size); IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. - IMGUI_API void SetGlyphVisible(ImWchar c, bool visible); IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3fa5adae1701..c66f52cd4103 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3770,8 +3770,10 @@ void ImFont::BuildLookupTable() } // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) - SetGlyphVisible((ImWchar)' ', false); - SetGlyphVisible((ImWchar)'\t', false); + if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)' ')) + glyph->Visible = false; + if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)'\t')) + glyph->Visible = false; // Setup Fallback character const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; @@ -3827,12 +3829,6 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) return true; } -void ImFont::SetGlyphVisible(ImWchar c, bool visible) -{ - if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c)) - glyph->Visible = visible ? 1 : 0; -} - void ImFont::GrowIndex(int new_size) { IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); From 1a31e31ae92db10431a35bc5fbb5465848659e9a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 17:55:35 +0100 Subject: [PATCH 206/716] (Breaking) Fonts: removed ImFontConfig::GlyphExtraSpacing option which seems largely obsolete and unused. (#242) --- docs/CHANGELOG.txt | 3 +++ docs/FONTS.md | 2 +- imgui.cpp | 1 + imgui.h | 6 +++--- imgui_draw.cpp | 5 +---- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bf40370200f4..72f0ed126f44 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,9 @@ HOW TO UPDATE? Breaking changes: +- Removed ImFontConfig::GlyphExtraSpacing option which seems largely obsolete and + unused. If you were using this please report it! (#242). + Other changes: - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), diff --git a/docs/FONTS.md b/docs/FONTS.md index e36afdf817d0..e9fbcbe42712 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -110,7 +110,7 @@ ImGui::PopFont(); **For advanced options create a ImFontConfig structure and pass it to the AddFont() function (it will be copied internally):** ```cpp ImFontConfig config; -config.GlyphExtraSpacing.x = 1.0f; +config.RasterizerDensity = 2.0f; ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); ``` diff --git a/imgui.cpp b/imgui.cpp index 8f99608b24dd..3a7e600058ec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,6 +430,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/02/03 (1.91.9) - removed ImFontConfig::GlyphExtraSpacing option which seems largely obsolete and unused. If you were using this please report it! - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. the new flags (ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg + existing ImGuiColorEditFlags_AlphaPreviewHalf) may be combined better and allow finer controls: diff --git a/imgui.h b/imgui.h index f80e9d255f28..f6bfa4e5d0d6 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19181 +#define IMGUI_VERSION_NUM 19182 #define IMGUI_HAS_TABLE /* @@ -3257,7 +3257,7 @@ struct ImFontConfig int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. + //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font @@ -3281,7 +3281,7 @@ struct ImFontGlyph unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. unsigned int Codepoint : 30; // 0x0000..0x10FFFF - float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) + float AdvanceX; // Horizontal distance to advance layout with float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c66f52cd4103..78fa4c1eac79 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3349,7 +3349,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas) if (r->Font == NULL || r->GlyphID == 0) continue; - // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH + // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, PixelSnapH IM_ASSERT(r->Font->ContainerAtlas == atlas); ImVec2 uv0, uv1; atlas->CalcCustomRectUV(r, &uv0, &uv1); @@ -3858,9 +3858,6 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa // Snap to pixel if (cfg->PixelSnapH) advance_x = IM_ROUND(advance_x); - - // Bake spacing - advance_x += cfg->GlyphExtraSpacing.x; } int glyph_idx = Glyphs.Size; From 2d20e13746c05bfe36d4a57ac465e7a9fe9005d9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 4 Feb 2025 20:19:57 +0100 Subject: [PATCH 207/716] Backends: GLFW: Added comment about io.AddMouseSourceEvent() not being properly called. (#8374) --- backends/imgui_impl_glfw.cpp | 2 ++ backends/imgui_impl_glfw.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 01a6a5566397..66183561f08a 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -9,6 +9,8 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features or Issues: +// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 53a22415d87c..bba6d09ea8c1 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -8,6 +8,8 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// Missing features or Issues: +// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. From cfed18afc79c1bdea142cccd74639734edbfbaf6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Feb 2025 12:34:37 +0100 Subject: [PATCH 208/716] Add ImFontConfig::GlyphExtraAdvanceX as a replacement for GlyphExtraSpacing.x (#242) Partly restore 1a31e31. --- docs/CHANGELOG.txt | 3 +-- imgui.cpp | 2 +- imgui.h | 5 +++-- imgui_draw.cpp | 3 +++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 72f0ed126f44..a81ef2038f2b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,8 +41,7 @@ HOW TO UPDATE? Breaking changes: -- Removed ImFontConfig::GlyphExtraSpacing option which seems largely obsolete and - unused. If you were using this please report it! (#242). +- Renamed ImFontConfig::GlyphExtraSpacing.x option to GlyphExtraAdvanceX. (#242) Other changes: diff --git a/imgui.cpp b/imgui.cpp index 3a7e600058ec..4de75457ddc9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -430,7 +430,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2025/02/03 (1.91.9) - removed ImFontConfig::GlyphExtraSpacing option which seems largely obsolete and unused. If you were using this please report it! + - 2025/02/06 (1.91.9) - renamed ImFontConfig::GlyphExtraSpacing.x to ImFontConfig::GlyphExtraAdvanceX. - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. the new flags (ImGuiColorEditFlags_AlphaOpaque, ImGuiColorEditFlags_AlphaNoBg + existing ImGuiColorEditFlags_AlphaPreviewHalf) may be combined better and allow finer controls: diff --git a/imgui.h b/imgui.h index f6bfa4e5d0d6..a3f660366ad2 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19182 +#define IMGUI_VERSION_NUM 19183 #define IMGUI_HAS_TABLE /* @@ -3257,11 +3257,12 @@ struct ImFontConfig int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. + //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX) ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 78fa4c1eac79..ed5164bb77a7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3858,6 +3858,9 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa // Snap to pixel if (cfg->PixelSnapH) advance_x = IM_ROUND(advance_x); + + // Bake extra spacing + advance_x += cfg->GlyphExtraAdvanceX; } int glyph_idx = Glyphs.Size; From 0625b37760215f2b890e8605e7070bb8c9521a22 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Feb 2025 18:37:32 +0100 Subject: [PATCH 209/716] Scrollbar: Rework logic that fades-out scrollbar when it becomes too small. Amend 0236bc246f --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a81ef2038f2b..7977ef681a77 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,8 @@ Other changes: - InputTextWithHint(): Fixed buffer-overflow (luckily often with no visible effect) when a user callback modified the buffer contents in a way that altered the visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] +- Scrollbar: Rework logic that fades-out scrollbar when it becomes too small, + which amusingly made it disappear when using very big font/frame size. - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] - Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index be015a6f44ff..612ff62a639f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -971,8 +971,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 // When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the window resize grab) float alpha = 1.0f; - if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f) - alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f)); + if ((axis == ImGuiAxis_Y) && bb_frame_height < bb_frame_width) + alpha = ImSaturate(bb_frame_height / ImMax(bb_frame_width * 2.0f, 1.0f)); if (alpha <= 0.0f) return false; @@ -989,7 +989,8 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 // But we maintain a minimum size in pixel to allow for the user to still aim inside. IM_ASSERT(ImMax(size_contents_v, size_visible_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers. const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_visible_v), (ImS64)1); - const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), style.GrabMinSize, scrollbar_size_v); + const float grab_h_minsize = ImMin(bb.GetSize()[axis], style.GrabMinSize); + const float grab_h_pixels = ImClamp(scrollbar_size_v * ((float)size_visible_v / (float)win_size_v), grab_h_minsize, scrollbar_size_v); const float grab_h_norm = grab_h_pixels / scrollbar_size_v; // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar(). From 4f1d3809c32b0dd8745273bf7e22b4aa37494ce8 Mon Sep 17 00:00:00 2001 From: fdsa <14tanks999@gmail.com> Date: Wed, 5 Feb 2025 18:41:03 -0800 Subject: [PATCH 210/716] Fixed tabs and spaces (#8377) --- .github/ISSUE_TEMPLATE/issue_template.yml | 2 +- backends/imgui_impl_glfw.cpp | 2 +- backends/imgui_impl_glut.cpp | 2 +- backends/imgui_impl_sdlrenderer2.cpp | 34 +++++++++---------- backends/imgui_impl_sdlrenderer3.cpp | 34 +++++++++---------- backends/imgui_impl_wgpu.cpp | 8 ++--- backends/imgui_impl_win32.cpp | 30 ++++++++-------- docs/CONTRIBUTING.md | 10 +++--- docs/FAQ.md | 2 +- docs/TODO.txt | 2 +- examples/example_allegro5/README.md | 6 ++-- .../project.pbxproj | 12 +++---- examples/example_apple_metal/main.mm | 4 +-- examples/example_sdl3_opengl3/Makefile | 8 ++--- examples/example_sdl3_sdlgpu3/Makefile | 8 ++--- examples/example_sdl3_sdlrenderer3/Makefile | 8 ++--- .../example_win32_opengl3/build_mingw.bat | 2 +- imgui.h | 2 +- imgui_demo.cpp | 18 +++++----- misc/freetype/README.md | 2 +- misc/freetype/imgui_freetype.cpp | 10 +++--- 21 files changed, 103 insertions(+), 103 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/issue_template.yml b/.github/ISSUE_TEMPLATE/issue_template.yml index c1b57de4b739..46ed826d520a 100644 --- a/.github/ISSUE_TEMPLATE/issue_template.yml +++ b/.github/ISSUE_TEMPLATE/issue_template.yml @@ -8,7 +8,7 @@ body: For anything else: **we are happy to use 'GitHub Issues' for many types of open-ended questions**. We are encouraging 'Issues' becoming a large, centralized, tagged, cross-referenced database of Dear ImGui contents. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users. - + **If you are using Dear ImGui as part of a job that you are being well-paid for** and your company is not a sponsor. Please be mindful that this is a Free Software and you might be about to ask volunteers to help you doing your job. Please put extra effort describing your issue or question properly. If your company is wealthy, please read [Funding](https://github.com/ocornut/imgui/wiki/Funding) and consider getting in touch. - type: markdown attributes: diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 66183561f08a..454a36d368ce 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -469,7 +469,7 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) { - // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too. + // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too. } #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 diff --git a/backends/imgui_impl_glut.cpp b/backends/imgui_impl_glut.cpp index ef7f17922ec5..a68f9dbc8ed7 100644 --- a/backends/imgui_impl_glut.cpp +++ b/backends/imgui_impl_glut.cpp @@ -50,7 +50,7 @@ static int g_Time = 0; // Current time, in milliseconds -// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above. +// Glut has one function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above. static ImGuiKey ImGui_ImplGLUT_KeyToImGuiKey(int key) { switch (key) diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 8245854c262c..bfaeb9138161 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -100,10 +100,10 @@ void ImGui_ImplSDLRenderer2_Shutdown() static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer) { - // Clear out any viewports and cliprect set by the user + // Clear out any viewports and cliprect set by the user // FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process. - SDL_RenderSetViewport(renderer, nullptr); - SDL_RenderSetClipRect(renderer, nullptr); + SDL_RenderSetViewport(renderer, nullptr); + SDL_RenderSetClipRect(renderer, nullptr); } void ImGui_ImplSDLRenderer2_NewFrame() @@ -117,21 +117,21 @@ void ImGui_ImplSDLRenderer2_NewFrame() void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) { - // If there's a scale factor set by the user, use that instead + // If there's a scale factor set by the user, use that instead // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here. float rsx = 1.0f; - float rsy = 1.0f; - SDL_RenderGetScale(renderer, &rsx, &rsy); + float rsy = 1.0f; + SDL_RenderGetScale(renderer, &rsx, &rsy); ImVec2 render_scale; - render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; - render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; + render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; + render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); - int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); - if (fb_width == 0 || fb_height == 0) - return; + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); + int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); + if (fb_width == 0 || fb_height == 0) + return; // Backup SDL_Renderer state that will be modified to restore it afterwards struct BackupSDLRendererState @@ -154,9 +154,9 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* render_state.Renderer = renderer; platform_io.Renderer_RenderState = &render_state; - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = render_scale; + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = render_scale; // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) @@ -201,7 +201,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* #endif // Bind texture, Draw - SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); + SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); SDL_RenderGeometryRaw(renderer, tex, xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 99253d9643fd..42fefa0cd8f3 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -99,10 +99,10 @@ void ImGui_ImplSDLRenderer3_Shutdown() static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer) { - // Clear out any viewports and cliprect set by the user + // Clear out any viewports and cliprect set by the user // FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process. - SDL_SetRenderViewport(renderer, nullptr); - SDL_SetRenderClipRect(renderer, nullptr); + SDL_SetRenderViewport(renderer, nullptr); + SDL_SetRenderClipRect(renderer, nullptr); } void ImGui_ImplSDLRenderer3_NewFrame() @@ -136,21 +136,21 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); - // If there's a scale factor set by the user, use that instead + // If there's a scale factor set by the user, use that instead // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here. float rsx = 1.0f; - float rsy = 1.0f; - SDL_GetRenderScale(renderer, &rsx, &rsy); + float rsy = 1.0f; + SDL_GetRenderScale(renderer, &rsx, &rsy); ImVec2 render_scale; - render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; - render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; + render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; + render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; - // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); - int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); - if (fb_width == 0 || fb_height == 0) - return; + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); + int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); + if (fb_width == 0 || fb_height == 0) + return; // Backup SDL_Renderer state that will be modified to restore it afterwards struct BackupSDLRendererState @@ -175,9 +175,9 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* render_state.Renderer = renderer; platform_io.Renderer_RenderState = &render_state; - // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = render_scale; + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = render_scale; // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) @@ -218,7 +218,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+ // Bind texture, Draw - SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); + SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); SDL_RenderGeometryRaw8BitColor(renderer, bd->ColorBuffer, tex, xy, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert), diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 84de56df2057..a81662d8429d 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -268,13 +268,13 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); #ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN - WGPUShaderSourceWGSL wgsl_desc = {}; + WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_desc.code = { wgsl_source, WGPU_STRLEN }; + wgsl_desc.code = { wgsl_source, WGPU_STRLEN }; #else - WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; + WGPUShaderModuleWGSLDescriptor wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderModuleWGSLDescriptor; - wgsl_desc.code = wgsl_source; + wgsl_desc.code = wgsl_source; #endif WGPUShaderModuleDescriptor desc = {}; diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index f1cf6eccc52b..03ab53523d37 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -790,9 +790,9 @@ static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) { typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG); static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = nullptr; - if (RtlVerifyVersionInfoFn == nullptr) - if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll")) - RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo"); + if (RtlVerifyVersionInfoFn == nullptr) + if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll")) + RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo"); if (RtlVerifyVersionInfoFn == nullptr) return FALSE; @@ -800,10 +800,10 @@ static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD) ULONGLONG conditionMask = 0; versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW); versionInfo.dwMajorVersion = major; - versionInfo.dwMinorVersion = minor; - VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); - VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); - return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE; + versionInfo.dwMinorVersion = minor; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE; } #define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA @@ -861,16 +861,16 @@ float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) UINT xdpi = 96, ydpi = 96; if (_IsWindows8Point1OrGreater()) { - static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process - static PFN_GetDpiForMonitor GetDpiForMonitorFn = nullptr; - if (GetDpiForMonitorFn == nullptr && shcore_dll != nullptr) + static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process + static PFN_GetDpiForMonitor GetDpiForMonitorFn = nullptr; + if (GetDpiForMonitorFn == nullptr && shcore_dll != nullptr) GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor"); - if (GetDpiForMonitorFn != nullptr) - { - GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + if (GetDpiForMonitorFn != nullptr) + { + GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! - return xdpi / 96.0f; - } + return xdpi / 96.0f; + } } #ifndef NOGDI const HDC dc = ::GetDC(nullptr); diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 5cc9cdb53f40..f70cf0e23448 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -34,7 +34,7 @@ Only if you: Then please [use the Discussions forums](https://github.com/ocornut/imgui/discussions) instead of opening an issue. -If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new issue. +If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new issue. ## How to open an issue @@ -52,7 +52,7 @@ Steps: - **Please INCLUDE CODE. Provide a Minimal, Complete, and Verifiable Example ([MCVE](https://stackoverflow.com/help/mcve)) to demonstrate your problem**. An ideal submission includes a small piece of code that anyone can paste into one of the examples applications (examples/../main.cpp) or demo (imgui_demo.cpp) to understand and reproduce it. **Narrowing your problem to its shortest and purest form is the easiest way to understand it, explain it and fix it**. Please test your shortened code to ensure it exhibits the problem. **Often while creating the MCVE you will solve the problem!** Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time. - **Attach screenshots (or GIF/video) to clarify the context**. They often convey useful information that is omitted by the description. You can drag pictures/files in the message edit box. Avoid using 3rd party image hosting services, prefer the long-term longevity of GitHub attachments (you can drag pictures into your post). On Windows, you can use [ScreenToGif](https://www.screentogif.com/) to easily capture .gif files. - **If you are discussing an assert or a crash, please provide a debugger callstack**. Never state "it crashes" without additional information. If you don't know how to use a debugger and retrieve a callstack, learning about it will be useful. -- **Please make sure that your project has asserts enabled.** Calls to IM_ASSERT() are scattered in the code to help catch common issues. When an assert is triggered read the comments around it. By default IM_ASSERT() calls the standard assert() function. To verify that your asserts are enabled, add the line `IM_ASSERT(false);` in your main() function. Your application should display an error message and abort. If your application doesn't report an error, your asserts are disabled. +- **Please make sure that your project has asserts enabled.** Calls to IM_ASSERT() are scattered in the code to help catch common issues. When an assert is triggered read the comments around it. By default IM_ASSERT() calls the standard assert() function. To verify that your asserts are enabled, add the line `IM_ASSERT(false);` in your main() function. Your application should display an error message and abort. If your application doesn't report an error, your asserts are disabled. - Please state if you have made substantial modifications to your copy of Dear ImGui or the back-end. - If you are not calling Dear ImGui directly from C++, please provide information about your Language and the wrapper/binding you are using. - Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proofread your messages before sending them. Edits are not seen by those users unless they browse the site. @@ -65,12 +65,12 @@ If you have been using Dear ImGui for a while or have been using C/C++ for sever ## How to open a Pull Request -- **Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance.** PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. +- **Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance.** PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. - Many PRs are useful to demonstrate a need and a possible solution but aren't adequate for merging (causing other issues, not seeing other aspects of the big picture, etc.). In doubt, don't hesitate to push a PR because that is always the first step toward pointing toward a problem, and finding the mergeable solution! Even if a PR stays unmerged for a long time, its presence can be useful for other users and helps toward finding a general solution. -- **When adding a feature,** please describe the usage context (how you intend to use it, why you need it, etc.). Be mindful of [The XY Problem](http://xyproblem.info/). +- **When adding a feature,** please describe the usage context (how you intend to use it, why you need it, etc.). Be mindful of [The XY Problem](http://xyproblem.info/). - **When fixing a warning or compilation problem,** please post the compiler log and specify the compiler version and platform you are using. - **Attach screenshots (or GIF/video) to clarify the context and demonstrate the feature at a glance.** You can drag pictures/files in the message edit box. Prefer the long-term longevity of GitHub attachments over 3rd party hosting (you can drag pictures into your post). -- **Make sure your code follows the coding style already used in the codebase:** 4 spaces indentations (no tabs), `local_variable`, `FunctionName()`, `MemberName`, `// Text Comment`, `//CodeComment();`, C-style casts, etc.. We don't use modern C++ idioms and tend to use only a minimum of C++11 features. The applications under examples/ are generally less consistent because they sometimes try to mimic the coding style often adopted by a certain ecosystem (e.g. DirectX-related code tend to use the style of their sample). +- **Make sure your code follows the coding style already used in the codebase:** 4 spaces indentations (no tabs), `local_variable`, `FunctionName()`, `MemberName`, `// Text Comment`, `//CodeComment();`, C-style casts, etc.. We don't use modern C++ idioms and tend to use only a minimum of C++11 features. The applications under examples/ are generally less consistent because they sometimes try to mimic the coding style often adopted by a certain ecosystem (e.g. DirectX-related code tend to use the style of their sample). - **Make sure you create a branch dedicated to the pull request**. In Git, 1 PR is associated to 1 branch. If you keep pushing to the same branch after you submitted the PR, your new commits will appear in the PR (we can still cherry-pick individual commits). ## Copyright / Contributor License Agreement diff --git a/docs/FAQ.md b/docs/FAQ.md index 8dde1967b469..6e8d6c26f7dd 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -233,7 +233,7 @@ for (int n = 0; n < 3; n++) ImGui::End(); - + A primer on labels and the ID Stack... diff --git a/docs/TODO.txt b/docs/TODO.txt index 2a42874cd3fe..31238ff83536 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -9,7 +9,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - doc: add a proper documentation system (maybe relying on automation? #435) - doc: checklist app to verify backends/integration of imgui (test inputs, rendering, callback, etc.). - doc/tips: tips of the day: website? applet in imgui_club? - + - window: preserve/restore relative focus ordering (persistent or not), and e.g. of multiple reappearing windows (#2304) -> also see docking reference to same #. - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis). (#690) - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass. diff --git a/examples/example_allegro5/README.md b/examples/example_allegro5/README.md index 4af31f6f3a2e..940b47fdb22d 100644 --- a/examples/example_allegro5/README.md +++ b/examples/example_allegro5/README.md @@ -24,9 +24,9 @@ You may install Allegro using vcpkg: git clone https://github.com/Microsoft/vcpkg cd vcpkg bootstrap-vcpkg.bat -vcpkg install allegro5 --triplet=x86-windows ; for win32 -vcpkg install allegro5 --triplet=x64-windows ; for win64 -vcpkg integrate install ; register include / libs in Visual Studio +vcpkg install allegro5 --triplet=x86-windows ; for win32 +vcpkg install allegro5 --triplet=x64-windows ; for win64 +vcpkg integrate install ; register include / libs in Visual Studio ``` Build: diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj index 4bb4fc288791..5f657eab9495 100644 --- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj +++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj @@ -268,9 +268,9 @@ 8309BDBB253CCCAD0045E2A1 /* imgui_impl_metal.mm in Sources */, 83BBEA0920EB54E700295997 /* imgui.cpp in Sources */, 83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */, - 83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */, + 83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */, 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, - 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */, + 07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */, 8309BDA5253CCC070045E2A1 /* main.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -281,10 +281,10 @@ files = ( 8309BDBE253CCCB60045E2A1 /* imgui_impl_metal.mm in Sources */, 8309BDBF253CCCB60045E2A1 /* imgui_impl_osx.mm in Sources */, - 83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */, - 83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */, - 83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */, - 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, + 83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */, + 83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */, + 83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */, + 5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */, 07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */, 8309BDA8253CCC080045E2A1 /* main.mm in Sources */, ); diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 109ef6153c3e..830f1aed33b6 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -129,7 +129,7 @@ -(void)drawInMTKView:(MTKView*)view if (renderPassDescriptor == nil) { [commandBuffer commit]; - return; + return; } // Start the Dear ImGui frame @@ -192,7 +192,7 @@ -(void)drawInMTKView:(MTKView*)view [renderEncoder popDebugGroup]; [renderEncoder endEncoding]; - // Present + // Present [commandBuffer presentDrawable:view.currentDrawable]; [commandBuffer commit]; } diff --git a/examples/example_sdl3_opengl3/Makefile b/examples/example_sdl3_opengl3/Makefile index 741e97d0c270..c2ef3ba556c3 100644 --- a/examples/example_sdl3_opengl3/Makefile +++ b/examples/example_sdl3_opengl3/Makefile @@ -54,11 +54,11 @@ ifeq ($(UNAME_S), Darwin) #APPLE endif ifeq ($(OS), Windows_NT) - ECHO_MESSAGE = "MinGW" - LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl3` + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl3` - CXXFLAGS += `pkg-config --cflags sdl3` - CFLAGS = $(CXXFLAGS) + CXXFLAGS += `pkg-config --cflags sdl3` + CFLAGS = $(CXXFLAGS) endif ##--------------------------------------------------------------------- diff --git a/examples/example_sdl3_sdlgpu3/Makefile b/examples/example_sdl3_sdlgpu3/Makefile index f6239e0fa845..c3159d88804e 100644 --- a/examples/example_sdl3_sdlgpu3/Makefile +++ b/examples/example_sdl3_sdlgpu3/Makefile @@ -43,11 +43,11 @@ ifeq ($(UNAME_S), Darwin) #APPLE endif ifeq ($(OS), Windows_NT) - ECHO_MESSAGE = "MinGW" - LIBS += -lgdi32 -limm32 `pkg-config --static --libs sdl3` + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -limm32 `pkg-config --static --libs sdl3` - CXXFLAGS += `pkg-config --cflags sdl3` - CFLAGS = $(CXXFLAGS) + CXXFLAGS += `pkg-config --cflags sdl3` + CFLAGS = $(CXXFLAGS) endif ##--------------------------------------------------------------------- diff --git a/examples/example_sdl3_sdlrenderer3/Makefile b/examples/example_sdl3_sdlrenderer3/Makefile index 238576c7c341..2ca98654574b 100644 --- a/examples/example_sdl3_sdlrenderer3/Makefile +++ b/examples/example_sdl3_sdlrenderer3/Makefile @@ -43,11 +43,11 @@ ifeq ($(UNAME_S), Darwin) #APPLE endif ifeq ($(OS), Windows_NT) - ECHO_MESSAGE = "MinGW" - LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl3` + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl3` - CXXFLAGS += `pkg-config --cflags sdl3` - CFLAGS = $(CXXFLAGS) + CXXFLAGS += `pkg-config --cflags sdl3` + CFLAGS = $(CXXFLAGS) endif ##--------------------------------------------------------------------- diff --git a/examples/example_win32_opengl3/build_mingw.bat b/examples/example_win32_opengl3/build_mingw.bat index 7672185858d2..e9f804f5d00a 100644 --- a/examples/example_win32_opengl3/build_mingw.bat +++ b/examples/example_win32_opengl3/build_mingw.bat @@ -1,4 +1,4 @@ -@REM Build for MINGW64 or 32 from MSYS2. +@REM Build for MINGW64 or 32 from MSYS2. @set OUT_DIR=Debug @set OUT_EXE=example_win32_opengl3 @set INCLUDES=-I../.. -I../../backends diff --git a/imgui.h b/imgui.h index a3f660366ad2..acec7bf999ac 100644 --- a/imgui.h +++ b/imgui.h @@ -1177,7 +1177,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). // Elide display / Alignment - ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only! + ImGuiInputTextFlags_ElideLeft = 1 << 17, // When text doesn't fit, elide left side to ensure right side stays visible. Useful for path/filenames. Single-line only! // Callback features ImGuiInputTextFlags_CallbackCompletion = 1 << 18, // Callback on pressing TAB (for completion handling) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 530ed6cc41bc..dd6ebb93e8d2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -584,7 +584,7 @@ void ImGui::ShowDemoWindow(bool* p_open) "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n" "- You not are not supposed to rely on it in the course of a normal application run.\n" "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n" - "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!" + "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call! " "Otherwise it would severely hinder your ability to catch and correct mistakes!"); ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert); ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog); @@ -1035,8 +1035,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SeparatorText("Custom"); HelpMarker( - "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize" - "tooltip activation details across your application. You may however decide to use custom" + "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " + "tooltip activation details across your application. You may however decide to use custom " "flags for a specific tooltip instance."); // The following examples are passed for documentation purpose but may not be useful to most users. @@ -2271,8 +2271,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Text("Set defaults in code:"); ImGui::SameLine(); HelpMarker( "SetColorEditOptions() is designed to allow you to set boot-time default.\n" - "We don't have Push/Pop functions because you can force options on a per-widget basis if needed," - "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid" + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " "encouraging you to persistently save values that aren't forward-compatible."); if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); @@ -2295,8 +2295,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Spacing(); ImGui::Text("HSV encoded colors"); ImGui::SameLine(); HelpMarker( - "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV" - "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the" + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); ImGui::Text("Color widget with InputHSV:"); ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); @@ -3558,7 +3558,7 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) if (ImGui::TreeNode("Multi-Select (trees)")) { HelpMarker( - "This is rather advanced and experimental. If you are getting started with multi-select," + "This is rather advanced and experimental. If you are getting started with multi-select, " "please don't start by looking at how to use it for a tree!\n\n" "Future versions will try to simplify and formalize some of this."); @@ -9493,7 +9493,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) float th = (n == 0) ? 1.0f : thickness; draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle - draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse + draw_list->AddEllipse(ImVec2(x + sz*0.5f, y + sz*0.5f), ImVec2(sz*0.5f, sz*0.3f), col, -0.3f, circle_segments, th); x += sz + spacing; // Ellipse draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, ImDrawFlags_None, th); x += sz + spacing; // Square draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, ImDrawFlags_None, th); x += sz + spacing; // Square with all rounded corners draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 3955b080e2fc..6e2e8671e9e2 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -38,7 +38,7 @@ You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain color ### Using OpenType SVG fonts (SVGinOT) - *SVG in Open Type* is a standard by Adobe and Mozilla for color OpenType and Open Font Format fonts. It allows font creators to embed complete SVG files within a font enabling full color and even animations. -- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT +- Popular fonts such as [twemoji](https://github.com/13rac1/twemoji-color-font) and fonts made with [scfbuild](https://github.com/13rac1/scfbuild) is SVGinOT. - Two alternatives are possible to render SVG fonts: use "lunasvg" or "plutosvg". plutosvg will support some more fonts (e.g. NotoColorEmoji-Regular) and may load them faster. #### Using lunasvg diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 029991bbdec3..875060d7f394 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -269,11 +269,11 @@ namespace if (glyph_index == 0) return nullptr; - // If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts. - // - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 - // - https://github.com/ocornut/imgui/issues/4567 - // - https://github.com/ocornut/imgui/issues/4566 - // You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version. + // If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts. + // - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 + // - https://github.com/ocornut/imgui/issues/4567 + // - https://github.com/ocornut/imgui/issues/4566 + // You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version. FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags); if (error) return nullptr; From 914fbcf2e52d43db71d13f12f1a9971719f1c560 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 16:23:00 +0100 Subject: [PATCH 211/716] Fonts: removed unnecessary const qualifier from ImFont::FindGlyph() Amend 0bde57c --- imgui.h | 16 +++++++++------- imgui_draw.cpp | 4 ++-- imgui_widgets.cpp | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/imgui.h b/imgui.h index acec7bf999ac..24f8fc2b0e2c 100644 --- a/imgui.h +++ b/imgui.h @@ -3412,6 +3412,7 @@ struct ImFontAtlas // Members //------------------------------------------- + // Input ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. @@ -3443,8 +3444,8 @@ struct ImFontAtlas int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines // [Obsolete] - //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ - //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ + //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; // Font runtime data and rendering @@ -3459,7 +3460,7 @@ struct ImFont // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // All glyphs. - const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) // [Internal] Members: Cold ~32/40 bytes // Conceptually ConfigData[] is the list of font sources merged to create this font. @@ -3480,12 +3481,13 @@ struct ImFont // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c); - IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c); + IMGUI_API ImFontGlyph* FindGlyph(ImWchar c); + IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } bool IsLoaded() const { return ContainerAtlas != NULL; } const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 @@ -3552,7 +3554,7 @@ struct ImGuiPlatformIO IMGUI_API ImGuiPlatformIO(); //------------------------------------------------------------------ - // Interface with OS and Platform backend + // Input - Interface with OS and Platform backend (most common stuff) //------------------------------------------------------------------ // Optional: Access OS clipboard @@ -3577,7 +3579,7 @@ struct ImGuiPlatformIO ImWchar Platform_LocaleDecimalPoint; // '.' //------------------------------------------------------------------ - // Interface with Renderer Backend + // Input - Interface with Renderer Backend //------------------------------------------------------------------ // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ed5164bb77a7..5bf0f0b1802a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3903,7 +3903,7 @@ void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) } // Find glyph, return fallback if missing -const ImFontGlyph* ImFont::FindGlyph(ImWchar c) +ImFontGlyph* ImFont::FindGlyph(ImWchar c) { if (c >= (size_t)IndexLookup.Size) return FallbackGlyph; @@ -3913,7 +3913,7 @@ const ImFontGlyph* ImFont::FindGlyph(ImWchar c) return &Glyphs.Data[i]; } -const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) +ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) { if (c >= (size_t)IndexLookup.Size) return NULL; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 612ff62a639f..d246147bdebc 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4252,7 +4252,7 @@ void ImGui::PushPasswordFont() ImGuiContext& g = *GImGui; ImFont* in_font = g.Font; ImFont* out_font = &g.InputTextPasswordFont; - const ImFontGlyph* glyph = in_font->FindGlyph('*'); + ImFontGlyph* glyph = in_font->FindGlyph('*'); out_font->FontSize = in_font->FontSize; out_font->Scale = in_font->Scale; out_font->Ascent = in_font->Ascent; From 4982602f6feb0df9fe67e20a197aa074bfde3780 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 18:16:04 +0100 Subject: [PATCH 212/716] Windows, Style: Added style.WindowBorderHoverPadding setting to configure inner/outer padding applied to hit-testing of windows borders. Amend 3c7177c6, 59f3c4fc2, ae7f833c6. Could be latched inside windows to be multi-dpi friendly, but likely won't matter soon. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 21 ++++++++++----------- imgui.h | 1 + imgui_demo.cpp | 5 ++++- imgui_internal.h | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7977ef681a77..b9888b134ffd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,9 @@ Other changes: - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) +- Windows, Style: Added style.WindowBorderHoverPadding setting to configure + inner/outer padding applied to hit-testing of windows borders and detection + of hovered window. - InputTextWithHint(): Fixed buffer-overflow (luckily often with no visible effect) when a user callback modified the buffer contents in a way that altered the visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] diff --git a/imgui.cpp b/imgui.cpp index 4de75457ddc9..29fe4a220d8b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1167,11 +1167,7 @@ CODE // When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear - static const float NAV_ACTIVATE_HIGHLIGHT_TIMER = 0.10f; // Time to highlight an item activated by a shortcut. - -// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend) -static const float WINDOWS_HOVER_PADDING = 4.0f; // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow(). static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time. static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved. @@ -1318,6 +1314,7 @@ ImGuiStyle::ImGuiStyle() WindowPadding = ImVec2(8,8); // Padding within a window WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. + WindowBorderHoverPadding = 4.0f; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders. WindowMinSize = ImVec2(32,32); // Minimum window size WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text WindowMenuButtonPosition = ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left. @@ -1379,6 +1376,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) WindowPadding = ImTrunc(WindowPadding * scale_factor); WindowRounding = ImTrunc(WindowRounding * scale_factor); WindowMinSize = ImTrunc(WindowMinSize * scale_factor); + WindowBorderHoverPadding = ImTrunc(WindowBorderHoverPadding * scale_factor); ChildRounding = ImTrunc(ChildRounding * scale_factor); PopupRounding = ImTrunc(PopupRounding * scale_factor); FramePadding = ImTrunc(FramePadding * scale_factor); @@ -5037,7 +5035,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() // FIXME-DPI: This storage was added on 2021/03/31 for test engine, but if we want to multiply WINDOWS_HOVER_PADDING // by DpiScale, we need to make this window-agnostic anyhow, maybe need storing inside ImGuiWindow. - g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING)); + g.WindowsBorderHoverPadding = ImMax(ImMax(g.Style.TouchExtraPadding.x, g.Style.TouchExtraPadding.y), g.Style.WindowBorderHoverPadding); // Find the window hovered by mouse: // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow. @@ -5800,7 +5798,7 @@ void ImGui::FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_vi hovered_window = g.MovingWindow; ImVec2 padding_regular = g.Style.TouchExtraPadding; - ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular; + ImVec2 padding_for_resize = ImMax(g.Style.TouchExtraPadding, ImVec2(g.Style.WindowBorderHoverPadding, g.Style.WindowBorderHoverPadding)); for (int i = g.Windows.Size - 1; i >= 0; i--) { ImGuiWindow* window = g.Windows[i]; @@ -6502,7 +6500,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si int ret_auto_fit_mask = 0x00; const float grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); const float grip_hover_inner_size = (resize_grip_count > 0) ? IM_TRUNC(grip_draw_size * 0.75f) : 0.0f; - const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f; + const float grip_hover_outer_size = g.WindowsBorderHoverPadding; ImRect clamp_rect = visibility_rect; const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar); @@ -6570,7 +6568,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y; bool hovered, held; - ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, g.WindowsBorderHoverPadding); ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID() ItemAdd(border_rect, border_id, NULL, ImGuiItemFlags_NoNav); ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus); @@ -6608,7 +6606,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si const ImVec2 border_curr = (window->Pos + ImMin(def.SegmentN1, def.SegmentN2) * window->Size); const float border_target_rel_mode_for_axis = border_curr[axis] + g.IO.MouseDelta[axis]; - const float border_target_abs_mode_for_axis = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING; // Match ButtonBehavior() padding above. + const float border_target_abs_mode_for_axis = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + g.WindowsBorderHoverPadding; // Match ButtonBehavior() padding above. // Use absolute mode position ImVec2 border_target = window->Pos; @@ -6697,7 +6695,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si // Recalculate next expected border expected coordinates if (*border_held != -1) - g.WindowResizeBorderExpectedRect = GetResizeBorderRect(window, *border_held, grip_hover_inner_size, WINDOWS_HOVER_PADDING); + g.WindowResizeBorderExpectedRect = GetResizeBorderRect(window, *border_held, grip_hover_inner_size, g.WindowsBorderHoverPadding); return ret_auto_fit_mask; } @@ -10184,7 +10182,8 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations - IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); + IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting!"); + IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders. IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); diff --git a/imgui.h b/imgui.h index 24f8fc2b0e2c..d58473801aea 100644 --- a/imgui.h +++ b/imgui.h @@ -2146,6 +2146,7 @@ struct ImGuiStyle ImVec2 WindowPadding; // Padding within a window. float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). + float WindowBorderHoverPadding; // Hit-testing extent outside/inside resizing border. Also extend determination of hovered window. Generally meaningfully larger than WindowBorderSize to make it easy to reach borders. ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constrain individual windows, use SetNextWindowSizeConstraints(). ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index dd6ebb93e8d2..3c40de2e7dd9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7985,11 +7985,14 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SeparatorText("Widgets"); + ImGui::SeparatorText("Windows"); ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); + + ImGui::SeparatorText("Widgets"); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); diff --git a/imgui_internal.h b/imgui_internal.h index d59c19c601a3..0aa894d56fca 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2083,7 +2083,7 @@ struct ImGuiContext ImVector CurrentWindowStack; ImGuiStorage WindowsById; // Map window's ImGuiID to ImGuiWindow* int WindowsActiveCount; // Number of unique windows submitted by frame - ImVec2 WindowsHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, WINDOWS_HOVER_PADDING). + float WindowsBorderHoverPadding; // Padding around resizable windows for which hovering on counts as hovering the window == ImMax(style.TouchExtraPadding, style.WindowBorderHoverPadding). This isn't so multi-dpi friendly. ImGuiID DebugBreakInWindow; // Set to break in Begin() call. ImGuiWindow* CurrentWindow; // Window being drawn into ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs. From e5668b8c738bd76d372a46e6a3d10812193be12f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 22:48:31 +0100 Subject: [PATCH 213/716] Internals: rename ImGuiNextWindowData::Flags to HasFlags for consistency and to reduce mistakes. --- imgui.cpp | 52 +++++++++++++++++++++++------------------------ imgui_internal.h | 9 +++++--- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 12 +++++------ 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 29fe4a220d8b..4ba2051d5532 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6068,7 +6068,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I // A SetNextWindowSize() call always has priority (#8020) // (since the code in Begin() never supported SizeVal==0.0f aka auto-resize via SetNextWindowSize() call, we don't support it here for now) // FIXME: We only support ImGuiCond_Always in this path. Supporting other paths would requires to obtain window pointer. - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) != 0 && (g.NextWindowData.SizeCond & ImGuiCond_Always) != 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) != 0 && (g.NextWindowData.SizeCond & ImGuiCond_Always) != 0) { if (g.NextWindowData.SizeVal.x > 0.0f) { @@ -6084,11 +6084,11 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I SetNextWindowSize(size); // Forward child flags (we allow prior settings to merge but it'll only work for adding flags) - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasChildFlags) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) g.NextWindowData.ChildFlags |= child_flags; else g.NextWindowData.ChildFlags = child_flags; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasChildFlags; // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value. // FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround. @@ -6302,7 +6302,7 @@ static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& s { ImGuiContext& g = *GImGui; ImVec2 new_size = size_desired; - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint) { // See comments in SetNextWindowSizeConstraints() for details about setting size_min an size_max. ImRect cr = g.NextWindowData.SizeConstraintRect; @@ -6780,7 +6780,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar ImU32 bg_col = GetColorU32(GetWindowBgColorIdx(window)); bool override_alpha = false; float alpha = 1.0f; - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasBgAlpha) { alpha = g.NextWindowData.BgAlphaVal; override_alpha = true; @@ -6950,7 +6950,7 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) { ImGuiContext& g = *GImGui; window->SkipRefresh = false; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasRefreshPolicy) == 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasRefreshPolicy) == 0) return; if (g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_TryToAvoidRefresh) { @@ -7031,7 +7031,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) { UpdateWindowInFocusOrderList(window, window_just_created, flags); window->Flags = (ImGuiWindowFlags)flags; - window->ChildFlags = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : 0; + window->ChildFlags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : 0; window->LastFrameActive = current_frame; window->LastTimeActive = (float)g.Time; window->BeginOrderWithinParent = 0; @@ -7095,7 +7095,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // (FIXME: Consider splitting the HasXXX flags into X/Y components bool window_pos_set_by_api = false; bool window_size_x_set_by_api = false, window_size_y_set_by_api = false; - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasPos) { window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0; if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f) @@ -7111,7 +7111,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond); } } - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) { window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f); window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f); @@ -7121,7 +7121,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) g.NextWindowData.SizeVal.y = window->SizeFull.y; SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond); } - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasScroll) { if (g.NextWindowData.ScrollVal.x >= 0.0f) { @@ -7134,13 +7134,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->ScrollTargetCenterRatio.y = 0.0f; } } - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasContentSize) window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal; else if (first_begin_of_the_frame) window->ContentSizeExplicit = ImVec2(0.0f, 0.0f); - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasCollapsed) SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond); - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasFocus) FocusWindow(window); if (window->Appearing) SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); @@ -8223,7 +8223,7 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi { ImGuiContext& g = *GImGui; IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasPos; g.NextWindowData.PosVal = pos; g.NextWindowData.PosPivotVal = pivot; g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always; @@ -8233,7 +8233,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) { ImGuiContext& g = *GImGui; IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasSize; g.NextWindowData.SizeVal = size; g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always; } @@ -8245,7 +8245,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond) void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data) { ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasSizeConstraint; g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max); g.NextWindowData.SizeCallback = custom_callback; g.NextWindowData.SizeCallbackUserData = custom_callback_user_data; @@ -8256,14 +8256,14 @@ void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& s void ImGui::SetNextWindowContentSize(const ImVec2& size) { ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasContentSize; g.NextWindowData.ContentSizeVal = ImTrunc(size); } void ImGui::SetNextWindowScroll(const ImVec2& scroll) { ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasScroll; g.NextWindowData.ScrollVal = scroll; } @@ -8271,7 +8271,7 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) { ImGuiContext& g = *GImGui; IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags. - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasCollapsed; g.NextWindowData.CollapsedVal = collapsed; g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always; } @@ -8279,7 +8279,7 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond) void ImGui::SetNextWindowBgAlpha(float alpha) { ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasBgAlpha; g.NextWindowData.BgAlphaVal = alpha; } @@ -8287,7 +8287,7 @@ void ImGui::SetNextWindowBgAlpha(float alpha) void ImGui::SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags) { ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasRefreshPolicy; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasRefreshPolicy; g.NextWindowData.RefreshFlagsVal = flags; } @@ -11301,7 +11301,7 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext // See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones). //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; const bool is_touchscreen = (g.IO.MouseSource == ImGuiMouseSource_TouchScreen); - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasPos) == 0) { ImVec2 tooltip_pos = is_touchscreen ? (g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_TOUCH * g.Style.MouseCursorScale) : (g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_MOUSE * g.Style.MouseCursorScale); ImVec2 tooltip_pivot = is_touchscreen ? TOOLTIP_DEFAULT_PIVOT_TOUCH : ImVec2(0.0f, 0.0f); @@ -11724,7 +11724,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla // Center modal windows by default for increased visibility // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves) // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window. - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasPos) == 0) { const ImGuiViewport* viewport = GetMainViewport(); SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f)); @@ -12017,7 +12017,7 @@ void ImGui::SetWindowFocus(const char* name) void ImGui::SetNextWindowFocus() { ImGuiContext& g = *GImGui; - g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus; + g.NextWindowData.HasFlags |= ImGuiNextWindowDataFlags_HasFocus; } // Similar to IsWindowHovered() @@ -16548,7 +16548,7 @@ static void ShowDebugLogFlag(const char* name, ImGuiDebugLogFlags flags) void ImGui::ShowDebugLogWindow(bool* p_open) { ImGuiContext& g = *GImGui; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1) { @@ -16868,7 +16868,7 @@ static int StackToolFormatLevelInfo(ImGuiIDStackTool* tool, int n, bool format_f void ImGui::ShowIDStackToolWindow(bool* p_open) { ImGuiContext& g = *GImGui; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0) SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver); if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1) { diff --git a/imgui_internal.h b/imgui_internal.h index 0aa894d56fca..ad9dc91e8b1b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1201,7 +1201,9 @@ enum ImGuiNextWindowDataFlags_ // Storage for SetNexWindow** functions struct ImGuiNextWindowData { - ImGuiNextWindowDataFlags Flags; + ImGuiNextWindowDataFlags HasFlags; + + // Members below are NOT cleared. Always rely on HasFlags. ImGuiCond PosCond; ImGuiCond SizeCond; ImGuiCond CollapsedCond; @@ -1220,7 +1222,7 @@ struct ImGuiNextWindowData ImGuiWindowRefreshFlags RefreshFlagsVal; ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); } - inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; } + inline void ClearFlags() { HasFlags = ImGuiNextWindowDataFlags_None; } }; enum ImGuiNextItemDataFlags_ @@ -1237,7 +1239,8 @@ struct ImGuiNextItemData { ImGuiNextItemDataFlags HasFlags; // Called HasFlags instead of Flags to avoid mistaking this ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData. - // Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem() + + // Members below are NOT cleared by ItemAdd() meaning they are still valid during e.g. NavProcessItem(). Always rely on HasFlags. ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData() ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values) float Width; // Set by SetNextItemWidth() diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 71d1e7d8be3b..3bd9502d09dd 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -415,7 +415,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Reset scroll if we are reactivating it if ((previous_flags & (ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY)) == 0) - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll) == 0) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasScroll) == 0) SetNextWindowScroll(ImVec2(0.0f, 0.0f)); // Create scrolling region (without border and zero window padding) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d246147bdebc..2b95c0dd58f3 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1829,7 +1829,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); - ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.Flags; + ImGuiNextWindowDataFlags backup_next_window_data_flags = g.NextWindowData.HasFlags; g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values if (window->SkipItems) return false; @@ -1898,7 +1898,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF if (!popup_open) return false; - g.NextWindowData.Flags = backup_next_window_data_flags; + g.NextWindowData.HasFlags = backup_next_window_data_flags; return BeginComboPopup(popup_id, bb, flags); } @@ -1913,7 +1913,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags // Set popup size float w = bb.GetWidth(); - if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) + if (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint) { g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w); } @@ -1927,9 +1927,9 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4; else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20; ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX); - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size constraint_min.x = w; - if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f) + if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f) constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items); SetNextWindowSizeConstraints(constraint_min, constraint_max); } @@ -2061,7 +2061,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* (*getter)(vo preview_value = getter(user_data, *current_item); // The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here. - if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)) + if (popup_max_height_in_items != -1 && !(g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasSizeConstraint)) SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items))); if (!BeginCombo(label, preview_value, ImGuiComboFlags_None)) From e368015d79a9deffc45894fcd33586092f968395 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 22:56:02 +0100 Subject: [PATCH 214/716] Tables: a clipped scrolling table correctly clears SetNextWindowXXX flags. (#8196) Amend 43c51eb12 --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b9888b134ffd..8fa53fc2589d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -55,6 +55,8 @@ Other changes: visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] - Scrollbar: Rework logic that fades-out scrollbar when it becomes too small, which amusingly made it disappear when using very big font/frame size. +- Tables: fixed calling SetNextWindowScroll() on clipped scrolling table + to not leak the value into a subsequent window. (#8196) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] - Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 3bd9502d09dd..2c1a0d3629c0 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -340,6 +340,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG { ItemSize(outer_rect); ItemAdd(outer_rect, id); + g.NextWindowData.ClearFlags(); return false; } From 50dbb086f23594c1b3b8db8ecaf255b6cbace832 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 22:57:15 +0100 Subject: [PATCH 215/716] Tables: sneakily honor ImGuiNextWindowDataFlags_HasChildFlags/ImGuiNextWindowDataFlags_HasWindowFlags as a way to facilitate various hacks/workarounds. --- imgui_internal.h | 6 ++++-- imgui_tables.cpp | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index ad9dc91e8b1b..f2aaeaa83d72 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1194,8 +1194,9 @@ enum ImGuiNextWindowDataFlags_ ImGuiNextWindowDataFlags_HasFocus = 1 << 5, ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6, ImGuiNextWindowDataFlags_HasScroll = 1 << 7, - ImGuiNextWindowDataFlags_HasChildFlags = 1 << 8, - ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 9, + ImGuiNextWindowDataFlags_HasWindowFlags = 1 << 8, + ImGuiNextWindowDataFlags_HasChildFlags = 1 << 9, + ImGuiNextWindowDataFlags_HasRefreshPolicy = 1 << 10, }; // Storage for SetNexWindow** functions @@ -1212,6 +1213,7 @@ struct ImGuiNextWindowData ImVec2 SizeVal; ImVec2 ContentSizeVal; ImVec2 ScrollVal; + ImGuiWindowFlags WindowFlags; // Only honored by BeginTable() ImGuiChildFlags ChildFlags; bool CollapsedVal; ImRect SizeConstraintRect; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 2c1a0d3629c0..c2e0127768a4 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -420,8 +420,11 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG SetNextWindowScroll(ImVec2(0.0f, 0.0f)); // Create scrolling region (without border and zero window padding) - ImGuiWindowFlags child_window_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None; - BeginChildEx(name, instance_id, outer_rect.GetSize(), ImGuiChildFlags_None, child_window_flags); + ImGuiChildFlags child_child_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasChildFlags) ? g.NextWindowData.ChildFlags : ImGuiChildFlags_None; + ImGuiWindowFlags child_window_flags = (g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasWindowFlags) ? g.NextWindowData.WindowFlags : ImGuiWindowFlags_None; + if (flags & ImGuiTableFlags_ScrollX) + child_window_flags |= ImGuiWindowFlags_HorizontalScrollbar; + BeginChildEx(name, instance_id, outer_rect.GetSize(), child_child_flags, child_window_flags); table->InnerWindow = g.CurrentWindow; table->WorkRect = table->InnerWindow->WorkRect; table->OuterRect = table->InnerWindow->Rect(); From e8ad60cc4f7ade30db505f739772befd3eb62b26 Mon Sep 17 00:00:00 2001 From: edenware <52419657+edenoftheware@users.noreply.github.com> Date: Fri, 7 Feb 2025 21:01:46 -0600 Subject: [PATCH 216/716] Fix typo (#8382) --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index d58473801aea..6f9f11ebc5c3 100644 --- a/imgui.h +++ b/imgui.h @@ -3132,7 +3132,7 @@ struct ImDrawList // General polygon // - Only simple polygons are supported by filling functions (no self-intersections, no holes). - // - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience fo user but not used by main library. + // - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library. IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness); IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col); From 2206e31e5449217b7298d7d704ef5da1763a128f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 11:37:55 +0100 Subject: [PATCH 217/716] Demo: Combos: demonstrate a very simple way to add a filter to a combo. (#718) --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 32 +++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8fa53fc2589d..c30f81817609 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,8 @@ Other changes: which amusingly made it disappear when using very big font/frame size. - Tables: fixed calling SetNextWindowScroll() on clipped scrolling table to not leak the value into a subsequent window. (#8196) +- Demo: Combos: demonstrate a very simple way to add a filter to a combo, + by showing the filter inside the combo contents. (#718) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] - Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3c40de2e7dd9..0898ef251610 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1435,7 +1435,6 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) const char* combo_preview_value = items[item_selected_idx]; - if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) @@ -1451,23 +1450,46 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::EndCombo(); } + // Show case embedding a filter using a simple trick: displaying the filter inside combo contents. + // See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. + if (ImGui::BeginCombo("combo 2 (w/ filter)", combo_preview_value, flags)) + { + static ImGuiTextFilter filter; + if (ImGui::IsWindowAppearing()) + { + ImGui::SetKeyboardFocusHere(); + filter.Clear(); + } + ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F); + filter.Draw("##Filter", -FLT_MIN); + + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_selected_idx == n); + if (filter.PassFilter(items[n])) + if (ImGui::Selectable(items[n], is_selected)) + item_selected_idx = n; + } + ImGui::EndCombo(); + } + ImGui::Spacing(); ImGui::SeparatorText("One-liner variants"); - HelpMarker("Flags above don't apply to this section."); + HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section."); // Simplified one-liner Combo() API, using values packed in a single constant string // This is a convenience for when the selection set is small and known at compile-time. static int item_current_2 = 0; - ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + ImGui::Combo("combo 3 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); // Simplified one-liner Combo() using an array of const char* // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview - ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); + ImGui::Combo("combo 4 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); // Simplified one-liner Combo() using an accessor function static int item_current_4 = 0; - ImGui::Combo("combo 4 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items)); + ImGui::Combo("combo 5 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items)); ImGui::TreePop(); } From a18622c3695c8fb178acefad2da26f3ba2e50ffc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 12:02:01 +0100 Subject: [PATCH 218/716] TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 6 +++++- imgui.h | 2 +- imgui_demo.cpp | 3 +++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c30f81817609..ab4345fb3601 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,8 @@ Other changes: which amusingly made it disappear when using very big font/frame size. - Tables: fixed calling SetNextWindowScroll() on clipped scrolling table to not leak the value into a subsequent window. (#8196) +- TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to + handle UTF-8 regardless of system regional settings. (#7660) [@achabense] - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] diff --git a/imgui.cpp b/imgui.cpp index 4ba2051d5532..2402bf109ae3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15090,7 +15090,11 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const cha #endif static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) { - return (INT_PTR)::ShellExecuteA(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT) > 32; + const int path_wsize = ::MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); + ImVector path_wbuf; + path_wbuf.resize(path_wsize); + ::MultiByteToWideChar(CP_UTF8, 0, path, -1, path_wbuf.Data, path_wsize); + return (INT_PTR)::ShellExecuteW(NULL, L"open", path_wbuf.Data, NULL, NULL, SW_SHOWDEFAULT) > 32; } #else #include diff --git a/imgui.h b/imgui.h index 6f9f11ebc5c3..29daaae7e179 100644 --- a/imgui.h +++ b/imgui.h @@ -3565,7 +3565,7 @@ struct ImGuiPlatformIO void* Platform_ClipboardUserData; // Optional: Open link/folder/file in OS Shell - // (default to use ShellExecuteA() on Windows, system() on Linux/Mac) + // (default to use ShellExecuteW() on Windows, system() on Linux/Mac) bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path); void* Platform_OpenInShellUserData; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0898ef251610..2774fbc96c9c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7771,6 +7771,9 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_WIN32_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS"); #endif +#ifdef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS"); +#endif #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS"); #endif From a431e1277e8f4907ff874b466b71b98696cdc227 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 12:09:44 +0100 Subject: [PATCH 219/716] Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) --- backends/imgui_impl_sdl2.cpp | 3 +++ backends/imgui_impl_sdl3.cpp | 2 ++ docs/CHANGELOG.txt | 2 ++ 3 files changed, 7 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index a27962a316bb..abe0e4342d6f 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f. // 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190) @@ -480,6 +481,8 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; +#else + platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; }; #endif // Gamepad handling diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index d5de5443e244..16ab5706bdb5 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten. // 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807) @@ -464,6 +465,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL3_GetClipboardText; platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData; + platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; }; // Gamepad handling bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ab4345fb3601..74416e373bd0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,8 @@ Other changes: handle UTF-8 regardless of system regional settings. (#7660) [@achabense] - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) +- Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn + handler. (#7660) [@achabense] - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] - Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) From 88cda0cab6f369c2629f6a32b0eaae4436d77c1c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 12:39:54 +0100 Subject: [PATCH 220/716] Fixed minor warning. Added comment. --- backends/imgui_impl_opengl3.cpp | 1 + imgui.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index efc1a3c49283..9465388a66ef 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -303,6 +303,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) // GLES 2 bd->GlVersion = 200; bd->GlProfileIsES2 = true; + IM_UNUSED(gl_version_str); #else // Desktop or GLES 3 GLint major = 0; diff --git a/imgui.cpp b/imgui.cpp index 2402bf109ae3..b909e0c306ed 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2399,7 +2399,7 @@ int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* int e = 0; e = (*out_char < mins[len]) << 6; // non-canonical encoding e |= ((*out_char >> 11) == 0x1b) << 7; // surrogate half? - e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range? + e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8; // out of range we can store in ImWchar (FIXME: May evolve) e |= (s[1] & 0xc0) >> 2; e |= (s[2] & 0xc0) >> 4; e |= (s[3] ) >> 6; From 4dc9df6aae8ff1f09701c13c053ed9fd55efaff4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 19:29:18 +0100 Subject: [PATCH 221/716] Tables: fixed an issue where Columns Visible/Hidden state wouldn't be correctly overridden when hot-reloading .ini state. (#7934) --- docs/CHANGELOG.txt | 3 +++ imgui_internal.h | 4 ++-- imgui_tables.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 74416e373bd0..b76f7455b95e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,8 @@ Other changes: which amusingly made it disappear when using very big font/frame size. - Tables: fixed calling SetNextWindowScroll() on clipped scrolling table to not leak the value into a subsequent window. (#8196) +- Tables: fixed an issue where Columns Visible/Hidden state wouldn't be correctly + overridden when hot-reloading .ini state. (#7934) - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] - Demo: Combos: demonstrate a very simple way to add a filter to a combo, @@ -67,6 +69,7 @@ Other changes: - Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) + ----------------------------------------------------------------------- VERSION 1.91.8 (Released 2025-01-31) ----------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index f2aaeaa83d72..b904909d741b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2944,7 +2944,7 @@ struct ImGuiTableColumnSettings ImGuiTableColumnIdx DisplayOrder; ImGuiTableColumnIdx SortOrder; ImU8 SortDirection : 2; - ImU8 IsEnabled : 1; // "Visible" in ini file + ImS8 IsEnabled : 2; // "Visible" in ini file ImU8 IsStretch : 1; ImGuiTableColumnSettings() @@ -2954,7 +2954,7 @@ struct ImGuiTableColumnSettings Index = -1; DisplayOrder = SortOrder = -1; SortDirection = ImGuiSortDirection_None; - IsEnabled = 1; + IsEnabled = -1; IsStretch = 0; } }; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c2e0127768a4..3a023d426a16 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3741,7 +3741,7 @@ void ImGui::TableLoadSettings(ImGuiTable* table) else column->DisplayOrder = (ImGuiTableColumnIdx)column_n; display_order_mask |= (ImU64)1 << column->DisplayOrder; - column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled; + column->IsUserEnabled = column->IsUserEnabledNextFrame = (column_settings->IsEnabled != -1 ? column_settings->IsEnabled == 1 : (column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1); column->SortOrder = column_settings->SortOrder; column->SortDirection = column_settings->SortDirection; } From 3b2f2602b4d6ecb0d7c09865dccbf8036afc002a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 21:33:49 +0100 Subject: [PATCH 222/716] Windows: Fixed an issue where BeginChild() inside a collapsed Begin() wouldn't inherit the SkipItems flag. Amend/fix a89f05a10 (old!) Discovered while looking at glyph being processed in WIP branch. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 2 +- imgui.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b76f7455b95e..1253dc41d71a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,9 @@ Other changes: - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) +- Windows: Fixed an issue where BeginChild() inside a collapsed Begin() + wouldn't inherit the SkipItems flag, resulting in missing coarse clipping + opportunity for code not checking the BeginChild() return value. - Windows, Style: Added style.WindowBorderHoverPadding setting to configure inner/outer padding applied to hit-testing of windows borders and detection of hovered window. diff --git a/imgui.cpp b/imgui.cpp index b909e0c306ed..1945dd6c47cf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7702,7 +7702,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Hide along with parent or if parent is collapsed if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0)) window->HiddenFramesCanSkipItems = 1; - if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0)) + if (parent_window && parent_window->HiddenFramesCannotSkipItems > 0) window->HiddenFramesCannotSkipItems = 1; } diff --git a/imgui.h b/imgui.h index 29daaae7e179..86137e5e12aa 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19183 +#define IMGUI_VERSION_NUM 19184 #define IMGUI_HAS_TABLE /* From 6916f935eb221b351178349deb33282cbc24f7a9 Mon Sep 17 00:00:00 2001 From: fdsa <14tanks999@gmail.com> Date: Tue, 11 Feb 2025 13:12:55 -0800 Subject: [PATCH 223/716] InputText: Allow CTRL+Shift+Z to redo even outside of OSX. (#8389) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 3 ++- imgui_demo.cpp | 8 ++++---- imgui_widgets.cpp | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1253dc41d71a..cdb5e3845e1d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,7 @@ Other changes: - Windows, Style: Added style.WindowBorderHoverPadding setting to configure inner/outer padding applied to hit-testing of windows borders and detection of hovered window. +- InputText: Allow CTRL+Shift+Z to redo even outside of OSX. (#8389) [@tanksdude] - InputTextWithHint(): Fixed buffer-overflow (luckily often with no visible effect) when a user callback modified the buffer contents in a way that altered the visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] diff --git a/imgui.cpp b/imgui.cpp index 1945dd6c47cf..af4aa2068507 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -142,7 +142,8 @@ CODE - CTRL+Shift+Left/Right: Select words. - CTRL+A or Double-Click: Select All. - CTRL+X, CTRL+C, CTRL+V: Use OS clipboard. - - CTRL+Z, CTRL+Y: Undo, Redo. + - CTRL+Z Undo. + - CTRL+Y or CTRL+Shift+Z: Redo. - ESCAPE: Revert text to its original value. - On OSX, controls are automatically adjusted to match standard OSX text editing 2ts and behaviors. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 2774fbc96c9c..db9a6de1a71e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -861,8 +861,8 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) "Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or Double-Click to select all.\n" - "CTRL+X,CTRL+C,CTRL+V clipboard.\n" - "CTRL+Z,CTRL+Y undo/redo.\n" + "CTRL+X,CTRL+C,CTRL+V for clipboard.\n" + "CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo.\n" "ESCAPE to revert.\n\n" "PROGRAMMER:\n" "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " @@ -8237,7 +8237,7 @@ void ImGui::ShowUserGuide() ImGui::BulletText("CTRL+Left/Right to word jump."); ImGui::BulletText("CTRL+A or double-click to select all."); ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); - ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo."); + ImGui::BulletText("CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo."); ImGui::BulletText("ESCAPE to revert."); ImGui::Unindent(); ImGui::BulletText("With keyboard navigation enabled:"); @@ -8273,7 +8273,7 @@ static void ShowExampleAppMainMenuBar() if (ImGui::BeginMenu("Edit")) { if (ImGui::MenuItem("Undo", "CTRL+Z")) {} - if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item + if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item ImGui::Separator(); if (ImGui::MenuItem("Cut", "CTRL+X")) {} if (ImGui::MenuItem("Copy", "CTRL+C")) {} diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2b95c0dd58f3..6676a96d5452 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4804,14 +4804,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl const bool is_startend_key_down = is_osx && io.KeyCtrl && !io.KeySuper && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End - // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: formet would be handled by InputText) + // Using Shortcut() with ImGuiInputFlags_RouteFocused (default policy) to allow routing operations for other code (e.g. calling window trying to use CTRL+A and CTRL+B: former would be handled by InputText) // Otherwise we could simply assume that we own the keys as we are active. const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat; const bool is_cut = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_X, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete, f_repeat, id)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection()); const bool is_copy = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, 0, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert, 0, id)) && !is_password && (!is_multiline || state->HasSelection()); const bool is_paste = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_V, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert, f_repeat, id)) && !is_readonly; const bool is_undo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable; - const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || (is_osx && Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id))) && !is_readonly && is_undoable; + const bool is_redo = (Shortcut(ImGuiMod_Ctrl | ImGuiKey_Y, f_repeat, id) || Shortcut(ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Z, f_repeat, id)) && !is_readonly && is_undoable; const bool is_select_all = Shortcut(ImGuiMod_Ctrl | ImGuiKey_A, 0, id); // We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful. From 3d900edba7c47bf957a7c7bfcf9773ecf923fa53 Mon Sep 17 00:00:00 2001 From: PuPuHX <654524200@qq.com> Date: Tue, 11 Feb 2025 10:57:47 +0800 Subject: [PATCH 224/716] Examples: Win32+DirectX12: Fixed ExampleDescriptorHeapAllocator overflow free index. Amend 40b2286d1. --- examples/example_win32_directx12/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 5b1a7af370bf..e83ce7dcbbc9 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -54,7 +54,7 @@ struct ExampleDescriptorHeapAllocator HeapHandleIncrement = device->GetDescriptorHandleIncrementSize(HeapType); FreeIndices.reserve((int)desc.NumDescriptors); for (int n = desc.NumDescriptors; n > 0; n--) - FreeIndices.push_back(n); + FreeIndices.push_back(n - 1); } void Destroy() { From ef7ffaff7425ceabb2145ff4cf1df3cdadd252c9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Feb 2025 15:46:17 +0100 Subject: [PATCH 225/716] Styles, Tabs: (Breaking) Renamed TabMinWidthForCloseButton to TabCloseButtonMinWidthUnselected. Added TabCloseButtonMinWidthSelected. (#8387) --- docs/CHANGELOG.txt | 8 ++++++++ imgui.cpp | 6 ++++-- imgui.h | 8 +++++++- imgui_demo.cpp | 12 ++++++++---- imgui_widgets.cpp | 10 +++++++--- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cdb5e3845e1d..7036ba64df0f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -42,6 +42,7 @@ HOW TO UPDATE? Breaking changes: - Renamed ImFontConfig::GlyphExtraSpacing.x option to GlyphExtraAdvanceX. (#242) +- Renamed style.TabMinWidthForCloseButton to style.TabCloseButtonMinWidthUnselected. Other changes: @@ -63,6 +64,13 @@ Other changes: to not leak the value into a subsequent window. (#8196) - Tables: fixed an issue where Columns Visible/Hidden state wouldn't be correctly overridden when hot-reloading .ini state. (#7934) +- Styles, Tabs: made the Close Button of selected tabs always visible by default, + without requiring to hover the tab. (#8387) + - Added style.TabCloseButtonMinWidthSelected/TabCloseButtonMinWidthUnselected settings + to configure visibility of the Close Button for selected and unselected tabs. + (-1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width) + - Default for selected tabs: TabCloseButtonMinWidthSelected = -1.0f (always visible) + - Default for unselected tabs: TabCloseButtonMinWidthUnselected = 0.0f (visible when hovered) - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] - Demo: Combos: demonstrate a very simple way to add a filter to a combo, diff --git a/imgui.cpp b/imgui.cpp index af4aa2068507..d6b763631eda 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1339,7 +1339,8 @@ ImGuiStyle::ImGuiStyle() LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. - TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + TabCloseButtonMinWidthSelected = -1.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. + TabCloseButtonMinWidthUnselected = 0.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected. TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar. TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees). @@ -1394,7 +1395,8 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) GrabRounding = ImTrunc(GrabRounding * scale_factor); LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor); TabRounding = ImTrunc(TabRounding * scale_factor); - TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImTrunc(TabMinWidthForCloseButton * scale_factor) : FLT_MAX; + TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : FLT_MAX; + TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : FLT_MAX; TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor); SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); diff --git a/imgui.h b/imgui.h index 86137e5e12aa..6174b8a89f6d 100644 --- a/imgui.h +++ b/imgui.h @@ -2170,7 +2170,8 @@ struct ImGuiStyle float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabBorderSize; // Thickness of border around tabs. - float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected. + float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. + float TabCloseButtonMinWidthUnselected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. FLT_MAX: never show close button when unselected. float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus. float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). @@ -2201,6 +2202,11 @@ struct ImGuiStyle IMGUI_API ImGuiStyle(); IMGUI_API void ScaleAllSizes(float scale_factor); + + // Obsolete names +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // TabMinWidthForCloseButton = TabCloseButtonMinWidthUnselected // Renamed in 1.91.9. +#endif }; //----------------------------------------------------------------------------- diff --git a/imgui_demo.cpp b/imgui_demo.cpp index db9a6de1a71e..7671b7764ba3 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7991,10 +7991,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); - ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); - ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); ImGui::SeparatorText("Rounding"); ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); @@ -8003,6 +7999,14 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + + ImGui::SeparatorText("Tabs"); + ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); + ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); + ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); + ImGui::DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f"); + ImGui::DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f"); ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); ImGui::SeparatorText("Tables"); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6676a96d5452..1b56d5944b97 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -10369,9 +10369,13 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, bool close_button_pressed = false; bool close_button_visible = false; if (close_button_id != 0) - if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz, g.Style.TabMinWidthForCloseButton)) - if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id) - close_button_visible = true; + { + bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id; // Any interaction account for this too. + if (is_contents_visible) + close_button_visible = (g.Style.TabCloseButtonMinWidthSelected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected)); + else + close_button_visible = (g.Style.TabCloseButtonMinWidthUnselected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected)); + } bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x); if (close_button_visible) From 7221f5e739c78e8367ac368f120248b2fed93b19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Feb 2025 19:01:02 +0100 Subject: [PATCH 226/716] Styles, Tabs: Fixed ef7ffaf. (#8387) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d6b763631eda..a69ae6c036e5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1395,8 +1395,8 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) GrabRounding = ImTrunc(GrabRounding * scale_factor); LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor); TabRounding = ImTrunc(TabRounding * scale_factor); - TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : FLT_MAX; - TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : FLT_MAX; + TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : TabCloseButtonMinWidthSelected; + TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : TabCloseButtonMinWidthUnselected; TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor); SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); From 7cd31c3557caadcf095fcf6da513b1a763ac77dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Feb 2025 19:08:52 +0100 Subject: [PATCH 227/716] Tables: tamed some .ini settings optimizations to more accurately allow overwriting/hot-reloading settings. (#7934) --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 23 +++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7036ba64df0f..d897ace83126 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,8 @@ Other changes: to not leak the value into a subsequent window. (#8196) - Tables: fixed an issue where Columns Visible/Hidden state wouldn't be correctly overridden when hot-reloading .ini state. (#7934) +- Tables: tamed some .ini settings optimizations to more accurately allow + overwriting/hot-reloading settings in more situations. (#7934) - Styles, Tabs: made the Close Button of selected tabs always visible by default, without requiring to hover the tab. (#8387) - Added style.TabCloseButtonMinWidthSelected/TabCloseButtonMinWidthUnselected settings diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 3a023d426a16..b7726e90820f 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -577,6 +577,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // Initialize table->SettingsOffset = -1; table->IsSortSpecsDirty = true; + table->IsSettingsDirty = true; // Records itself into .ini file even when in default state (#7934) table->InstanceInteracted = -1; table->ContextPopupColumn = -1; table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; @@ -3718,6 +3719,19 @@ void ImGui::TableLoadSettings(ImGuiTable* table) table->SettingsLoadedFlags = settings->SaveFlags; table->RefScale = settings->RefScale; + // Initialize default columns settings + for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + { + ImGuiTableColumn* column = &table->Columns[column_n]; + column->StretchWeight = -1.0f; + column->WidthRequest = -1.0f; + column->AutoFitQueue = 0x00; + column->DisplayOrder = (ImGuiTableColumnIdx)column_n; + column->IsUserEnabled = column->IsUserEnabledNextFrame = (column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; + column->SortOrder = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1; + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? (ImS8)ImGuiSortDirection_None : (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + } + // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings(); ImU64 display_order_mask = 0; @@ -3734,14 +3748,12 @@ void ImGui::TableLoadSettings(ImGuiTable* table) column->StretchWeight = column_settings->WidthOrWeight; else column->WidthRequest = column_settings->WidthOrWeight; - column->AutoFitQueue = 0x00; } if (settings->SaveFlags & ImGuiTableFlags_Reorderable) column->DisplayOrder = column_settings->DisplayOrder; - else - column->DisplayOrder = (ImGuiTableColumnIdx)column_n; display_order_mask |= (ImU64)1 << column->DisplayOrder; - column->IsUserEnabled = column->IsUserEnabledNextFrame = (column_settings->IsEnabled != -1 ? column_settings->IsEnabled == 1 : (column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1); + if ((settings->SaveFlags & ImGuiTableFlags_Hideable) && column_settings->IsEnabled != -1) + column->IsUserEnabled = column->IsUserEnabledNextFrame = column_settings->IsEnabled == 1; column->SortOrder = column_settings->SortOrder; column->SortDirection = column_settings->SortDirection; } @@ -3837,8 +3849,7 @@ static void TableSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandle const bool save_visible = (settings->SaveFlags & ImGuiTableFlags_Hideable) != 0; const bool save_order = (settings->SaveFlags & ImGuiTableFlags_Reorderable) != 0; const bool save_sort = (settings->SaveFlags & ImGuiTableFlags_Sortable) != 0; - if (!save_size && !save_visible && !save_order && !save_sort) - continue; + // We need to save the [Table] entry even if all the bools are false, since this records a table with "default settings". buf->reserve(buf->size() + 30 + settings->ColumnsCount * 50); // ballpark reserve buf->appendf("[%s][0x%08X,%d]\n", handler->TypeName, settings->ID, settings->ColumnsCount); From a931fb7f51269edda025180710fbd7a286e09688 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Feb 2025 19:15:00 +0100 Subject: [PATCH 228/716] Fixed static analyzer warning. (was harmless as initialized in NewFrame) --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index a69ae6c036e5..251e46819b3a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3906,6 +3906,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) InputEventsNextEventId = 1; WindowsActiveCount = 0; + WindowsBorderHoverPadding = 0.0f; CurrentWindow = NULL; HoveredWindow = NULL; HoveredWindowUnderMovingWindow = NULL; From b78cc37891608c582cd71b2bdc299f6ff8392432 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Feb 2025 19:27:43 +0100 Subject: [PATCH 229/716] Backends: SDL2: Fixed build for versions older than 2.0.14. (#7660) --- backends/imgui_impl_sdl2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index abe0e4342d6f..24585a9d337d 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -116,6 +116,7 @@ #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 #endif #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) +#define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14) #if SDL_HAS_VULKAN #include #endif @@ -481,7 +482,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData; #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; }; -#else +#elif SDL_HAS_OPEN_URL platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; }; #endif From f94a5f0e8c4b22476891cc18372ff5caaebe8492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Tassoux?= Date: Thu, 13 Feb 2025 14:30:49 +0100 Subject: [PATCH 230/716] Docs: Update doc about plutosvg (#8395) --- imconfig.h | 3 +-- misc/freetype/README.md | 16 ++++------------ 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/imconfig.h b/imconfig.h index 8f8bc3b9a9bb..a1e29e849bc8 100644 --- a/imconfig.h +++ b/imconfig.h @@ -88,8 +88,7 @@ //---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT) // Only works in combination with IMGUI_ENABLE_FREETYPE. -// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg. -// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions. +// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions. // - Both require headers to be available in the include path + program to be linked with the library code (not provided). // - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) //#define IMGUI_ENABLE_FREETYPE_PLUTOSVG diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 6e2e8671e9e2..e1bd0198bb11 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -48,15 +48,7 @@ Requires: [lunasvg](https://github.com/sammycage/lunasvg) v2.3.2 and above #### Using plutosvg (and plutovg) - Add `#define IMGUI_ENABLE_FREETYPE_PLUTOSVG` in your `imconfig.h`. -- Compile and link with plutosvg *and* plutovg (which is required by plutosvg) - -_Compilation hints for plutovg_ -- Compile all source files in `plutovg/source/*.c` -- Add include directory: `plutovg/include` + `plutovg/stb` - -_Compilation hints for plutosvg_ -- Compile `plutosvg/source/plutosvg.c` -- Add include directory: `plutosvg/source` -- Add define: `PLUTOSVG_HAS_FREETYPE` -- Link with: plutovg, freetype - +- Get latest plutosvg binaries or build yourself. Under Windows you may use vcpkg with: `vcpkg install plutosvg --triplet=x64-windows`. Alternatively, if you build imgui from vcpkg, you just need to enable the plutosvg feature: `vcpkg install imgui[plutosvg] --triplet=x64-windows` +- If you prefer to build plutosvg manually: + - Compilation hints for plutovg: Compile all source files in `plutovg/source/*.c` + Add include directory: `plutovg/include` + `plutovg/stb` + - Compilation hints for plutosvg: Compile `plutosvg/source/plutosvg.c` + Add include directory: `plutosvg/source` + Add define: `PLUTOSVG_HAS_FREETYPE` + Link with: plutovg, freetype From 890ead6a718c95c730012d7c2c3e5844a4a93bb9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Feb 2025 15:40:49 +0100 Subject: [PATCH 231/716] Backends: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" without -KHR on API 1.3. (#8326, #8365) --- backends/imgui_impl_vulkan.cpp | 11 ++++++++--- backends/imgui_impl_vulkan.h | 13 +++++++------ docs/CHANGELOG.txt | 4 ++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 2bd40f624aed..7be2ed1d1b30 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-13: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326) // 2025-01-09: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in descriptor pool. (#6642) // 2025-01-06: Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. // 2024-12-11: Vulkan: Fixed setting VkSwapchainCreateInfoKHR::preTransform for platforms not supporting VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR. (#8222) @@ -1082,9 +1083,11 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { - // Manually load those two (see #5446) - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); + // Manually load those two (see #5446, #8326, #8365) + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func(v->ApiVersion < VK_API_VERSION_1_3 ? "vkCmdBeginRenderingKHR" : "vkCmdBeginRendering", user_data)); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func(v->ApiVersion < VK_API_VERSION_1_3 ? "vkCmdEndRenderingKHR" : "vkCmdEndRendering", user_data)); } #endif @@ -1155,6 +1158,8 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; + if (bd->VulkanInitInfo.ApiVersion == 0) + bd->VulkanInitInfo.ApiVersion = VK_HEADER_VERSION_COMPLETE; ImGui_ImplVulkan_CreateDeviceObjects(); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 6f4839c1301b..9b79d3250873 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -75,16 +75,17 @@ // - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. struct ImGui_ImplVulkan_InitInfo { + uint32_t ApiVersion; // Fill with API version of Instance, e.g. VK_API_VERSION_1_3, which might be lower than header version (VK_HEADER_VERSION_COMPLETE) VkInstance Instance; VkPhysicalDevice PhysicalDevice; VkDevice Device; uint32_t QueueFamily; VkQueue Queue; - VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 - VkRenderPass RenderPass; // Ignored if using dynamic rendering - uint32_t MinImageCount; // >= 2 - uint32_t ImageCount; // >= MinImageCount - VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT + VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 + VkRenderPass RenderPass; // Ignored if using dynamic rendering + uint32_t MinImageCount; // >= 2 + uint32_t ImageCount; // >= MinImageCount + VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT // (Optional) VkPipelineCache PipelineCache; @@ -103,7 +104,7 @@ struct ImGui_ImplVulkan_InitInfo // (Optional) Allocation, Debugging const VkAllocationCallbacks* Allocator; void (*CheckVkResultFn)(VkResult err); - VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. + VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d897ace83126..ec2180fac618 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -80,6 +80,10 @@ Other changes: - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) [@achabense] - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] +- Backends: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. + Default to header version if unspecified. (#8326, #8365) [@mklefrancois] +- Backends: Vulkan: Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" + (without -KHR suffix) on API 1.3. (#8326, #8365) [@mklefrancois] - Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) From 12963f52314d126817da333675fe2f6bcde44ffe Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Feb 2025 15:49:47 +0100 Subject: [PATCH 232/716] Examples: Vulkan: make ApiVersion a little more visible in examples. (#8326, #8365) --- backends/imgui_impl_vulkan.h | 2 +- examples/example_glfw_vulkan/main.cpp | 1 + examples/example_sdl2_vulkan/main.cpp | 1 + examples/example_sdl3_vulkan/main.cpp | 1 + examples/example_win32_vulkan/main.cpp | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 9b79d3250873..c8afc92ac5c6 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -75,7 +75,7 @@ // - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. struct ImGui_ImplVulkan_InitInfo { - uint32_t ApiVersion; // Fill with API version of Instance, e.g. VK_API_VERSION_1_3, which might be lower than header version (VK_HEADER_VERSION_COMPLETE) + uint32_t ApiVersion; // Fill with API version of Instance, e.g. VK_API_VERSION_1_3 or your value of VkApplicationInfo::apiVersion. May be lower than header version (VK_HEADER_VERSION_COMPLETE) VkInstance Instance; VkPhysicalDevice PhysicalDevice; VkDevice Device; diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 31da972dfcf0..ce7fcde5e127 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -396,6 +396,7 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForVulkan(window, true); ImGui_ImplVulkan_InitInfo init_info = {}; + //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version. init_info.Instance = g_Instance; init_info.PhysicalDevice = g_PhysicalDevice; init_info.Device = g_Device; diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index c0282f9328f7..0c29154bcabb 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -396,6 +396,7 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForVulkan(window); ImGui_ImplVulkan_InitInfo init_info = {}; + //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version. init_info.Instance = g_Instance; init_info.PhysicalDevice = g_PhysicalDevice; init_info.Device = g_Device; diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 52544c34229a..99e441d7ef4b 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -400,6 +400,7 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForVulkan(window); ImGui_ImplVulkan_InitInfo init_info = {}; + //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version. init_info.Instance = g_Instance; init_info.PhysicalDevice = g_PhysicalDevice; init_info.Device = g_Device; diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index f337d8e7de5a..427a2494a43b 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -387,6 +387,7 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); ImGui_ImplVulkan_InitInfo init_info = {}; + //init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version. init_info.Instance = g_Instance; init_info.PhysicalDevice = g_PhysicalDevice; init_info.Device = g_Device; From e1ae7db4cccf1cb6a516a43dd8f63899f504ca52 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Feb 2025 16:03:40 +0100 Subject: [PATCH 233/716] Backends: Vulkan: Fixed building with older headers not supporting VK_HEADER_VERSION_COMPLETE. (#8326, #8365) --- backends/imgui_impl_vulkan.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 7be2ed1d1b30..af084cc0ef26 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1159,7 +1159,14 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) bd->VulkanInitInfo = *info; if (bd->VulkanInitInfo.ApiVersion == 0) + { + // We don't care about other versions for now, so don't need to make this exhaustive (with #ifdef VK_VERSION_1_X checks) +#ifdef VK_HEADER_VERSION_COMPLETE bd->VulkanInitInfo.ApiVersion = VK_HEADER_VERSION_COMPLETE; +#else + bd->VulkanInitInfo.ApiVersion = VK_API_VERSION_1_0; +#endif + } ImGui_ImplVulkan_CreateDeviceObjects(); From 98c2f6b0c450b2401a2db97a6c96c042b2bfd404 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Feb 2025 16:19:41 +0100 Subject: [PATCH 234/716] Tables, Error Handling: Recovery from invalid index in TableSetColumnIndex(). (#1651) --- docs/CHANGELOG.txt | 1 + imgui_tables.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ec2180fac618..283d485dfd4d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -66,6 +66,7 @@ Other changes: overridden when hot-reloading .ini state. (#7934) - Tables: tamed some .ini settings optimizations to more accurately allow overwriting/hot-reloading settings in more situations. (#7934) +- Tables, Error Handling: Recovery from invalid index in TableSetColumnIndex(). (#1651) - Styles, Tabs: made the Close Button of selected tabs always visible by default, without requiring to hover the tab. (#8387) - Added style.TabCloseButtonMinWidthSelected/TabCloseButtonMinWidthUnselected settings diff --git a/imgui_tables.cpp b/imgui_tables.cpp index b7726e90820f..6486dccd60b4 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2106,7 +2106,11 @@ bool ImGui::TableSetColumnIndex(int column_n) { if (table->CurrentColumn != -1) TableEndCell(table); - IM_ASSERT(column_n >= 0 && table->ColumnsCount); + if ((column_n >= 0 && column_n < table->ColumnsCount) == false) + { + IM_ASSERT_USER_ERROR(column_n >= 0 && column_n < table->ColumnsCount, "TableSetColumnIndex() invalid column index!"); + return false; + } TableBeginCell(table, column_n); } From ec4cd2cb8cf144ea16935806d11d5639a84f73dd Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 14 Feb 2025 12:19:24 +0100 Subject: [PATCH 235/716] Backends: Vulkan: Fixed crash with using no prototypes + *BREAKING* Added ApiVersion to ImGui_ImplVulkan_LoadFunctions(). (#8326, #8365, #8400) --- backends/imgui_impl_vulkan.cpp | 43 ++++++++++++++++++++-------------- backends/imgui_impl_vulkan.h | 2 +- docs/CHANGELOG.txt | 4 ++++ 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index af084cc0ef26..7379e000b741 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). // 2025-02-13: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326) // 2025-01-09: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in descriptor pool. (#6642) // 2025-01-06: Vulkan: Added more ImGui_ImplVulkanH_XXXX helper functions to simplify our examples. @@ -1081,22 +1082,34 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() } #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) +static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { // Manually load those two (see #5446, #8326, #8365) - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func(v->ApiVersion < VK_API_VERSION_1_3 ? "vkCmdBeginRenderingKHR" : "vkCmdBeginRendering", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func(v->ApiVersion < VK_API_VERSION_1_3 ? "vkCmdEndRenderingKHR" : "vkCmdEndRendering", user_data)); + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func(api_version < VK_API_VERSION_1_3 ? "vkCmdBeginRenderingKHR" : "vkCmdBeginRendering", user_data)); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func(api_version < VK_API_VERSION_1_3 ? "vkCmdEndRenderingKHR" : "vkCmdEndRendering", user_data)); } #endif -bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) +// If unspecified by user, assume that ApiVersion == HeaderVersion + // We don't care about other versions than 1.3 for our checks, so don't need to make this exhaustive (e.g. with all #ifdef VK_VERSION_1_X checks) +static uint32_t ImGui_ImplVulkan_GetDefaultApiVersion() +{ +#ifdef VK_HEADER_VERSION_COMPLETE + return VK_HEADER_VERSION_COMPLETE; +#else + return VK_API_VERSION_1_0; +#endif +} + +bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { // Load function pointers // You can use the default Vulkan loader using: - // ImGui_ImplVulkan_LoadFunctions([](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); }); + // ImGui_ImplVulkan_LoadFunctions(VK_API_VERSION_1_3, [](const char* function_name, void*) { return vkGetInstanceProcAddr(your_vk_isntance, function_name); }); // But this would be roughly equivalent to not setting VK_NO_PROTOTYPES. + if (api_version == 0) + api_version = ImGui_ImplVulkan_GetDefaultApiVersion(); + #ifdef IMGUI_IMPL_VULKAN_USE_LOADER #define IMGUI_VULKAN_FUNC_LOAD(func) \ func = reinterpret_cast(loader_func(#func, user_data)); \ @@ -1106,7 +1119,7 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch #undef IMGUI_VULKAN_FUNC_LOAD #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - ImGui_ImplVulkan_LoadDynamicRenderingFunctions(loader_func, user_data); + ImGui_ImplVulkan_LoadDynamicRenderingFunctions(api_version, loader_func, user_data); #endif #else IM_UNUSED(loader_func); @@ -1121,11 +1134,14 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) { IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); + if (info->ApiVersion == 0) + info->ApiVersion = ImGui_ImplVulkan_GetDefaultApiVersion(); + if (info->UseDynamicRendering) { #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #ifndef IMGUI_IMPL_VULKAN_USE_LOADER - ImGui_ImplVulkan_LoadDynamicRenderingFunctions([](const char* function_name, void* user_data) { return vkGetInstanceProcAddr((VkInstance)user_data, function_name); }, (void*)info->Instance); + ImGui_ImplVulkan_LoadDynamicRenderingFunctions(info->ApiVersion, [](const char* function_name, void* user_data) { return vkGetInstanceProcAddr((VkInstance)user_data, function_name); }, (void*)info->Instance); #endif IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR != nullptr); IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR != nullptr); @@ -1158,15 +1174,6 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; - if (bd->VulkanInitInfo.ApiVersion == 0) - { - // We don't care about other versions for now, so don't need to make this exhaustive (with #ifdef VK_VERSION_1_X checks) -#ifdef VK_HEADER_VERSION_COMPLETE - bd->VulkanInitInfo.ApiVersion = VK_HEADER_VERSION_COMPLETE; -#else - bd->VulkanInitInfo.ApiVersion = VK_API_VERSION_1_0; -#endif - } ImGui_ImplVulkan_CreateDeviceObjects(); diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index c8afc92ac5c6..c3f40e138ae9 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -124,7 +124,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet d // Optional: load Vulkan functions with a custom function loader // This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES -IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr); +IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr); // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 283d485dfd4d..9ca3a0c81d35 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,10 @@ Breaking changes: - Renamed ImFontConfig::GlyphExtraSpacing.x option to GlyphExtraAdvanceX. (#242) - Renamed style.TabMinWidthForCloseButton to style.TabCloseButtonMinWidthUnselected. +- Backends: Vulkan: Added 'uint32_t api_version' argument to ImGui_ImplVulkan_LoadFunctions(). + Note that it was also added to ImGui_ImplVulkan_InitInfo but for the later it is optional. + (#8326, #8365, #8400) + Other changes: From 474305c476a777c94db750c961af5a94c6df4237 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 14 Feb 2025 16:15:09 +0100 Subject: [PATCH 236/716] ImFont: simpler constructor. --- imgui_draw.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5bf0f0b1802a..ca66b6d7947d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3685,21 +3685,8 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) ImFont::ImFont() { - FontSize = 0.0f; - FallbackAdvanceX = 0.0f; - FallbackChar = 0; - EllipsisChar = 0; - EllipsisWidth = EllipsisCharStep = 0.0f; - EllipsisCharCount = 0; - FallbackGlyph = NULL; - ContainerAtlas = NULL; - ConfigData = NULL; - ConfigDataCount = 0; - DirtyLookupTables = false; + memset(this, 0, sizeof(*this)); Scale = 1.0f; - Ascent = Descent = 0.0f; - MetricsTotalSurface = 0; - memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); } ImFont::~ImFont() From 2860d7ba05667be5e2e51cf27d658352884800b8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 14 Feb 2025 19:44:35 +0100 Subject: [PATCH 237/716] Selectable: Fixed horizontal label alignment with SelectableTextAlign.x > 0 and specifying a selectable size. (#8338) Regression from ed7551c1d --- docs/CHANGELOG.txt | 3 ++- imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9ca3a0c81d35..938b83aaf28f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,7 +47,6 @@ Breaking changes: Note that it was also added to ImGui_ImplVulkan_InitInfo but for the later it is optional. (#8326, #8365, #8400) - Other changes: - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), @@ -71,6 +70,8 @@ Other changes: - Tables: tamed some .ini settings optimizations to more accurately allow overwriting/hot-reloading settings in more situations. (#7934) - Tables, Error Handling: Recovery from invalid index in TableSetColumnIndex(). (#1651) +- Selectable: Fixed horizontal label alignment with SelectableTextAlign.x > 0 and + specifying a selectable size. (#8338) - Styles, Tabs: made the Close Button of selected tabs always visible by default, without requiring to hover the tab. (#8387) - Added style.TabCloseButtonMinWidthSelected/TabCloseButtonMinWidthUnselected settings diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1b56d5944b97..eb2b26bd086f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7101,7 +7101,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl // Text stays at the submission position. Alignment/clipping extents ignore SpanAllColumns. if (is_visible) - RenderTextClipped(pos, ImVec2(window->WorkRect.Max.x, pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb); + RenderTextClipped(pos, ImVec2(ImMin(pos.x + size.x, window->WorkRect.Max.x), pos.y + size.y), label, NULL, &label_size, style.SelectableTextAlign, &bb); // Automatically close popups if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) From 78ec1272e962ec9ca5515222cde87ee9f0b1c105 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 14 Feb 2025 21:39:45 +0100 Subject: [PATCH 238/716] ImDrawList: added InitialFringeScale in ImDrawListSharedData. Default to 1.0f. This is to allow some DPI mods with less changes. Only the initial value in SetupDrawListSharedData() will need change. --- imgui.cpp | 1 + imgui_draw.cpp | 3 ++- imgui_internal.h | 3 ++- imgui_widgets.cpp | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 251e46819b3a..c27095fd452f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5136,6 +5136,7 @@ static void SetupDrawListSharedData() g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill; if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; + g.DrawListSharedData.InitialFringeScale = 1.0f; // FIXME-DPI: Change this for some DPI scaling experiments. } void ImGui::NewFrame() diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ca66b6d7947d..3953212a1e9f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -374,6 +374,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) ImDrawListSharedData::ImDrawListSharedData() { memset(this, 0, sizeof(*this)); + InitialFringeScale = 1.0f; for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++) { const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx); @@ -433,7 +434,7 @@ void ImDrawList::_ResetForNewFrame() _Path.resize(0); _Splitter.Clear(); CmdBuffer.push_back(ImDrawCmd()); - _FringeScale = 1.0f; + _FringeScale = _Data->InitialFringeScale; } void ImDrawList::_ClearFreeMemory() diff --git a/imgui_internal.h b/imgui_internal.h index b904909d741b..e272d5479124 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -786,8 +786,9 @@ struct IMGUI_API ImDrawListSharedData float FontScale; // Current/default font scale (== FontSize / Font->FontSize) float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc - ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() + float InitialFringeScale; // Initial scale to apply to AA fringe ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) + ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() ImVector TempBuffer; // Temporary write buffer // Lookup tables diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index eb2b26bd086f..2d45c5d51843 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -913,7 +913,7 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis) const ImRect outer_rect = window->Rect(); const ImRect inner_rect = window->InnerRect; const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar) - IM_ASSERT(scrollbar_size > 0.0f); + IM_ASSERT(scrollbar_size >= 0.0f); const float border_size = IM_ROUND(window->WindowBorderSize * 0.5f); const float border_top = (window->Flags & ImGuiWindowFlags_MenuBar) ? IM_ROUND(g.Style.FrameBorderSize * 0.5f) : 0.0f; if (axis == ImGuiAxis_X) From c4a32a129d55eb66158408b61f51d40907a5aace Mon Sep 17 00:00:00 2001 From: Nico van Bentum Date: Thu, 13 Feb 2025 21:50:12 +0100 Subject: [PATCH 239/716] Tabs: fixed middle-button to close not checking hovering, only close button visibility. (#8399, #8387) Main bug has been here since 54a60aaa4, but it's only ef7ffaff7 which made it very visible. --- docs/CHANGELOG.txt | 4 +++- imgui_widgets.cpp | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 938b83aaf28f..19b334ba64a8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -72,13 +72,15 @@ Other changes: - Tables, Error Handling: Recovery from invalid index in TableSetColumnIndex(). (#1651) - Selectable: Fixed horizontal label alignment with SelectableTextAlign.x > 0 and specifying a selectable size. (#8338) -- Styles, Tabs: made the Close Button of selected tabs always visible by default, +- Tabs, Style: made the Close Button of selected tabs always visible by default, without requiring to hover the tab. (#8387) - Added style.TabCloseButtonMinWidthSelected/TabCloseButtonMinWidthUnselected settings to configure visibility of the Close Button for selected and unselected tabs. (-1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width) - Default for selected tabs: TabCloseButtonMinWidthSelected = -1.0f (always visible) - Default for unselected tabs: TabCloseButtonMinWidthUnselected = 0.0f (visible when hovered) +- Tabs: fixed middle-mouse-button to close tab not checking that close button + is hovered, merely it's visibility. (#8399, #8387) [@nicovanbentum] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] - Demo: Combos: demonstrate a very simple way to add a filter to a combo, diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2d45c5d51843..6e08cec22e5a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -10368,9 +10368,10 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false bool close_button_pressed = false; bool close_button_visible = false; + bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id; // Any interaction account for this too. + if (close_button_id != 0) { - bool is_hovered = g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == tab_id || g.ActiveId == close_button_id; // Any interaction account for this too. if (is_contents_visible) close_button_visible = (g.Style.TabCloseButtonMinWidthSelected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthSelected)); else @@ -10386,7 +10387,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, g.LastItemData = last_item_backup; // Close with middle mouse button - if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) + if (is_hovered && !(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) close_button_pressed = true; } else if (unsaved_marker_visible) From 8f0411ff037790ec65bfb3118473dde532c47785 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 18 Feb 2025 18:19:10 +0100 Subject: [PATCH 240/716] Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) --- backends/imgui_impl_opengl3.cpp | 30 +++++++++++++++++++++++------- docs/CHANGELOG.txt | 2 ++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 9465388a66ef..14ae90a7e122 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-06-28: OpenGL: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748) // 2024-05-07: OpenGL: Update loader for Linux to support EGL/GLVND. (#7562) @@ -169,6 +170,7 @@ // - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases // Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version. #define IMGL3W_IMPL +#define IMGUI_IMPL_OPENGL_LOADER_IMGL3W #include "imgui_impl_opengl3_loader.h" #endif @@ -276,6 +278,21 @@ struct ImGui_ImplOpenGL3_VtxAttribState }; #endif +// Not static to allow third-party code to use that if they want to (but undocumented) +bool ImGui_ImplOpenGL3_InitLoader(); +bool ImGui_ImplOpenGL3_InitLoader() +{ + // Initialize our loader +#ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W + if (glGetIntegerv == NULL && imgl3wInit() != 0) + { + fprintf(stderr, "Failed to initialize OpenGL loader!\n"); + return false; + } +#endif + return true; +} + // Functions bool ImGui_ImplOpenGL3_Init(const char* glsl_version) { @@ -283,14 +300,9 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); - // Initialize our loader -#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) - if (imgl3wInit() != 0) - { - fprintf(stderr, "Failed to initialize OpenGL loader!\n"); + // Initialize loader + if (!ImGui_ImplOpenGL3_InitLoader()) return false; - } -#endif // Setup backend capabilities flags ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)(); @@ -406,6 +418,8 @@ void ImGui_ImplOpenGL3_NewFrame() ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL3_Init()?"); + ImGui_ImplOpenGL3_InitLoader(); // Lazily init loader if not already done for e.g. DLL boundaries. + if (!bd->ShaderHandle) ImGui_ImplOpenGL3_CreateDeviceObjects(); if (!bd->FontTexture) @@ -497,6 +511,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (fb_width <= 0 || fb_height <= 0) return; + ImGui_ImplOpenGL3_InitLoader(); // Lazily init loader if not already done for e.g. DLL boundaries. + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); // Backup GL state diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 19b334ba64a8..a50bab51eff7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -87,6 +87,8 @@ Other changes: by showing the filter inside the combo contents. (#718) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) [@achabense] +- Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend + from e.g. other DLL boundaries. (#8406) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] - Backends: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. (#8326, #8365) [@mklefrancois] From 8a35386ba750fa4c6a77dcbf57211d481528fe43 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 18 Feb 2025 18:40:47 +0100 Subject: [PATCH 241/716] Added ImGuiMouseCursor_Wait mouse cursor (busy/wait/hourglass shape) + support in SDL2,SDL3,Win32,Allegro5 backends. --- backends/imgui_impl_allegro5.cpp | 2 ++ backends/imgui_impl_glfw.cpp | 1 + backends/imgui_impl_glfw.h | 1 + backends/imgui_impl_osx.h | 2 ++ backends/imgui_impl_osx.mm | 6 ++++-- backends/imgui_impl_sdl2.cpp | 2 ++ backends/imgui_impl_sdl3.cpp | 2 ++ backends/imgui_impl_win32.cpp | 2 ++ docs/CHANGELOG.txt | 2 ++ imgui.h | 1 + imgui_demo.cpp | 2 +- 11 files changed, 20 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 3718b64eace4..7307affde40a 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. // 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn @@ -594,6 +595,7 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor() case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break; case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break; case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break; + case ImGuiMouseCursor_Wait: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY; break; case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break; } al_set_system_mouse_cursor(bd->Display, cursor_id); diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 454a36d368ce..8bb61d14e2d3 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -11,6 +11,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. +// [ ] Missing ImGuiMouseCursor_Wait cursor. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index bba6d09ea8c1..260a06b146f4 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -10,6 +10,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. +// [ ] Missing ImGuiMouseCursor_Wait cursor. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 2e7eabb2b415..e4cda54ae25d 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -10,6 +10,8 @@ // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. +// Missing features or Issues: +// [ ] Missing ImGuiMouseCursor_Wait cursor. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 92c26418f8f6..53bdace566c7 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -10,6 +10,8 @@ // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. +// Missing features or Issues: +// [ ] Missing ImGuiMouseCursor_Wait cursor. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -422,12 +424,12 @@ bool ImGui_ImplOSX_Init(NSView* view) bd->MouseCursors[ImGuiMouseCursor_Arrow] = [NSCursor arrowCursor]; bd->MouseCursors[ImGuiMouseCursor_TextInput] = [NSCursor IBeamCursor]; bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = [NSCursor closedHandCursor]; - bd->MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor]; - bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor]; bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = [NSCursor respondsToSelector:@selector(_windowResizeNorthSouthCursor)] ? [NSCursor _windowResizeNorthSouthCursor] : [NSCursor resizeUpDownCursor]; bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = [NSCursor respondsToSelector:@selector(_windowResizeEastWestCursor)] ? [NSCursor _windowResizeEastWestCursor] : [NSCursor resizeLeftRightCursor]; bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor]; bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor]; + bd->MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor]; + bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor]; // Note that imgui.cpp also include default OSX clipboard handlers which can be enabled // by adding '#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS' in imconfig.h and adding '-framework ApplicationServices' to your linker command-line. diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 24585a9d337d..d8fd43ae48ff 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f. @@ -499,6 +500,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); + bd->MouseCursors[ImGuiMouseCursor_Wait] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); // Set platform dependent data in viewport diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 16ab5706bdb5..246a91213e07 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten. @@ -480,6 +481,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NESW_RESIZE); bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE); bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER); + bd->MouseCursors[ImGuiMouseCursor_Wait] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED); // Set platform dependent data in viewport diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 03ab53523d37..cd1cc7ad554e 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL). @@ -256,6 +257,7 @@ static bool ImGui_ImplWin32_UpdateMouseCursor(ImGuiIO& io, ImGuiMouseCursor imgu case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; + case ImGuiMouseCursor_Wait: win32_cursor = IDC_WAIT; break; case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break; } ::SetCursor(::LoadCursor(nullptr, win32_cursor)); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a50bab51eff7..a72107d127ec 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,10 +83,12 @@ Other changes: is hovered, merely it's visibility. (#8399, #8387) [@nicovanbentum] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] +- Misc: Added ImGuiMouseCursor_Wait mouse cursor (busy/wait/hourglass shape). - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) [@achabense] +- Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait. - Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] diff --git a/imgui.h b/imgui.h index 6174b8a89f6d..5a9b1250c991 100644 --- a/imgui.h +++ b/imgui.h @@ -1833,6 +1833,7 @@ enum ImGuiMouseCursor_ ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) + ImGuiMouseCursor_Wait, // When waiting for something to process/load. ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. ImGuiMouseCursor_COUNT }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7671b7764ba3..a2b3de5f9ab1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7593,7 +7593,7 @@ static void ShowDemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); if (ImGui::TreeNode("Mouse Cursors")) { - const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" }; + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "NotAllowed" }; IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); ImGuiMouseCursor current = ImGui::GetMouseCursor(); From eec097fe35c0bb2bba60c0a5ce0664cc3507f3bf Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 18 Feb 2025 18:52:08 +0100 Subject: [PATCH 242/716] Added ImGuiMouseCursor_Progress mouse cursor 8a35386+ support in SDL2,SDL3,Win32,Allegro5 backends. Amend 8a35386 --- backends/imgui_impl_allegro5.cpp | 3 ++- backends/imgui_impl_glfw.cpp | 2 +- backends/imgui_impl_glfw.h | 2 +- backends/imgui_impl_osx.h | 2 +- backends/imgui_impl_osx.mm | 2 +- backends/imgui_impl_sdl2.cpp | 3 ++- backends/imgui_impl_sdl3.cpp | 3 ++- backends/imgui_impl_win32.cpp | 3 ++- docs/CHANGELOG.txt | 6 ++++-- imgui.h | 1 + imgui_demo.cpp | 2 +- 11 files changed, 18 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 7307affde40a..9db3e51981b4 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -20,7 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. +// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn @@ -596,6 +596,7 @@ static void ImGui_ImplAllegro5_UpdateMouseCursor() case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break; case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break; case ImGuiMouseCursor_Wait: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY; break; + case ImGuiMouseCursor_Progress: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS; break; case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break; } al_set_system_mouse_cursor(bd->Display, cursor_id); diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 8bb61d14e2d3..69cde6c08910 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -11,7 +11,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. -// [ ] Missing ImGuiMouseCursor_Wait cursor. +// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 260a06b146f4..e203b556fe95 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -10,7 +10,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // Missing features or Issues: // [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. -// [ ] Missing ImGuiMouseCursor_Wait cursor. +// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index e4cda54ae25d..9d0aec07a0fc 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -11,7 +11,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // Missing features or Issues: -// [ ] Missing ImGuiMouseCursor_Wait cursor. +// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 53bdace566c7..4726462cbec5 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -11,7 +11,7 @@ // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // Missing features or Issues: -// [ ] Missing ImGuiMouseCursor_Wait cursor. +// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index d8fd43ae48ff..fbfa2fba8d9a 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,7 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. +// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: from SDL 2.30.9, SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f. @@ -501,6 +501,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); bd->MouseCursors[ImGuiMouseCursor_Wait] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); + bd->MouseCursors[ImGuiMouseCursor_Progress] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAITARROW); bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); // Set platform dependent data in viewport diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 246a91213e07..006316afbb8b 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,7 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. +// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. // 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten. @@ -482,6 +482,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NWSE_RESIZE); bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER); bd->MouseCursors[ImGuiMouseCursor_Wait] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); + bd->MouseCursors[ImGuiMouseCursor_Progress] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_PROGRESS); bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED); // Set platform dependent data in viewport diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index cd1cc7ad554e..49948c529441 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,7 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-02-18: Added ImGuiMouseCursor_Wait mouse cursor support. +// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL). @@ -258,6 +258,7 @@ static bool ImGui_ImplWin32_UpdateMouseCursor(ImGuiIO& io, ImGuiMouseCursor imgu case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; case ImGuiMouseCursor_Hand: win32_cursor = IDC_HAND; break; case ImGuiMouseCursor_Wait: win32_cursor = IDC_WAIT; break; + case ImGuiMouseCursor_Progress: win32_cursor = IDC_APPSTARTING; break; case ImGuiMouseCursor_NotAllowed: win32_cursor = IDC_NO; break; } ::SetCursor(::LoadCursor(nullptr, win32_cursor)); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a72107d127ec..7f2b4554ad6d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,12 +83,14 @@ Other changes: is hovered, merely it's visibility. (#8399, #8387) [@nicovanbentum] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] -- Misc: Added ImGuiMouseCursor_Wait mouse cursor (busy/wait/hourglass shape). +- Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors + (busy/wait/hourglass shape, with or without an arrow cursor). - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) [@achabense] -- Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait. +- Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait + and ImGuiMouseCursor_Progress cursors. - Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] diff --git a/imgui.h b/imgui.h index 5a9b1250c991..16c0b2c22e35 100644 --- a/imgui.h +++ b/imgui.h @@ -1834,6 +1834,7 @@ enum ImGuiMouseCursor_ ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks) ImGuiMouseCursor_Wait, // When waiting for something to process/load. + ImGuiMouseCursor_Progress, // When waiting for something to process/load, but application is still interactive. ImGuiMouseCursor_NotAllowed, // When hovering something with disallowed interaction. Usually a crossed circle. ImGuiMouseCursor_COUNT }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a2b3de5f9ab1..3be8647248d0 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7593,7 +7593,7 @@ static void ShowDemoWindowInputs() IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors"); if (ImGui::TreeNode("Mouse Cursors")) { - const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "NotAllowed" }; + const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "Wait", "Progress", "NotAllowed" }; IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT); ImGuiMouseCursor current = ImGui::GetMouseCursor(); From 8b7b3ce03eef61933727a0823741469e4f6d9b33 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Feb 2025 10:14:38 +0100 Subject: [PATCH 243/716] Tables: fixed an issue where Columns Width state wouldn't be correctly restored when hot-reloading .ini state. (#7934) Amend 7cd31c355 column->SortDirection initialized setting was wrong in first block but without side-effect, since sorting always stored explicitly in .ini data. --- docs/CHANGELOG.txt | 4 ++-- imgui_tables.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7f2b4554ad6d..044be4360761 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -65,8 +65,8 @@ Other changes: which amusingly made it disappear when using very big font/frame size. - Tables: fixed calling SetNextWindowScroll() on clipped scrolling table to not leak the value into a subsequent window. (#8196) -- Tables: fixed an issue where Columns Visible/Hidden state wouldn't be correctly - overridden when hot-reloading .ini state. (#7934) +- Tables: fixed an issue where Columns Visible/Width state wouldn't be correctly + restored when hot-reloading .ini state. (#7934) - Tables: tamed some .ini settings optimizations to more accurately allow overwriting/hot-reloading settings in more situations. (#7934) - Tables, Error Handling: Recovery from invalid index in TableSetColumnIndex(). (#1651) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 6486dccd60b4..3a24ec4c476b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1608,6 +1608,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo flags = column->Flags; // Initialize defaults + // FIXME: Similar to code in TableLoadSettings(), best to see how if we can merge. column->InitStretchWeightOrWidth = init_width_or_weight; if (table->IsInitializing) { @@ -1627,7 +1628,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo // Init default visibility/sort state if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) column->IsUserEnabled = column->IsUserEnabledNextFrame = false; - if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) + if ((flags & ImGuiTableColumnFlags_DefaultSort) && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) { column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); @@ -3724,16 +3725,17 @@ void ImGui::TableLoadSettings(ImGuiTable* table) table->RefScale = settings->RefScale; // Initialize default columns settings + // FIXME: Similar to code in TableSetupColumn(), best to see how if we can merge. for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; - column->StretchWeight = -1.0f; - column->WidthRequest = -1.0f; + column->StretchWeight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) && (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : -1.0f; + column->WidthRequest = (column->Flags & ImGuiTableColumnFlags_WidthFixed) && (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : -1.0f; column->AutoFitQueue = 0x00; column->DisplayOrder = (ImGuiTableColumnIdx)column_n; column->IsUserEnabled = column->IsUserEnabledNextFrame = (column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; column->SortOrder = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1; - column->SortDirection = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? (ImS8)ImGuiSortDirection_None : (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); + column->SortDirection = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? ((column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None; } // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn From 05742f9b6ff06d7ce47669bd5b30fd74390ba11f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Feb 2025 10:55:44 +0100 Subject: [PATCH 244/716] Tables: share code between TableSetupColumn() and TableLoadSettings(). (#7934) --- imgui_tables.cpp | 61 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 3a24ec4c476b..f6aff8c026fb 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1565,6 +1565,31 @@ void ImGui::EndTable() NavUpdateCurrentWindowIsScrollPushableX(); } +// Called in TableSetupColumn() when initializing and in TableLoadSettings() for defaults before applying stored settings. +// 'init_mask' specify which fields to initialize. +static void TableInitColumnDefaults(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags init_mask) +{ + ImGuiTableColumnFlags flags = column->Flags; + if (init_mask & ImGuiTableFlags_Resizable) + { + float init_width_or_weight = column->InitStretchWeightOrWidth; + column->WidthRequest = ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f; + column->StretchWeight = (init_width_or_weight > 0.0f && (flags & ImGuiTableColumnFlags_WidthStretch)) ? init_width_or_weight : -1.0f; + if (init_width_or_weight > 0.0f) // Disable auto-fit if an explicit width/weight has been specified + column->AutoFitQueue = 0x00; + } + if (init_mask & ImGuiTableFlags_Reorderable) + column->DisplayOrder = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(column); + if (init_mask & ImGuiTableFlags_Hideable) + column->IsUserEnabled = column->IsUserEnabledNextFrame = (flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; + if (init_mask & ImGuiTableFlags_Sortable) + { + // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. + column->SortOrder = (flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1; + column->SortDirection = (flags & ImGuiTableColumnFlags_DefaultSort) ? ((flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None; + } +} + // See "COLUMNS SIZING POLICIES" comments at the top of this file // If (init_width_or_weight <= 0.0f) it is ignored void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) @@ -1593,7 +1618,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); // When passing a width automatically enforce WidthFixed policy - // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) + // (whereas TableSetupColumnFlags would default to WidthAuto if table is not resizable) if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f) if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame) flags |= ImGuiTableColumnFlags_WidthFixed; @@ -1608,31 +1633,13 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo flags = column->Flags; // Initialize defaults - // FIXME: Similar to code in TableLoadSettings(), best to see how if we can merge. column->InitStretchWeightOrWidth = init_width_or_weight; if (table->IsInitializing) { - // Init width or weight - if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) - { - if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) - column->WidthRequest = init_width_or_weight; - if (flags & ImGuiTableColumnFlags_WidthStretch) - column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f; - - // Disable auto-fit if an explicit width/weight has been specified - if (init_width_or_weight > 0.0f) - column->AutoFitQueue = 0x00; - } - - // Init default visibility/sort state - if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) - column->IsUserEnabled = column->IsUserEnabledNextFrame = false; - if ((flags & ImGuiTableColumnFlags_DefaultSort) && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0) - { - column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs. - column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending); - } + ImGuiTableFlags init_flags = ~0; + if (column->WidthRequest >= 0.0f && column->StretchWeight >= 0.0f) + init_flags &= ~ImGuiTableFlags_Resizable; + TableInitColumnDefaults(table, column, init_flags); } // Store name (append with zero-terminator in contiguous buffer) @@ -3725,17 +3732,11 @@ void ImGui::TableLoadSettings(ImGuiTable* table) table->RefScale = settings->RefScale; // Initialize default columns settings - // FIXME: Similar to code in TableSetupColumn(), best to see how if we can merge. for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { ImGuiTableColumn* column = &table->Columns[column_n]; - column->StretchWeight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) && (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : -1.0f; - column->WidthRequest = (column->Flags & ImGuiTableColumnFlags_WidthFixed) && (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : -1.0f; + TableInitColumnDefaults(table, column, ~0); column->AutoFitQueue = 0x00; - column->DisplayOrder = (ImGuiTableColumnIdx)column_n; - column->IsUserEnabled = column->IsUserEnabledNextFrame = (column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; - column->SortOrder = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? 0 : -1; - column->SortDirection = (column->Flags & ImGuiTableColumnFlags_DefaultSort) ? ((column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending)) : (ImS8)ImGuiSortDirection_None; } // Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn From 85c488ee121b5f2a3c51141a571dc20f9fd16710 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Feb 2025 11:46:56 +0100 Subject: [PATCH 245/716] Hot-fix for broken MouseDrawCursor support for ImGuiMouseCursor_Wait/ImGuiMouseCursor_Progress/ImGuiMouseCursor_NotAllowed. Amend 8a35386, eec097f. --- imgui_draw.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3953212a1e9f..6ff583db637a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2466,6 +2466,8 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand + { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait + { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed }; From 6dc376f676b3a09375ad53dce652cebac3cb3dc9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Feb 2025 11:54:32 +0100 Subject: [PATCH 246/716] ImFontAtlas: added software/drawlist version of ImGuiMouseCursor_Wait/ImGuiMouseCursor_Progress + moved GetMouseCursorTexData() to internals. --- imgui.cpp | 9 ++++++++- imgui.h | 1 - imgui_draw.cpp | 22 +++++++++++----------- imgui_internal.h | 2 ++ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c27095fd452f..e24079487d41 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3793,7 +3793,7 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso { // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. ImVec2 offset, size, uv[4]; - if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) + if (!ImFontAtlasGetMouseCursorTexData(font_atlas, mouse_cursor, &offset, &size, &uv[0], &uv[2])) continue; const ImVec2 pos = base_pos - offset; const float scale = base_scale; @@ -3806,6 +3806,13 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); + if (mouse_cursor == ImGuiMouseCursor_Wait || mouse_cursor == ImGuiMouseCursor_Progress) + { + float a_min = ImFmod((float)g.Time * 5.0f, 2.0f * IM_PI); + float a_max = a_min + IM_PI * 1.65f; + draw_list->PathArcTo(pos + ImVec2(14, -1) * scale, 6.0f * scale, a_min, a_max); + draw_list->PathStroke(col_fill, ImDrawFlags_None, 3.0f * scale); + } draw_list->PopTextureID(); } } diff --git a/imgui.h b/imgui.h index 16c0b2c22e35..a607a669e98e 100644 --- a/imgui.h +++ b/imgui.h @@ -3415,7 +3415,6 @@ struct ImFontAtlas // [Internal] IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; - IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); //------------------------------------------- // Members diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6ff583db637a..3fd71cf3c4e8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2402,7 +2402,7 @@ ImFontConfig::ImFontConfig() // - ImFontAtlas::AddCustomRectRegular() // - ImFontAtlas::AddCustomRectFontGlyph() // - ImFontAtlas::CalcCustomRectUV() -// - ImFontAtlas::GetMouseCursorTexData() +// - ImFontAtlasGetMouseCursorTexData() // - ImFontAtlas::Build() // - ImFontAtlasBuildMultiplyCalcLookupTable() // - ImFontAtlasBuildMultiplyRectAlpha8() @@ -2466,8 +2466,8 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand - { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait - { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress + { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Wait // Arrow + custom code in ImGui::RenderMouseCursor() + { ImVec2(0,3), ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Progress // Arrow + custom code in ImGui::RenderMouseCursor() { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed }; @@ -2754,24 +2754,24 @@ void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* ou *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); } -bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) +bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) { if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT) return false; - if (Flags & ImFontAtlasFlags_NoMouseCursors) + if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) return false; - IM_ASSERT(PackIdMouseCursors != -1); - ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors); + IM_ASSERT(atlas->PackIdMouseCursors != -1); + ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y); ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; *out_size = size; *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; - out_uv_border[0] = (pos) * TexUvScale; - out_uv_border[1] = (pos + size) * TexUvScale; + out_uv_border[0] = (pos) * atlas->TexUvScale; + out_uv_border[1] = (pos + size) * atlas->TexUvScale; pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - out_uv_fill[0] = (pos) * TexUvScale; - out_uv_fill[1] = (pos + size) * TexUvScale; + out_uv_fill[0] = (pos) * atlas->TexUvScale; + out_uv_fill[1] = (pos + size) * atlas->TexUvScale; return true; } diff --git a/imgui_internal.h b/imgui_internal.h index e272d5479124..f0cf1c1068f3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3587,6 +3587,8 @@ IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_ta IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v); +IMGUI_API bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); + //----------------------------------------------------------------------------- // [SECTION] Test Engine specific hooks (imgui_test_engine) //----------------------------------------------------------------------------- From a6bcbb173b36c1c0a12dfa75f996f440d16c1daa Mon Sep 17 00:00:00 2001 From: Tygyh <32486062+tygyh@users.noreply.github.com> Date: Thu, 20 Feb 2025 18:07:25 +0100 Subject: [PATCH 247/716] Examples: Android: Update kotlin version (#8409) --- examples/example_android_opengl3/android/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_android_opengl3/android/app/build.gradle b/examples/example_android_opengl3/android/app/build.gradle index 53181baa2157..3a68c83718df 100644 --- a/examples/example_android_opengl3/android/app/build.gradle +++ b/examples/example_android_opengl3/android/app/build.gradle @@ -42,5 +42,5 @@ repositories { mavenCentral() } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } From 1e18a6cf6018e8de4cb38ebd87d2b9213f09823b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Feb 2025 16:55:35 +0100 Subject: [PATCH 248/716] Examples: GLFW+Vulkan: make GLFW_DIR overridable in cmake bit. (#8419) --- examples/example_glfw_vulkan/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/example_glfw_vulkan/CMakeLists.txt b/examples/example_glfw_vulkan/CMakeLists.txt index 443a144eae65..75475dbae873 100644 --- a/examples/example_glfw_vulkan/CMakeLists.txt +++ b/examples/example_glfw_vulkan/CMakeLists.txt @@ -15,7 +15,9 @@ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVK_PROTOTYPES") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVK_PROTOTYPES") # GLFW -set(GLFW_DIR ../../../glfw) # Set this to point to an up-to-date GLFW repo +if(NOT GLFW_DIR) + set(GLFW_DIR ../../../glfw) # Set this to point to an up-to-date GLFW repo +endif() option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" OFF) option(GLFW_BUILD_TESTS "Build the GLFW test programs" OFF) option(GLFW_BUILD_DOCS "Build the GLFW documentation" OFF) From 434b7710f3f291cad628b88d4ffb45e0fa3d249e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Feb 2025 16:49:35 +0100 Subject: [PATCH 249/716] Internals: packing ImGuiDataVarInfo + misc renaming + value of ImGuiDataType_Pointer doesn't need to be Count+1 --- imgui.cpp | 18 +++++++++--------- imgui_internal.h | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e24079487d41..501a19c6675d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3367,7 +3367,7 @@ void ImGui::PopStyleColor(int count) } } -static const ImGuiDataVarInfo GStyleVarInfo[] = +static const ImGuiDataVarInfo GStyleVarsInfo[] = { { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha @@ -3407,15 +3407,15 @@ static const ImGuiDataVarInfo GStyleVarInfo[] = const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) { IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); - IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT); - return &GStyleVarInfo[idx]; + IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarsInfo) == ImGuiStyleVar_COUNT); + return &GStyleVarsInfo[idx]; } void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 1) + if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 1) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); return; @@ -3429,7 +3429,7 @@ void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) + if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); return; @@ -3443,7 +3443,7 @@ void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) + if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); return; @@ -3457,7 +3457,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); - if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2) + if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); return; @@ -3481,8 +3481,8 @@ void ImGui::PopStyleVar(int count) ImGuiStyleMod& backup = g.StyleVarStack.back(); const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx); void* data = info->GetVarPtr(&g.Style); - if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } - else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + if (info->DataType == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (info->DataType == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } g.StyleVarStack.pop_back(); count--; } diff --git a/imgui_internal.h b/imgui_internal.h index f0cf1c1068f3..22d0354231bd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -814,9 +814,9 @@ struct ImDrawDataBuilder struct ImGuiDataVarInfo { - ImGuiDataType Type; - ImU32 Count; // 1+ - ImU32 Offset; // Offset in parent structure + ImGuiDataType DataType : 8; + ImU32 Count : 8; // 1+ + ImU32 Offset : 16; // Offset in parent structure void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); } }; @@ -837,7 +837,7 @@ struct ImGuiDataTypeInfo // Extend ImGuiDataType_ enum ImGuiDataTypePrivate_ { - ImGuiDataType_Pointer = ImGuiDataType_COUNT + 1, + ImGuiDataType_Pointer = ImGuiDataType_COUNT, ImGuiDataType_ID, }; From edc66d79c7df44899cb1e9be4f839ef4371be91b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Feb 2025 23:09:54 +0100 Subject: [PATCH 250/716] Nav: extract code into a NavUpdateWindowingApplyFocus() so it may be reused elsewhere. --- imgui.cpp | 50 +++++++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 501a19c6675d..9e2a5e2002e1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1212,6 +1212,7 @@ static void UpdateWindowInFocusOrderList(ImGuiWindow* window, bool j // Navigation static void NavUpdate(); static void NavUpdateWindowing(); +static void NavUpdateWindowingApplyFocus(ImGuiWindow* window); static void NavUpdateWindowingOverlay(); static void NavUpdateCancelRequest(); static void NavUpdateCreateMoveRequest(); @@ -13651,6 +13652,33 @@ static void NavUpdateWindowingTarget(int focus_change_dir) g.NavWindowingToggleLayer = false; } +// Apply focus and close overlay +static void ImGui::NavUpdateWindowingApplyFocus(ImGuiWindow* apply_focus_window) +{ + ImGuiContext& g = *GImGui; + if (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow) + { + ClearActiveID(); + SetNavCursorVisibleAfterMove(); + ClosePopupsOverWindow(apply_focus_window, false); + FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); + apply_focus_window = g.NavWindow; + if (apply_focus_window->NavLastIds[0] == 0) + NavInitWindow(apply_focus_window, false); + + // If the window has ONLY a menu layer (no main layer), select it directly + // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame, + // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since + // the target window as already been previewed once. + // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases, + // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask* + // won't be valid. + if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu)) + g.NavLayer = ImGuiNavLayer_Menu; + } + g.NavWindowingTarget = NULL; +} + // Windowing management mode // Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer) // Gamepad: Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer) @@ -13802,28 +13830,8 @@ static void ImGui::NavUpdateWindowing() } // Apply final focus - if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow)) - { - ClearActiveID(); - SetNavCursorVisibleAfterMove(); - ClosePopupsOverWindow(apply_focus_window, false); - FocusWindow(apply_focus_window, ImGuiFocusRequestFlags_RestoreFocusedChild); - apply_focus_window = g.NavWindow; - if (apply_focus_window->NavLastIds[0] == 0) - NavInitWindow(apply_focus_window, false); - - // If the window has ONLY a menu layer (no main layer), select it directly - // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame, - // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since - // the target window as already been previewed once. - // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases, - // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask* - // won't be valid. - if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu)) - g.NavLayer = ImGuiNavLayer_Menu; - } if (apply_focus_window) - g.NavWindowingTarget = NULL; + NavUpdateWindowingApplyFocus(apply_focus_window); // Apply menu/layer toggle if (apply_toggle_layer && g.NavWindow) From 74afea04d6432e3cbcadd43f8eaf771aed48a1c8 Mon Sep 17 00:00:00 2001 From: Tygyh <32486062+tygyh@users.noreply.github.com> Date: Sat, 22 Feb 2025 23:36:40 +0100 Subject: [PATCH 251/716] Fix typos in docs (#8427) --- docs/CHANGELOG.txt | 4 ++-- docs/CONTRIBUTING.md | 2 +- docs/TODO.txt | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 044be4360761..0d1bbd0523af 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -346,7 +346,7 @@ Other changes: initial mouse down event. - Note that it may reveal incorrect usage if you were using InputInt/InputFloat without persistent storage by relying solely on e.g. IsItemDeactivatedAfterEdit(): - this was never supported and didn't work consistantly (see #8149). + this was never supported and didn't work consistently (see #8149). - InputText: fixed a bug (regression in 1.91.2) where modifying text buffer within a callback would sometimes prevents further appending to the buffer. - Tabs, Style: made ImGuiCol_TabDimmedSelectedOverline alpha 0 (not visible) in default @@ -450,7 +450,7 @@ Other changes: supported by InputFloat, InputInt, InputScalar etc. widgets. It actually never was. (#8065, #3946) - imgui_freetype: Added support for plutosvg (as an alternative to lunasvg) to render OpenType SVG fonts. Requires defining IMGUI_ENABLE_FREETYPE_PLUTOSVG along with IMGUI_ENABLE_FREETYPE. - Providing headers/librairies for plutosvg + plutovg is up to you (see #7927 for help). + Providing headers/libraries for plutosvg + plutovg is up to you (see #7927 for help). (#7927, #7187, #6591, #6607) [@pthom] - Backends: DX11, DX12, SDLRenderer2/3. Vulkan, WGPU: expose selected state in ImGui_ImplXXXX_RenderState structures during render loop user draw callbacks. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index f70cf0e23448..fb946c4b3db4 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -77,5 +77,5 @@ If you have been using Dear ImGui for a while or have been using C/C++ for sever Any code you submit will become part of the repository and be distributed under the [Dear ImGui license](https://github.com/ocornut/imgui/blob/master/LICENSE.txt). By submitting code to the project you agree that the code is your work and that you can give it to the project. -You also agree by submitting your code that you grant all transferrable rights to the code to the project maintainer, including for example re-licensing the code, modifying the code, and distributing it in source or binary forms. Specifically, this includes a requirement that you assign copyright to the project maintainer. For this reason, do not modify any copyright statements in files in any PRs. +You also agree by submitting your code that you grant all transferable rights to the code to the project maintainer, including for example re-licensing the code, modifying the code, and distributing it in source or binary forms. Specifically, this includes a requirement that you assign copyright to the project maintainer. For this reason, do not modify any copyright statements in files in any PRs. diff --git a/docs/TODO.txt b/docs/TODO.txt index 31238ff83536..14a152a4bec0 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -22,7 +22,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window: using SetWindowPos() inside Begin() and moving the window with the mouse reacts a very ugly glitch. We should just defer the SetWindowPos() call. - window: GetWindowSize() returns (0,0) when not calculated? (#1045) - window: investigate better auto-positioning for new windows. - - window: top most window flag? more z-order contrl? (#2574) + - window: top most window flag? more z-order control? (#2574) - window/size: manually triggered auto-fit (double-click on grip) shouldn't resize window down to viewport size? - window/size: how to allow to e.g. auto-size vertically to fit contents, but be horizontally resizable? Assuming SetNextWindowSize() is modified to treat -1.0f on each axis as "keep as-is" (would be good but might break erroneous code): Problem is UpdateWindowManualResize() and lots of code treat (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) together. - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. -> this may require enforcing that it is illegal to submit contents if Begin returns false. @@ -57,7 +57,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - widgets: start exposing PushItemFlag() and ImGuiItemFlags - widgets: alignment options in style (e.g. center Selectable, Right-Align within Button, etc.) #1260 - widgets: activate by identifier (trigger button, focus given id) - - widgets: custom glyph/shapes replacements for stock sapes. (also #6090 #2431 #2235 #6517) + - widgets: custom glyph/shapes replacements for stock shapes. (also #6090 #2431 #2235 #6517) - widgets: coloredit: keep reporting as active when picker is on? - widgets: group/scalarn functions: expose more per-component information. e.g. store NextItemData.ComponentIdx set by scalarn function, groups can expose them back somehow. - selectable: using (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported. @@ -137,7 +137,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - image/image button: misalignment on padded/bordered button? - image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that? - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt() - - slider: add dragging-based widgets to edit values with mouse (on 2 axises), saving screen real-estate. + - slider: add dragging-based widgets to edit values with mouse (on 2 axes), saving screen real-estate. - slider: tint background based on value (e.g. v_min -> v_max, or use 0.0f either side of the sign) - slider: relative dragging? + precision dragging - slider: step option (#1183) @@ -213,7 +213,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - log: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?). code is commented because it fails with multiple Begin/End pairs. - log: obsolete LogButtons().... (was: LogButtons() options for specifying depth and/or hiding depth slider) - - filters: set a current filter that certains items (e.g. tree node) can automatically query to hide themselves + - filters: set a current filter that certain items (e.g. tree node) can automatically query to hide themselves - filters: handle wild-cards (with implicit leading/trailing *), reg-exprs - filters: fuzzy matches (may use code at blog.forrestthewoods.com/4cffeed33fdb) From 5dce79e9410bfe0fd1709980b637ce38a2313ed0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 24 Feb 2025 10:52:15 +0100 Subject: [PATCH 252/716] Backends: DirectX12: Fixed an issue where pre-1.91.5 legacy ImGui_ImplDX12_Init() signature started breaking in 1.91.8 due to missing command queue. (#8429) --- backends/imgui_impl_dx12.cpp | 25 ++++++++++++++++++++++--- backends/imgui_impl_dx12.h | 5 +++-- docs/CHANGELOG.txt | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 6f17f587aff9..8449832c5b09 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -19,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-24: DirectX12: Fixed an issue where ImGui_ImplDX12_Init() signature change from 2024-11-15 combined with change from 2025-01-15 made legacy ImGui_ImplDX12_Init() crash. (#8429) // 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. // 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. // 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete). @@ -75,6 +76,8 @@ struct ImGui_ImplDX12_Data ID3D12Device* pd3dDevice; ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; + ID3D12CommandQueue* pCommandQueue; + bool commandQueueOwned; DXGI_FORMAT RTVFormat; DXGI_FORMAT DSVFormat; ID3D12DescriptorHeap* pd3dSrvDescHeap; @@ -430,7 +433,7 @@ static void ImGui_ImplDX12_CreateFontsTexture() hr = cmdList->Close(); IM_ASSERT(SUCCEEDED(hr)); - ID3D12CommandQueue* cmdQueue = bd->InitInfo.CommandQueue; + ID3D12CommandQueue* cmdQueue = bd->pCommandQueue; cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList); hr = cmdQueue->Signal(fence, 1); IM_ASSERT(SUCCEEDED(hr)); @@ -702,6 +705,9 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (!bd || !bd->pd3dDevice) return; + if (bd->commandQueueOwned) + SafeRelease(bd->pCommandQueue); + bd->commandQueueOwned = false; SafeRelease(bd->pRootSignature); SafeRelease(bd->pPipelineState); @@ -732,6 +738,8 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) init_info = &bd->InitInfo; bd->pd3dDevice = init_info->Device; + IM_ASSERT(init_info->CommandQueue != NULL); + bd->pCommandQueue = init_info->CommandQueue; bd->RTVFormat = init_info->RTVFormat; bd->DSVFormat = init_info->DSVFormat; bd->numFramesInFlight = init_info->NumFramesInFlight; @@ -793,8 +801,19 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO init_info.RTVFormat = rtv_format; init_info.SrvDescriptorHeap = srv_descriptor_heap; init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle; - init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle;; - return ImGui_ImplDX12_Init(&init_info); + init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle; + + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.NodeMask = 1; + HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue)); + IM_ASSERT(SUCCEEDED(hr)); + + bool ret = ImGui_ImplDX12_Init(&init_info); + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + bd->commandQueueOwned = true; + return ret; } #endif diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index a57c1694d36e..736e9f5c2e3e 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -27,7 +27,7 @@ struct ImGui_ImplDX12_InitInfo { ID3D12Device* Device; - ID3D12CommandQueue* CommandQueue; + ID3D12CommandQueue* CommandQueue; // Command queue used for queuing texture uploads. int NumFramesInFlight; DXGI_FORMAT RTVFormat; // RenderTarget format. DXGI_FORMAT DSVFormat; // DepthStencilView format. @@ -54,7 +54,8 @@ IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy initialization API Obsoleted in 1.91.5 -// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' +// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap' +// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field. IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle); #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0d1bbd0523af..ae09637033fc 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,8 @@ Other changes: and ImGuiMouseCursor_Progress cursors. - Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) +- Backends: DirectX12: Fixed an issue where pre-1.91.5 legacy ImGui_ImplDX12_Init() + signature started breaking in 1.91.8 due to missing command queue. (#8429) - Backends: Metal: Fixed a crash on application resources. (#8367, #7419) [@anszom] - Backends: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. (#8326, #8365) [@mklefrancois] From ef969a53f5fe8b956dc252718f14997393e3344f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 24 Feb 2025 11:44:48 +0100 Subject: [PATCH 253/716] Tabs: fixed Unsaved Marker not being visible when Close Button is. (#8430, #8387) --- imgui_widgets.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6e08cec22e5a..f011805f98d1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -10377,9 +10377,15 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, else close_button_visible = (g.Style.TabCloseButtonMinWidthUnselected < 0.0f) ? true : (is_hovered && bb.GetWidth() >= ImMax(button_sz, g.Style.TabCloseButtonMinWidthUnselected)); } - bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x); - if (close_button_visible) + // When tabs/document is unsaved, the unsaved marker takes priority over the close button. + const bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x) && (!close_button_visible || !is_hovered); + if (unsaved_marker_visible) + { + const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz)); + RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); + } + else if (close_button_visible) { ImGuiLastItemData last_item_backup = g.LastItemData; if (CloseButton(close_button_id, button_pos)) @@ -10390,11 +10396,6 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, if (is_hovered && !(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2)) close_button_pressed = true; } - else if (unsaved_marker_visible) - { - const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz)); - RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); - } // This is all rather complicated // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) From dac40d04872e32399f81b1bf8d0befe87c4cd647 Mon Sep 17 00:00:00 2001 From: TheMode Date: Sat, 22 Feb 2025 11:36:41 +0100 Subject: [PATCH 254/716] Backends: SDL2, SDL3: don't call SDL_GetGlobalMouseState() when mouse position is in relative mode. (#8425, #8407) --- backends/imgui_impl_sdl2.cpp | 5 ++++- backends/imgui_impl_sdl3.cpp | 4 +++- docs/CHANGELOG.txt | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index fbfa2fba8d9a..361fc3b57e3f 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array. @@ -622,8 +623,10 @@ static void ImGui_ImplSDL2_UpdateMouseData() SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); // (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured) - if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0) + const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0; + if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { + // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) int window_x, window_y, mouse_x_global, mouse_y_global; SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global); SDL_GetWindowPosition(bd->Window, &window_x, &window_y); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 006316afbb8b..d2433793e609 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. // 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array. @@ -588,7 +589,8 @@ static void ImGui_ImplSDL3_UpdateMouseData() SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y); // (Optional) Fallback to provide mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured) - if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0) + const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode(bd->Window); + if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) float mouse_x_global, mouse_y_global; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ae09637033fc..d0acdcb9210d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -87,10 +87,12 @@ Other changes: (busy/wait/hourglass shape, with or without an arrow cursor). - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) -- Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn +- Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) [@achabense] - Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. +- Backends: SDL2, SDL3: Avoid calling SDL_GetGlobalMouseState() when mouse is in + relative mode. (#8425, #8407) [@TheMode] - Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) - Backends: DirectX12: Fixed an issue where pre-1.91.5 legacy ImGui_ImplDX12_Init() From 030746faff4a0181ec3149b8457f7bd0a5770819 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 24 Feb 2025 17:45:16 +0100 Subject: [PATCH 255/716] Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker. (#7961, #7669) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 24 +++++++++++++++++------- imgui.h | 3 ++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d0acdcb9210d..d5c4ded328f0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,8 @@ Other changes: is hovered, merely it's visibility. (#8399, #8387) [@nicovanbentum] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] +- Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) + to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors (busy/wait/hourglass shape, with or without an arrow cursor). - Demo: Combos: demonstrate a very simple way to add a filter to a combo, diff --git a/imgui.cpp b/imgui.cpp index 9e2a5e2002e1..a5d52d415d7c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1454,6 +1454,7 @@ ImGuiIO::ImGuiIO() ConfigMemoryCompactTimer = 60.0f; ConfigDebugIsDebuggerPresent = false; ConfigDebugHighlightIdConflicts = true; + ConfigDebugHighlightIdConflictsShowItemPicker = true; ConfigDebugBeginReturnValueOnce = false; ConfigDebugBeginReturnValueLoop = false; @@ -10445,15 +10446,24 @@ void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip() //BulletText("Code intending to use duplicate ID may use e.g. PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()"); // Not making this too visible for fear of it being abused. BulletText("Set io.ConfigDebugHighlightIdConflicts=false to disable this warning in non-programmers builds."); Separator(); - Text("(Hold CTRL to: use"); - SameLine(); - if (SmallButton("Item Picker")) - DebugStartItemPicker(); - SameLine(); - Text("to break in item call-stack, or"); - SameLine(); + if (g.IO.ConfigDebugHighlightIdConflictsShowItemPicker) + { + Text("(Hold CTRL to: use "); + SameLine(0.0f, 0.0f); + if (SmallButton("Item Picker")) + DebugStartItemPicker(); + SameLine(0.0f, 0.0f); + Text(" to break in item call-stack, or "); + } + else + { + Text("(Hold CTRL to "); + } + SameLine(0.0f, 0.0f); if (SmallButton("Open FAQ->About ID Stack System") && g.PlatformIO.Platform_OpenInShellFn != NULL) g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage"); + SameLine(0.0f, 0.0f); + Text(")"); EndErrorTooltip(); } diff --git a/imgui.h b/imgui.h index a607a669e98e..5cba09f1c414 100644 --- a/imgui.h +++ b/imgui.h @@ -2319,7 +2319,8 @@ struct ImGuiIO // - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers. // - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead! // - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system - bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message when multiple items have conflicting identifiers. + bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message popup when multiple items have conflicting identifiers. + bool ConfigDebugHighlightIdConflictsShowItemPicker;//=true // Show "Item Picker" button in aforementioned popup. // Tools to test correct Begin/End and BeginChild/EndChild behaviors. // - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX() From 6e29450f76db356ebee19a9ac4ee8f4fc129e961 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 25 Feb 2025 16:02:10 +0100 Subject: [PATCH 256/716] Internals: added IsItemActiveAsInputText() helper. --- imgui_internal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_internal.h b/imgui_internal.h index 22d0354231bd..c4ec9cc93a25 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3481,6 +3481,7 @@ namespace ImGui inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); } inline ImGuiInputTextState* GetInputTextState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active IMGUI_API void SetNextItemRefVal(ImGuiDataType data_type, void* p_data); + inline bool IsItemActiveAsInputText() { ImGuiContext& g = *GImGui; return g.ActiveId != 0 && g.ActiveId == g.LastItemData.ID && g.InputTextState.ID == g.LastItemData.ID; } // This may be useful to apply workaround that a based on distinguish whenever an item is active as a text input field. // Color IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); From 4c0604ec2ee9a9121ea4ecb55543ff507ca81bcc Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 18 Jan 2025 16:03:46 +0100 Subject: [PATCH 257/716] Font: shallow refactor, rename ConfigData[] fields to Sources[], ConfigDataCount to SourcesCount. In theory this is all internal stuff. --- imgui.cpp | 12 ++-- imgui.h | 10 +-- imgui_draw.cpp | 114 +++++++++++++++---------------- imgui_internal.h | 6 +- misc/freetype/imgui_freetype.cpp | 54 +++++++-------- 5 files changed, 98 insertions(+), 98 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a5d52d415d7c..64514028ff86 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16215,7 +16215,7 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co void ImGui::DebugNodeFont(ImFont* font) { bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)", - font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); + font->Sources ? font->Sources[0].Name : "", font->FontSize, font->Glyphs.Size, font->SourcesCount); // Display preview text if (!opened) @@ -16248,14 +16248,14 @@ void ImGui::DebugNodeFont(ImFont* font) Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface); Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); - for (int config_i = 0; config_i < font->ConfigDataCount; config_i++) - if (font->ConfigData) + for (int config_i = 0; config_i < font->SourcesCount; config_i++) + if (font->Sources) { - const ImFontConfig* cfg = &font->ConfigData[config_i]; + const ImFontConfig* src = &font->Sources[config_i]; int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(cfg, &oversample_h, &oversample_v); + ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", - config_i, cfg->Name, cfg->OversampleH, oversample_h, cfg->OversampleV, oversample_v, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y); + config_i, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); } // Display all glyphs of the fonts in separate pages of 256 characters diff --git a/imgui.h b/imgui.h index 5cba09f1c414..1bdc2cb10b13 100644 --- a/imgui.h +++ b/imgui.h @@ -3441,7 +3441,7 @@ struct ImFontAtlas ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. - ImVector ConfigData; // Configuration data + ImVector Sources; // Source/configuration data ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines // [Internal] Font builder @@ -3472,10 +3472,10 @@ struct ImFont ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) // [Internal] Members: Cold ~32/40 bytes - // Conceptually ConfigData[] is the list of font sources merged to create this font. + // Conceptually Sources[] is the list of font sources merged to create this font. ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into - const ImFontConfig* ConfigData; // 4-8 // in // Pointer within ContainerAtlas->ConfigData to ConfigDataCount instances - short ConfigDataCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. + ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances + short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. short EllipsisCharCount; // 1 // out // 1 or 3 ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') @@ -3494,7 +3494,7 @@ struct ImFont IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return ConfigData ? ConfigData->Name : ""; } + const char* GetDebugName() const { return Sources ? Sources->Name : ""; } // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3fd71cf3c4e8..206c29ce5a06 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2408,7 +2408,7 @@ ImFontConfig::ImFontConfig() // - ImFontAtlasBuildMultiplyRectAlpha8() // - ImFontAtlasBuildWithStbTruetype() // - ImFontAtlasGetBuilderForStbTruetype() -// - ImFontAtlasUpdateConfigDataPointers() +// - ImFontAtlasUpdateSourcesPointers() // - ImFontAtlasBuildSetupFont() // - ImFontAtlasBuildPackCustomRects() // - ImFontAtlasBuildRender8bppRectFromString() @@ -2487,7 +2487,7 @@ ImFontAtlas::~ImFontAtlas() void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - for (ImFontConfig& font_cfg : ConfigData) + for (ImFontConfig& font_cfg : Sources) if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas) { IM_FREE(font_cfg.FontData); @@ -2496,12 +2496,12 @@ void ImFontAtlas::ClearInputData() // When clearing this we lose access to the font name and other information used to build the font. for (ImFont* font : Fonts) - if (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size) + if (font->Sources >= Sources.Data && font->Sources < Sources.Data + Sources.Size) { - font->ConfigData = NULL; - font->ConfigDataCount = 0; + font->Sources = NULL; + font->SourcesCount = 0; } - ConfigData.clear(); + Sources.clear(); CustomRects.clear(); PackIdMouseCursors = PackIdLines = -1; // Important: we leave TexReady untouched @@ -2584,8 +2584,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) else IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. - ConfigData.push_back(*font_cfg); - ImFontConfig& new_font_cfg = ConfigData.back(); + Sources.push_back(*font_cfg); + ImFontConfig& new_font_cfg = Sources.back(); if (new_font_cfg.DstFont == NULL) new_font_cfg.DstFont = Fonts.back(); if (!new_font_cfg.FontDataOwnedByAtlas) @@ -2601,8 +2601,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // - We may support it better later and remove this rounding. new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels); - // Pointers to ConfigData and BuilderData are otherwise dangling - ImFontAtlasUpdateConfigDataPointers(this); + // Pointers to Sources data are otherwise dangling + ImFontAtlasUpdateSourcesPointers(this); // Invalidate texture TexReady = false; @@ -2780,7 +2780,7 @@ bool ImFontAtlas::Build() IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); // Default font is none are specified - if (ConfigData.Size == 0) + if (Sources.Size == 0) AddFontDefault(); // Select builder @@ -2822,11 +2822,11 @@ void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig *data = table[*data]; } -void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v) +void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v) { // Automatically disable horizontal oversampling over size 36 - *out_oversample_h = (cfg->OversampleH != 0) ? cfg->OversampleH : (cfg->SizePixels * cfg->RasterizerDensity > 36.0f || cfg->PixelSnapH) ? 1 : 2; - *out_oversample_v = (cfg->OversampleV != 0) ? cfg->OversampleV : 1; + *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (src->SizePixels * src->RasterizerDensity > 36.0f || src->PixelSnapH) ? 1 : 2; + *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1; } #ifdef IMGUI_ENABLE_STB_TRUETYPE @@ -2869,7 +2869,7 @@ static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { - IM_ASSERT(atlas->ConfigData.Size > 0); + IM_ASSERT(atlas->Sources.Size > 0); ImFontAtlasBuildInit(atlas); @@ -2883,32 +2883,32 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Temporary storage for building ImVector src_tmp_array; ImVector dst_tmp_array; - src_tmp_array.resize(atlas->ConfigData.Size); + src_tmp_array.resize(atlas->Sources.Size); dst_tmp_array.resize(atlas->Fonts.Size); memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); // 1. Initialize font loading structure, check font data validity - for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) + for (int src_i = 0; src_i < atlas->Sources.Size; src_i++) { ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - ImFontConfig& cfg = atlas->ConfigData[src_i]; - IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + ImFontConfig& src = atlas->Sources[src_i]; + IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas)); - // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + // Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) src_tmp.DstIndex = -1; for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) - if (cfg.DstFont == atlas->Fonts[output_i]) + if (src.DstFont == atlas->Fonts[output_i]) src_tmp.DstIndex = output_i; if (src_tmp.DstIndex == -1) { - IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array? return false; } // Initialize helper structure for font loading and verify that the TTF/OTF data is correct - const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo); + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src.FontData, src.FontNo); IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); - if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset)) + if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)src.FontData, font_offset)) { IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); return false; @@ -2916,7 +2916,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // Measure highest codepoints ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault(); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common @@ -2995,12 +2995,12 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) buf_packedchars_out_n += src_tmp.GlyphsCount; // Automatic selection of oversampling parameters - ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontConfig& src = atlas->Sources[src_i]; int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(&cfg, &oversample_h, &oversample_v); + ImFontAtlasBuildGetOversampleFactors(&src, &oversample_h, &oversample_v); // Convert our ranges in the format stb_truetype wants - src_tmp.PackRange.font_size = cfg.SizePixels * cfg.RasterizerDensity; + src_tmp.PackRange.font_size = src.SizePixels * src.RasterizerDensity; src_tmp.PackRange.first_unicode_codepoint_in_range = 0; src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; @@ -3009,7 +3009,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) src_tmp.PackRange.v_oversample = (unsigned char)oversample_v; // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) - const float scale = (cfg.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels * cfg.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels * cfg.RasterizerDensity); + const float scale = (src.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels * src.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -src.SizePixels * src.RasterizerDensity); for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) { int x0, y0, x1, y1; @@ -3069,7 +3069,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) // 8. Render/rasterize font characters into the texture for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { - ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontConfig& src = atlas->Sources[src_i]; ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; if (src_tmp.GlyphsCount == 0) continue; @@ -3077,10 +3077,10 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); // Apply multiply operator - if (cfg.RasterizerMultiply != 1.0f) + if (src.RasterizerMultiply != 1.0f) { unsigned char multiply_table[256]; - ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply); stbrp_rect* r = &src_tmp.Rects[0]; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) if (r->was_packed) @@ -3098,22 +3098,22 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { // When merging fonts with MergeMode=true: // - We can have multiple input fonts writing into a same destination font. - // - dst_font->ConfigData is != from cfg which is our source configuration. + // - dst_font->Sources is != from src which is our source configuration. ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - ImFontConfig& cfg = atlas->ConfigData[src_i]; - ImFont* dst_font = cfg.DstFont; + ImFontConfig& src = atlas->Sources[src_i]; + ImFont* dst_font = src.DstFont; - const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels); + const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels); int unscaled_ascent, unscaled_descent, unscaled_line_gap; stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); const float ascent = ImCeil(unscaled_ascent * font_scale); const float descent = ImFloor(unscaled_descent * font_scale); - ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); - const float font_off_x = cfg.GlyphOffset.x; - const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); + ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent); + const float font_off_x = src.GlyphOffset.x; + const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent); - const float inv_rasterization_scale = 1.0f / cfg.RasterizerDensity; + const float inv_rasterization_scale = 1.0f / src.RasterizerDensity; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) { @@ -3127,7 +3127,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) float y0 = q.y0 * inv_rasterization_scale + font_off_y; float x1 = q.x1 * inv_rasterization_scale + font_off_x; float y1 = q.y1 * inv_rasterization_scale + font_off_y; - dst_font->AddGlyph(&cfg, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale); + dst_font->AddGlyph(&src, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale); } } @@ -3147,17 +3147,17 @@ const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() #endif // IMGUI_ENABLE_STB_TRUETYPE -void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas) +void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas) { - for (ImFontConfig& font_cfg : atlas->ConfigData) + for (ImFontConfig& src : atlas->Sources) { - ImFont* font = font_cfg.DstFont; - if (!font_cfg.MergeMode) + ImFont* font = src.DstFont; + if (!src.MergeMode) { - font->ConfigData = &font_cfg; - font->ConfigDataCount = 0; + font->Sources = &src; + font->SourcesCount = 0; } - font->ConfigDataCount++; + font->SourcesCount++; } } @@ -3167,7 +3167,7 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f { font->ClearOutputData(); font->FontSize = font_config->SizePixels; - IM_ASSERT(font->ConfigData == font_config); + IM_ASSERT(font->Sources == font_config); font->ContainerAtlas = atlas; font->Ascent = ascent; font->Descent = descent; @@ -3786,7 +3786,7 @@ void ImFont::BuildLookupTable() // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. - const ImWchar ellipsis_chars[] = { ConfigData->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; + const ImWchar ellipsis_chars[] = { Sources->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; if (EllipsisChar == 0) EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); @@ -3830,27 +3830,27 @@ void ImFont::GrowIndex(int new_size) // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). -// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font. -void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +// 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. +void ImFont::AddGlyph(const ImFontConfig* src, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) { - if (cfg != NULL) + if (src != NULL) { // Clamp & recenter if needed const float advance_x_original = advance_x; - advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX); + advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX, src->GlyphMaxAdvanceX); if (advance_x != advance_x_original) { - float char_off_x = cfg->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; + float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; x0 += char_off_x; x1 += char_off_x; } // Snap to pixel - if (cfg->PixelSnapH) + if (src->PixelSnapH) advance_x = IM_ROUND(advance_x); // Bake extra spacing - advance_x += cfg->GlyphExtraAdvanceX; + advance_x += src->GlyphExtraAdvanceX; } int glyph_idx = Glyphs.Size; diff --git a/imgui_internal.h b/imgui_internal.h index c4ec9cc93a25..c70bb999c595 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3577,16 +3577,16 @@ struct ImFontBuilderIO #ifdef IMGUI_ENABLE_STB_TRUETYPE IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); #endif -IMGUI_API void ImFontAtlasUpdateConfigDataPointers(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); +IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, float ascent, float descent); IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); -IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* cfg, int* out_oversample_h, int* out_oversample_v); +IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); IMGUI_API bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 875060d7f394..73b9862bcfb9 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -166,7 +166,7 @@ namespace // NB: No ctor/dtor, explicitly call Init()/Shutdown() struct FreeTypeFont { - bool InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + bool InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. void CloseFont(); void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); @@ -185,9 +185,9 @@ namespace float InvRasterizationDensity; }; - bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& cfg, unsigned int extra_font_builder_flags) + bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_font_builder_flags) { - FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)cfg.FontData, (uint32_t)cfg.FontDataSize, (uint32_t)cfg.FontNo, &Face); + FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src.FontData, (uint32_t)src.FontDataSize, (uint32_t)src.FontNo, &Face); if (error != 0) return false; error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE); @@ -195,7 +195,7 @@ namespace return false; // Convert to FreeType flags (NB: Bold and Oblique are processed separately) - UserFlags = cfg.FontBuilderFlags | extra_font_builder_flags; + UserFlags = src.FontBuilderFlags | extra_font_builder_flags; LoadFlags = 0; if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) @@ -222,11 +222,11 @@ namespace if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) LoadFlags |= FT_LOAD_COLOR; - RasterizationDensity = cfg.RasterizerDensity; + RasterizationDensity = src.RasterizerDensity; InvRasterizationDensity = 1.0f / RasterizationDensity; memset(&Info, 0, sizeof(Info)); - SetPixelHeight((uint32_t)cfg.SizePixels); + SetPixelHeight((uint32_t)src.SizePixels); return true; } @@ -443,7 +443,7 @@ struct ImFontBuildDstDataFT bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags) { - IM_ASSERT(atlas->ConfigData.Size > 0); + IM_ASSERT(atlas->Sources.Size > 0); ImFontAtlasBuildInit(atlas); @@ -458,36 +458,36 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u bool src_load_color = false; ImVector src_tmp_array; ImVector dst_tmp_array; - src_tmp_array.resize(atlas->ConfigData.Size); + src_tmp_array.resize(atlas->Sources.Size); dst_tmp_array.resize(atlas->Fonts.Size); memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); // 1. Initialize font loading structure, check font data validity - for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++) + for (int src_i = 0; src_i < atlas->Sources.Size; src_i++) { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontConfig& src = atlas->Sources[src_i]; FreeTypeFont& font_face = src_tmp.Font; - IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas)); + IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas)); - // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) + // Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) src_tmp.DstIndex = -1; for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) - if (cfg.DstFont == atlas->Fonts[output_i]) + if (src.DstFont == atlas->Fonts[output_i]) src_tmp.DstIndex = output_i; - IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array? + IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array? if (src_tmp.DstIndex == -1) return false; // Load font - if (!font_face.InitFont(ft_library, cfg, extra_flags)) + if (!font_face.InitFont(ft_library, src, extra_flags)) return false; // Measure highest codepoints - src_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0; + src_load_color |= (src.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0; ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); + src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault(); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) { // Check for valid range. This may also help detect *some* dangling pointers, because a common @@ -577,7 +577,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - ImFontConfig& cfg = atlas->ConfigData[src_i]; + ImFontConfig& src = atlas->Sources[src_i]; if (src_tmp.GlyphsCount == 0) continue; @@ -585,10 +585,10 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u buf_rects_out_n += src_tmp.GlyphsCount; // Compute multiply table if requested - const bool multiply_enabled = (cfg.RasterizerMultiply != 1.0f); + const bool multiply_enabled = (src.RasterizerMultiply != 1.0f); unsigned char multiply_table[256]; if (multiply_enabled) - ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply); + ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply); // Gather the sizes of all rectangles we will need to pack for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) @@ -687,18 +687,18 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // When merging fonts with MergeMode=true: // - We can have multiple input fonts writing into a same destination font. - // - dst_font->ConfigData is != from cfg which is our source configuration. - ImFontConfig& cfg = atlas->ConfigData[src_i]; - ImFont* dst_font = cfg.DstFont; + // - dst_font->Sources is != from src which is our source configuration. + ImFontConfig& src = atlas->Sources[src_i]; + ImFont* dst_font = src.DstFont; const float ascent = src_tmp.Font.Info.Ascender; const float descent = src_tmp.Font.Info.Descender; - ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent); + ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent); if (src_tmp.GlyphsCount == 0) continue; - const float font_off_x = cfg.GlyphOffset.x; - const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent); + const float font_off_x = src.GlyphOffset.x; + const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent); const int padding = atlas->TexGlyphPadding; for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) @@ -724,7 +724,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u float v0 = (ty) / (float)atlas->TexHeight; float u1 = (tx + info.Width) / (float)atlas->TexWidth; float v1 = (ty + info.Height) / (float)atlas->TexHeight; - dst_font->AddGlyph(&cfg, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity); + dst_font->AddGlyph(&src, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity); ImFontGlyph* dst_glyph = &dst_font->Glyphs.back(); IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint); From a86fcbd9474bb4121f25cbf9196674d79f90f1f1 Mon Sep 17 00:00:00 2001 From: Russ Gibson Date: Wed, 26 Feb 2025 05:38:08 -0800 Subject: [PATCH 258/716] Examples: SDL3+SDL_Renderer: removed reference to OpenGL to remove confusion. (#8434) --- examples/example_sdl3_sdlrenderer3/Makefile | 2 +- examples/example_sdl3_sdlrenderer3/main.cpp | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/example_sdl3_sdlrenderer3/Makefile b/examples/example_sdl3_sdlrenderer3/Makefile index 2ca98654574b..c7ee64fc7712 100644 --- a/examples/example_sdl3_sdlrenderer3/Makefile +++ b/examples/example_sdl3_sdlrenderer3/Makefile @@ -44,7 +44,7 @@ endif ifeq ($(OS), Windows_NT) ECHO_MESSAGE = "MinGW" - LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl3` + LIBS += -lgdi32 -limm32 `pkg-config --static --libs sdl3` CXXFLAGS += `pkg-config --cflags sdl3` CFLAGS = $(CXXFLAGS) diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 483350fcb47a..68078eebdebd 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -15,11 +15,6 @@ #include "imgui_impl_sdlrenderer3.h" #include #include -#if defined(IMGUI_IMPL_OPENGL_ES2) -#include -#else -#include -#endif #ifdef __EMSCRIPTEN__ #include "../libs/emscripten/emscripten_mainloop_stub.h" @@ -36,7 +31,7 @@ int main(int, char**) } // Create window with SDL_Renderer graphics context - Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + Uint32 window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags); if (window == nullptr) { From 242d856ede78544a6ed2debea3afecad884630c6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Feb 2025 14:40:41 +0100 Subject: [PATCH 259/716] Examples: SDL3+SDL_Renderer: removed reference to OpenGL to remove confusion. (#8434) Amend --- examples/example_sdl3_sdlrenderer3/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/example_sdl3_sdlrenderer3/Makefile b/examples/example_sdl3_sdlrenderer3/Makefile index c7ee64fc7712..1976fa924c0f 100644 --- a/examples/example_sdl3_sdlrenderer3/Makefile +++ b/examples/example_sdl3_sdlrenderer3/Makefile @@ -34,7 +34,7 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" - LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` LIBS += -L/usr/local/lib -L/opt/local/lib CXXFLAGS += `pkg-config sdl3 --cflags` From 4f4fb1d220d31ca8b04163ed80bed7108e6429bc Mon Sep 17 00:00:00 2001 From: "Jose L. Hidalgo (PpluX)" Date: Sat, 22 Feb 2025 12:47:30 +0100 Subject: [PATCH 260/716] Backends: WebGPU: update code for latest webgpu-native changes. (#8426) --- backends/imgui_impl_wgpu.cpp | 22 ++++++++++++---------- docs/CHANGELOG.txt | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index a81662d8429d..36d053e2b91b 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-26: Update for latest webgpu-native changes. // 2024-10-14: Update Dawn support for change of string usages. (#8082, #8083) // 2024-10-07: Expose selected render state in ImGui_ImplWGPU_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-10-07: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -65,7 +66,7 @@ using WGPUProgrammableStageDescriptor = WGPUComputeState; #endif // Dear ImGui prototypes from imgui_internal.h -extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0); +extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed); #define MEMALIGN(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align (copied from IM_ALIGN() macro). // WebGPU data @@ -267,7 +268,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUShaderSourceWGSL wgsl_desc = {}; wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL; wgsl_desc.code = { wgsl_source, WGPU_STRLEN }; @@ -282,7 +283,8 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(const c WGPUProgrammableStageDescriptor stage_desc = {}; stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc); -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN + +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) stage_desc.entryPoint = { "main", WGPU_STRLEN }; #else stage_desc.entryPoint = "main"; @@ -399,7 +401,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder { nullptr, "Dear ImGui Vertex buffer", -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPU_STRLEN, #endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, @@ -426,7 +428,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder { nullptr, "Dear ImGui Index buffer", -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPU_STRLEN, #endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index, @@ -539,7 +541,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture() // Upload texture to graphics system { WGPUTextureDescriptor tex_desc = {}; -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) tex_desc.label = { "Dear ImGui Font Texture", WGPU_STRLEN }; #else tex_desc.label = "Dear ImGui Font Texture"; @@ -567,12 +569,12 @@ static void ImGui_ImplWGPU_CreateFontsTexture() // Upload texture data { - WGPUImageCopyTexture dst_view = {}; + WGPUTexelCopyTextureInfo dst_view = {}; dst_view.texture = bd->renderResources.FontTexture; dst_view.mipLevel = 0; dst_view.origin = { 0, 0, 0 }; dst_view.aspect = WGPUTextureAspect_All; - WGPUTextureDataLayout layout = {}; + WGPUTexelCopyBufferLayout layout = {}; layout.offset = 0; layout.bytesPerRow = width * size_pp; layout.rowsPerImage = height; @@ -606,7 +608,7 @@ static void ImGui_ImplWGPU_CreateUniformBuffer() { nullptr, "Dear ImGui Uniform buffer", -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPU_STRLEN, #endif WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform, @@ -714,7 +716,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() // Create depth-stencil State WGPUDepthStencilState depth_stencil_state = {}; depth_stencil_state.format = bd->depthStencilFormat; -#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) depth_stencil_state.depthWriteEnabled = WGPUOptionalBool_False; #else depth_stencil_state.depthWriteEnabled = false; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d5c4ded328f0..b3af5d94c2bf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -104,8 +104,9 @@ Other changes: Default to header version if unspecified. (#8326, #8365) [@mklefrancois] - Backends: Vulkan: Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326, #8365) [@mklefrancois] -- Backends: WebGPU: Fix for DAWN API rename WGPUProgrammableStageDescriptor -> WGPUComputeState. +- Backends: WebGPU: Fix for DAWN API change WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) +- Backends: WebGPU: Fix for webgpu-native API changes. (#8426) [@pplux] ----------------------------------------------------------------------- From 6aa0810de5dad4add4e73ff6352df63429f921ee Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Feb 2025 15:10:28 +0100 Subject: [PATCH 261/716] Backends: WebGPU: update code for latest webgpu-native changes. Amend. (#8426) --- backends/imgui_impl_wgpu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 36d053e2b91b..45eaeba6457c 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -493,7 +493,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder { // Bind custom texture ImTextureID tex_id = pcmd->GetTexID(); - ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id)); + ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id), 0); auto bind_group = bd->renderResources.ImageBindGroups.GetVoidPtr(tex_id_hash); if (bind_group) { @@ -755,7 +755,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bg_layouts[1], bd->renderResources.FontTextureView); bd->renderResources.ImageBindGroup = image_bind_group; bd->renderResources.ImageBindGroupLayout = bg_layouts[1]; - bd->renderResources.ImageBindGroups.SetVoidPtr(ImHashData(&bd->renderResources.FontTextureView, sizeof(ImTextureID)), image_bind_group); + bd->renderResources.ImageBindGroups.SetVoidPtr(ImHashData(&bd->renderResources.FontTextureView, sizeof(ImTextureID), 0), image_bind_group); SafeRelease(vertex_shader_desc.module); SafeRelease(pixel_shader_desc.module); From 9996a2d51b47e8679936f58de31f6df382a83689 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Feb 2025 15:16:38 +0100 Subject: [PATCH 262/716] Backends: WebGPU: update code for latest webgpu-native changes. Fix for Emscripten. (#8426) --- backends/imgui_impl_wgpu.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 45eaeba6457c..4fffa23a5b0c 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -569,12 +569,20 @@ static void ImGui_ImplWGPU_CreateFontsTexture() // Upload texture data { +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUTexelCopyTextureInfo dst_view = {}; +#else + WGPUImageCopyTexture dst_view = {}; +#endif dst_view.texture = bd->renderResources.FontTexture; dst_view.mipLevel = 0; dst_view.origin = { 0, 0, 0 }; dst_view.aspect = WGPUTextureAspect_All; +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUTexelCopyBufferLayout layout = {}; +#else + WGPUTextureDataLayout layout = {}; +#endif layout.offset = 0; layout.bytesPerRow = width * size_pp; layout.rowsPerImage = height; From aaacb01b8d4441453928116240b5041625d43fbf Mon Sep 17 00:00:00 2001 From: "Jose L. Hidalgo (PpluX)" Date: Wed, 26 Feb 2025 15:19:56 +0100 Subject: [PATCH 263/716] Backends: WebGPU: Recreate image bind groups during render. (#8426, #8046, #7765, #8027) --- backends/imgui_impl_wgpu.cpp | 33 ++++++++++++++++----------------- docs/CHANGELOG.txt | 2 ++ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 4fffa23a5b0c..b04ac3bb7d63 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -17,7 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-02-26: Update for latest webgpu-native changes. +// 2025-02-26: Recreate image bind groups during render. (#8426, #8046, #7765, #8027) + Update for latest webgpu-native changes. // 2024-10-14: Update Dawn support for change of string usages. (#8082, #8083) // 2024-10-07: Expose selected render state in ImGui_ImplWGPU_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-10-07: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -78,7 +78,6 @@ struct RenderResources WGPUBuffer Uniforms = nullptr; // Shader uniforms WGPUBindGroup CommonBindGroup = nullptr; // Resources bind-group to bind the common resources to pipeline ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map) - WGPUBindGroup ImageBindGroup = nullptr; // Default font-resource of Dear ImGui WGPUBindGroupLayout ImageBindGroupLayout = nullptr; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM }; @@ -252,7 +251,6 @@ static void SafeRelease(RenderResources& res) SafeRelease(res.Sampler); SafeRelease(res.Uniforms); SafeRelease(res.CommonBindGroup); - SafeRelease(res.ImageBindGroup); SafeRelease(res.ImageBindGroupLayout); }; @@ -494,17 +492,13 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Bind custom texture ImTextureID tex_id = pcmd->GetTexID(); ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id), 0); - auto bind_group = bd->renderResources.ImageBindGroups.GetVoidPtr(tex_id_hash); - if (bind_group) + WGPUBindGroup bind_group = (WGPUBindGroup)bd->renderResources.ImageBindGroups.GetVoidPtr(tex_id_hash); + if (!bind_group) { - wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, nullptr); - } - else - { - WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bd->renderResources.ImageBindGroupLayout, (WGPUTextureView)tex_id); - bd->renderResources.ImageBindGroups.SetVoidPtr(tex_id_hash, image_bind_group); - wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, nullptr); + bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bd->renderResources.ImageBindGroupLayout, (WGPUTextureView)tex_id); + bd->renderResources.ImageBindGroups.SetVoidPtr(tex_id_hash, bind_group); } + wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, nullptr); // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); @@ -526,6 +520,16 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder global_idx_offset += draw_list->IdxBuffer.Size; global_vtx_offset += draw_list->VtxBuffer.Size; } + + // Remove all ImageBindGroups + ImGuiStorage& image_bind_groups = bd->renderResources.ImageBindGroups; + for (int i = 0; i < image_bind_groups.Data.Size; i++) + { + WGPUBindGroup bind_group = (WGPUBindGroup)image_bind_groups.Data[i].val_p; + SafeRelease(bind_group); + } + image_bind_groups.Data.resize(0); + platform_io.Renderer_RenderState = nullptr; } @@ -759,11 +763,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() common_bg_descriptor.entryCount = sizeof(common_bg_entries) / sizeof(WGPUBindGroupEntry); common_bg_descriptor.entries = common_bg_entries; bd->renderResources.CommonBindGroup = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor); - - WGPUBindGroup image_bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bg_layouts[1], bd->renderResources.FontTextureView); - bd->renderResources.ImageBindGroup = image_bind_group; bd->renderResources.ImageBindGroupLayout = bg_layouts[1]; - bd->renderResources.ImageBindGroups.SetVoidPtr(ImHashData(&bd->renderResources.FontTextureView, sizeof(ImTextureID), 0), image_bind_group); SafeRelease(vertex_shader_desc.module); SafeRelease(pixel_shader_desc.module); @@ -823,7 +823,6 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) bd->renderResources.Uniforms = nullptr; bd->renderResources.CommonBindGroup = nullptr; bd->renderResources.ImageBindGroups.Data.reserve(100); - bd->renderResources.ImageBindGroup = nullptr; bd->renderResources.ImageBindGroupLayout = nullptr; // Create buffers with a default size (they will later be grown as needed) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b3af5d94c2bf..ff249c140cd8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -104,6 +104,8 @@ Other changes: Default to header version if unspecified. (#8326, #8365) [@mklefrancois] - Backends: Vulkan: Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326, #8365) [@mklefrancois] +- Backends: WebGPU: Recreate image bind groups during render to allow reuse of + WGPUTextureView pointers. (#8426, #8046, #7765, #8027) [@pplux, @Jairard] - Backends: WebGPU: Fix for DAWN API change WGPUProgrammableStageDescriptor -> WGPUComputeState. [@PhantomCloak] (#8369) - Backends: WebGPU: Fix for webgpu-native API changes. (#8426) [@pplux] From aa83d5d455dcab4b65cca71efd6291f943feea67 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Feb 2025 15:34:31 +0100 Subject: [PATCH 264/716] Backends: SDL2, SDL3: Only start SDL_CaptureMouse() when mouse is being dragged. (#6410, #3650) To mitigate issues with e.g. Linux debuggers not claiming capture back. --- backends/imgui_impl_sdl2.cpp | 11 +++++++++-- backends/imgui_impl_sdl3.cpp | 11 +++++++++-- docs/CHANGELOG.txt | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 361fc3b57e3f..6256b4dddec4 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. @@ -609,8 +610,14 @@ static void ImGui_ImplSDL2_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside - SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE); + // - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside. + // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture. + bool want_capture = false; + for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) + if (ImGui::IsMouseDragging(button_n, 1.0f)) + want_capture = true; + SDL_CaptureMouse(want_capture ? SDL_TRUE : SDL_FALSE); + SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->Window == focused_window); #else diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index d2433793e609..2d8027184b60 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. @@ -574,8 +575,14 @@ static void ImGui_ImplSDL3_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside - SDL_CaptureMouse(bd->MouseButtonsDown != 0); + // - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside. + // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture. + bool want_capture = false; + for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) + if (ImGui::IsMouseDragging(button_n, 1.0f)) + want_capture = true; + SDL_CaptureMouse(want_capture); + SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->Window == focused_window); #else diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff249c140cd8..5a1b63ad2895 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -95,6 +95,8 @@ Other changes: and ImGuiMouseCursor_Progress cursors. - Backends: SDL2, SDL3: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. (#8425, #8407) [@TheMode] +- Backends: SDL2, SDL3: Only start SDL_CaptureMouse() when mouse is being dragged, + to mitigate issues with e.g. Linux debuggers not claiming capture back. (#6410, #3650) - Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) - Backends: DirectX12: Fixed an issue where pre-1.91.5 legacy ImGui_ImplDX12_Init() From 8bd3e20c86b1541f1da2c1f1d2444220432193fa Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 26 Feb 2025 18:06:31 -0500 Subject: [PATCH 265/716] Backends: WebGPU: include imgui.h before backend check (#8437) --- backends/imgui_impl_wgpu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index b04ac3bb7d63..4bf03e8f1b0c 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -41,6 +41,8 @@ // 2021-02-18: Change blending equation to preserve alpha in output buffer. // 2021-01-28: Initial version. +#include "imgui.h" + // When targeting native platforms (i.e. NOT emscripten), one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN // or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details. #ifndef __EMSCRIPTEN__ @@ -53,7 +55,6 @@ #endif #endif -#include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_wgpu.h" #include From cdafefd4be389ef4c6747b102086278b2cc355c3 Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 27 Feb 2025 07:47:33 -0500 Subject: [PATCH 266/716] Backends: WebGPU: Add nextInChain field for VertexAttributes under Dawn (#8438) --- backends/imgui_impl_wgpu.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 4bf03e8f1b0c..3187be29a39f 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -687,9 +687,15 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() // Vertex input configuration WGPUVertexAttribute attribute_desc[] = { +#ifdef IMGUI_IMPL_WEBGPU_BACKEND_DAWN + { nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 }, + { nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 }, + { nullptr, WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 }, +#else { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 }, { WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 }, { WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 }, +#endif }; WGPUVertexBufferLayout buffer_layouts[1]; From 494ea57b65325f00165da10e6b57b4f295a65bca Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Feb 2025 19:28:01 +0100 Subject: [PATCH 267/716] Image: removed 'tint_col', 'border_col' parameters from Image(). Added ImageWithBg(). Added style.ImageBorderSize, ImGuiStyleVar_ImageBorderSize. (#8131, #8238) Displaying a black background behind Font Atlas texture. --- docs/CHANGELOG.txt | 18 ++++++++++++++++++ imgui.cpp | 23 ++++++++++++++++++----- imgui.h | 11 ++++++++--- imgui_demo.cpp | 11 +++++------ imgui_internal.h | 1 - imgui_widgets.cpp | 30 +++++++++++++++++++++++++----- 6 files changed, 74 insertions(+), 20 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5a1b63ad2895..9e797e3ec22d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,22 @@ HOW TO UPDATE? Breaking changes: +- Image: removed 'tint_col' and 'border_col' parameter from Image() function. (#8131, #8238) + - Old function signature: + void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); + - New function signatures: + void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1)); + void ImageWithBg(ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 bg_col = (0,0,0,0), ImVec4 tint_col = (1,1,1,1)); + - TL;DR: 'border_col' had misleading side-effect on layout, 'bg_col' was missing, parameter order couldn't be consistent with ImageButton(). + - New behavior always use ImGuiCol_Border color + style.ImageBorderSize / ImGuiStyleVar_ImageBorderSize. + - Old behavior altered border size (and therefore layout) based on border color's + alpha, which caused variety of problems. + - Old behavior used a fixed value of 1.0f for border size which was not tweakable. + - Kept legacy signature (will obsolete), which mimics the old behavior, + but uses Max(1.0f, style.ImageBorderSize) when border_col is specified. + - Added ImageWithBg() function which has both 'bg_col' (which was missing) and 'tint_col'. + It was impossible to add 'bg_col' to Image() with a parameter order consistent with + other functions, so we decided to remove 'tint_col' and introduce ImageWithBg(). - Renamed ImFontConfig::GlyphExtraSpacing.x option to GlyphExtraAdvanceX. (#242) - Renamed style.TabMinWidthForCloseButton to style.TabCloseButtonMinWidthUnselected. - Backends: Vulkan: Added 'uint32_t api_version' argument to ImGui_ImplVulkan_LoadFunctions(). @@ -70,6 +86,8 @@ Other changes: - Tables: tamed some .ini settings optimizations to more accurately allow overwriting/hot-reloading settings in more situations. (#7934) - Tables, Error Handling: Recovery from invalid index in TableSetColumnIndex(). (#1651) +- Image: Added ImageWithBg() variant with bg color and tint color. (#8131, #8238) +- Image, Style: Added style.ImageBorderSize, ImGuiStyleVar_ImageBorderSize. (#8131, #8238) - Selectable: Fixed horizontal label alignment with SelectableTextAlign.x > 0 and specifying a selectable size. (#8338) - Tabs, Style: made the Close Button of selected tabs always visible by default, diff --git a/imgui.cpp b/imgui.cpp index 64514028ff86..6e038fad8730 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,6 +431,15 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238) + - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); + - new: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1)); + - new: void ImageWithBg(ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 bg_col = (0,0,0,0), ImVec4 tint_col = (1,1,1,1)); + - TL;DR: 'border_col' had misleading side-effect on layout, 'bg_col' was missing, parameter order couldn't be consistent with ImageButton(). + - new behavior always use ImGuiCol_Border color + style.ImageBorderSize / ImGuiStyleVar_ImageBorderSize. + - old behavior altered border size (and therefore layout) based on border color's alpha, which caused variety of problems + old behavior a fixed 1.0f for border size which was not tweakable. + - kept legacy signature (will obsolete), which mimics the old behavior, but uses Max(1.0f, style.ImageBorderSize) when border_col is specified. + - added ImageWithBg() function which has both 'bg_col' (which was missing) and 'tint_col'. It was impossible to add 'bg_col' to Image() with a parameter order consistent with other functions, so we decided to remove 'tint_col' and introduce ImageWithBg(). - 2025/02/06 (1.91.9) - renamed ImFontConfig::GlyphExtraSpacing.x to ImFontConfig::GlyphExtraAdvanceX. - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. @@ -1338,6 +1347,7 @@ ImGuiStyle::ImGuiStyle() GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + ImageBorderSize = 0.0f; // Thickness of border around tabs. TabRounding = 5.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. TabBorderSize = 0.0f; // Thickness of border around tabs. TabCloseButtonMinWidthSelected = -1.0f; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. @@ -1395,6 +1405,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) GrabMinSize = ImTrunc(GrabMinSize * scale_factor); GrabRounding = ImTrunc(GrabRounding * scale_factor); LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor); + ImageBorderSize = ImTrunc(ImageBorderSize * scale_factor); TabRounding = ImTrunc(TabRounding * scale_factor); TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : TabCloseButtonMinWidthSelected; TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : TabCloseButtonMinWidthUnselected; @@ -3393,6 +3404,7 @@ static const ImGuiDataVarInfo GStyleVarsInfo[] = { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize @@ -15422,11 +15434,12 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) { ImGuiContext& g = *GImGui; - ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; - Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons - ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); - ImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border); - Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col); + PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); + ImVec2 image_pos = GetCursorScreenPos(); + ImVec2 image_size((float)atlas->TexWidth, (float)atlas->TexHeight); + GetWindowDrawList()->AddRectFilled(image_pos, image_pos + image_size + ImVec2(g.Style.ImageBorderSize, g.Style.ImageBorderSize), IM_COL32(0, 0, 0, 255)); + Image(atlas->TexID, image_size); + PopStyleVar(); TreePop(); } } diff --git a/imgui.h b/imgui.h index 1bdc2cb10b13..ee9697ea8b84 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19184 +#define IMGUI_VERSION_NUM 19185 #define IMGUI_HAS_TABLE /* @@ -566,9 +566,10 @@ namespace ImGui // Widgets: Images // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. - // - Note that Image() may add +2.0f to provided size if a border is visible, ImageButton() adds style.FramePadding*2.0f to provided size. + // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. - IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0)); + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1)); + IMGUI_API void ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Widgets: Combo Box (Dropdown) @@ -1714,6 +1715,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_ScrollbarRounding, // float ScrollbarRounding ImGuiStyleVar_GrabMinSize, // float GrabMinSize ImGuiStyleVar_GrabRounding, // float GrabRounding + ImGuiStyleVar_ImageBorderSize, // float ImageBorderSize ImGuiStyleVar_TabRounding, // float TabRounding ImGuiStyleVar_TabBorderSize, // float TabBorderSize ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize @@ -2170,6 +2172,7 @@ struct ImGuiStyle float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar. float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs. float LogSliderDeadzone; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero. + float ImageBorderSize; // Thickness of border around Image() calls. float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs. float TabBorderSize; // Thickness of border around tabs. float TabCloseButtonMinWidthSelected; // -1: always visible. 0.0f: visible when hovered. >0.0f: visible when hovered if minimum width. @@ -3614,6 +3617,8 @@ struct ImGuiPlatformImeData #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.91.9 (from February 2025) + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- border_col was removed in favor of ImGuiCol_ImageBorder. // OBSOLETED in 1.91.0 (from July 2024) static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } static inline void PopButtonRepeat() { PopItemFlag(); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3be8647248d0..4372dfb4555c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1348,15 +1348,12 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) float my_tex_w = (float)io.Fonts->TexWidth; float my_tex_h = (float)io.Fonts->TexHeight; { - static bool use_text_color_for_tint = false; - ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint); ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); ImVec2 pos = ImGui::GetCursorScreenPos(); ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right - ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint - ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border); - ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col); + ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize)); + ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); if (ImGui::BeginItemTooltip()) { float region_sz = 32.0f; @@ -1371,9 +1368,10 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); - ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col); + ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); ImGui::EndTooltip(); } + ImGui::PopStyleVar(); } IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons"); @@ -8031,6 +8029,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); + ImGui::SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, 1.0f, "%.0f"); ImGui::SeparatorText("Tooltips"); for (int n = 0; n < 2; n++) diff --git a/imgui_internal.h b/imgui_internal.h index c70bb999c595..985f8b1890c5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1998,7 +1998,6 @@ struct ImGuiMetricsConfig bool ShowDrawCmdMesh = true; bool ShowDrawCmdBoundingBoxes = true; bool ShowTextEncodingViewer = false; - bool ShowAtlasTintedWithTextColor = false; int ShowWindowsRectsType = -1; int ShowTablesRectsType = -1; int HighlightMonitorIdx = -1; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f011805f98d1..8d5aa9581d76 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1062,25 +1062,45 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. -void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +void ImGui::ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { + ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; - const float border_size = (border_col.w > 0.0f) ? 1.0f : 0.0f; - const ImVec2 padding(border_size, border_size); + const ImVec2 padding(g.Style.ImageBorderSize, g.Style.ImageBorderSize); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + image_size + padding * 2.0f); ItemSize(bb); if (!ItemAdd(bb, 0)) return; // Render - if (border_size > 0.0f) - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f, ImDrawFlags_None, border_size); + if (g.Style.ImageBorderSize > 0.0f) + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, g.Style.ImageBorderSize); + if (bg_col.w > 0.0f) + window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); } +void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1) +{ + ImageWithBg(user_texture_id, image_size, uv0, uv1); +} + +// 1.91.9 (February 2025) removed 'tint_col' and 'border_col' parameters, made border size not depend on color value. (#8131, #8238) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +{ + ImGuiContext& g = *GImGui; + PushStyleVar(ImGuiStyleVar_ImageBorderSize, (border_col.w > 0.0f) ? ImMax(1.0f, g.Style.ImageBorderSize) : 0.0f); // Preserve legacy behavior where border is always visible when border_col's Alpha is >0.0f + PushStyleColor(ImGuiCol_Border, border_col); + ImageWithBg(user_texture_id, image_size, uv0, uv1, ImVec4(0, 0, 0, 0), tint_col); + PopStyleColor(); + PopStyleVar(); +} +#endif + bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) { ImGuiContext& g = *GImGui; From 482a1f50b61ee71b515a5a4a1c5f6a998214780a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Feb 2025 16:08:51 +0100 Subject: [PATCH 268/716] Internals: rename ImGuiDataVarInfo to ImGuiStyleVarInfo. Move ImGuiStyleMod, ImGuiColorMod to own section. # Conflicts: # imgui.cpp --- imgui.cpp | 90 ++++++++++++++++++++++++------------------------ imgui.h | 2 ++ imgui_internal.h | 49 ++++++++++++++------------ 3 files changed, 74 insertions(+), 67 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6e038fad8730..30477001f6e4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3380,45 +3380,45 @@ void ImGui::PopStyleColor(int count) } } -static const ImGuiDataVarInfo GStyleVarsInfo[] = -{ - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign - { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign - { ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding +static const ImGuiStyleVarInfo GStyleVarsInfo[] = +{ + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, DisabledAlpha) }, // ImGuiStyleVar_DisabledAlpha + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowBorderSize) }, // ImGuiStyleVar_WindowBorderSize + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, WindowTitleAlign) }, // ImGuiStyleVar_WindowTitleAlign + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ChildRounding) }, // ImGuiStyleVar_ChildRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ChildBorderSize) }, // ImGuiStyleVar_ChildBorderSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, PopupRounding) }, // ImGuiStyleVar_PopupRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, PopupBorderSize) }, // ImGuiStyleVar_PopupBorderSize + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, FrameBorderSize) }, // ImGuiStyleVar_FrameBorderSize + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, CellPadding) }, // ImGuiStyleVar_CellPadding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarSize) }, // ImGuiStyleVar_ScrollbarSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ScrollbarRounding) }, // ImGuiStyleVar_ScrollbarRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, GrabRounding) }, // ImGuiStyleVar_GrabRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ImageBorderSize) }, // ImGuiStyleVar_ImageBorderSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextAlign) }, // ImGuiStyleVar_SeparatorTextAlign + { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextPadding) }, // ImGuiStyleVar_SeparatorTextPadding }; -const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) +const ImGuiStyleVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) { IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT); IM_STATIC_ASSERT(IM_ARRAYSIZE(GStyleVarsInfo) == ImGuiStyleVar_COUNT); @@ -3428,7 +3428,7 @@ const ImGuiDataVarInfo* ImGui::GetStyleVarInfo(ImGuiStyleVar idx) void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) { ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 1) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); @@ -3442,7 +3442,7 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x) { ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); @@ -3456,7 +3456,7 @@ void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x) void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y) { ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); @@ -3470,7 +3470,7 @@ void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y) void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; - const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx); + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx); if (var_info->DataType != ImGuiDataType_Float || var_info->Count != 2) { IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!"); @@ -3493,10 +3493,10 @@ void ImGui::PopStyleVar(int count) { // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. ImGuiStyleMod& backup = g.StyleVarStack.back(); - const ImGuiDataVarInfo* info = GetStyleVarInfo(backup.VarIdx); - void* data = info->GetVarPtr(&g.Style); - if (info->DataType == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } - else if (info->DataType == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } + const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(backup.VarIdx); + void* data = var_info->GetVarPtr(&g.Style); + if (var_info->DataType == ImGuiDataType_Float && var_info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; } + else if (var_info->DataType == ImGuiDataType_Float && var_info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; } g.StyleVarStack.pop_back(); count--; } diff --git a/imgui.h b/imgui.h index ee9697ea8b84..caf8088b2938 100644 --- a/imgui.h +++ b/imgui.h @@ -2195,6 +2195,8 @@ struct ImGuiStyle bool AntiAliasedFill; // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList). float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality. float CircleTessellationMaxError; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry. + + // Colors ImVec4 Colors[ImGuiCol_COUNT]; // Behaviors diff --git a/imgui_internal.h b/imgui_internal.h index 985f8b1890c5..f896171cd0d7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -14,6 +14,7 @@ Index of this file: // [SECTION] Macros // [SECTION] Generic helpers // [SECTION] ImDrawList support +// [SECTION] Style support // [SECTION] Data types support // [SECTION] Widgets support: flags, enums, data structures // [SECTION] Popup support @@ -145,7 +146,6 @@ struct ImGuiBoxSelectState; // Box-selection state (currently used by mu struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it struct ImGuiContext; // Main Dear ImGui context struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine -struct ImGuiDataVarInfo; // Variable information (e.g. to access style variables from an enum) struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum struct ImGuiDeactivatedItemData; // Data for IsItemDeactivated()/IsItemDeactivatedAfterEdit() function. struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery @@ -166,6 +166,7 @@ struct ImGuiOldColumns; // Storage data for a columns set for legacy struct ImGuiPopupData; // Storage for current popup stack struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it +struct ImGuiStyleVarInfo; // Style variable information (e.g. to access style variables from an enum) struct ImGuiTabBar; // Storage for a tab bar struct ImGuiTabItem; // Storage for a tab item (within a tab bar) struct ImGuiTable; // Storage for a table @@ -809,17 +810,38 @@ struct ImDrawDataBuilder }; //----------------------------------------------------------------------------- -// [SECTION] Data types support +// [SECTION] Style support //----------------------------------------------------------------------------- -struct ImGuiDataVarInfo +struct ImGuiStyleVarInfo { - ImGuiDataType DataType : 8; ImU32 Count : 8; // 1+ + ImGuiDataType DataType : 8; ImU32 Offset : 16; // Offset in parent structure void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); } }; +// Stacked color modifier, backup of modified data so we can restore it +struct ImGuiColorMod +{ + ImGuiCol Col; + ImVec4 BackupValue; +}; + +// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. +struct ImGuiStyleMod +{ + ImGuiStyleVar VarIdx; + union { int BackupInt[2]; float BackupFloat[2]; }; + ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } + ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } +}; + +//----------------------------------------------------------------------------- +// [SECTION] Data types support +//----------------------------------------------------------------------------- + struct ImGuiDataTypeStorage { ImU8 Data[8]; // Opaque storage to fit any data up to ImGuiDataType_COUNT @@ -1038,23 +1060,6 @@ enum ImGuiPlotType ImGuiPlotType_Histogram, }; -// Stacked color modifier, backup of modified data so we can restore it -struct ImGuiColorMod -{ - ImGuiCol Col; - ImVec4 BackupValue; -}; - -// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable. -struct ImGuiStyleMod -{ - ImGuiStyleVar VarIdx; - union { int BackupInt[2]; float BackupFloat[2]; }; - ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; } - ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; } - ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; } -}; - // Storage data for BeginComboPreview()/EndComboPreview() struct IMGUI_API ImGuiComboPreviewData { @@ -3114,7 +3119,7 @@ namespace ImGui IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess); // Parameter stacks (shared) - IMGUI_API const ImGuiDataVarInfo* GetStyleVarInfo(ImGuiStyleVar idx); + IMGUI_API const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx); IMGUI_API void BeginDisabledOverrideReenable(); IMGUI_API void EndDisabledOverrideReenable(); From 1aab00da8589d06ed861a0b40e9dfaeff791084f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Feb 2025 21:55:17 +0100 Subject: [PATCH 269/716] Misc shallow tweaks/tidying up. (#8446) --- backends/imgui_impl_dx10.cpp | 11 ++++------- backends/imgui_impl_dx11.cpp | 11 ++++------- backends/imgui_impl_dx12.cpp | 27 +++++++++------------------ backends/imgui_impl_metal.h | 1 + backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_osx.h | 1 + 6 files changed, 20 insertions(+), 33 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 5471eef5311c..801983211aba 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -87,8 +87,7 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); // Setup viewport - D3D10_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D10_VIEWPORT)); + D3D10_VIEWPORT vp = {}; vp.Width = (UINT)draw_data->DisplaySize.x; vp.Height = (UINT)draw_data->DisplaySize.y; vp.MinDepth = 0.0f; @@ -152,8 +151,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) { if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; - D3D10_BUFFER_DESC desc; - memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); + D3D10_BUFFER_DESC desc = {}; desc.Usage = D3D10_USAGE_DYNAMIC; desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); desc.BindFlags = D3D10_BIND_VERTEX_BUFFER; @@ -167,8 +165,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) { if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D10_BUFFER_DESC desc; - memset(&desc, 0, sizeof(D3D10_BUFFER_DESC)); + D3D10_BUFFER_DESC desc = {}; desc.Usage = D3D10_USAGE_DYNAMIC; desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); desc.BindFlags = D3D10_BIND_INDEX_BUFFER; @@ -431,7 +428,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects() // Create the constant buffer { - D3D10_BUFFER_DESC desc; + D3D10_BUFFER_DESC desc = {}; desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX10); desc.Usage = D3D10_USAGE_DYNAMIC; desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index b38fece264b5..9f39588810eb 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -90,8 +90,7 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); // Setup viewport - D3D11_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D11_VIEWPORT)); + D3D11_VIEWPORT vp = {}; vp.Width = draw_data->DisplaySize.x; vp.Height = draw_data->DisplaySize.y; vp.MinDepth = 0.0f; @@ -158,8 +157,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) { if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; - D3D11_BUFFER_DESC desc; - memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); + D3D11_BUFFER_DESC desc = {}; desc.Usage = D3D11_USAGE_DYNAMIC; desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; @@ -172,8 +170,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) { if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D11_BUFFER_DESC desc; - memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); + D3D11_BUFFER_DESC desc = {}; desc.Usage = D3D11_USAGE_DYNAMIC; desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); desc.BindFlags = D3D11_BIND_INDEX_BUFFER; @@ -447,7 +444,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() // Create the constant buffer { - D3D11_BUFFER_DESC desc; + D3D11_BUFFER_DESC desc = {}; desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11); desc.Usage = D3D11_USAGE_DYNAMIC; desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 8449832c5b09..e9a2c119c4b6 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -137,8 +137,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic } // Setup viewport - D3D12_VIEWPORT vp; - memset(&vp, 0, sizeof(D3D12_VIEWPORT)); + D3D12_VIEWPORT vp = {}; vp.Width = draw_data->DisplaySize.x; vp.Height = draw_data->DisplaySize.y; vp.MinDepth = 0.0f; @@ -149,14 +148,12 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic // Bind shader and vertex buffers unsigned int stride = sizeof(ImDrawVert); unsigned int offset = 0; - D3D12_VERTEX_BUFFER_VIEW vbv; - memset(&vbv, 0, sizeof(D3D12_VERTEX_BUFFER_VIEW)); + D3D12_VERTEX_BUFFER_VIEW vbv = {}; vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset; vbv.SizeInBytes = fr->VertexBufferSize * stride; vbv.StrideInBytes = stride; command_list->IASetVertexBuffers(0, 1, &vbv); - D3D12_INDEX_BUFFER_VIEW ibv; - memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW)); + D3D12_INDEX_BUFFER_VIEW ibv = {}; ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress(); ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx); ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; @@ -196,13 +193,11 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL { SafeRelease(fr->VertexBuffer); fr->VertexBufferSize = draw_data->TotalVtxCount + 5000; - D3D12_HEAP_PROPERTIES props; - memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); + D3D12_HEAP_PROPERTIES props = {}; props.Type = D3D12_HEAP_TYPE_UPLOAD; props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - D3D12_RESOURCE_DESC desc; - memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC)); + D3D12_RESOURCE_DESC desc = {}; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert); desc.Height = 1; @@ -219,13 +214,11 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL { SafeRelease(fr->IndexBuffer); fr->IndexBufferSize = draw_data->TotalIdxCount + 10000; - D3D12_HEAP_PROPERTIES props; - memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); + D3D12_HEAP_PROPERTIES props = {}; props.Type = D3D12_HEAP_TYPE_UPLOAD; props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - D3D12_RESOURCE_DESC desc; - memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC)); + D3D12_RESOURCE_DESC desc = {}; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx); desc.Height = 1; @@ -333,8 +326,7 @@ static void ImGui_ImplDX12_CreateFontsTexture() // Upload texture to graphics system ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; { - D3D12_HEAP_PROPERTIES props; - memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); + D3D12_HEAP_PROPERTIES props = {}; props.Type = D3D12_HEAP_TYPE_DEFAULT; props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; @@ -561,8 +553,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. // See https://github.com/ocornut/imgui/pull/638 for sources and details. - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc; - memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC)); + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.NodeMask = 1; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.pRootSignature = bd->pRootSignature; diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index 351c2eff735c..d46998269cea 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -13,6 +13,7 @@ // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp +#pragma once #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 14ae90a7e122..1311d1bc9f0e 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -284,7 +284,7 @@ bool ImGui_ImplOpenGL3_InitLoader() { // Initialize our loader #ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W - if (glGetIntegerv == NULL && imgl3wInit() != 0) + if (glGetIntegerv == nullptr && imgl3wInit() != 0) { fprintf(stderr, "Failed to initialize OpenGL loader!\n"); return false; diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 9d0aec07a0fc..5d4dd8d41b7f 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -21,6 +21,7 @@ // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). // - Introduction, links and more at the top of imgui.cpp +#pragma once #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE From 9c2876b9f8f3859951390f27186527393001fe20 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 27 Feb 2025 22:04:56 +0100 Subject: [PATCH 270/716] ShowFontAtlas() uses ImageWithBg(). (#8131, #8238) Amend 494ea57 --- imgui.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 30477001f6e4..64d447be306d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15435,10 +15435,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { ImGuiContext& g = *GImGui; PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); - ImVec2 image_pos = GetCursorScreenPos(); - ImVec2 image_size((float)atlas->TexWidth, (float)atlas->TexHeight); - GetWindowDrawList()->AddRectFilled(image_pos, image_pos + image_size + ImVec2(g.Style.ImageBorderSize, g.Style.ImageBorderSize), IM_COL32(0, 0, 0, 255)); - Image(atlas->TexID, image_size); + ImageWithBg(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); PopStyleVar(); TreePop(); } From c5ade6591e39216ec950136a6d8e3e3274f2bddf Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 2 Mar 2025 13:39:29 +0100 Subject: [PATCH 271/716] TextLink(), TextLinkOpenURL(): fixed honoring text baseline alignment. (#8451, #7660) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9e797e3ec22d..f7241d7de398 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -99,6 +99,8 @@ Other changes: - Default for unselected tabs: TabCloseButtonMinWidthUnselected = 0.0f (visible when hovered) - Tabs: fixed middle-mouse-button to close tab not checking that close button is hovered, merely it's visibility. (#8399, #8387) [@nicovanbentum] +- TextLink(), TextLinkOpenURL(): fixed honoring text baseline alignment. + (#8451, #7660) [@achabense] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] - Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8d5aa9581d76..76dabb8f9c55 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1444,7 +1444,7 @@ bool ImGui::TextLink(const char* label) const ImGuiID id = window->GetID(label); const char* label_end = FindRenderedTextEnd(label); - ImVec2 pos = window->DC.CursorPos; + ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 size = CalcTextSize(label, label_end, true); ImRect bb(pos, pos + size); ItemSize(size, 0.0f); From 4819eae8674209f7ddf70cd9a8b2e10528405fff Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 2 Mar 2025 14:15:11 +0100 Subject: [PATCH 272/716] Clipper: Fixed an issue where passing an out of bound index to IncludeItemByIndex() could incorrectly offset the final cursor. One case where it would manifest was calling Combo() with an out of range index. (#8450) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f7241d7de398..0fd46d378274 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -103,6 +103,9 @@ Other changes: (#8451, #7660) [@achabense] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] +- Clipper: Fixed an issue where passing an out of bound index to IncludeItemByIndex() + could incorrectly offset the final cursor, even if that index was not iterated through. + One case where it would manifest was calling Combo() with an out of range index. (#8450) - Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors diff --git a/imgui.cpp b/imgui.cpp index 64d447be306d..77e3c1d36422 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3258,11 +3258,11 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) { clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount); - if (clipper->DisplayStart > already_submitted) //-V1051 - clipper->SeekCursorForItem(clipper->DisplayStart); data->StepNo++; - if (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size) + if (clipper->DisplayStart >= clipper->DisplayEnd) continue; + if (clipper->DisplayStart > already_submitted) + clipper->SeekCursorForItem(clipper->DisplayStart); return true; } @@ -3279,7 +3279,7 @@ bool ImGuiListClipper::Step() ImGuiContext& g = *Ctx; bool need_items_height = (ItemsHeight <= 0.0f); bool ret = ImGuiListClipper_StepInternal(this); - if (ret && (DisplayStart == DisplayEnd)) + if (ret && (DisplayStart >= DisplayEnd)) ret = false; if (g.CurrentTable && g.CurrentTable->IsUnfrozenRows == false) IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): inside frozen table row.\n"); From ce13f6b73e30307fa150b1e88f6014a454da466c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 13:10:58 +0100 Subject: [PATCH 273/716] Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. (#8452) Amend 8e4010479 --- backends/imgui_impl_glfw.cpp | 9 ++++++++- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imgui_internal.h | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 69cde6c08910..874a0a440997 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -28,7 +28,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: +// 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. +// 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn // - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn // - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn @@ -598,8 +599,14 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw bd->Time = 0.0; ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); +#if GLFW_VERSION_COMBINED < 3300 + platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window, text); }; + platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window); }; +#else platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(nullptr, text); }; platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(nullptr); }; +#endif + #ifdef __EMSCRIPTEN__ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; }; #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0fd46d378274..bc0f8f17f4a0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -112,6 +112,8 @@ Other changes: (busy/wait/hourglass shape, with or without an arrow cursor). - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) +- Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled + with asserts enabled. (#8452) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler. (#7660) [@achabense] - Backends: SDL2, SDL3, Win32, Allegro5: Added support for ImGuiMouseCursor_Wait diff --git a/imgui.h b/imgui.h index caf8088b2938..641b1ab92123 100644 --- a/imgui.h +++ b/imgui.h @@ -907,7 +907,7 @@ namespace ImGui IMGUI_API void PopClipRect(); // Focus, Activation - IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of of a newly appearing window. + IMGUI_API void SetItemDefaultFocus(); // make last item the default focused item of a newly appearing window. IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget. // Keyboard/Gamepad Navigation diff --git a/imgui_internal.h b/imgui_internal.h index f896171cd0d7..4bdc6e94791c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2940,7 +2940,7 @@ struct IMGUI_API ImGuiTableTempData ImGuiTableTempData() { memset(this, 0, sizeof(*this)); LastTimeActive = -1.0f; } }; -// sizeof() ~ 12 +// sizeof() ~ 16 struct ImGuiTableColumnSettings { float WidthOrWeight; From eefd2da0f68ebec8e93484088f5257612e37281f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 17:38:09 +0100 Subject: [PATCH 274/716] Demo: (Refactor) Added new empty sections.. Renamed existing helper functions. --- docs/CHANGELOG.txt | 1 + imgui_demo.cpp | 191 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 154 insertions(+), 38 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bc0f8f17f4a0..390681161e0a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -110,6 +110,7 @@ Other changes: to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors (busy/wait/hourglass shape, with or without an arrow cursor). +- Demo: Reorganized "Widgets" section to be alphabetically ordered and split in more functions. - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) - Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 4372dfb4555c..81d6cfca82da 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -72,13 +72,36 @@ Index of this file: // [SECTION] Helpers // [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) // [SECTION] Demo Window / ShowDemoWindow() -// [SECTION] ShowDemoWindowMenuBar() -// [SECTION] ShowDemoWindowWidgets() -// [SECTION] ShowDemoWindowMultiSelect() -// [SECTION] ShowDemoWindowLayout() -// [SECTION] ShowDemoWindowPopups() -// [SECTION] ShowDemoWindowTables() -// [SECTION] ShowDemoWindowInputs() +// [SECTION] DemoWindowMenuBar() +// [SECTION] DemoWindowWidgets() +// [SECTION] DemoWindowWidgetsBasic() +// [SECTION] DemoWindowWidgetsBullets() +// [SECTION] DemoWindowWidgetsCollapsingHeaders() +// [SECTION] DemoWindowWidgetsComboBoxes() +// [SECTION] DemoWindowWidgetsColorAndPickers() +// [SECTION] DemoWindowWidgetsDataTypes() +// [SECTION] DemoWindowWidgetsDisableBlocks() +// [SECTION] DemoWindowWidgetsDragAndDrop() +// [SECTION] DemoWindowWidgetsDragsAndSliders() +// [SECTION] DemoWindowWidgetsImages() +// [SECTION] DemoWindowWidgetsListBoxes() +// [SECTION] DemoWindowWidgetsMultiComponents() +// [SECTION] DemoWindowWidgetsPlotting() +// [SECTION] DemoWindowWidgetsProgressBars() +// [SECTION] DemoWindowWidgetsQueryingStatuses() +// [SECTION] DemoWindowWidgetsSelectables() +// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() +// [SECTION] DemoWindowWidgetsTabs() +// [SECTION] DemoWindowWidgetsText() +// [SECTION] DemoWindowWidgetsTextFilter() +// [SECTION] DemoWindowWidgetsTextInput() +// [SECTION] DemoWindowWidgetsTooltips() +// [SECTION] DemoWindowWidgetsTreeNodes() +// [SECTION] DemoWindowWidgetsVerticalSliders() +// [SECTION] DemoWindowLayout() +// [SECTION] DemoWindowPopups() +// [SECTION] DemoWindowTables() +// [SECTION] DemoWindowInputs() // [SECTION] About Window / ShowAboutWindow() // [SECTION] Style Editor / ShowStyleEditor() // [SECTION] User Guide / ShowUserGuide() @@ -225,14 +248,14 @@ static void ShowExampleMenuFile(); // We split the contents of the big ShowDemoWindow() function into smaller functions // (because the link time of very large functions tends to grow non-linearly) -static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data); -static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data); -static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data); -static void ShowDemoWindowLayout(); -static void ShowDemoWindowPopups(); -static void ShowDemoWindowTables(); -static void ShowDemoWindowColumns(); -static void ShowDemoWindowInputs(); +static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); +static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); +static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); +static void DemoWindowLayout(); +static void DemoWindowPopups(); +static void DemoWindowTables(); +static void DemoWindowColumns(); +static void DemoWindowInputs(); //----------------------------------------------------------------------------- // [SECTION] Helpers @@ -475,7 +498,7 @@ void ImGui::ShowDemoWindow(bool* p_open) //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) // Menu Bar - ShowDemoWindowMenuBar(&demo_data); + DemoWindowMenuBar(&demo_data); ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); @@ -683,11 +706,11 @@ void ImGui::ShowDemoWindow(bool* p_open) } // All demo contents - ShowDemoWindowWidgets(&demo_data); - ShowDemoWindowLayout(); - ShowDemoWindowPopups(); - ShowDemoWindowTables(); - ShowDemoWindowInputs(); + DemoWindowWidgets(&demo_data); + DemoWindowLayout(); + DemoWindowPopups(); + DemoWindowTables(); + DemoWindowInputs(); // End of ShowDemoWindow() ImGui::PopItemWidth(); @@ -695,10 +718,10 @@ void ImGui::ShowDemoWindow(bool* p_open) } //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowMenuBar() +// [SECTION] DemoWindowMenuBar() //----------------------------------------------------------------------------- -static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) +static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Menu"); if (ImGui::BeginMenuBar()) @@ -770,10 +793,10 @@ static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data) } //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowWidgets() +// [SECTION] DemoWindowWidgets() //----------------------------------------------------------------------------- -static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) +static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets"); //ImGui::SetNextItemOpen(true, ImGuiCond_Once); @@ -1680,7 +1703,7 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - ShowDemoWindowMultiSelect(demo_data); + DemoWindowWidgetsSelectionAndMultiSelect(demo_data); // To wire InputText() with std::string or any other custom string type, // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. @@ -2986,6 +3009,70 @@ static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data) } } +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsBasic() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsBullets() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsCollapsingHeaders() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsColorAndPickers() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsComboBoxes() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsDataTypes() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsDisableBlocks() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsDragAndDrop() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsDragsAndSliders() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsImages() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsListBoxes() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsMultiComponents() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsPlotting() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsProgressBars() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsQueryingStatuses() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsSelectables() +//----------------------------------------------------------------------------- + static const char* ExampleNames[] = { "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper", @@ -3212,13 +3299,13 @@ struct ExampleDualListBox }; //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowMultiSelect() +// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() //----------------------------------------------------------------------------- // Multi-selection demos // Also read: https://github.com/ocornut/imgui/wiki/Multi-Select //----------------------------------------------------------------------------- -static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) +static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); if (ImGui::TreeNode("Selection State & Multi-Select")) @@ -3954,10 +4041,38 @@ static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data) } //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowLayout() +// [SECTION] DemoWindowWidgetsTabs() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsText() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsTextFilter() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsTextInput() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsTooltips() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsTreeNodes() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsVerticalSliders() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowLayout() //----------------------------------------------------------------------------- -static void ShowDemoWindowLayout() +static void DemoWindowLayout() { IMGUI_DEMO_MARKER("Layout"); if (!ImGui::CollapsingHeader("Layout & Scrolling")) @@ -4820,10 +4935,10 @@ static void ShowDemoWindowLayout() } //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowPopups() +// [SECTION] DemoWindowPopups() //----------------------------------------------------------------------------- -static void ShowDemoWindowPopups() +static void DemoWindowPopups() { IMGUI_DEMO_MARKER("Popups"); if (!ImGui::CollapsingHeader("Popups & Modal windows")) @@ -5284,10 +5399,10 @@ static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags) } //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowTables() +// [SECTION] DemoWindowTables() //----------------------------------------------------------------------------- -static void ShowDemoWindowTables() +static void DemoWindowTables() { //ImGui::SetNextItemOpen(true, ImGuiCond_Once); IMGUI_DEMO_MARKER("Tables"); @@ -7184,7 +7299,7 @@ static void ShowDemoWindowTables() ImGui::PopID(); - ShowDemoWindowColumns(); + DemoWindowColumns(); if (disable_indent) ImGui::PopStyleVar(); @@ -7192,7 +7307,7 @@ static void ShowDemoWindowTables() // Demonstrate old/legacy Columns API! // [2020: Columns are under-featured and not maintained. Prefer using the more flexible and powerful BeginTable() API!] -static void ShowDemoWindowColumns() +static void DemoWindowColumns() { IMGUI_DEMO_MARKER("Columns (legacy API)"); bool open = ImGui::TreeNode("Legacy Columns API"); @@ -7399,10 +7514,10 @@ static void ShowDemoWindowColumns() } //----------------------------------------------------------------------------- -// [SECTION] ShowDemoWindowInputs() +// [SECTION] DemoWindowInputs() //----------------------------------------------------------------------------- -static void ShowDemoWindowInputs() +static void DemoWindowInputs() { IMGUI_DEMO_MARKER("Inputs & Focus"); if (ImGui::CollapsingHeader("Inputs & Focus")) From b2c55c9db56bc7ceb0618c9e247deeff3cb43f47 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 17:50:48 +0100 Subject: [PATCH 275/716] Demo: (Refactor) Moved code into DemoWindowWidgetsBasic() section. --- imgui_demo.cpp | 411 +++++++++++++++++++++++++------------------------ 1 file changed, 209 insertions(+), 202 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 81d6cfca82da..1e43ea3c4f9e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -250,6 +250,7 @@ static void ShowExampleMenuFile(); // (because the link time of very large functions tends to grow non-linearly) static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); +static void DemoWindowWidgetsBasic(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); static void DemoWindowLayout(); static void DemoWindowPopups(); @@ -807,203 +808,8 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) if (disable_all) ImGui::BeginDisabled(); - IMGUI_DEMO_MARKER("Widgets/Basic"); - if (ImGui::TreeNode("Basic")) - { - ImGui::SeparatorText("General"); - - IMGUI_DEMO_MARKER("Widgets/Basic/Button"); - static int clicked = 0; - if (ImGui::Button("Button")) - clicked++; - if (clicked & 1) - { - ImGui::SameLine(); - ImGui::Text("Thanks for clicking me!"); - } - - IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox"); - static bool check = true; - ImGui::Checkbox("checkbox", &check); - - IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton"); - static int e = 0; - ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); - ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); - ImGui::RadioButton("radio c", &e, 2); - - // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. - IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)"); - for (int i = 0; i < 7; i++) - { - if (i > 0) - ImGui::SameLine(); - ImGui::PushID(i); - ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); - ImGui::Button("Click"); - ImGui::PopStyleColor(3); - ImGui::PopID(); - } - - // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements - // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) - // See 'Demo->Layout->Text Baseline Alignment' for details. - ImGui::AlignTextToFramePadding(); - ImGui::Text("Hold to repeat:"); - ImGui::SameLine(); - - // Arrow buttons with Repeater - IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)"); - static int counter = 0; - float spacing = ImGui::GetStyle().ItemInnerSpacing.x; - ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); - if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } - ImGui::SameLine(0.0f, spacing); - if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } - ImGui::PopItemFlag(); - ImGui::SameLine(); - ImGui::Text("%d", counter); - - ImGui::Button("Tooltip"); - ImGui::SetItemTooltip("I am a tooltip"); - - ImGui::LabelText("label", "Value"); - - ImGui::SeparatorText("Inputs"); - - { - // To wire InputText() with std::string or any other custom string type, - // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. - IMGUI_DEMO_MARKER("Widgets/Basic/InputText"); - static char str0[128] = "Hello, world!"; - ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); - ImGui::SameLine(); HelpMarker( - "USER:\n" - "Hold SHIFT or use mouse to select text.\n" - "CTRL+Left/Right to word jump.\n" - "CTRL+A or Double-Click to select all.\n" - "CTRL+X,CTRL+C,CTRL+V for clipboard.\n" - "CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo.\n" - "ESCAPE to revert.\n\n" - "PROGRAMMER:\n" - "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " - "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " - "in imgui_demo.cpp)."); + DemoWindowWidgetsBasic(); - static char str1[128] = ""; - ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); - - IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); - static int i0 = 123; - ImGui::InputInt("input int", &i0); - - static float f0 = 0.001f; - ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); - - static double d0 = 999999.00000001; - ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); - - static float f1 = 1.e10f; - ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); - ImGui::SameLine(); HelpMarker( - "You can input value using the scientific notation,\n" - " e.g. \"1e+8\" becomes \"100000000\"."); - - static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; - ImGui::InputFloat3("input float3", vec4a); - } - - ImGui::SeparatorText("Drags"); - - { - IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); - static int i1 = 50, i2 = 42, i3 = 128; - ImGui::DragInt("drag int", &i1, 1); - ImGui::SameLine(); HelpMarker( - "Click and drag to edit value.\n" - "Hold SHIFT/ALT for faster/slower edit.\n" - "Double-click or CTRL+click to input value."); - ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); - ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround); - - static float f1 = 1.00f, f2 = 0.0067f; - ImGui::DragFloat("drag float", &f1, 0.005f); - ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); - //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround); - } - - ImGui::SeparatorText("Sliders"); - - { - IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); - static int i1 = 0; - ImGui::SliderInt("slider int", &i1, -1, 3); - ImGui::SameLine(); HelpMarker("CTRL+click to input value."); - - static float f1 = 0.123f, f2 = 0.0f; - ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); - ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); - - IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle"); - static float angle = 0.0f; - ImGui::SliderAngle("slider angle", &angle); - - // Using the format string to display a name instead of an integer. - // Here we completely omit '%d' from the format string, so it'll only display a name. - // This technique can also be used with DragInt(). - IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)"); - enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; - static int elem = Element_Fire; - const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; - const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; - ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here. - ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); - } - - ImGui::SeparatorText("Selectors/Pickers"); - - { - IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); - static float col1[3] = { 1.0f, 0.0f, 0.2f }; - static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; - ImGui::ColorEdit3("color 1", col1); - ImGui::SameLine(); HelpMarker( - "Click on the color square to open a color picker.\n" - "Click and hold to use drag and drop.\n" - "Right-click on the color square to show options.\n" - "CTRL+click on individual component to input value.\n"); - - ImGui::ColorEdit4("color 2", col2); - } - - { - // Using the _simplified_ one-liner Combo() api here - // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. - IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; - static int item_current = 0; - ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); - ImGui::SameLine(); HelpMarker( - "Using the simplified one-liner Combo API here.\n" - "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); - } - - { - // Using the _simplified_ one-liner ListBox() api here - // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. - IMGUI_DEMO_MARKER("Widgets/Basic/ListBox"); - const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; - static int item_current = 1; - ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); - ImGui::SameLine(); HelpMarker( - "Using the simplified one-liner ListBox API here.\n" - "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); - } - - ImGui::TreePop(); - } IMGUI_DEMO_MARKER("Widgets/Tooltips"); if (ImGui::TreeNode("Tooltips")) @@ -1097,12 +903,6 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - // Testing ImGuiOnceUponAFrame helper. - //static ImGuiOnceUponAFrame once; - //for (int i = 0; i < 5; i++) - // if (once) - // ImGui::Text("This will be displayed only once."); - IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); if (ImGui::TreeNode("Tree Nodes")) { @@ -3013,6 +2813,213 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) // [SECTION] DemoWindowWidgetsBasic() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsBasic() +{ + IMGUI_DEMO_MARKER("Widgets/Basic"); + if (ImGui::TreeNode("Basic")) + { + ImGui::SeparatorText("General"); + + IMGUI_DEMO_MARKER("Widgets/Basic/Button"); + static int clicked = 0; + if (ImGui::Button("Button")) + clicked++; + if (clicked & 1) + { + ImGui::SameLine(); + ImGui::Text("Thanks for clicking me!"); + } + + IMGUI_DEMO_MARKER("Widgets/Basic/Checkbox"); + static bool check = true; + ImGui::Checkbox("checkbox", &check); + + IMGUI_DEMO_MARKER("Widgets/Basic/RadioButton"); + static int e = 0; + ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); + ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); + ImGui::RadioButton("radio c", &e, 2); + + // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)"); + for (int i = 0; i < 7; i++) + { + if (i > 0) + ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.7f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.8f, 0.8f)); + ImGui::Button("Click"); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + + // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements + // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!) + // See 'Demo->Layout->Text Baseline Alignment' for details. + ImGui::AlignTextToFramePadding(); + ImGui::Text("Hold to repeat:"); + ImGui::SameLine(); + + // Arrow buttons with Repeater + IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)"); + static int counter = 0; + float spacing = ImGui::GetStyle().ItemInnerSpacing.x; + ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); + if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } + ImGui::SameLine(0.0f, spacing); + if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } + ImGui::PopItemFlag(); + ImGui::SameLine(); + ImGui::Text("%d", counter); + + ImGui::Button("Tooltip"); + ImGui::SetItemTooltip("I am a tooltip"); + + ImGui::LabelText("label", "Value"); + + ImGui::SeparatorText("Inputs"); + + { + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + IMGUI_DEMO_MARKER("Widgets/Basic/InputText"); + static char str0[128] = "Hello, world!"; + ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); + ImGui::SameLine(); HelpMarker( + "USER:\n" + "Hold SHIFT or use mouse to select text.\n" + "CTRL+Left/Right to word jump.\n" + "CTRL+A or Double-Click to select all.\n" + "CTRL+X,CTRL+C,CTRL+V for clipboard.\n" + "CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo.\n" + "ESCAPE to revert.\n\n" + "PROGRAMMER:\n" + "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() " + "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated " + "in imgui_demo.cpp)."); + + static char str1[128] = ""; + ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); + + IMGUI_DEMO_MARKER("Widgets/Basic/InputInt, InputFloat"); + static int i0 = 123; + ImGui::InputInt("input int", &i0); + + static float f0 = 0.001f; + ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); + + static double d0 = 999999.00000001; + ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); + + static float f1 = 1.e10f; + ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); + ImGui::SameLine(); HelpMarker( + "You can input value using the scientific notation,\n" + " e.g. \"1e+8\" becomes \"100000000\"."); + + static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + ImGui::InputFloat3("input float3", vec4a); + } + + ImGui::SeparatorText("Drags"); + + { + IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat"); + static int i1 = 50, i2 = 42, i3 = 128; + ImGui::DragInt("drag int", &i1, 1); + ImGui::SameLine(); HelpMarker( + "Click and drag to edit value.\n" + "Hold SHIFT/ALT for faster/slower edit.\n" + "Double-click or CTRL+click to input value."); + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround); + + static float f1 = 1.00f, f2 = 0.0067f; + ImGui::DragFloat("drag float", &f1, 0.005f); + ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); + //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround); + } + + ImGui::SeparatorText("Sliders"); + + { + IMGUI_DEMO_MARKER("Widgets/Basic/SliderInt, SliderFloat"); + static int i1 = 0; + ImGui::SliderInt("slider int", &i1, -1, 3); + ImGui::SameLine(); HelpMarker("CTRL+click to input value."); + + static float f1 = 0.123f, f2 = 0.0f; + ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); + ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic); + + IMGUI_DEMO_MARKER("Widgets/Basic/SliderAngle"); + static float angle = 0.0f; + ImGui::SliderAngle("slider angle", &angle); + + // Using the format string to display a name instead of an integer. + // Here we completely omit '%d' from the format string, so it'll only display a name. + // This technique can also be used with DragInt(). + IMGUI_DEMO_MARKER("Widgets/Basic/Slider (enum)"); + enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; + static int elem = Element_Fire; + const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; + const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown"; + ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name); // Use ImGuiSliderFlags_NoInput flag to disable CTRL+Click here. + ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer."); + } + + ImGui::SeparatorText("Selectors/Pickers"); + + { + IMGUI_DEMO_MARKER("Widgets/Basic/ColorEdit3, ColorEdit4"); + static float col1[3] = { 1.0f, 0.0f, 0.2f }; + static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" + "Click and hold to use drag and drop.\n" + "Right-click on the color square to show options.\n" + "CTRL+click on individual component to input value.\n"); + + ImGui::ColorEdit4("color 2", col2); + } + + { + // Using the _simplified_ one-liner Combo() api here + // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. + IMGUI_DEMO_MARKER("Widgets/Basic/Combo"); + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; + static int item_current = 0; + ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner Combo API here.\n" + "Refer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); + } + + { + // Using the _simplified_ one-liner ListBox() api here + // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. + IMGUI_DEMO_MARKER("Widgets/Basic/ListBox"); + const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; + static int item_current = 1; + ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\n" + "Refer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); + } + + // Testing ImGuiOnceUponAFrame helper. + //static ImGuiOnceUponAFrame once; + //for (int i = 0; i < 5; i++) + // if (once) + // ImGui::Text("This will be displayed only once."); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsBullets() //----------------------------------------------------------------------------- From de3f68a233ac35697671c3e0dcbcd333604c3af5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 17:51:34 +0100 Subject: [PATCH 276/716] Demo: (Refactor) Moved code into DemoWindowWidgetsTooltips(), DemoWindowWidgetsTreeNodes() sections. --- imgui_demo.cpp | 447 +++++++++++++++++++++++++------------------------ 1 file changed, 228 insertions(+), 219 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 1e43ea3c4f9e..479aa53d54d4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -252,6 +252,8 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsBasic(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); +static void DemoWindowWidgetsTooltips(); +static void DemoWindowWidgetsTreeNodes(); static void DemoWindowLayout(); static void DemoWindowPopups(); static void DemoWindowTables(); @@ -809,225 +811,8 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::BeginDisabled(); DemoWindowWidgetsBasic(); - - - IMGUI_DEMO_MARKER("Widgets/Tooltips"); - if (ImGui::TreeNode("Tooltips")) - { - // Tooltips are windows following the mouse. They do not take focus away. - ImGui::SeparatorText("General"); - - // Typical use cases: - // - Short-form (text only): SetItemTooltip("Hello"); - // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); } - - // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } - // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } - - HelpMarker( - "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" - "We provide a helper SetItemTooltip() function to perform the two with standards flags."); - - ImVec2 sz = ImVec2(-FLT_MIN, 0.0f); - - ImGui::Button("Basic", sz); - ImGui::SetItemTooltip("I am a tooltip"); - - ImGui::Button("Fancy", sz); - if (ImGui::BeginItemTooltip()) - { - ImGui::Text("I am a fancy tooltip"); - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); - ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); - ImGui::EndTooltip(); - } - - ImGui::SeparatorText("Always On"); - - // Showcase NOT relying on a IsItemHovered() to emit a tooltip. - // Here the tooltip is always emitted when 'always_on == true'. - static int always_on = 0; - ImGui::RadioButton("Off", &always_on, 0); - ImGui::SameLine(); - ImGui::RadioButton("Always On (Simple)", &always_on, 1); - ImGui::SameLine(); - ImGui::RadioButton("Always On (Advanced)", &always_on, 2); - if (always_on == 1) - ImGui::SetTooltip("I am following you around."); - else if (always_on == 2 && ImGui::BeginTooltip()) - { - ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f)); - ImGui::EndTooltip(); - } - - ImGui::SeparatorText("Custom"); - - HelpMarker( - "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " - "tooltip activation details across your application. You may however decide to use custom " - "flags for a specific tooltip instance."); - - // The following examples are passed for documentation purpose but may not be useful to most users. - // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from - // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. - // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. - ImGui::Button("Manual", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ImGui::SetTooltip("I am a manually emitted tooltip."); - - ImGui::Button("DelayNone", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone)) - ImGui::SetTooltip("I am a tooltip with no delay."); - - ImGui::Button("DelayShort", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay)) - ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort); - - ImGui::Button("DelayLong", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) - ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal); - - ImGui::Button("Stationary", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) - ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating."); - - // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', - // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. - ImGui::BeginDisabled(); - ImGui::Button("Disabled item", sz); - if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) - ImGui::SetTooltip("I am a a tooltip for a disabled item."); - ImGui::EndDisabled(); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); - if (ImGui::TreeNode("Tree Nodes")) - { - IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees"); - if (ImGui::TreeNode("Basic trees")) - { - for (int i = 0; i < 5; i++) - { - // Use SetNextItemOpen() so set the default state of a node to be open. We could - // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! - if (i == 0) - ImGui::SetNextItemOpen(true, ImGuiCond_Once); - - // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. - // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)', - // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine. - ImGui::PushID(i); - if (ImGui::TreeNode("", "Child %d", i)) - { - ImGui::Text("blah blah"); - ImGui::SameLine(); - if (ImGui::SmallButton("button")) {} - ImGui::TreePop(); - } - ImGui::PopID(); - } - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes"); - if (ImGui::TreeNode("Advanced, with Selectable nodes")) - { - HelpMarker( - "This is a more typical looking tree with selectable nodes.\n" - "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); - static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; - static bool align_label_with_current_x_position = false; - static bool test_drag_and_drop = false; - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere); - ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); - ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); - ImGui::Text("Hello!"); - if (align_label_with_current_x_position) - ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); - - // 'selection_mask' is dumb representation of what may be user-side selection state. - // You may retain selection state inside or outside your objects in whatever format you see fit. - // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end - /// of the loop. May be a pointer to your own node type, etc. - static int selection_mask = (1 << 2); - int node_clicked = -1; - for (int i = 0; i < 6; i++) - { - // Disable the default "open on single-click behavior" + set Selected flag according to our selection. - // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection. - ImGuiTreeNodeFlags node_flags = base_flags; - const bool is_selected = (selection_mask & (1 << i)) != 0; - if (is_selected) - node_flags |= ImGuiTreeNodeFlags_Selected; - if (i < 3) - { - // Items 0..2 are Tree Node - bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) - node_clicked = i; - if (test_drag_and_drop && ImGui::BeginDragDropSource()) - { - ImGui::SetDragDropPayload("_TREENODE", NULL, 0); - ImGui::Text("This is a drag and drop source"); - ImGui::EndDragDropSource(); - } - if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) - { - // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. - ImGui::SameLine(); - if (ImGui::SmallButton("button")) {} - } - if (node_open) - { - ImGui::BulletText("Blah blah\nBlah Blah"); - ImGui::SameLine(); - ImGui::SmallButton("Button"); - ImGui::TreePop(); - } - } - else - { - // Items 3..5 are Tree Leaves - // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can - // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). - node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet - ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); - if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) - node_clicked = i; - if (test_drag_and_drop && ImGui::BeginDragDropSource()) - { - ImGui::SetDragDropPayload("_TREENODE", NULL, 0); - ImGui::Text("This is a drag and drop source"); - ImGui::EndDragDropSource(); - } - } - } - if (node_clicked != -1) - { - // Update selection state - // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) - if (ImGui::GetIO().KeyCtrl) - selection_mask ^= (1 << node_clicked); // CTRL+click to toggle - else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection - selection_mask = (1 << node_clicked); // Click to single-select - } - if (align_label_with_current_x_position) - ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); - ImGui::TreePop(); - } - ImGui::TreePop(); - } + DemoWindowWidgetsTooltips(); + DemoWindowWidgetsTreeNodes(); IMGUI_DEMO_MARKER("Widgets/Collapsing Headers"); if (ImGui::TreeNode("Collapsing Headers")) @@ -4067,10 +3852,234 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // [SECTION] DemoWindowWidgetsTooltips() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsTooltips() +{ + IMGUI_DEMO_MARKER("Widgets/Tooltips"); + if (ImGui::TreeNode("Tooltips")) + { + // Tooltips are windows following the mouse. They do not take focus away. + ImGui::SeparatorText("General"); + + // Typical use cases: + // - Short-form (text only): SetItemTooltip("Hello"); + // - Short-form (any contents): if (BeginItemTooltip()) { Text("Hello"); EndTooltip(); } + + // - Full-form (text only): if (IsItemHovered(...)) { SetTooltip("Hello"); } + // - Full-form (any contents): if (IsItemHovered(...) && BeginTooltip()) { Text("Hello"); EndTooltip(); } + + HelpMarker( + "Tooltip are typically created by using a IsItemHovered() + SetTooltip() sequence.\n\n" + "We provide a helper SetItemTooltip() function to perform the two with standards flags."); + + ImVec2 sz = ImVec2(-FLT_MIN, 0.0f); + + ImGui::Button("Basic", sz); + ImGui::SetItemTooltip("I am a tooltip"); + + ImGui::Button("Fancy", sz); + if (ImGui::BeginItemTooltip()) + { + ImGui::Text("I am a fancy tooltip"); + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); + ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime())); + ImGui::EndTooltip(); + } + + ImGui::SeparatorText("Always On"); + + // Showcase NOT relying on a IsItemHovered() to emit a tooltip. + // Here the tooltip is always emitted when 'always_on == true'. + static int always_on = 0; + ImGui::RadioButton("Off", &always_on, 0); + ImGui::SameLine(); + ImGui::RadioButton("Always On (Simple)", &always_on, 1); + ImGui::SameLine(); + ImGui::RadioButton("Always On (Advanced)", &always_on, 2); + if (always_on == 1) + ImGui::SetTooltip("I am following you around."); + else if (always_on == 2 && ImGui::BeginTooltip()) + { + ImGui::ProgressBar(sinf((float)ImGui::GetTime()) * 0.5f + 0.5f, ImVec2(ImGui::GetFontSize() * 25, 0.0f)); + ImGui::EndTooltip(); + } + + ImGui::SeparatorText("Custom"); + + HelpMarker( + "Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() is the preferred way to standardize " + "tooltip activation details across your application. You may however decide to use custom " + "flags for a specific tooltip instance."); + + // The following examples are passed for documentation purpose but may not be useful to most users. + // Passing ImGuiHoveredFlags_ForTooltip to IsItemHovered() will pull ImGuiHoveredFlags flags values from + // 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav' depending on whether mouse or keyboard/gamepad is being used. + // With default settings, ImGuiHoveredFlags_ForTooltip is equivalent to ImGuiHoveredFlags_DelayShort + ImGuiHoveredFlags_Stationary. + ImGui::Button("Manual", sz); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + ImGui::SetTooltip("I am a manually emitted tooltip."); + + ImGui::Button("DelayNone", sz); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNone)) + ImGui::SetTooltip("I am a tooltip with no delay."); + + ImGui::Button("DelayShort", sz); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_NoSharedDelay)) + ImGui::SetTooltip("I am a tooltip with a short delay (%0.2f sec).", ImGui::GetStyle().HoverDelayShort); + + ImGui::Button("DelayLong", sz); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_NoSharedDelay)) + ImGui::SetTooltip("I am a tooltip with a long delay (%0.2f sec).", ImGui::GetStyle().HoverDelayNormal); + + ImGui::Button("Stationary", sz); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary)) + ImGui::SetTooltip("I am a tooltip requiring mouse to be stationary before activating."); + + // Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav', + // which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag. + ImGui::BeginDisabled(); + ImGui::Button("Disabled item", sz); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) + ImGui::SetTooltip("I am a a tooltip for a disabled item."); + ImGui::EndDisabled(); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsTreeNodes() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsTreeNodes() +{ + IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); + if (ImGui::TreeNode("Tree Nodes")) + { + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees"); + if (ImGui::TreeNode("Basic trees")) + { + for (int i = 0; i < 5; i++) + { + // Use SetNextItemOpen() so set the default state of a node to be open. We could + // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing! + if (i == 0) + ImGui::SetNextItemOpen(true, ImGuiCond_Once); + + // Here we use PushID() to generate a unique base ID, and then the "" used as TreeNode id won't conflict. + // An alternative to using 'PushID() + TreeNode("", ...)' to generate a unique ID is to use 'TreeNode((void*)(intptr_t)i, ...)', + // aka generate a dummy pointer-sized value to be hashed. The demo below uses that technique. Both are fine. + ImGui::PushID(i); + if (ImGui::TreeNode("", "Child %d", i)) + { + ImGui::Text("blah blah"); + ImGui::SameLine(); + if (ImGui::SmallButton("button")) {} + ImGui::TreePop(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes"); + if (ImGui::TreeNode("Advanced, with Selectable nodes")) + { + HelpMarker( + "This is a more typical looking tree with selectable nodes.\n" + "Click to select, CTRL+Click to toggle, click on arrows or double-click to open."); + static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; + static bool align_label_with_current_x_position = false; + static bool test_drag_and_drop = false; + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", &base_flags, ImGuiTreeNodeFlags_OpenOnArrow); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", &base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", &base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &base_flags, ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &base_flags, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::SameLine(); HelpMarker("Reduce hit area to the text label and a bit of margin."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere); + ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); + ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); + ImGui::Text("Hello!"); + if (align_label_with_current_x_position) + ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing()); + + // 'selection_mask' is dumb representation of what may be user-side selection state. + // You may retain selection state inside or outside your objects in whatever format you see fit. + // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end + /// of the loop. May be a pointer to your own node type, etc. + static int selection_mask = (1 << 2); + int node_clicked = -1; + for (int i = 0; i < 6; i++) + { + // Disable the default "open on single-click behavior" + set Selected flag according to our selection. + // To alter selection we use IsItemClicked() && !IsItemToggledOpen(), so clicking on an arrow doesn't alter selection. + ImGuiTreeNodeFlags node_flags = base_flags; + const bool is_selected = (selection_mask & (1 << i)) != 0; + if (is_selected) + node_flags |= ImGuiTreeNodeFlags_Selected; + if (i < 3) + { + // Items 0..2 are Tree Node + bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i); + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) + node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } + if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanLabelWidth)) + { + // Item 2 has an additional inline button to help demonstrate SpanLabelWidth. + ImGui::SameLine(); + if (ImGui::SmallButton("button")) {} + } + if (node_open) + { + ImGui::BulletText("Blah blah\nBlah Blah"); + ImGui::SameLine(); + ImGui::SmallButton("Button"); + ImGui::TreePop(); + } + } + else + { + // Items 3..5 are Tree Leaves + // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can + // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text(). + node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet + ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i); + if (ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen()) + node_clicked = i; + if (test_drag_and_drop && ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload("_TREENODE", NULL, 0); + ImGui::Text("This is a drag and drop source"); + ImGui::EndDragDropSource(); + } + } + } + if (node_clicked != -1) + { + // Update selection state + // (process outside of tree loop to avoid visual inconsistencies during the clicking frame) + if (ImGui::GetIO().KeyCtrl) + selection_mask ^= (1 << node_clicked); // CTRL+click to toggle + else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection + selection_mask = (1 << node_clicked); // Click to single-select + } + if (align_label_with_current_x_position) + ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing()); + ImGui::TreePop(); + } + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsVerticalSliders() //----------------------------------------------------------------------------- From 94877a137d6aac1aba010bcace0f5730c2f153fc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 17:56:15 +0100 Subject: [PATCH 277/716] Demo: (Refactor) Moved code into DemoWindowWidgetsBullets(), DemoWindowWidgetsCollapsingHeaders(), DemoWindowWidgetsCollapsingText() sections. --- imgui_demo.cpp | 243 ++++++++++++++++++++++++++----------------------- 1 file changed, 129 insertions(+), 114 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 479aa53d54d4..f40f5ddaec3b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -251,7 +251,10 @@ static void ShowExampleMenuFile(); static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsBasic(); +static void DemoWindowWidgetsBullets(); +static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); +static void DemoWindowWidgetsText(); static void DemoWindowWidgetsTooltips(); static void DemoWindowWidgetsTreeNodes(); static void DemoWindowLayout(); @@ -811,123 +814,12 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::BeginDisabled(); DemoWindowWidgetsBasic(); + DemoWindowWidgetsBullets(); + DemoWindowWidgetsCollapsingHeaders(); + DemoWindowWidgetsText(); DemoWindowWidgetsTooltips(); DemoWindowWidgetsTreeNodes(); - IMGUI_DEMO_MARKER("Widgets/Collapsing Headers"); - if (ImGui::TreeNode("Collapsing Headers")) - { - static bool closable_group = true; - ImGui::Checkbox("Show 2nd header", &closable_group); - if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) - { - ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); - for (int i = 0; i < 5; i++) - ImGui::Text("Some content %d", i); - } - if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) - { - ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); - for (int i = 0; i < 5; i++) - ImGui::Text("More content %d", i); - } - /* - if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) - ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); - */ - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Bullets"); - if (ImGui::TreeNode("Bullets")) - { - ImGui::BulletText("Bullet point 1"); - ImGui::BulletText("Bullet point 2\nOn multiple lines"); - if (ImGui::TreeNode("Tree node")) - { - ImGui::BulletText("Another bullet point"); - ImGui::TreePop(); - } - ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); - ImGui::Bullet(); ImGui::SmallButton("Button"); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text"); - if (ImGui::TreeNode("Text")) - { - IMGUI_DEMO_MARKER("Widgets/Text/Colored Text"); - if (ImGui::TreeNode("Colorful Text")) - { - // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. - ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); - ImGui::TextDisabled("Disabled"); - ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping"); - if (ImGui::TreeNode("Word Wrapping")) - { - // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. - ImGui::TextWrapped( - "This text should automatically wrap on the edge of the window. The current implementation " - "for text wrapping follows simple rules suitable for English and possibly other languages."); - ImGui::Spacing(); - - static float wrap_width = 200.0f; - ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - for (int n = 0; n < 2; n++) - { - ImGui::Text("Test paragraph %d:", n); - ImVec2 pos = ImGui::GetCursorScreenPos(); - ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); - ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); - ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); - if (n == 0) - ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); - else - ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); - - // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) - draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); - draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); - ImGui::PopTextWrapPos(); - } - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text"); - if (ImGui::TreeNode("UTF-8 Text")) - { - // UTF-8 test with Japanese characters - // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) - // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 - // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you - // can save your source files as 'UTF-8 without signature'). - // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 - // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. - // Don't do this in your application! Please use u8"text in any language" in your application! - // Note that characters values are preserved even by InputText() if the font cannot be displayed, - // so you can safely copy & paste garbled characters into another application. - ImGui::TextWrapped( - "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. " - "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " - "Read docs/FONTS.md for details."); - ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); - ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); - static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; - //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis - ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); - ImGui::TreePop(); - } - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Images"); if (ImGui::TreeNode("Images")) { @@ -2809,10 +2701,55 @@ static void DemoWindowWidgetsBasic() // [SECTION] DemoWindowWidgetsBullets() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsBullets() +{ + IMGUI_DEMO_MARKER("Widgets/Bullets"); + if (ImGui::TreeNode("Bullets")) + { + ImGui::BulletText("Bullet point 1"); + ImGui::BulletText("Bullet point 2\nOn multiple lines"); + if (ImGui::TreeNode("Tree node")) + { + ImGui::BulletText("Another bullet point"); + ImGui::TreePop(); + } + ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)"); + ImGui::Bullet(); ImGui::SmallButton("Button"); + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsCollapsingHeaders() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsCollapsingHeaders() +{ + IMGUI_DEMO_MARKER("Widgets/Collapsing Headers"); + if (ImGui::TreeNode("Collapsing Headers")) + { + static bool closable_group = true; + ImGui::Checkbox("Show 2nd header", &closable_group); + if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("Some content %d", i); + } + if (ImGui::CollapsingHeader("Header with a close button", &closable_group)) + { + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + for (int i = 0; i < 5; i++) + ImGui::Text("More content %d", i); + } + /* + if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet)) + ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered()); + */ + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsColorAndPickers() //----------------------------------------------------------------------------- @@ -3840,6 +3777,84 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // [SECTION] DemoWindowWidgetsText() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsText() +{ + IMGUI_DEMO_MARKER("Widgets/Text"); + if (ImGui::TreeNode("Text")) + { + IMGUI_DEMO_MARKER("Widgets/Text/Colored Text"); + if (ImGui::TreeNode("Colorful Text")) + { + // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility. + ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink"); + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow"); + ImGui::TextDisabled("Disabled"); + ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle."); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping"); + if (ImGui::TreeNode("Word Wrapping")) + { + // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility. + ImGui::TextWrapped( + "This text should automatically wrap on the edge of the window. The current implementation " + "for text wrapping follows simple rules suitable for English and possibly other languages."); + ImGui::Spacing(); + + static float wrap_width = 200.0f; + ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f"); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + for (int n = 0; n < 2; n++) + { + ImGui::Text("Test paragraph %d:", n); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); + ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width); + if (n == 0) + ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width); + else + ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee ffffffff. gggggggg!hhhhhhhh"); + + // Draw actual text bounding box, following by marker of our expected limit (should not overlap!) + draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255)); + draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255)); + ImGui::PopTextWrapPos(); + } + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text/UTF-8 Text"); + if (ImGui::TreeNode("UTF-8 Text")) + { + // UTF-8 test with Japanese characters + // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) + // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 + // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you + // can save your source files as 'UTF-8 without signature'). + // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8 + // CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants. + // Don't do this in your application! Please use u8"text in any language" in your application! + // Note that characters values are preserved even by InputText() if the font cannot be displayed, + // so you can safely copy & paste garbled characters into another application. + ImGui::TextWrapped( + "CJK text will only appear if the font was loaded with the appropriate CJK character ranges. " + "Call io.Fonts->AddFontFromFileTTF() manually to load extra character ranges. " + "Read docs/FONTS.md for details."); + ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); + ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); + static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; + //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis + ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf)); + ImGui::TreePop(); + } + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsTextFilter() //----------------------------------------------------------------------------- From 22baec494bfec2df120c0acb491eb0a7b643cf40 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 17:57:43 +0100 Subject: [PATCH 278/716] Demo: (Refactor) Moved code into DemoWindowWidgetsComboBoxes(), DemoWindowWidgetsImages(), DemoWindowWidgetsListBoxes() sections. --- imgui_demo.cpp | 475 +++++++++++++++++++++++++------------------------ 1 file changed, 245 insertions(+), 230 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index f40f5ddaec3b..3b08b152f73f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -253,6 +253,9 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsBasic(); static void DemoWindowWidgetsBullets(); static void DemoWindowWidgetsCollapsingHeaders(); +static void DemoWindowWidgetsComboBoxes(); +static void DemoWindowWidgetsImages(); +static void DemoWindowWidgetsListBoxes(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsText(); static void DemoWindowWidgetsTooltips(); @@ -816,240 +819,13 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsBasic(); DemoWindowWidgetsBullets(); DemoWindowWidgetsCollapsingHeaders(); + DemoWindowWidgetsComboBoxes(); + DemoWindowWidgetsImages(); + DemoWindowWidgetsListBoxes(); DemoWindowWidgetsText(); DemoWindowWidgetsTooltips(); DemoWindowWidgetsTreeNodes(); - IMGUI_DEMO_MARKER("Widgets/Images"); - if (ImGui::TreeNode("Images")) - { - ImGuiIO& io = ImGui::GetIO(); - ImGui::TextWrapped( - "Below we are displaying the font texture (which is the only texture we have access to in this demo). " - "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " - "Hover the texture for a zoomed view!"); - - // Below we are displaying the font texture because it is the only texture we have access to inside the demo! - // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that - // will be passed to the rendering backend via the ImDrawCmd structure. - // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top - // of their respective source file to specify what they expect to be stored in ImTextureID, for example: - // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer - // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. - // More: - // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers - // to ImGui::Image(), and gather width/height through your own functions, etc. - // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, - // it will help you debug issues if you are confused about it. - // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). - // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md - // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImTextureID my_tex_id = io.Fonts->TexID; - float my_tex_w = (float)io.Fonts->TexWidth; - float my_tex_h = (float)io.Fonts->TexHeight; - { - ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); - ImVec2 pos = ImGui::GetCursorScreenPos(); - ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left - ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right - ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize)); - ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); - if (ImGui::BeginItemTooltip()) - { - float region_sz = 32.0f; - float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; - float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; - float zoom = 4.0f; - if (region_x < 0.0f) { region_x = 0.0f; } - else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } - if (region_y < 0.0f) { region_y = 0.0f; } - else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } - ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); - ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); - ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); - ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); - ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); - ImGui::EndTooltip(); - } - ImGui::PopStyleVar(); - } - - IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons"); - ImGui::TextWrapped("And now some textured buttons.."); - static int pressed_count = 0; - for (int i = 0; i < 8; i++) - { - // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures. - // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. - // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImGui::PushID(i); - if (i > 0) - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f)); - ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible - ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left - ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture - ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background - ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint - if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col)) - pressed_count += 1; - if (i > 0) - ImGui::PopStyleVar(); - ImGui::PopID(); - ImGui::SameLine(); - } - ImGui::NewLine(); - ImGui::Text("Pressed %d times.", pressed_count); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Combo"); - if (ImGui::TreeNode("Combo")) - { - // Combo Boxes are also called "Dropdown" in other systems - // Expose flags as checkbox for the demo - static ImGuiComboFlags flags = 0; - ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); - ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); - if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) - flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags - if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) - flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags - if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview)) - flags &= ~ImGuiComboFlags_NoPreview; - - // Override default popup height - if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall)) - flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall); - if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular)) - flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular); - if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest)) - flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest); - - // Using the generic BeginCombo() API, you have full control over how to display the combo contents. - // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - // stored in the object itself, etc.) - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_selected_idx = 0; // Here we store our selection data as an index. - - // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) - const char* combo_preview_value = items[item_selected_idx]; - if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) - { - for (int n = 0; n < IM_ARRAYSIZE(items); n++) - { - const bool is_selected = (item_selected_idx == n); - if (ImGui::Selectable(items[n], is_selected)) - item_selected_idx = n; - - // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - - // Show case embedding a filter using a simple trick: displaying the filter inside combo contents. - // See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. - if (ImGui::BeginCombo("combo 2 (w/ filter)", combo_preview_value, flags)) - { - static ImGuiTextFilter filter; - if (ImGui::IsWindowAppearing()) - { - ImGui::SetKeyboardFocusHere(); - filter.Clear(); - } - ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F); - filter.Draw("##Filter", -FLT_MIN); - - for (int n = 0; n < IM_ARRAYSIZE(items); n++) - { - const bool is_selected = (item_selected_idx == n); - if (filter.PassFilter(items[n])) - if (ImGui::Selectable(items[n], is_selected)) - item_selected_idx = n; - } - ImGui::EndCombo(); - } - - ImGui::Spacing(); - ImGui::SeparatorText("One-liner variants"); - HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section."); - - // Simplified one-liner Combo() API, using values packed in a single constant string - // This is a convenience for when the selection set is small and known at compile-time. - static int item_current_2 = 0; - ImGui::Combo("combo 3 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); - - // Simplified one-liner Combo() using an array of const char* - // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. - static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview - ImGui::Combo("combo 4 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); - - // Simplified one-liner Combo() using an accessor function - static int item_current_4 = 0; - ImGui::Combo("combo 5 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items)); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/List Boxes"); - if (ImGui::TreeNode("List boxes")) - { - // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() - // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. - // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() - // to always be called (inconsistent with BeginListBox()/EndListBox()). - - // Using the generic BeginListBox() API, you have full control over how to display the combo contents. - // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively - // stored in the object itself, etc.) - const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; - static int item_selected_idx = 0; // Here we store our selected data as an index. - - static bool item_highlight = false; - int item_highlighted_idx = -1; // Here we store our highlighted data as an index. - ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight); - - if (ImGui::BeginListBox("listbox 1")) - { - for (int n = 0; n < IM_ARRAYSIZE(items); n++) - { - const bool is_selected = (item_selected_idx == n); - if (ImGui::Selectable(items[n], is_selected)) - item_selected_idx = n; - - if (item_highlight && ImGui::IsItemHovered()) - item_highlighted_idx = n; - - // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndListBox(); - } - ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes."); - - // Custom size: use all width, 5 items tall - ImGui::Text("Full-width:"); - if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) - { - for (int n = 0; n < IM_ARRAYSIZE(items); n++) - { - bool is_selected = (item_selected_idx == n); - ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0; - if (ImGui::Selectable(items[n], is_selected, flags)) - item_selected_idx = n; - - // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndListBox(); - } - - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Selectables"); //ImGui::SetNextItemOpen(true, ImGuiCond_Once); if (ImGui::TreeNode("Selectables")) @@ -2758,6 +2534,99 @@ static void DemoWindowWidgetsCollapsingHeaders() // [SECTION] DemoWindowWidgetsComboBoxes() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsComboBoxes() +{ + IMGUI_DEMO_MARKER("Widgets/Combo"); + if (ImGui::TreeNode("Combo")) + { + // Combo Boxes are also called "Dropdown" in other systems + // Expose flags as checkbox for the demo + static ImGuiComboFlags flags = 0; + ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", &flags, ImGuiComboFlags_PopupAlignLeft); + ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo"); + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", &flags, ImGuiComboFlags_NoArrowButton)) + flags &= ~ImGuiComboFlags_NoPreview; // Clear incompatible flags + if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", &flags, ImGuiComboFlags_NoPreview)) + flags &= ~(ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_WidthFitPreview); // Clear incompatible flags + if (ImGui::CheckboxFlags("ImGuiComboFlags_WidthFitPreview", &flags, ImGuiComboFlags_WidthFitPreview)) + flags &= ~ImGuiComboFlags_NoPreview; + + // Override default popup height + if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightSmall", &flags, ImGuiComboFlags_HeightSmall)) + flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightSmall); + if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightRegular", &flags, ImGuiComboFlags_HeightRegular)) + flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightRegular); + if (ImGui::CheckboxFlags("ImGuiComboFlags_HeightLargest", &flags, ImGuiComboFlags_HeightLargest)) + flags &= ~(ImGuiComboFlags_HeightMask_ & ~ImGuiComboFlags_HeightLargest); + + // Using the generic BeginCombo() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_selected_idx = 0; // Here we store our selection data as an index. + + // Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[]) + const char* combo_preview_value = items[item_selected_idx]; + if (ImGui::BeginCombo("combo 1", combo_preview_value, flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_selected_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_selected_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + // Show case embedding a filter using a simple trick: displaying the filter inside combo contents. + // See https://github.com/ocornut/imgui/issues/718 for advanced/esoteric alternatives. + if (ImGui::BeginCombo("combo 2 (w/ filter)", combo_preview_value, flags)) + { + static ImGuiTextFilter filter; + if (ImGui::IsWindowAppearing()) + { + ImGui::SetKeyboardFocusHere(); + filter.Clear(); + } + ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F); + filter.Draw("##Filter", -FLT_MIN); + + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_selected_idx == n); + if (filter.PassFilter(items[n])) + if (ImGui::Selectable(items[n], is_selected)) + item_selected_idx = n; + } + ImGui::EndCombo(); + } + + ImGui::Spacing(); + ImGui::SeparatorText("One-liner variants"); + HelpMarker("The Combo() function is not greatly useful apart from cases were you want to embed all options in a single strings.\nFlags above don't apply to this section."); + + // Simplified one-liner Combo() API, using values packed in a single constant string + // This is a convenience for when the selection set is small and known at compile-time. + static int item_current_2 = 0; + ImGui::Combo("combo 3 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); + + // Simplified one-liner Combo() using an array of const char* + // This is not very useful (may obsolete): prefer using BeginCombo()/EndCombo() for full control. + static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview + ImGui::Combo("combo 4 (array)", &item_current_3, items, IM_ARRAYSIZE(items)); + + // Simplified one-liner Combo() using an accessor function + static int item_current_4 = 0; + ImGui::Combo("combo 5 (function)", &item_current_4, [](void* data, int n) { return ((const char**)data)[n]; }, items, IM_ARRAYSIZE(items)); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsDataTypes() //----------------------------------------------------------------------------- @@ -2778,10 +2647,156 @@ static void DemoWindowWidgetsCollapsingHeaders() // [SECTION] DemoWindowWidgetsImages() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsImages() +{ + IMGUI_DEMO_MARKER("Widgets/Images"); + if (ImGui::TreeNode("Images")) + { + ImGuiIO& io = ImGui::GetIO(); + ImGui::TextWrapped( + "Below we are displaying the font texture (which is the only texture we have access to in this demo). " + "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. " + "Hover the texture for a zoomed view!"); + + // Below we are displaying the font texture because it is the only texture we have access to inside the demo! + // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that + // will be passed to the rendering backend via the ImDrawCmd structure. + // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top + // of their respective source file to specify what they expect to be stored in ImTextureID, for example: + // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer + // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. + // More: + // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers + // to ImGui::Image(), and gather width/height through your own functions, etc. + // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, + // it will help you debug issues if you are confused about it. + // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). + // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md + // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImTextureID my_tex_id = io.Fonts->TexID; + float my_tex_w = (float)io.Fonts->TexWidth; + float my_tex_h = (float)io.Fonts->TexHeight; + { + ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left + ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right + ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize)); + ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + if (ImGui::BeginItemTooltip()) + { + float region_sz = 32.0f; + float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; + float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; + float zoom = 4.0f; + if (region_x < 0.0f) { region_x = 0.0f; } + else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; } + if (region_y < 0.0f) { region_y = 0.0f; } + else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; } + ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y); + ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz); + ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h); + ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h); + ImGui::ImageWithBg(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImGui::EndTooltip(); + } + ImGui::PopStyleVar(); + } + + IMGUI_DEMO_MARKER("Widgets/Images/Textured buttons"); + ImGui::TextWrapped("And now some textured buttons.."); + static int pressed_count = 0; + for (int i = 0; i < 8; i++) + { + // UV coordinates are often (0.0f, 0.0f) and (1.0f, 1.0f) to display an entire textures. + // Here are trying to display only a 32x32 pixels area of the texture, hence the UV computation. + // Read about UV coordinates here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + ImGui::PushID(i); + if (i > 0) + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(i - 1.0f, i - 1.0f)); + ImVec2 size = ImVec2(32.0f, 32.0f); // Size of the image we want to make visible + ImVec2 uv0 = ImVec2(0.0f, 0.0f); // UV coordinates for lower-left + ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h); // UV coordinates for (32,32) in our texture + ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); // Black background + ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint + if (ImGui::ImageButton("", my_tex_id, size, uv0, uv1, bg_col, tint_col)) + pressed_count += 1; + if (i > 0) + ImGui::PopStyleVar(); + ImGui::PopID(); + ImGui::SameLine(); + } + ImGui::NewLine(); + ImGui::Text("Pressed %d times.", pressed_count); + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsListBoxes() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsListBoxes() +{ + IMGUI_DEMO_MARKER("Widgets/List Boxes"); + if (ImGui::TreeNode("List boxes")) + { + // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() + // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. + // You may be tempted to simply use BeginChild() directly. However note that BeginChild() requires EndChild() + // to always be called (inconsistent with BeginListBox()/EndListBox()). + + // Using the generic BeginListBox() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // stored in the object itself, etc.) + const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; + static int item_selected_idx = 0; // Here we store our selected data as an index. + + static bool item_highlight = false; + int item_highlighted_idx = -1; // Here we store our highlighted data as an index. + ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight); + + if (ImGui::BeginListBox("listbox 1")) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_selected_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_selected_idx = n; + + if (item_highlight && ImGui::IsItemHovered()) + item_highlighted_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + ImGui::SameLine(); HelpMarker("Here we are sharing selection state between both boxes."); + + // Custom size: use all width, 5 items tall + ImGui::Text("Full-width:"); + if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + bool is_selected = (item_selected_idx == n); + ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0; + if (ImGui::Selectable(items[n], is_selected, flags)) + item_selected_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsMultiComponents() //----------------------------------------------------------------------------- From 4450d61ac25771bd0116754607a33a5eb1da33b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:01:41 +0100 Subject: [PATCH 279/716] Demo: (Refactor) Moved code into DemoWindowWidgetsSelectables(), DemoWindowWidgetsTextFilter(), DemoWindowWidgetsTextInputs() sections. --- imgui_demo.cpp | 779 +++++++++++++++++++++++++------------------------ 1 file changed, 397 insertions(+), 382 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3b08b152f73f..56688d4c4879 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -256,8 +256,11 @@ static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); static void DemoWindowWidgetsImages(); static void DemoWindowWidgetsListBoxes(); +static void DemoWindowWidgetsSelectables(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsText(); +static void DemoWindowWidgetsTextFilter(); +static void DemoWindowWidgetsTextInput(); static void DemoWindowWidgetsTooltips(); static void DemoWindowWidgetsTreeNodes(); static void DemoWindowLayout(); @@ -822,347 +825,14 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsComboBoxes(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); + DemoWindowWidgetsSelectables(); + DemoWindowWidgetsSelectionAndMultiSelect(demo_data); DemoWindowWidgetsText(); + DemoWindowWidgetsTextFilter(); + DemoWindowWidgetsTextInput(); DemoWindowWidgetsTooltips(); DemoWindowWidgetsTreeNodes(); - IMGUI_DEMO_MARKER("Widgets/Selectables"); - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (ImGui::TreeNode("Selectables")) - { - // Selectable() has 2 overloads: - // - The one taking "bool selected" as a read-only selection information. - // When Selectable() has been clicked it returns true and you can alter selection state accordingly. - // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) - // The earlier is more flexible, as in real application your selection may be stored in many different ways - // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). - IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); - if (ImGui::TreeNode("Basic")) - { - static bool selection[5] = { false, true, false, false }; - ImGui::Selectable("1. I am selectable", &selection[0]); - ImGui::Selectable("2. I am selectable", &selection[1]); - ImGui::Selectable("3. I am selectable", &selection[2]); - if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick)) - if (ImGui::IsMouseDoubleClicked(0)) - selection[3] = !selection[3]; - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line"); - if (ImGui::TreeNode("Rendering more items on the same line")) - { - // (1) Using SetNextItemAllowOverlap() - // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. - static bool selected[3] = { false, false, false }; - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2"); - ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3"); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables"); - if (ImGui::TreeNode("In Tables")) - { - static bool selected[10] = {}; - - if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) - { - for (int i = 0; i < 10; i++) - { - char label[32]; - sprintf(label, "Item %d", i); - ImGui::TableNextColumn(); - ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap - } - ImGui::EndTable(); - } - ImGui::Spacing(); - if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) - { - for (int i = 0; i < 10; i++) - { - char label[32]; - sprintf(label, "Item %d", i); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns); - ImGui::TableNextColumn(); - ImGui::Text("Some other contents"); - ImGui::TableNextColumn(); - ImGui::Text("123456"); - } - ImGui::EndTable(); - } - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); - if (ImGui::TreeNode("Grid")) - { - static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; - - // Add in a bit of silly fun... - const float time = (float)ImGui::GetTime(); - const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... - if (winning_state) - ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); - - for (int y = 0; y < 4; y++) - for (int x = 0; x < 4; x++) - { - if (x > 0) - ImGui::SameLine(); - ImGui::PushID(y * 4 + x); - if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) - { - // Toggle clicked cell + toggle neighbors - selected[y][x] ^= 1; - if (x > 0) { selected[y][x - 1] ^= 1; } - if (x < 3) { selected[y][x + 1] ^= 1; } - if (y > 0) { selected[y - 1][x] ^= 1; } - if (y < 3) { selected[y + 1][x] ^= 1; } - } - ImGui::PopID(); - } - - if (winning_state) - ImGui::PopStyleVar(); - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment"); - if (ImGui::TreeNode("Alignment")) - { - HelpMarker( - "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " - "basis using PushStyleVar(). You'll probably want to always keep your default situation to " - "left-align otherwise it becomes difficult to layout multiple items on a same line"); - static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; - for (int y = 0; y < 3; y++) - { - for (int x = 0; x < 3; x++) - { - ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); - char name[32]; - sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); - if (x > 0) ImGui::SameLine(); - ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); - ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); - ImGui::PopStyleVar(); - } - } - ImGui::TreePop(); - } - ImGui::TreePop(); - } - - DemoWindowWidgetsSelectionAndMultiSelect(demo_data); - - // To wire InputText() with std::string or any other custom string type, - // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. - IMGUI_DEMO_MARKER("Widgets/Text Input"); - if (ImGui::TreeNode("Text Input")) - { - IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input"); - if (ImGui::TreeNode("Multi-line Text Input")) - { - // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize - // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. - static char text[1024 * 16] = - "/*\n" - " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" - " the hexadecimal encoding of one offending instruction,\n" - " more formally, the invalid operand with locked CMPXCHG8B\n" - " instruction bug, is a design flaw in the majority of\n" - " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" - " processors (all in the P5 microarchitecture).\n" - "*/\n\n" - "label:\n" - "\tlock cmpxchg8b eax\n"; - - static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; - HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); - ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); - ImGui::SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets."); - ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); - ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input"); - if (ImGui::TreeNode("Filtered Text Input")) - { - struct TextFilters - { - // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) - static int FilterCasingSwap(ImGuiInputTextCallbackData* data) - { - if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase - else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase - return 0; - } - - // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) - static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) - { - if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) - return 0; - return 1; - } - }; - - static char buf1[32] = ""; ImGui::InputText("default", buf1, 32); - static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal); - static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); - static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase); - static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank); - static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. - static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text Input/Password input"); - if (ImGui::TreeNode("Password Input")) - { - static char password[64] = "password123"; - ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); - ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); - ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); - ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks"); - if (ImGui::TreeNode("Completion, History, Edit Callbacks")) - { - struct Funcs - { - static int MyCallback(ImGuiInputTextCallbackData* data) - { - if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) - { - data->InsertChars(data->CursorPos, ".."); - } - else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) - { - if (data->EventKey == ImGuiKey_UpArrow) - { - data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, "Pressed Up!"); - data->SelectAll(); - } - else if (data->EventKey == ImGuiKey_DownArrow) - { - data->DeleteChars(0, data->BufTextLen); - data->InsertChars(0, "Pressed Down!"); - data->SelectAll(); - } - } - else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) - { - // Toggle casing of first character - char c = data->Buf[0]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; - data->BufDirty = true; - - // Increment a counter - int* p_int = (int*)data->UserData; - *p_int = *p_int + 1; - } - return 0; - } - }; - static char buf1[64]; - ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); - ImGui::SameLine(); HelpMarker( - "Here we append \"..\" each time Tab is pressed. " - "See 'Examples>Console' for a more meaningful demonstration of using this callback."); - - static char buf2[64]; - ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); - ImGui::SameLine(); HelpMarker( - "Here we replace and select text each time Up/Down are pressed. " - "See 'Examples>Console' for a more meaningful demonstration of using this callback."); - - static char buf3[64]; - static int edit_count = 0; - ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); - ImGui::SameLine(); HelpMarker( - "Here we toggle the casing of the first character on every edit + count edits."); - ImGui::SameLine(); ImGui::Text("(%d)", edit_count); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback"); - if (ImGui::TreeNode("Resize Callback")) - { - // To wire InputText() with std::string or any other custom string type, - // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper - // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. - HelpMarker( - "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" - "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); - struct Funcs - { - static int MyResizeCallback(ImGuiInputTextCallbackData* data) - { - if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) - { - ImVector* my_str = (ImVector*)data->UserData; - IM_ASSERT(my_str->begin() == data->Buf); - my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 - data->Buf = my_str->begin(); - } - return 0; - } - - // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. - // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' - static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) - { - IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); - return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); - } - }; - - // For this demo we are using ImVector as a string container. - // Note that because we need to store a terminating zero character, our size/capacity are 1 more - // than usually reported by a typical string class. - static ImVector my_str; - if (my_str.empty()) - my_str.push_back(0); - Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); - ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment"); - if (ImGui::TreeNode("Eliding, Alignment")) - { - static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp"; - static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft; - ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft); - ImGui::InputText("Path", buf1, IM_ARRAYSIZE(buf1), flags); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous"); - if (ImGui::TreeNode("Miscellaneous")) - { - static char buf1[16]; - static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll; - ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); - ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo); - ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags); - ImGui::TreePop(); - } - - ImGui::TreePop(); - } - // Tabs IMGUI_DEMO_MARKER("Widgets/Tabs"); if (ImGui::TreeNode("Tabs")) @@ -2240,26 +1910,6 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section."); ImGui::TreePop(); } - - IMGUI_DEMO_MARKER("Widgets/Text Filter"); - if (ImGui::TreeNode("Text Filter")) - { - // Helper class to easy setup a text filter. - // You may want to implement a more feature-full filtering scheme in your own application. - HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings."); - static ImGuiTextFilter filter; - ImGui::Text("Filter usage:\n" - " \"\" display all lines\n" - " \"xxx\" display lines containing \"xxx\"\n" - " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" - " \"-xxx\" hide lines containing \"xxx\""); - filter.Draw(); - const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; - for (int i = 0; i < IM_ARRAYSIZE(lines); i++) - if (filter.PassFilter(lines[i])) - ImGui::BulletText("%s", lines[i]); - ImGui::TreePop(); - } } //----------------------------------------------------------------------------- @@ -2790,31 +2440,171 @@ static void DemoWindowWidgetsListBoxes() if (is_selected) ImGui::SetItemDefaultFocus(); } - ImGui::EndListBox(); + ImGui::EndListBox(); + } + + ImGui::TreePop(); + } +} + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsMultiComponents() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsPlotting() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsProgressBars() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsQueryingStatuses() +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsSelectables() +//----------------------------------------------------------------------------- + +static void DemoWindowWidgetsSelectables() +{ + IMGUI_DEMO_MARKER("Widgets/Selectables"); + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (ImGui::TreeNode("Selectables")) + { + // Selectable() has 2 overloads: + // - The one taking "bool selected" as a read-only selection information. + // When Selectable() has been clicked it returns true and you can alter selection state accordingly. + // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases) + // The earlier is more flexible, as in real application your selection may be stored in many different ways + // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc). + IMGUI_DEMO_MARKER("Widgets/Selectables/Basic"); + if (ImGui::TreeNode("Basic")) + { + static bool selection[5] = { false, true, false, false }; + ImGui::Selectable("1. I am selectable", &selection[0]); + ImGui::Selectable("2. I am selectable", &selection[1]); + ImGui::Selectable("3. I am selectable", &selection[2]); + if (ImGui::Selectable("4. I am double clickable", selection[3], ImGuiSelectableFlags_AllowDoubleClick)) + if (ImGui::IsMouseDoubleClicked(0)) + selection[3] = !selection[3]; + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line"); + if (ImGui::TreeNode("Rendering more items on the same line")) + { + // (1) Using SetNextItemAllowOverlap() + // (2) Using the Selectable() override that takes "bool* p_selected" parameter, the bool value is toggled automatically. + static bool selected[3] = { false, false, false }; + ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(); ImGui::SmallButton("Link 1"); + ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(); ImGui::SmallButton("Link 2"); + ImGui::SetNextItemAllowOverlap(); ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(); ImGui::SmallButton("Link 3"); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables"); + if (ImGui::TreeNode("In Tables")) + { + static bool selected[10] = {}; + + if (ImGui::BeginTable("split1", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + { + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i]); // FIXME-TABLE: Selection overlap + } + ImGui::EndTable(); + } + ImGui::Spacing(); + if (ImGui::BeginTable("split2", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders)) + { + for (int i = 0; i < 10; i++) + { + char label[32]; + sprintf(label, "Item %d", i); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Selectable(label, &selected[i], ImGuiSelectableFlags_SpanAllColumns); + ImGui::TableNextColumn(); + ImGui::Text("Some other contents"); + ImGui::TableNextColumn(); + ImGui::Text("123456"); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Selectables/Grid"); + if (ImGui::TreeNode("Grid")) + { + static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } }; + + // Add in a bit of silly fun... + const float time = (float)ImGui::GetTime(); + const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected... + if (winning_state) + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f))); + + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + { + if (x > 0) + ImGui::SameLine(); + ImGui::PushID(y * 4 + x); + if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50))) + { + // Toggle clicked cell + toggle neighbors + selected[y][x] ^= 1; + if (x > 0) { selected[y][x - 1] ^= 1; } + if (x < 3) { selected[y][x + 1] ^= 1; } + if (y > 0) { selected[y - 1][x] ^= 1; } + if (y < 3) { selected[y + 1][x] ^= 1; } + } + ImGui::PopID(); + } + + if (winning_state) + ImGui::PopStyleVar(); + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment"); + if (ImGui::TreeNode("Alignment")) + { + HelpMarker( + "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item " + "basis using PushStyleVar(). You'll probably want to always keep your default situation to " + "left-align otherwise it becomes difficult to layout multiple items on a same line"); + static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true }; + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 3; x++) + { + ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f); + char name[32]; + sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y); + if (x > 0) ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment); + ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80)); + ImGui::PopStyleVar(); + } + } + ImGui::TreePop(); } - ImGui::TreePop(); } } //----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgetsMultiComponents() -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgetsPlotting() -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgetsProgressBars() -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgetsQueryingStatuses() -//----------------------------------------------------------------------------- - +// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() //----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgetsSelectables() +// Multi-selection demos +// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select //----------------------------------------------------------------------------- static const char* ExampleNames[] = @@ -3042,13 +2832,6 @@ struct ExampleDualListBox } }; -//----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgetsSelectionAndMultiSelect() -//----------------------------------------------------------------------------- -// Multi-selection demos -// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select -//----------------------------------------------------------------------------- - static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data) { IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select"); @@ -3874,10 +3657,242 @@ static void DemoWindowWidgetsText() // [SECTION] DemoWindowWidgetsTextFilter() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsTextFilter() +{ + IMGUI_DEMO_MARKER("Widgets/Text Filter"); + if (ImGui::TreeNode("Text Filter")) + { + // Helper class to easy setup a text filter. + // You may want to implement a more feature-full filtering scheme in your own application. + HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings."); + static ImGuiTextFilter filter; + ImGui::Text("Filter usage:\n" + " \"\" display all lines\n" + " \"xxx\" display lines containing \"xxx\"\n" + " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n" + " \"-xxx\" hide lines containing \"xxx\""); + filter.Draw(); + const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" }; + for (int i = 0; i < IM_ARRAYSIZE(lines); i++) + if (filter.PassFilter(lines[i])) + ImGui::BulletText("%s", lines[i]); + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsTextInput() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsTextInput() +{ + // To wire InputText() with std::string or any other custom string type, + // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file. + IMGUI_DEMO_MARKER("Widgets/Text Input"); + if (ImGui::TreeNode("Text Input")) + { + IMGUI_DEMO_MARKER("Widgets/Text Input/Multi-line Text Input"); + if (ImGui::TreeNode("Multi-line Text Input")) + { + // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize + // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings. + static char text[1024 * 16] = + "/*\n" + " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n" + " the hexadecimal encoding of one offending instruction,\n" + " more formally, the invalid operand with locked CMPXCHG8B\n" + " instruction bug, is a design flaw in the majority of\n" + " Intel Pentium, Pentium MMX, and Pentium OverDrive\n" + " processors (all in the P5 microarchitecture).\n" + "*/\n\n" + "label:\n" + "\tlock cmpxchg8b eax\n"; + + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput; + HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include in here)"); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", &flags, ImGuiInputTextFlags_AllowTabInput); + ImGui::SameLine(); HelpMarker("When _AllowTabInput is set, passing through the widget with Tabbing doesn't automatically activate it, in order to also cycling through subsequent widgets."); + ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", &flags, ImGuiInputTextFlags_CtrlEnterForNewLine); + ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Filtered Text Input"); + if (ImGui::TreeNode("Filtered Text Input")) + { + struct TextFilters + { + // Modify character input by altering 'data->Eventchar' (ImGuiInputTextFlags_CallbackCharFilter callback) + static int FilterCasingSwap(ImGuiInputTextCallbackData* data) + { + if (data->EventChar >= 'a' && data->EventChar <= 'z') { data->EventChar -= 'a' - 'A'; } // Lowercase becomes uppercase + else if (data->EventChar >= 'A' && data->EventChar <= 'Z') { data->EventChar += 'a' - 'A'; } // Uppercase becomes lowercase + return 0; + } + + // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i', otherwise return 1 (filter out) + static int FilterImGuiLetters(ImGuiInputTextCallbackData* data) + { + if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) + return 0; + return 1; + } + }; + + static char buf1[32] = ""; ImGui::InputText("default", buf1, 32); + static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal); + static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase); + static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank); + static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. + static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Password input"); + if (ImGui::TreeNode("Password Input")) + { + static char password[64] = "password123"; + ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n"); + ImGui::InputTextWithHint("password (w/ hint)", "", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password); + ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password)); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Completion, History, Edit Callbacks"); + if (ImGui::TreeNode("Completion, History, Edit Callbacks")) + { + struct Funcs + { + static int MyCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion) + { + data->InsertChars(data->CursorPos, ".."); + } + else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory) + { + if (data->EventKey == ImGuiKey_UpArrow) + { + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, "Pressed Up!"); + data->SelectAll(); + } + else if (data->EventKey == ImGuiKey_DownArrow) + { + data->DeleteChars(0, data->BufTextLen); + data->InsertChars(0, "Pressed Down!"); + data->SelectAll(); + } + } + else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit) + { + // Toggle casing of first character + char c = data->Buf[0]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32; + data->BufDirty = true; + + // Increment a counter + int* p_int = (int*)data->UserData; + *p_int = *p_int + 1; + } + return 0; + } + }; + static char buf1[64]; + ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); + ImGui::SameLine(); HelpMarker( + "Here we append \"..\" each time Tab is pressed. " + "See 'Examples>Console' for a more meaningful demonstration of using this callback."); + + static char buf2[64]; + ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); + ImGui::SameLine(); HelpMarker( + "Here we replace and select text each time Up/Down are pressed. " + "See 'Examples>Console' for a more meaningful demonstration of using this callback."); + + static char buf3[64]; + static int edit_count = 0; + ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); + ImGui::SameLine(); HelpMarker( + "Here we toggle the casing of the first character on every edit + count edits."); + ImGui::SameLine(); ImGui::Text("(%d)", edit_count); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Resize Callback"); + if (ImGui::TreeNode("Resize Callback")) + { + // To wire InputText() with std::string or any other custom string type, + // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper + // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string. + HelpMarker( + "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n" + "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string."); + struct Funcs + { + static int MyResizeCallback(ImGuiInputTextCallbackData* data) + { + if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) + { + ImVector* my_str = (ImVector*)data->UserData; + IM_ASSERT(my_str->begin() == data->Buf); + my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1 + data->Buf = my_str->begin(); + } + return 0; + } + + // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace. + // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)' + static bool MyInputTextMultiline(const char* label, ImVector* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0) + { + IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); + return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str); + } + }; + + // For this demo we are using ImVector as a string container. + // Note that because we need to store a terminating zero character, our size/capacity are 1 more + // than usually reported by a typical string class. + static ImVector my_str; + if (my_str.empty()) + my_str.push_back(0); + Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16)); + ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity()); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Eliding, Alignment"); + if (ImGui::TreeNode("Eliding, Alignment")) + { + static char buf1[128] = "/path/to/some/folder/with/long/filename.cpp"; + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_ElideLeft; + ImGui::CheckboxFlags("ImGuiInputTextFlags_ElideLeft", &flags, ImGuiInputTextFlags_ElideLeft); + ImGui::InputText("Path", buf1, IM_ARRAYSIZE(buf1), flags); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Text Input/Miscellaneous"); + if (ImGui::TreeNode("Miscellaneous")) + { + static char buf1[16]; + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_EscapeClearsAll; + ImGui::CheckboxFlags("ImGuiInputTextFlags_EscapeClearsAll", &flags, ImGuiInputTextFlags_EscapeClearsAll); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_NoUndoRedo", &flags, ImGuiInputTextFlags_NoUndoRedo); + ImGui::InputText("Hello", buf1, IM_ARRAYSIZE(buf1), flags); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsTooltips() //----------------------------------------------------------------------------- From 4d0c776a8089ccaa272f1cf51097e1d606f66d99 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:08:22 +0100 Subject: [PATCH 280/716] Demo: (Refactor) Moved code into DemoWindowWidgetsPlotting(), DemoWindowWidgetsProgressBars(), DemoWindowWidgetsTabs() sections. --- imgui_demo.cpp | 505 +++++++++++++++++++++++++------------------------ 1 file changed, 259 insertions(+), 246 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 56688d4c4879..468e32b598d9 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -256,8 +256,11 @@ static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); static void DemoWindowWidgetsImages(); static void DemoWindowWidgetsListBoxes(); +static void DemoWindowWidgetsPlotting(); +static void DemoWindowWidgetsProgressBars(); static void DemoWindowWidgetsSelectables(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); +static void DemoWindowWidgetsTabs(); static void DemoWindowWidgetsText(); static void DemoWindowWidgetsTextFilter(); static void DemoWindowWidgetsTextInput(); @@ -825,260 +828,17 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsComboBoxes(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); + DemoWindowWidgetsPlotting(); + DemoWindowWidgetsProgressBars(); DemoWindowWidgetsSelectables(); DemoWindowWidgetsSelectionAndMultiSelect(demo_data); + DemoWindowWidgetsTabs(); DemoWindowWidgetsText(); DemoWindowWidgetsTextFilter(); DemoWindowWidgetsTextInput(); DemoWindowWidgetsTooltips(); DemoWindowWidgetsTreeNodes(); - // Tabs - IMGUI_DEMO_MARKER("Widgets/Tabs"); - if (ImGui::TreeNode("Tabs")) - { - IMGUI_DEMO_MARKER("Widgets/Tabs/Basic"); - if (ImGui::TreeNode("Basic")) - { - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; - if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) - { - if (ImGui::BeginTabItem("Avocado")) - { - ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Broccoli")) - { - ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Cucumber")) - { - ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); - } - ImGui::Separator(); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button"); - if (ImGui::TreeNode("Advanced & Close Button")) - { - // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). - static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; - ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); - ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); - ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline); - if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) - tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) - tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) - tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); - - // Tab Bar - ImGui::AlignTextToFramePadding(); - ImGui::Text("Opened:"); - const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; - static bool opened[4] = { true, true, true, true }; // Persistent user state - for (int n = 0; n < IM_ARRAYSIZE(opened); n++) - { - ImGui::SameLine(); - ImGui::Checkbox(names[n], &opened[n]); - } - - // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): - // the underlying bool will be set to false when the tab is closed. - if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) - { - for (int n = 0; n < IM_ARRAYSIZE(opened); n++) - if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) - { - ImGui::Text("This is the %s tab!", names[n]); - if (n & 1) - ImGui::Text("I am an odd tab."); - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); - } - ImGui::Separator(); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags"); - if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) - { - static ImVector active_tabs; - static int next_tab_id = 0; - if (next_tab_id == 0) // Initialize with some default tabs - for (int i = 0; i < 3; i++) - active_tabs.push_back(next_tab_id++); - - // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. - // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... - // but they tend to make more sense together) - static bool show_leading_button = true; - static bool show_trailing_button = true; - ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); - ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); - - // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs - static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; - ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) - tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); - if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) - tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); - - if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) - { - // Demo a Leading TabItemButton(): click the "?" button to open a menu - if (show_leading_button) - if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) - ImGui::OpenPopup("MyHelpMenu"); - if (ImGui::BeginPopup("MyHelpMenu")) - { - ImGui::Selectable("Hello!"); - ImGui::EndPopup(); - } - - // Demo Trailing Tabs: click the "+" button to add a new tab. - // (In your app you may want to use a font icon instead of the "+") - // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. - if (show_trailing_button) - if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) - active_tabs.push_back(next_tab_id++); // Add new tab - - // Submit our regular tabs - for (int n = 0; n < active_tabs.Size; ) - { - bool open = true; - char name[16]; - snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); - if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) - { - ImGui::Text("This is the %s tab!", name); - ImGui::EndTabItem(); - } - - if (!open) - active_tabs.erase(active_tabs.Data + n); - else - n++; - } - - ImGui::EndTabBar(); - } - ImGui::Separator(); - ImGui::TreePop(); - } - ImGui::TreePop(); - } - - // Plot/Graph widgets are not very good. - // Consider using a third-party library such as ImPlot: https://github.com/epezent/implot - // (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) - IMGUI_DEMO_MARKER("Widgets/Plotting"); - if (ImGui::TreeNode("Plotting")) - { - static bool animate = true; - ImGui::Checkbox("Animate", &animate); - - // Plot as lines and plot as histogram - static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; - ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); - ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); - //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!"); - - // Fill an array of contiguous float values to plot - // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float - // and the sizeof() of your structure in the "stride" parameter. - static float values[90] = {}; - static int values_offset = 0; - static double refresh_time = 0.0; - if (!animate || refresh_time == 0.0) - refresh_time = ImGui::GetTime(); - while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo - { - static float phase = 0.0f; - values[values_offset] = cosf(phase); - values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); - phase += 0.10f * values_offset; - refresh_time += 1.0f / 60.0f; - } - - // Plots can display overlay texts - // (in this example, we will display an average value) - { - float average = 0.0f; - for (int n = 0; n < IM_ARRAYSIZE(values); n++) - average += values[n]; - average /= (float)IM_ARRAYSIZE(values); - char overlay[32]; - sprintf(overlay, "avg %f", average); - ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); - } - - // Use functions to generate output - // FIXME: This is actually VERY awkward because current plot API only pass in indices. - // We probably want an API passing floats and user provide sample rate/count. - struct Funcs - { - static float Sin(void*, int i) { return sinf(i * 0.1f); } - static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } - }; - static int func_type = 0, display_count = 70; - ImGui::SeparatorText("Functions"); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); - ImGui::Combo("func", &func_type, "Sin\0Saw\0"); - ImGui::SameLine(); - ImGui::SliderInt("Sample count", &display_count, 1, 400); - float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; - ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); - ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); - ImGui::Separator(); - - ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); - ImGui::TextLinkOpenURL("https://github.com/epezent/implot"); - ImGui::Separator(); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Progress Bars"); - if (ImGui::TreeNode("Progress Bars")) - { - // Animate a simple progress bar - static float progress = 0.0f, progress_dir = 1.0f; - progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; - if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } - if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } - - // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, - // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. - ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::Text("Progress Bar"); - - float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); - char buf[32]; - sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); - ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); - - // Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value. - // Adjust the factor if you want to adjust the animation speed. - ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching.."); - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); - ImGui::Text("Indeterminate"); - - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Color"); if (ImGui::TreeNode("Color/Picker Widgets")) { @@ -2455,10 +2215,114 @@ static void DemoWindowWidgetsListBoxes() // [SECTION] DemoWindowWidgetsPlotting() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsPlotting() +{ + // Plot/Graph widgets are not very good. +// Consider using a third-party library such as ImPlot: https://github.com/epezent/implot +// (see others https://github.com/ocornut/imgui/wiki/Useful-Extensions) + IMGUI_DEMO_MARKER("Widgets/Plotting"); + if (ImGui::TreeNode("Plotting")) + { + ImGui::Text("Need better plotting and graphing? Consider using ImPlot:"); + ImGui::TextLinkOpenURL("https://github.com/epezent/implot"); + ImGui::Separator(); + + static bool animate = true; + ImGui::Checkbox("Animate", &animate); + + // Plot as lines and plot as histogram + static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; + ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr)); + ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f)); + //ImGui::SameLine(); HelpMarker("Consider using ImPlot instead!"); + + // Fill an array of contiguous float values to plot + // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float + // and the sizeof() of your structure in the "stride" parameter. + static float values[90] = {}; + static int values_offset = 0; + static double refresh_time = 0.0; + if (!animate || refresh_time == 0.0) + refresh_time = ImGui::GetTime(); + while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo + { + static float phase = 0.0f; + values[values_offset] = cosf(phase); + values_offset = (values_offset + 1) % IM_ARRAYSIZE(values); + phase += 0.10f * values_offset; + refresh_time += 1.0f / 60.0f; + } + + // Plots can display overlay texts + // (in this example, we will display an average value) + { + float average = 0.0f; + for (int n = 0; n < IM_ARRAYSIZE(values); n++) + average += values[n]; + average /= (float)IM_ARRAYSIZE(values); + char overlay[32]; + sprintf(overlay, "avg %f", average); + ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f)); + } + + // Use functions to generate output + // FIXME: This is actually VERY awkward because current plot API only pass in indices. + // We probably want an API passing floats and user provide sample rate/count. + struct Funcs + { + static float Sin(void*, int i) { return sinf(i * 0.1f); } + static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; } + }; + static int func_type = 0, display_count = 70; + ImGui::SeparatorText("Functions"); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + ImGui::Combo("func", &func_type, "Sin\0Saw\0"); + ImGui::SameLine(); + ImGui::SliderInt("Sample count", &display_count, 1, 400); + float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw; + ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80)); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsProgressBars() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsProgressBars() +{ + IMGUI_DEMO_MARKER("Widgets/Progress Bars"); + if (ImGui::TreeNode("Progress Bars")) + { + // Animate a simple progress bar + static float progress = 0.0f, progress_dir = 1.0f; + progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime; + if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; } + if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; } + + // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width, + // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth. + ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f)); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Progress Bar"); + + float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f); + char buf[32]; + sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753); + ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf); + + // Pass an animated negative value, e.g. -1.0f * (float)ImGui::GetTime() is the recommended value. + // Adjust the factor if you want to adjust the animation speed. + ImGui::ProgressBar(-1.0f * (float)ImGui::GetTime(), ImVec2(0.0f, 0.0f), "Searching.."); + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); + ImGui::Text("Indeterminate"); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsQueryingStatuses() //----------------------------------------------------------------------------- @@ -3571,6 +3435,155 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d // [SECTION] DemoWindowWidgetsTabs() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsTabs() +{ + IMGUI_DEMO_MARKER("Widgets/Tabs"); + if (ImGui::TreeNode("Tabs")) + { + IMGUI_DEMO_MARKER("Widgets/Tabs/Basic"); + if (ImGui::TreeNode("Basic")) + { + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None; + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + if (ImGui::BeginTabItem("Avocado")) + { + ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Broccoli")) + { + ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + if (ImGui::BeginTabItem("Cucumber")) + { + ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah"); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Tabs/Advanced & Close Button"); + if (ImGui::TreeNode("Advanced & Close Button")) + { + // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0). + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; + ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", &tab_bar_flags, ImGuiTabBarFlags_Reorderable); + ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); + ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline); + if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) + tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + // Tab Bar + ImGui::AlignTextToFramePadding(); + ImGui::Text("Opened:"); + const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" }; + static bool opened[4] = { true, true, true, true }; // Persistent user state + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + { + ImGui::SameLine(); + ImGui::Checkbox(names[n], &opened[n]); + } + + // Passing a bool* to BeginTabItem() is similar to passing one to Begin(): + // the underlying bool will be set to false when the tab is closed. + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + for (int n = 0; n < IM_ARRAYSIZE(opened); n++) + if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", names[n]); + if (n & 1) + ImGui::Text("I am an odd tab."); + ImGui::EndTabItem(); + } + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Tabs/TabItemButton & Leading-Trailing flags"); + if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags")) + { + static ImVector active_tabs; + static int next_tab_id = 0; + if (next_tab_id == 0) // Initialize with some default tabs + for (int i = 0; i < 3; i++) + active_tabs.push_back(next_tab_id++); + + // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together. + // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags... + // but they tend to make more sense together) + static bool show_leading_button = true; + static bool show_trailing_button = true; + ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button); + ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button); + + // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs + static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown; + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown); + if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll)) + tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll); + + if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags)) + { + // Demo a Leading TabItemButton(): click the "?" button to open a menu + if (show_leading_button) + if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip)) + ImGui::OpenPopup("MyHelpMenu"); + if (ImGui::BeginPopup("MyHelpMenu")) + { + ImGui::Selectable("Hello!"); + ImGui::EndPopup(); + } + + // Demo Trailing Tabs: click the "+" button to add a new tab. + // (In your app you may want to use a font icon instead of the "+") + // We submit it before the regular tabs, but thanks to the ImGuiTabItemFlags_Trailing flag it will always appear at the end. + if (show_trailing_button) + if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip)) + active_tabs.push_back(next_tab_id++); // Add new tab + + // Submit our regular tabs + for (int n = 0; n < active_tabs.Size; ) + { + bool open = true; + char name[16]; + snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]); + if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None)) + { + ImGui::Text("This is the %s tab!", name); + ImGui::EndTabItem(); + } + + if (!open) + active_tabs.erase(active_tabs.Data + n); + else + n++; + } + + ImGui::EndTabBar(); + } + ImGui::Separator(); + ImGui::TreePop(); + } + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsText() //----------------------------------------------------------------------------- From 510a9a77d6ad5f2ab017ea7d13979e80a5a53989 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:11:16 +0100 Subject: [PATCH 281/716] Demo: (Refactor) Moved code into DemoWindowWidgetsDataTypes() section. --- imgui_demo.cpp | 261 +++++++++++++++++++++++++------------------------ 1 file changed, 133 insertions(+), 128 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 468e32b598d9..692f67af4b7c 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -254,6 +254,7 @@ static void DemoWindowWidgetsBasic(); static void DemoWindowWidgetsBullets(); static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); +static void DemoWindowWidgetsDataTypes(); static void DemoWindowWidgetsImages(); static void DemoWindowWidgetsListBoxes(); static void DemoWindowWidgetsPlotting(); @@ -826,6 +827,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsBullets(); DemoWindowWidgetsCollapsingHeaders(); DemoWindowWidgetsComboBoxes(); + DemoWindowWidgetsDataTypes(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); DemoWindowWidgetsPlotting(); @@ -1087,134 +1089,6 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Data Types"); - if (ImGui::TreeNode("Data Types")) - { - // DragScalar/InputScalar/SliderScalar functions allow various data types - // - signed/unsigned - // - 8/16/32/64-bits - // - integer/float/double - // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum - // to pass the type, and passing all arguments by pointer. - // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. - // In practice, if you frequently use a given type that is not covered by the normal API entry points, - // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, - // and then pass their address to the generic function. For example: - // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") - // { - // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); - // } - - // Setup limits (as helper variables so we can take their address, as explained above) - // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. - #ifndef LLONG_MIN - ImS64 LLONG_MIN = -9223372036854775807LL - 1; - ImS64 LLONG_MAX = 9223372036854775807LL; - ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); - #endif - const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; - const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; - const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; - const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; - const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; - const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; - const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; - const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; - const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; - const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; - - // State - static char s8_v = 127; - static ImU8 u8_v = 255; - static short s16_v = 32767; - static ImU16 u16_v = 65535; - static ImS32 s32_v = -1; - static ImU32 u32_v = (ImU32)-1; - static ImS64 s64_v = -1; - static ImU64 u64_v = (ImU64)-1; - static float f32_v = 0.123f; - static double f64_v = 90000.01234567890123456789; - - const float drag_speed = 0.2f; - static bool drag_clamp = false; - IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); - ImGui::SeparatorText("Drags"); - ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); - ImGui::SameLine(); HelpMarker( - "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" - "You can override the clamping limits by using CTRL+Click to input a value."); - ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); - ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); - ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); - ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); - ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); - ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X"); - ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); - ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); - ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); - ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); - ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); - ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); - ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); - - IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); - ImGui::SeparatorText("Sliders"); - ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); - ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); - ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); - ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); - ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); - ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); - ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); - ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X"); - ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); - ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); - ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); - ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64); - ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64); - ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64); - ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms"); - ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms"); - ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms"); - ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); - ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); - ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); - ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); - ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); - ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); - - ImGui::SeparatorText("Sliders (reverse)"); - ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); - ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); - ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); - ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); - ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64); - ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms"); - - IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); - static bool inputs_step = true; - static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None; - ImGui::SeparatorText("Inputs"); - ImGui::Checkbox("Show step buttons", &inputs_step); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); - ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal); - ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal); - ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags); - ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags); - ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags); - ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags); - ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags); - ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags); - ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags); - ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags); - ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags); - ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags); - ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags); - ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags); - - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets"); if (ImGui::TreeNode("Multi-component Widgets")) { @@ -2041,6 +1915,137 @@ static void DemoWindowWidgetsComboBoxes() // [SECTION] DemoWindowWidgetsDataTypes() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsDataTypes() +{ + IMGUI_DEMO_MARKER("Widgets/Data Types"); + if (ImGui::TreeNode("Data Types")) + { + // DragScalar/InputScalar/SliderScalar functions allow various data types + // - signed/unsigned + // - 8/16/32/64-bits + // - integer/float/double + // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum + // to pass the type, and passing all arguments by pointer. + // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each type. + // In practice, if you frequently use a given type that is not covered by the normal API entry points, + // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*, + // and then pass their address to the generic function. For example: + // bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld") + // { + // return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format); + // } + + // Setup limits (as helper variables so we can take their address, as explained above) + // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2. + #ifndef LLONG_MIN + ImS64 LLONG_MIN = -9223372036854775807LL - 1; + ImS64 LLONG_MAX = 9223372036854775807LL; + ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1); + #endif + const char s8_zero = 0, s8_one = 1, s8_fifty = 50, s8_min = -128, s8_max = 127; + const ImU8 u8_zero = 0, u8_one = 1, u8_fifty = 50, u8_min = 0, u8_max = 255; + const short s16_zero = 0, s16_one = 1, s16_fifty = 50, s16_min = -32768, s16_max = 32767; + const ImU16 u16_zero = 0, u16_one = 1, u16_fifty = 50, u16_min = 0, u16_max = 65535; + const ImS32 s32_zero = 0, s32_one = 1, s32_fifty = 50, s32_min = INT_MIN/2, s32_max = INT_MAX/2, s32_hi_a = INT_MAX/2 - 100, s32_hi_b = INT_MAX/2; + const ImU32 u32_zero = 0, u32_one = 1, u32_fifty = 50, u32_min = 0, u32_max = UINT_MAX/2, u32_hi_a = UINT_MAX/2 - 100, u32_hi_b = UINT_MAX/2; + const ImS64 s64_zero = 0, s64_one = 1, s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2, s64_hi_a = LLONG_MAX/2 - 100, s64_hi_b = LLONG_MAX/2; + const ImU64 u64_zero = 0, u64_one = 1, u64_fifty = 50, u64_min = 0, u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2; + const float f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f; + const double f64_zero = 0., f64_one = 1., f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0; + + // State + static char s8_v = 127; + static ImU8 u8_v = 255; + static short s16_v = 32767; + static ImU16 u16_v = 65535; + static ImS32 s32_v = -1; + static ImU32 u32_v = (ImU32)-1; + static ImS64 s64_v = -1; + static ImU64 u64_v = (ImU64)-1; + static float f32_v = 0.123f; + static double f64_v = 90000.01234567890123456789; + + const float drag_speed = 0.2f; + static bool drag_clamp = false; + IMGUI_DEMO_MARKER("Widgets/Data Types/Drags"); + ImGui::SeparatorText("Drags"); + ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp); + ImGui::SameLine(); HelpMarker( + "As with every widget in dear imgui, we never modify values unless there is a user interaction.\n" + "You can override the clamping limits by using CTRL+Click to input a value."); + ImGui::DragScalar("drag s8", ImGuiDataType_S8, &s8_v, drag_speed, drag_clamp ? &s8_zero : NULL, drag_clamp ? &s8_fifty : NULL); + ImGui::DragScalar("drag u8", ImGuiDataType_U8, &u8_v, drag_speed, drag_clamp ? &u8_zero : NULL, drag_clamp ? &u8_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s16", ImGuiDataType_S16, &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL); + ImGui::DragScalar("drag u16", ImGuiDataType_U16, &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s32", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL); + ImGui::DragScalar("drag s32 hex", ImGuiDataType_S32, &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL, "0x%08X"); + ImGui::DragScalar("drag u32", ImGuiDataType_U32, &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms"); + ImGui::DragScalar("drag s64", ImGuiDataType_S64, &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL); + ImGui::DragScalar("drag u64", ImGuiDataType_U64, &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL); + ImGui::DragScalar("drag float", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f"); + ImGui::DragScalar("drag float log", ImGuiDataType_Float, &f32_v, 0.005f, &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic); + ImGui::DragScalar("drag double", ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL, "%.10f grams"); + ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic); + + IMGUI_DEMO_MARKER("Widgets/Data Types/Sliders"); + ImGui::SeparatorText("Sliders"); + ImGui::SliderScalar("slider s8 full", ImGuiDataType_S8, &s8_v, &s8_min, &s8_max, "%d"); + ImGui::SliderScalar("slider u8 full", ImGuiDataType_U8, &u8_v, &u8_min, &u8_max, "%u"); + ImGui::SliderScalar("slider s16 full", ImGuiDataType_S16, &s16_v, &s16_min, &s16_max, "%d"); + ImGui::SliderScalar("slider u16 full", ImGuiDataType_U16, &u16_v, &u16_min, &u16_max, "%u"); + ImGui::SliderScalar("slider s32 low", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty,"%d"); + ImGui::SliderScalar("slider s32 high", ImGuiDataType_S32, &s32_v, &s32_hi_a, &s32_hi_b, "%d"); + ImGui::SliderScalar("slider s32 full", ImGuiDataType_S32, &s32_v, &s32_min, &s32_max, "%d"); + ImGui::SliderScalar("slider s32 hex", ImGuiDataType_S32, &s32_v, &s32_zero, &s32_fifty, "0x%04X"); + ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); + ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); + ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); + ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64); + ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64); + ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64); + ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms"); + ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms"); + ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms"); + ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); + ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); + ImGui::SliderScalar("slider double low", ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f grams"); + ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one, "%.10f", ImGuiSliderFlags_Logarithmic); + ImGui::SliderScalar("slider double high", ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams"); + + ImGui::SeparatorText("Sliders (reverse)"); + ImGui::SliderScalar("slider s8 reverse", ImGuiDataType_S8, &s8_v, &s8_max, &s8_min, "%d"); + ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); + ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); + ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); + ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64); + ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms"); + + IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); + static bool inputs_step = true; + static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None; + ImGui::SeparatorText("Inputs"); + ImGui::Checkbox("Show step buttons", &inputs_step); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly); + ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal); + ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal); + ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags); + ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags); + ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags); + ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags); + ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags); + ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags); + ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags); + ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags); + ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags); + ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags); + ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags); + ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsDisableBlocks() //----------------------------------------------------------------------------- From caf3faa054d02e0cc569aaa62cf6cec2e30f5e36 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:14:23 +0100 Subject: [PATCH 282/716] Demo: (Refactor) Moved code into DemoWindowWidgetsColorAndPickers() section. --- imgui_demo.cpp | 391 +++++++++++++++++++++++++------------------------ 1 file changed, 198 insertions(+), 193 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 692f67af4b7c..cc0427231164 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -254,6 +254,7 @@ static void DemoWindowWidgetsBasic(); static void DemoWindowWidgetsBullets(); static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); +static void DemoWindowWidgetsColorAndPickers(); static void DemoWindowWidgetsDataTypes(); static void DemoWindowWidgetsImages(); static void DemoWindowWidgetsListBoxes(); @@ -827,6 +828,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsBullets(); DemoWindowWidgetsCollapsingHeaders(); DemoWindowWidgetsComboBoxes(); + DemoWindowWidgetsColorAndPickers(); DemoWindowWidgetsDataTypes(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); @@ -841,199 +843,6 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsTooltips(); DemoWindowWidgetsTreeNodes(); - IMGUI_DEMO_MARKER("Widgets/Color"); - if (ImGui::TreeNode("Color/Picker Widgets")) - { - static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); - static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None; - - ImGui::SeparatorText("Options"); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); - ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); - - IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); - ImGui::SeparatorText("Inline color editor"); - ImGui::Text("Color widget:"); - ImGui::SameLine(); HelpMarker( - "Click on the color square to open a color picker.\n" - "CTRL+click on individual component to input value.\n"); - ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags); - - IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); - ImGui::Text("Color widget HSV with Alpha:"); - ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); - - IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); - ImGui::Text("Color widget with Float Display:"); - ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags); - - IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); - ImGui::Text("Color button with Picker:"); - ImGui::SameLine(); HelpMarker( - "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" - "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " - "be used for the tooltip and picker popup."); - ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); - - IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); - ImGui::Text("Color button with Custom Picker Popup:"); - - // Generate a default palette. The palette will persist and can be edited. - static bool saved_palette_init = true; - static ImVec4 saved_palette[32] = {}; - if (saved_palette_init) - { - for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) - { - ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, - saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); - saved_palette[n].w = 1.0f; // Alpha - } - saved_palette_init = false; - } - - static ImVec4 backup_color; - bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags); - ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); - open_popup |= ImGui::Button("Palette"); - if (open_popup) - { - ImGui::OpenPopup("mypicker"); - backup_color = color; - } - if (ImGui::BeginPopup("mypicker")) - { - ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); - ImGui::Separator(); - ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); - ImGui::SameLine(); - - ImGui::BeginGroup(); // Lock X position - ImGui::Text("Current"); - ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); - ImGui::Text("Previous"); - if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) - color = backup_color; - ImGui::Separator(); - ImGui::Text("Palette"); - for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) - { - ImGui::PushID(n); - if ((n % 8) != 0) - ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); - - ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; - if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) - color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! - - // Allow user to drop colors into each palette entry. Note that ColorButton() is already a - // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) - memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) - memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); - ImGui::EndDragDropTarget(); - } - - ImGui::PopID(); - } - ImGui::EndGroup(); - ImGui::EndPopup(); - } - - IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)"); - ImGui::Text("Color button only:"); - static bool no_border = false; - ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); - ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); - - IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); - ImGui::SeparatorText("Color picker"); - - static bool ref_color = false; - static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); - static int picker_mode = 0; - static int display_mode = 0; - static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar; - - ImGui::PushID("Color picker"); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha); - ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar); - ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview); - if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview) - { - ImGui::SameLine(); - ImGui::Checkbox("With Ref Color", &ref_color); - if (ref_color) - { - ImGui::SameLine(); - ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags); - } - } - - ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); - ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); - - ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0"); - ImGui::SameLine(); HelpMarker( - "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " - "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " - "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); - - ImGuiColorEditFlags flags = base_flags | color_picker_flags; - if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; - if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; - if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays - if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode - if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; - if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; - ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); - - ImGui::Text("Set defaults in code:"); - ImGui::SameLine(); HelpMarker( - "SetColorEditOptions() is designed to allow you to set boot-time default.\n" - "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " - "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " - "encouraging you to persistently save values that aren't forward-compatible."); - if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) - ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); - if (ImGui::Button("Default: Float + HDR + Hue Wheel")) - ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); - - // Always display a small version of both types of pickers - // (that's in order to make it more visible in the demo to people who are skimming quickly through it) - ImGui::Text("Both types:"); - float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f; - ImGui::SetNextItemWidth(w); - ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); - ImGui::SameLine(); - ImGui::SetNextItemWidth(w); - ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); - ImGui::PopID(); - - // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) - static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! - ImGui::Spacing(); - ImGui::Text("HSV encoded colors"); - ImGui::SameLine(); HelpMarker( - "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " - "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " - "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); - ImGui::Text("Color widget with InputHSV:"); - ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); - ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); - ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); - - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags"); if (ImGui::TreeNode("Drag/Slider Flags")) { @@ -1814,6 +1623,202 @@ static void DemoWindowWidgetsCollapsingHeaders() // [SECTION] DemoWindowWidgetsColorAndPickers() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsColorAndPickers() +{ + IMGUI_DEMO_MARKER("Widgets/Color"); + if (ImGui::TreeNode("Color/Picker Widgets")) + { + static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f); + static ImGuiColorEditFlags base_flags = ImGuiColorEditFlags_None; + + ImGui::SeparatorText("Options"); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &base_flags, ImGuiColorEditFlags_NoAlpha); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaOpaque", &base_flags, ImGuiColorEditFlags_AlphaOpaque); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaNoBg", &base_flags, ImGuiColorEditFlags_AlphaNoBg); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaPreviewHalf", &base_flags, ImGuiColorEditFlags_AlphaPreviewHalf); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoDragDrop", &base_flags, ImGuiColorEditFlags_NoDragDrop); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoOptions", &base_flags, ImGuiColorEditFlags_NoOptions); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options."); + ImGui::CheckboxFlags("ImGuiColorEditFlags_HDR", &base_flags, ImGuiColorEditFlags_HDR); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets."); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit"); + ImGui::SeparatorText("Inline color editor"); + ImGui::Text("Color widget:"); + ImGui::SameLine(); HelpMarker( + "Click on the color square to open a color picker.\n" + "CTRL+click on individual component to input value.\n"); + ImGui::ColorEdit3("MyColor##1", (float*)&color, base_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (HSV, with Alpha)"); + ImGui::Text("Color widget HSV with Alpha:"); + ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | base_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorEdit (float display)"); + ImGui::Text("Color widget with Float Display:"); + ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | base_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with Picker)"); + ImGui::Text("Color button with Picker:"); + ImGui::SameLine(); HelpMarker( + "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n" + "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only " + "be used for the tooltip and picker popup."); + ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | base_flags); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (with custom Picker popup)"); + ImGui::Text("Color button with Custom Picker Popup:"); + + // Generate a default palette. The palette will persist and can be edited. + static bool saved_palette_init = true; + static ImVec4 saved_palette[32] = {}; + if (saved_palette_init) + { + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, + saved_palette[n].x, saved_palette[n].y, saved_palette[n].z); + saved_palette[n].w = 1.0f; // Alpha + } + saved_palette_init = false; + } + + static ImVec4 backup_color; + bool open_popup = ImGui::ColorButton("MyColor##3b", color, base_flags); + ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x); + open_popup |= ImGui::Button("Palette"); + if (open_popup) + { + ImGui::OpenPopup("mypicker"); + backup_color = color; + } + if (ImGui::BeginPopup("mypicker")) + { + ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!"); + ImGui::Separator(); + ImGui::ColorPicker4("##picker", (float*)&color, base_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview); + ImGui::SameLine(); + + ImGui::BeginGroup(); // Lock X position + ImGui::Text("Current"); + ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)); + ImGui::Text("Previous"); + if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40))) + color = backup_color; + ImGui::Separator(); + ImGui::Text("Palette"); + for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++) + { + ImGui::PushID(n); + if ((n % 8) != 0) + ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y); + + ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip; + if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20))) + color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha! + + // Allow user to drop colors into each palette entry. Note that ColorButton() is already a + // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag. + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3); + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F)) + memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4); + ImGui::EndDragDropTarget(); + } + + ImGui::PopID(); + } + ImGui::EndGroup(); + ImGui::EndPopup(); + } + + IMGUI_DEMO_MARKER("Widgets/Color/ColorButton (simple)"); + ImGui::Text("Color button only:"); + static bool no_border = false; + ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border); + ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, base_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80)); + + IMGUI_DEMO_MARKER("Widgets/Color/ColorPicker"); + ImGui::SeparatorText("Color picker"); + + static bool ref_color = false; + static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f); + static int picker_mode = 0; + static int display_mode = 0; + static ImGuiColorEditFlags color_picker_flags = ImGuiColorEditFlags_AlphaBar; + + ImGui::PushID("Color picker"); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoAlpha", &color_picker_flags, ImGuiColorEditFlags_NoAlpha); + ImGui::CheckboxFlags("ImGuiColorEditFlags_AlphaBar", &color_picker_flags, ImGuiColorEditFlags_AlphaBar); + ImGui::CheckboxFlags("ImGuiColorEditFlags_NoSidePreview", &color_picker_flags, ImGuiColorEditFlags_NoSidePreview); + if (color_picker_flags & ImGuiColorEditFlags_NoSidePreview) + { + ImGui::SameLine(); + ImGui::Checkbox("With Ref Color", &ref_color); + if (ref_color) + { + ImGui::SameLine(); + ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | base_flags); + } + } + + ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0ImGuiColorEditFlags_PickerHueBar\0ImGuiColorEditFlags_PickerHueWheel\0"); + ImGui::SameLine(); HelpMarker("When not specified explicitly, user can right-click the picker to change mode."); + + ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0ImGuiColorEditFlags_NoInputs\0ImGuiColorEditFlags_DisplayRGB\0ImGuiColorEditFlags_DisplayHSV\0ImGuiColorEditFlags_DisplayHex\0"); + ImGui::SameLine(); HelpMarker( + "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, " + "but the user can change it with a right-click on those inputs.\n\nColorPicker defaults to displaying RGB+HSV+Hex " + "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions()."); + + ImGuiColorEditFlags flags = base_flags | color_picker_flags; + if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar; + if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel; + if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs; // Disable all RGB/HSV/Hex displays + if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB; // Override display mode + if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV; + if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex; + ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL); + + ImGui::Text("Set defaults in code:"); + ImGui::SameLine(); HelpMarker( + "SetColorEditOptions() is designed to allow you to set boot-time default.\n" + "We don't have Push/Pop functions because you can force options on a per-widget basis if needed, " + "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid " + "encouraging you to persistently save values that aren't forward-compatible."); + if (ImGui::Button("Default: Uint8 + HSV + Hue Bar")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar); + if (ImGui::Button("Default: Float + HDR + Hue Wheel")) + ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel); + + // Always display a small version of both types of pickers + // (that's in order to make it more visible in the demo to people who are skimming quickly through it) + ImGui::Text("Both types:"); + float w = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.y) * 0.40f; + ImGui::SetNextItemWidth(w); + ImGui::ColorPicker3("##MyColor##5", (float*)&color, ImGuiColorEditFlags_PickerHueBar | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + ImGui::SameLine(); + ImGui::SetNextItemWidth(w); + ImGui::ColorPicker3("##MyColor##6", (float*)&color, ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoAlpha); + ImGui::PopID(); + + // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0) + static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV! + ImGui::Spacing(); + ImGui::Text("HSV encoded colors"); + ImGui::SameLine(); HelpMarker( + "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV " + "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the " + "added benefit that you can manipulate hue values with the picker even when saturation or value are zero."); + ImGui::Text("Color widget with InputHSV:"); + ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float); + ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsComboBoxes() //----------------------------------------------------------------------------- From 9b486e47fef41c506941151dc586c4ad75bb784a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:40:14 +0100 Subject: [PATCH 283/716] Demo: (Refactor) Moved code into DemoWindowWidgetsDragsAndSliders(), DemoWindowWidgetsMultiComponents(), DemoWindowWidgetsVerticalSliders() sections. --- imgui_demo.cpp | 317 +++++++++++++++++++++++++------------------------ 1 file changed, 164 insertions(+), 153 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index cc0427231164..9d9cf112b913 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -256,9 +256,11 @@ static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); static void DemoWindowWidgetsColorAndPickers(); static void DemoWindowWidgetsDataTypes(); +static void DemoWindowWidgetsDragsAndSliders(); static void DemoWindowWidgetsImages(); static void DemoWindowWidgetsListBoxes(); static void DemoWindowWidgetsPlotting(); +static void DemoWindowWidgetsMultiComponents(); static void DemoWindowWidgetsProgressBars(); static void DemoWindowWidgetsSelectables(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); @@ -268,6 +270,7 @@ static void DemoWindowWidgetsTextFilter(); static void DemoWindowWidgetsTextInput(); static void DemoWindowWidgetsTooltips(); static void DemoWindowWidgetsTreeNodes(); +static void DemoWindowWidgetsVerticalSliders(); static void DemoWindowLayout(); static void DemoWindowPopups(); static void DemoWindowTables(); @@ -830,8 +833,10 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsComboBoxes(); DemoWindowWidgetsColorAndPickers(); DemoWindowWidgetsDataTypes(); + DemoWindowWidgetsDragsAndSliders(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); + DemoWindowWidgetsMultiComponents(); DemoWindowWidgetsPlotting(); DemoWindowWidgetsProgressBars(); DemoWindowWidgetsSelectables(); @@ -842,159 +847,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsTextInput(); DemoWindowWidgetsTooltips(); DemoWindowWidgetsTreeNodes(); - - IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags"); - if (ImGui::TreeNode("Drag/Slider Flags")) - { - // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! - static ImGuiSliderFlags flags = ImGuiSliderFlags_None; - ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); - ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput); - ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds."); - ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange); - ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp."); - ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); - ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); - ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); - ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); - ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); - ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); - ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks); - ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic."); - ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); - ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); - - // Drags - static float drag_f = 0.5f; - static int drag_i = 50; - ImGui::Text("Underlying float value: %f", drag_f); - ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); - ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); - ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); - ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); - //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange - //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags); - ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); - - // Sliders - static float slider_f = 0.5f; - static int slider_i = 50; - const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround; - ImGui::Text("Underlying float value: %f", slider_f); - ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders); - ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Range Widgets"); - if (ImGui::TreeNode("Range Widgets")) - { - static float begin = 10, end = 90; - static int begin_i = 100, end_i = 1000; - ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); - ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); - ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets"); - if (ImGui::TreeNode("Multi-component Widgets")) - { - static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; - static int vec4i[4] = { 1, 5, 100, 255 }; - - ImGui::SeparatorText("2-wide"); - ImGui::InputFloat2("input float2", vec4f); - ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); - ImGui::InputInt2("input int2", vec4i); - ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); - ImGui::SliderInt2("slider int2", vec4i, 0, 255); - - ImGui::SeparatorText("3-wide"); - ImGui::InputFloat3("input float3", vec4f); - ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); - ImGui::InputInt3("input int3", vec4i); - ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); - ImGui::SliderInt3("slider int3", vec4i, 0, 255); - - ImGui::SeparatorText("4-wide"); - ImGui::InputFloat4("input float4", vec4f); - ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); - ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); - ImGui::InputInt4("input int4", vec4i); - ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); - ImGui::SliderInt4("slider int4", vec4i, 0, 255); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Vertical Sliders"); - if (ImGui::TreeNode("Vertical Sliders")) - { - const float spacing = 4; - ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); - - static int int_value = 0; - ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); - ImGui::SameLine(); - - static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; - ImGui::PushID("set1"); - for (int i = 0; i < 7; i++) - { - if (i > 0) ImGui::SameLine(); - ImGui::PushID(i); - ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f)); - ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); - ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); - if (ImGui::IsItemActive() || ImGui::IsItemHovered()) - ImGui::SetTooltip("%.3f", values[i]); - ImGui::PopStyleColor(4); - ImGui::PopID(); - } - ImGui::PopID(); - - ImGui::SameLine(); - ImGui::PushID("set2"); - static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; - const int rows = 3; - const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); - for (int nx = 0; nx < 4; nx++) - { - if (nx > 0) ImGui::SameLine(); - ImGui::BeginGroup(); - for (int ny = 0; ny < rows; ny++) - { - ImGui::PushID(nx * rows + ny); - ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); - if (ImGui::IsItemActive() || ImGui::IsItemHovered()) - ImGui::SetTooltip("%.3f", values2[nx]); - ImGui::PopID(); - } - ImGui::EndGroup(); - } - ImGui::PopID(); - - ImGui::SameLine(); - ImGui::PushID("set3"); - for (int i = 0; i < 4; i++) - { - if (i > 0) ImGui::SameLine(); - ImGui::PushID(i); - ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); - ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); - ImGui::PopStyleVar(); - ImGui::PopID(); - } - ImGui::PopID(); - ImGui::PopStyleVar(); - ImGui::TreePop(); - } + DemoWindowWidgetsVerticalSliders(); IMGUI_DEMO_MARKER("Widgets/Drag and drop"); if (ImGui::TreeNode("Drag and Drop")) @@ -2063,6 +1916,53 @@ static void DemoWindowWidgetsDataTypes() // [SECTION] DemoWindowWidgetsDragsAndSliders() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsDragsAndSliders() +{ + IMGUI_DEMO_MARKER("Widgets/Drag and Slider Flags"); + if (ImGui::TreeNode("Drag/Slider Flags")) + { + // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same! + static ImGuiSliderFlags flags = ImGuiSliderFlags_None; + ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp); + ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput); + ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds."); + ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange); + ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp."); + ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic); + ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values)."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat); + ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits)."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput); + ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget."); + ImGui::CheckboxFlags("ImGuiSliderFlags_NoSpeedTweaks", &flags, ImGuiSliderFlags_NoSpeedTweaks); + ImGui::SameLine(); HelpMarker("Disable keyboard modifiers altering tweak speed. Useful if you want to alter tweak speed yourself based on your own logic."); + ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround); + ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)"); + + // Drags + static float drag_f = 0.5f; + static int drag_i = 50; + ImGui::Text("Underlying float value: %f", drag_f); + ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags); + ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags); + ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags); + ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags); + //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange + //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags); + ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags); + + // Sliders + static float slider_f = 0.5f; + static int slider_i = 50; + const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround; + ImGui::Text("Underlying float value: %f", slider_f); + ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders); + ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsImages() //----------------------------------------------------------------------------- @@ -2221,6 +2121,49 @@ static void DemoWindowWidgetsListBoxes() // [SECTION] DemoWindowWidgetsMultiComponents() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsMultiComponents() +{ + IMGUI_DEMO_MARKER("Widgets/Multi-component Widgets"); + if (ImGui::TreeNode("Multi-component Widgets")) + { + static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; + static int vec4i[4] = { 1, 5, 100, 255 }; + + ImGui::SeparatorText("2-wide"); + ImGui::InputFloat2("input float2", vec4f); + ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); + ImGui::InputInt2("input int2", vec4i); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); + ImGui::SliderInt2("slider int2", vec4i, 0, 255); + + ImGui::SeparatorText("3-wide"); + ImGui::InputFloat3("input float3", vec4f); + ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); + ImGui::InputInt3("input int3", vec4i); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); + ImGui::SliderInt3("slider int3", vec4i, 0, 255); + + ImGui::SeparatorText("4-wide"); + ImGui::InputFloat4("input float4", vec4f); + ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f); + ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f); + ImGui::InputInt4("input int4", vec4i); + ImGui::DragInt4("drag int4", vec4i, 1, 0, 255); + ImGui::SliderInt4("slider int4", vec4i, 0, 255); + + ImGui::SeparatorText("Ranges"); + static float begin = 10, end = 90; + static int begin_i = 100, end_i = 1000; + ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp); + ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units"); + ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsPlotting() //----------------------------------------------------------------------------- @@ -4152,6 +4095,74 @@ static void DemoWindowWidgetsTreeNodes() // [SECTION] DemoWindowWidgetsVerticalSliders() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsVerticalSliders() +{ + IMGUI_DEMO_MARKER("Widgets/Vertical Sliders"); + if (ImGui::TreeNode("Vertical Sliders")) + { + const float spacing = 4; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + static int int_value = 0; + ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5); + ImGui::SameLine(); + + static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f }; + ImGui::PushID("set1"); + for (int i = 0; i < 7; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleColor(ImGuiCol_FrameBg, (ImVec4)ImColor::HSV(i / 7.0f, 0.5f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_FrameBgActive, (ImVec4)ImColor::HSV(i / 7.0f, 0.7f, 0.5f)); + ImGui::PushStyleColor(ImGuiCol_SliderGrab, (ImVec4)ImColor::HSV(i / 7.0f, 0.9f, 0.9f)); + ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values[i]); + ImGui::PopStyleColor(4); + ImGui::PopID(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set2"); + static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f }; + const int rows = 3; + const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows)); + for (int nx = 0; nx < 4; nx++) + { + if (nx > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + for (int ny = 0; ny < rows; ny++) + { + ImGui::PushID(nx * rows + ny); + ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, ""); + if (ImGui::IsItemActive() || ImGui::IsItemHovered()) + ImGui::SetTooltip("%.3f", values2[nx]); + ImGui::PopID(); + } + ImGui::EndGroup(); + } + ImGui::PopID(); + + ImGui::SameLine(); + ImGui::PushID("set3"); + for (int i = 0; i < 4; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::PushID(i); + ImGui::PushStyleVar(ImGuiStyleVar_GrabMinSize, 40); + ImGui::VSliderFloat("##v", ImVec2(40, 160), &values[i], 0.0f, 1.0f, "%.2f\nsec"); + ImGui::PopStyleVar(); + ImGui::PopID(); + } + ImGui::PopID(); + ImGui::PopStyleVar(); + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowLayout() //----------------------------------------------------------------------------- From 0758594bd2ea56c341005911b74700cea57216a7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:45:59 +0100 Subject: [PATCH 284/716] Demo: (Refactor) Moved code into DemoWindowWidgetsDragAndDrop() section. --- imgui_demo.cpp | 307 +++++++++++++++++++++++++------------------------ 1 file changed, 156 insertions(+), 151 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9d9cf112b913..b2a0a5e78dec 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -256,6 +256,7 @@ static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); static void DemoWindowWidgetsColorAndPickers(); static void DemoWindowWidgetsDataTypes(); +static void DemoWindowWidgetsDragAndDrop(); static void DemoWindowWidgetsDragsAndSliders(); static void DemoWindowWidgetsImages(); static void DemoWindowWidgetsListBoxes(); @@ -833,6 +834,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsComboBoxes(); DemoWindowWidgetsColorAndPickers(); DemoWindowWidgetsDataTypes(); + DemoWindowWidgetsDragAndDrop(); DemoWindowWidgetsDragsAndSliders(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); @@ -849,157 +851,6 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsTreeNodes(); DemoWindowWidgetsVerticalSliders(); - IMGUI_DEMO_MARKER("Widgets/Drag and drop"); - if (ImGui::TreeNode("Drag and Drop")) - { - IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets"); - if (ImGui::TreeNode("Drag and drop in standard widgets")) - { - // ColorEdit widgets automatically act as drag source and drag target. - // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F - // to allow your own widgets to use colors in their drag and drop interaction. - // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. - HelpMarker("You can drag from the color squares."); - static float col1[3] = { 1.0f, 0.0f, 0.2f }; - static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; - ImGui::ColorEdit3("color 1", col1); - ImGui::ColorEdit4("color 2", col2); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items"); - if (ImGui::TreeNode("Drag and drop to copy/swap items")) - { - enum Mode - { - Mode_Copy, - Mode_Move, - Mode_Swap - }; - static int mode = 0; - if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); - if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); - if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } - static const char* names[9] = - { - "Bobby", "Beatrice", "Betty", - "Brianna", "Barry", "Bernard", - "Bibi", "Blaine", "Bryn" - }; - for (int n = 0; n < IM_ARRAYSIZE(names); n++) - { - ImGui::PushID(n); - if ((n % 3) != 0) - ImGui::SameLine(); - ImGui::Button(names[n], ImVec2(60, 60)); - - // Our buttons are both drag sources and drag targets here! - if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) - { - // Set payload to carry the index of our item (could be anything) - ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); - - // Display preview (could be anything, e.g. when dragging an image we could decide to display - // the filename and a small preview of the image, etc.) - if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } - if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } - if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } - ImGui::EndDragDropSource(); - } - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) - { - IM_ASSERT(payload->DataSize == sizeof(int)); - int payload_n = *(const int*)payload->Data; - if (mode == Mode_Copy) - { - names[n] = names[payload_n]; - } - if (mode == Mode_Move) - { - names[n] = names[payload_n]; - names[payload_n] = ""; - } - if (mode == Mode_Swap) - { - const char* tmp = names[n]; - names[n] = names[payload_n]; - names[payload_n] = tmp; - } - } - ImGui::EndDragDropTarget(); - } - ImGui::PopID(); - } - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); - if (ImGui::TreeNode("Drag to reorder items (simple)")) - { - // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. - // This code was always slightly faulty but in a way which was not easily noticeable. - // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. - ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); - - // Simple reordering - HelpMarker( - "We don't use the drag and drop api at all here! " - "Instead we query when the item is held but not hovered, and order items accordingly."); - static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; - for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) - { - const char* item = item_names[n]; - ImGui::Selectable(item); - - if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) - { - int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); - if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) - { - item_names[n] = item_names[n_next]; - item_names[n_next] = item; - ImGui::ResetMouseDragDelta(); - } - } - } - - ImGui::PopItemFlag(); - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location"); - if (ImGui::TreeNode("Tooltip at target location")) - { - for (int n = 0; n < 2; n++) - { - // Drop targets - ImGui::Button(n ? "drop here##1" : "drop here##0"); - if (ImGui::BeginDragDropTarget()) - { - ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip; - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags)) - { - IM_UNUSED(payload); - ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); - ImGui::SetTooltip("Cannot drop here!"); - } - ImGui::EndDragDropTarget(); - } - - // Drop source - static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f }; - if (n == 0) - ImGui::ColorButton("drag me", col4); - - } - ImGui::TreePop(); - } - - ImGui::TreePop(); - } - IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)"); if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) { @@ -1912,6 +1763,160 @@ static void DemoWindowWidgetsDataTypes() // [SECTION] DemoWindowWidgetsDragAndDrop() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsDragAndDrop() +{ + IMGUI_DEMO_MARKER("Widgets/Drag and drop"); + if (ImGui::TreeNode("Drag and Drop")) + { + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Standard widgets"); + if (ImGui::TreeNode("Drag and drop in standard widgets")) + { + // ColorEdit widgets automatically act as drag source and drag target. + // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F + // to allow your own widgets to use colors in their drag and drop interaction. + // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo. + HelpMarker("You can drag from the color squares."); + static float col1[3] = { 1.0f, 0.0f, 0.2f }; + static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f }; + ImGui::ColorEdit3("color 1", col1); + ImGui::ColorEdit4("color 2", col2); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and drop/Copy-swap items"); + if (ImGui::TreeNode("Drag and drop to copy/swap items")) + { + enum Mode + { + Mode_Copy, + Mode_Move, + Mode_Swap + }; + static int mode = 0; + if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine(); + if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine(); + if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; } + static const char* names[9] = + { + "Bobby", "Beatrice", "Betty", + "Brianna", "Barry", "Bernard", + "Bibi", "Blaine", "Bryn" + }; + for (int n = 0; n < IM_ARRAYSIZE(names); n++) + { + ImGui::PushID(n); + if ((n % 3) != 0) + ImGui::SameLine(); + ImGui::Button(names[n], ImVec2(60, 60)); + + // Our buttons are both drag sources and drag targets here! + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) + { + // Set payload to carry the index of our item (could be anything) + ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); + + // Display preview (could be anything, e.g. when dragging an image we could decide to display + // the filename and a small preview of the image, etc.) + if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } + if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); } + if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); } + ImGui::EndDragDropSource(); + } + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL")) + { + IM_ASSERT(payload->DataSize == sizeof(int)); + int payload_n = *(const int*)payload->Data; + if (mode == Mode_Copy) + { + names[n] = names[payload_n]; + } + if (mode == Mode_Move) + { + names[n] = names[payload_n]; + names[payload_n] = ""; + } + if (mode == Mode_Swap) + { + const char* tmp = names[n]; + names[n] = names[payload_n]; + names[payload_n] = tmp; + } + } + ImGui::EndDragDropTarget(); + } + ImGui::PopID(); + } + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)"); + if (ImGui::TreeNode("Drag to reorder items (simple)")) + { + // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice. + // This code was always slightly faulty but in a way which was not easily noticeable. + // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue. + ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); + + // Simple reordering + HelpMarker( + "We don't use the drag and drop api at all here! " + "Instead we query when the item is held but not hovered, and order items accordingly."); + static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" }; + for (int n = 0; n < IM_ARRAYSIZE(item_names); n++) + { + const char* item = item_names[n]; + ImGui::Selectable(item); + + if (ImGui::IsItemActive() && !ImGui::IsItemHovered()) + { + int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1); + if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names)) + { + item_names[n] = item_names[n_next]; + item_names[n_next] = item; + ImGui::ResetMouseDragDelta(); + } + } + } + + ImGui::PopItemFlag(); + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Tooltip at target location"); + if (ImGui::TreeNode("Tooltip at target location")) + { + for (int n = 0; n < 2; n++) + { + // Drop targets + ImGui::Button(n ? "drop here##1" : "drop here##0"); + if (ImGui::BeginDragDropTarget()) + { + ImGuiDragDropFlags drop_target_flags = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoPreviewTooltip; + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, drop_target_flags)) + { + IM_UNUSED(payload); + ImGui::SetMouseCursor(ImGuiMouseCursor_NotAllowed); + ImGui::SetTooltip("Cannot drop here!"); + } + ImGui::EndDragDropTarget(); + } + + // Drop source + static ImVec4 col4 = { 1.0f, 0.0f, 0.2f, 1.0f }; + if (n == 0) + ImGui::ColorButton("drag me", col4); + + } + ImGui::TreePop(); + } + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsDragsAndSliders() //----------------------------------------------------------------------------- From 7a919e80c9dd0a39f5d3a08a19e53504795ba03f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:49:02 +0100 Subject: [PATCH 285/716] Demo: (Refactor) Moved code into DemoWindowWidgetsQueryingStatuses() section. --- imgui_demo.cpp | 393 +++++++++++++++++++++++++------------------------ 1 file changed, 199 insertions(+), 194 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b2a0a5e78dec..bb3f6ef7c4e1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -263,6 +263,7 @@ static void DemoWindowWidgetsListBoxes(); static void DemoWindowWidgetsPlotting(); static void DemoWindowWidgetsMultiComponents(); static void DemoWindowWidgetsProgressBars(); +static void DemoWindowWidgetsQueryingStatuses(); static void DemoWindowWidgetsSelectables(); static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsTabs(); @@ -841,6 +842,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsMultiComponents(); DemoWindowWidgetsPlotting(); DemoWindowWidgetsProgressBars(); + DemoWindowWidgetsQueryingStatuses(); DemoWindowWidgetsSelectables(); DemoWindowWidgetsSelectionAndMultiSelect(demo_data); DemoWindowWidgetsTabs(); @@ -851,200 +853,6 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsTreeNodes(); DemoWindowWidgetsVerticalSliders(); - IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)"); - if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) - { - // Select an item type - const char* item_names[] = - { - "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", - "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" - }; - static int item_type = 4; - static bool item_disabled = false; - ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); - ImGui::SameLine(); - HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); - ImGui::Checkbox("Item Disabled", &item_disabled); - - // Submit selected items so we can query their status in the code following it. - bool ret = false; - static bool b = false; - static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; - static char str[16] = {}; - if (item_disabled) - ImGui::BeginDisabled(true); - if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction - if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button - if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater) - if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox - if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item - if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) - if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window) - if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input - if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) - if (item_type == 10){ ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item - if (item_type == 11){ ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) - if (item_type == 12){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node - if (item_type == 13){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. - if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } - if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } - - bool hovered_delay_none = ImGui::IsItemHovered(); - bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary); - bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort); - bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal); - bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary - - // Display the values of IsItemHovered() and other common item state functions. - // Note that the ImGuiHoveredFlags_XXX flags can be combined. - // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, - // we query every state in a single call to avoid storing them and to simplify the code. - ImGui::BulletText( - "Return value = %d\n" - "IsItemFocused() = %d\n" - "IsItemHovered() = %d\n" - "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" - "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" - "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" - "IsItemHovered(_AllowWhenDisabled) = %d\n" - "IsItemHovered(_RectOnly) = %d\n" - "IsItemActive() = %d\n" - "IsItemEdited() = %d\n" - "IsItemActivated() = %d\n" - "IsItemDeactivated() = %d\n" - "IsItemDeactivatedAfterEdit() = %d\n" - "IsItemVisible() = %d\n" - "IsItemClicked() = %d\n" - "IsItemToggledOpen() = %d\n" - "GetItemRectMin() = (%.1f, %.1f)\n" - "GetItemRectMax() = (%.1f, %.1f)\n" - "GetItemRectSize() = (%.1f, %.1f)", - ret, - ImGui::IsItemFocused(), - ImGui::IsItemHovered(), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow), - ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), - ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), - ImGui::IsItemActive(), - ImGui::IsItemEdited(), - ImGui::IsItemActivated(), - ImGui::IsItemDeactivated(), - ImGui::IsItemDeactivatedAfterEdit(), - ImGui::IsItemVisible(), - ImGui::IsItemClicked(), - ImGui::IsItemToggledOpen(), - ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, - ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, - ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y - ); - ImGui::BulletText( - "with Hovering Delay or Stationary test:\n" - "IsItemHovered() = = %d\n" - "IsItemHovered(_Stationary) = %d\n" - "IsItemHovered(_DelayShort) = %d\n" - "IsItemHovered(_DelayNormal) = %d\n" - "IsItemHovered(_Tooltip) = %d", - hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip); - - if (item_disabled) - ImGui::EndDisabled(); - - char buf[1] = ""; - ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly); - ImGui::SameLine(); - HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status."); - - ImGui::TreePop(); - } - - IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)"); - if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)")) - { - static bool embed_all_inside_a_child_window = false; - ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); - if (embed_all_inside_a_child_window) - ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders); - - // Testing IsWindowFocused() function with its various flags. - ImGui::BulletText( - "IsWindowFocused() = %d\n" - "IsWindowFocused(_ChildWindows) = %d\n" - "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" - "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" - "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" - "IsWindowFocused(_RootWindow) = %d\n" - "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" - "IsWindowFocused(_AnyWindow) = %d\n", - ImGui::IsWindowFocused(), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), - ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), - ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), - ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); - - // Testing IsWindowHovered() function with its various flags. - ImGui::BulletText( - "IsWindowHovered() = %d\n" - "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" - "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" - "IsWindowHovered(_ChildWindows) = %d\n" - "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" - "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" - "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" - "IsWindowHovered(_RootWindow) = %d\n" - "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" - "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" - "IsWindowHovered(_AnyWindow) = %d\n" - "IsWindowHovered(_Stationary) = %d\n", - ImGui::IsWindowHovered(), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), - ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), - ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), - ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), - ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); - - ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders); - ImGui::Text("This is another child window for testing the _ChildWindows flag."); - ImGui::EndChild(); - if (embed_all_inside_a_child_window) - ImGui::EndChild(); - - // Calling IsItemHovered() after begin returns the hovered status of the title bar. - // This is useful in particular if you want to create a context menu associated to the title bar of a window. - static bool test_window = false; - ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); - if (test_window) - { - ImGui::Begin("Title bar Hovered/Active tests", &test_window); - if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() - { - if (ImGui::MenuItem("Close")) { test_window = false; } - ImGui::EndPopup(); - } - ImGui::Text( - "IsItemHovered() after begin = %d (== is title bar hovered)\n" - "IsItemActive() after begin = %d (== is window being clicked/moved)\n", - ImGui::IsItemHovered(), ImGui::IsItemActive()); - ImGui::End(); - } - - ImGui::TreePop(); - } - // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd: // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space) if (disable_all) @@ -2285,6 +2093,203 @@ static void DemoWindowWidgetsProgressBars() // [SECTION] DemoWindowWidgetsQueryingStatuses() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsQueryingStatuses() +{ + IMGUI_DEMO_MARKER("Widgets/Querying Item Status (Edited,Active,Hovered etc.)"); + if (ImGui::TreeNode("Querying Item Status (Edited/Active/Hovered etc.)")) + { + // Select an item type + const char* item_names[] = + { + "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputTextMultiline", "InputFloat", + "InputFloat3", "ColorEdit4", "Selectable", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox" + }; + static int item_type = 4; + static bool item_disabled = false; + ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names)); + ImGui::SameLine(); + HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered()."); + ImGui::Checkbox("Item Disabled", &item_disabled); + + // Submit selected items so we can query their status in the code following it. + bool ret = false; + static bool b = false; + static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f }; + static char str[16] = {}; + if (item_disabled) + ImGui::BeginDisabled(true); + if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction + if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button + if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater) + if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox + if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item + if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing) + if (item_type == 6) { ret = ImGui::InputTextMultiline("ITEM: InputTextMultiline", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which uses a child window) + if (item_type == 7) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input + if (item_type == 8) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 9) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) + if (item_type == 10) { ret = ImGui::Selectable("ITEM: Selectable"); } // Testing selectable item + if (item_type == 11) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) + if (item_type == 12) { ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node + if (item_type == 13) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. + if (item_type == 14) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", ¤t, items, IM_ARRAYSIZE(items)); } + if (item_type == 15) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", ¤t, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } + + bool hovered_delay_none = ImGui::IsItemHovered(); + bool hovered_delay_stationary = ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary); + bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort); + bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal); + bool hovered_delay_tooltip = ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip); // = Normal + Stationary + + // Display the values of IsItemHovered() and other common item state functions. + // Note that the ImGuiHoveredFlags_XXX flags can be combined. + // Because BulletText is an item itself and that would affect the output of IsItemXXX functions, + // we query every state in a single call to avoid storing them and to simplify the code. + ImGui::BulletText( + "Return value = %d\n" + "IsItemFocused() = %d\n" + "IsItemHovered() = %d\n" + "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsItemHovered(_AllowWhenOverlappedByItem) = %d\n" + "IsItemHovered(_AllowWhenOverlappedByWindow) = %d\n" + "IsItemHovered(_AllowWhenDisabled) = %d\n" + "IsItemHovered(_RectOnly) = %d\n" + "IsItemActive() = %d\n" + "IsItemEdited() = %d\n" + "IsItemActivated() = %d\n" + "IsItemDeactivated() = %d\n" + "IsItemDeactivatedAfterEdit() = %d\n" + "IsItemVisible() = %d\n" + "IsItemClicked() = %d\n" + "IsItemToggledOpen() = %d\n" + "GetItemRectMin() = (%.1f, %.1f)\n" + "GetItemRectMax() = (%.1f, %.1f)\n" + "GetItemRectSize() = (%.1f, %.1f)", + ret, + ImGui::IsItemFocused(), + ImGui::IsItemHovered(), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByItem), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow), + ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled), + ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly), + ImGui::IsItemActive(), + ImGui::IsItemEdited(), + ImGui::IsItemActivated(), + ImGui::IsItemDeactivated(), + ImGui::IsItemDeactivatedAfterEdit(), + ImGui::IsItemVisible(), + ImGui::IsItemClicked(), + ImGui::IsItemToggledOpen(), + ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, + ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, + ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y + ); + ImGui::BulletText( + "with Hovering Delay or Stationary test:\n" + "IsItemHovered() = = %d\n" + "IsItemHovered(_Stationary) = %d\n" + "IsItemHovered(_DelayShort) = %d\n" + "IsItemHovered(_DelayNormal) = %d\n" + "IsItemHovered(_Tooltip) = %d", + hovered_delay_none, hovered_delay_stationary, hovered_delay_short, hovered_delay_normal, hovered_delay_tooltip); + + if (item_disabled) + ImGui::EndDisabled(); + + char buf[1] = ""; + ImGui::InputText("unused", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly); + ImGui::SameLine(); + HelpMarker("This widget is only here to be able to tab-out of the widgets above and see e.g. Deactivated() status."); + + ImGui::TreePop(); + } + + IMGUI_DEMO_MARKER("Widgets/Querying Window Status (Focused,Hovered etc.)"); + if (ImGui::TreeNode("Querying Window Status (Focused/Hovered etc.)")) + { + static bool embed_all_inside_a_child_window = false; + ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window); + if (embed_all_inside_a_child_window) + ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders); + + // Testing IsWindowFocused() function with its various flags. + ImGui::BulletText( + "IsWindowFocused() = %d\n" + "IsWindowFocused(_ChildWindows) = %d\n" + "IsWindowFocused(_ChildWindows|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n" + "IsWindowFocused(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_RootWindow) = %d\n" + "IsWindowFocused(_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowFocused(_AnyWindow) = %d\n", + ImGui::IsWindowFocused(), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow), + ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_NoPopupHierarchy), + ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)); + + // Testing IsWindowHovered() function with its various flags. + ImGui::BulletText( + "IsWindowHovered() = %d\n" + "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n" + "IsWindowHovered(_ChildWindows) = %d\n" + "IsWindowHovered(_ChildWindows|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n" + "IsWindowHovered(_ChildWindows|_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_RootWindow) = %d\n" + "IsWindowHovered(_RootWindow|_NoPopupHierarchy) = %d\n" + "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n" + "IsWindowHovered(_AnyWindow) = %d\n" + "IsWindowHovered(_Stationary) = %d\n", + ImGui::IsWindowHovered(), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_NoPopupHierarchy), + ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup), + ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow), + ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary)); + + ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders); + ImGui::Text("This is another child window for testing the _ChildWindows flag."); + ImGui::EndChild(); + if (embed_all_inside_a_child_window) + ImGui::EndChild(); + + // Calling IsItemHovered() after begin returns the hovered status of the title bar. + // This is useful in particular if you want to create a context menu associated to the title bar of a window. + static bool test_window = false; + ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window); + if (test_window) + { + ImGui::Begin("Title bar Hovered/Active tests", &test_window); + if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered() + { + if (ImGui::MenuItem("Close")) { test_window = false; } + ImGui::EndPopup(); + } + ImGui::Text( + "IsItemHovered() after begin = %d (== is title bar hovered)\n" + "IsItemActive() after begin = %d (== is window being clicked/moved)\n", + ImGui::IsItemHovered(), ImGui::IsItemActive()); + ImGui::End(); + } + + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsSelectables() //----------------------------------------------------------------------------- From 71b160cdbb15979dd4142719a5c0ed05d10373ea Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 18:53:45 +0100 Subject: [PATCH 286/716] Demo: (Refactor) Moved code into DemoWindowWidgetsDisableBlocks() section. --- imgui.h | 2 +- imgui_demo.cpp | 34 ++++++++++++++++++++++------------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index 641b1ab92123..1cda94914594 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19185 +#define IMGUI_VERSION_NUM 19186 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index bb3f6ef7c4e1..31904b1b4754 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -256,6 +256,7 @@ static void DemoWindowWidgetsCollapsingHeaders(); static void DemoWindowWidgetsComboBoxes(); static void DemoWindowWidgetsColorAndPickers(); static void DemoWindowWidgetsDataTypes(); +static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgetsDragAndDrop(); static void DemoWindowWidgetsDragsAndSliders(); static void DemoWindowWidgetsImages(); @@ -427,6 +428,7 @@ struct ImGuiDemoWindowData bool ShowAbout = false; // Other data + bool DisableSections = false; ExampleTreeNode* DemoTree = NULL; ~ImGuiDemoWindowData() { if (DemoTree) ExampleTree_DestroyNode(DemoTree); } @@ -825,7 +827,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) if (!ImGui::CollapsingHeader("Widgets")) return; - static bool disable_all = false; // The Checkbox for that is inside the "Disabled" section at the bottom + const bool disable_all = demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom if (disable_all) ImGui::BeginDisabled(); @@ -835,6 +837,13 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsComboBoxes(); DemoWindowWidgetsColorAndPickers(); DemoWindowWidgetsDataTypes(); + + if (disable_all) + ImGui::EndDisabled(); + DemoWindowWidgetsDisableBlocks(demo_data); + if (disable_all) + ImGui::BeginDisabled(); + DemoWindowWidgetsDragAndDrop(); DemoWindowWidgetsDragsAndSliders(); DemoWindowWidgetsImages(); @@ -853,18 +862,8 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsTreeNodes(); DemoWindowWidgetsVerticalSliders(); - // Demonstrate BeginDisabled/EndDisabled using a checkbox located at the bottom of the section (which is a bit odd: - // logically we'd have this checkbox at the top of the section, but we don't want this feature to steal that space) if (disable_all) ImGui::EndDisabled(); - - IMGUI_DEMO_MARKER("Widgets/Disable Block"); - if (ImGui::TreeNode("Disable block")) - { - ImGui::Checkbox("Disable entire section above", &disable_all); - ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section."); - ImGui::TreePop(); - } } //----------------------------------------------------------------------------- @@ -1567,6 +1566,17 @@ static void DemoWindowWidgetsDataTypes() // [SECTION] DemoWindowWidgetsDisableBlocks() //----------------------------------------------------------------------------- +static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data) +{ + IMGUI_DEMO_MARKER("Widgets/Disable Blocks"); + if (ImGui::TreeNode("Disable Blocks")) + { + ImGui::Checkbox("Disable entire section above", &demo_data->DisableSections); + ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across other sections."); + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsDragAndDrop() //----------------------------------------------------------------------------- @@ -1872,7 +1882,7 @@ static void DemoWindowWidgetsImages() static void DemoWindowWidgetsListBoxes() { IMGUI_DEMO_MARKER("Widgets/List Boxes"); - if (ImGui::TreeNode("List boxes")) + if (ImGui::TreeNode("List Boxes")) { // BeginListBox() is essentially a thin wrapper to using BeginChild()/EndChild() // using the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. From df317743272165a8bda2dbe85a0f751495a1e150 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 19:20:10 +0100 Subject: [PATCH 287/716] Disabled: Fixed an issue restoring Alpha in EndDisabled() when using nested BeginDisabled() calls with PushStyleVar(ImGuiStyleVar_DisabledAlpha) within. (#8454, #7640) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 4 +++- imgui_internal.h | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 390681161e0a..2df26e655e26 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -103,6 +103,8 @@ Other changes: (#8451, #7660) [@achabense] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to handle UTF-8 regardless of system regional settings. (#7660) [@achabense] +- Disabled: Fixed an issue restoring Alpha in EndDisabled() when using nested + BeginDisabled() calls with PushStyleVar(ImGuiStyleVar_DisabledAlpha) within. (#8454, #7640) - Clipper: Fixed an issue where passing an out of bound index to IncludeItemByIndex() could incorrectly offset the final cursor, even if that index was not iterated through. One case where it would manifest was calling Combo() with an out of range index. (#8450) diff --git a/imgui.cpp b/imgui.cpp index 77e3c1d36422..bae74db5f2c1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7084,6 +7084,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window_stack_data.Window = window; window_stack_data.ParentLastItemDataBackup = g.LastItemData; window_stack_data.DisabledOverrideReenable = (flags & ImGuiWindowFlags_Tooltip) && (g.CurrentItemFlags & ImGuiItemFlags_Disabled); + window_stack_data.DisabledOverrideReenableAlphaBackup = 0.0f; ErrorRecoveryStoreState(&window_stack_data.StackSizesInBegin); g.StackSizesInBeginForCurrentWindow = &window_stack_data.StackSizesInBegin; if (flags & ImGuiWindowFlags_ChildMenu) @@ -7950,6 +7951,7 @@ void ImGui::BeginDisabledOverrideReenable() { ImGuiContext& g = *GImGui; IM_ASSERT(g.CurrentItemFlags & ImGuiItemFlags_Disabled); + g.CurrentWindowStack.back().DisabledOverrideReenableAlphaBackup = g.Style.Alpha; g.Style.Alpha = g.DisabledAlphaBackup; g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled; g.ItemFlagsStack.push_back(g.CurrentItemFlags); @@ -7963,7 +7965,7 @@ void ImGui::EndDisabledOverrideReenable() IM_ASSERT(g.DisabledStackSize > 0); g.ItemFlagsStack.pop_back(); g.CurrentItemFlags = g.ItemFlagsStack.back(); - g.Style.Alpha = g.DisabledAlphaBackup * g.Style.DisabledAlpha; + g.Style.Alpha = g.CurrentWindowStack.back().DisabledOverrideReenableAlphaBackup; } void ImGui::PushTextWrapPos(float wrap_pos_x) diff --git a/imgui_internal.h b/imgui_internal.h index 4bdc6e94791c..40b854559c2c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1316,6 +1316,7 @@ struct ImGuiWindowStackData ImGuiLastItemData ParentLastItemDataBackup; ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting bool DisabledOverrideReenable; // Non-child window override disabled flag + float DisabledOverrideReenableAlphaBackup; }; struct ImGuiShrinkWidthItem From a7657f2ed45508bb719a8b9e2d8e7bda57eff4a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 4 Mar 2025 14:36:00 +0100 Subject: [PATCH 288/716] Examples: SDL3: Added comments to clarify setup for users of the unfortunate SDL_MAIN_USE_CALLBACKS feature. (#8455) --- docs/CHANGELOG.txt | 2 ++ examples/example_sdl3_opengl3/main.cpp | 5 +++++ examples/example_sdl3_sdlgpu3/main.cpp | 7 ++++++- examples/example_sdl3_sdlrenderer3/main.cpp | 5 +++++ examples/example_sdl3_vulkan/main.cpp | 7 ++++++- 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2df26e655e26..78c6f09da0f7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -115,6 +115,8 @@ Other changes: - Demo: Reorganized "Widgets" section to be alphabetically ordered and split in more functions. - Demo: Combos: demonstrate a very simple way to add a filter to a combo, by showing the filter inside the combo contents. (#718) +- Examples: SDL3: Added comments to clarify setup for users of the unfortunate + SDL_MAIN_USE_CALLBACKS feature. (#8455) - Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. (#8452) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 8cd54bd4ef68..d8666061dac6 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -26,6 +26,7 @@ int main(int, char**) { // Setup SDL + // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function] if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); @@ -139,6 +140,7 @@ int main(int, char**) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function] SDL_Event event; while (SDL_PollEvent(&event)) { @@ -148,6 +150,8 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } + + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function] if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { SDL_Delay(10); @@ -209,6 +213,7 @@ int main(int, char**) #endif // Cleanup + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function] ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index dbc7759ba5d5..630639f3fefb 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -26,7 +26,8 @@ int main(int, char**) { // Setup SDL - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD) != 0) + // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function] + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return -1; @@ -105,6 +106,7 @@ int main(int, char**) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function] SDL_Event event; while (SDL_PollEvent(&event)) { @@ -114,6 +116,8 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } + + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function] if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { SDL_Delay(10); @@ -199,6 +203,7 @@ int main(int, char**) } // Cleanup + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function] SDL_WaitForGPUIdle(gpu_device); ImGui_ImplSDL3_Shutdown(); ImGui_ImplSDLGPU3_Shutdown(); diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 68078eebdebd..ad05a0f919c2 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -24,6 +24,7 @@ int main(int, char**) { // Setup SDL + // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function] if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); @@ -101,6 +102,7 @@ int main(int, char**) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function] SDL_Event event; while (SDL_PollEvent(&event)) { @@ -110,6 +112,8 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } + + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function] if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { SDL_Delay(10); @@ -171,6 +175,7 @@ int main(int, char**) #endif // Cleanup + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function] ImGui_ImplSDLRenderer3_Shutdown(); ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 99e441d7ef4b..170eae45b01b 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -345,7 +345,8 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) int main(int, char**) { // Setup SDL - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD) != 0) + // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function] + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return -1; @@ -447,6 +448,7 @@ int main(int, char**) // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function] SDL_Event event; while (SDL_PollEvent(&event)) { @@ -456,6 +458,8 @@ int main(int, char**) if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) done = true; } + + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function] if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { SDL_Delay(10); @@ -531,6 +535,7 @@ int main(int, char**) } // Cleanup + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function] err = vkDeviceWaitIdle(g_Device); check_vk_result(err); ImGui_ImplVulkan_Shutdown(); From 324172fb1f096739e81c7f9f1f29939c5781e222 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 13:35:14 +0100 Subject: [PATCH 289/716] Demo: (Refactor) Moved DemoWindowWidgets() below the functions it calls, reducing amount of forward declarations. --- imgui_demo.cpp | 126 ++++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 75 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 31904b1b4754..775e0c731309 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -73,7 +73,6 @@ Index of this file: // [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) // [SECTION] Demo Window / ShowDemoWindow() // [SECTION] DemoWindowMenuBar() -// [SECTION] DemoWindowWidgets() // [SECTION] DemoWindowWidgetsBasic() // [SECTION] DemoWindowWidgetsBullets() // [SECTION] DemoWindowWidgetsCollapsingHeaders() @@ -98,6 +97,7 @@ Index of this file: // [SECTION] DemoWindowWidgetsTooltips() // [SECTION] DemoWindowWidgetsTreeNodes() // [SECTION] DemoWindowWidgetsVerticalSliders() +// [SECTION] DemoWindowWidgets() // [SECTION] DemoWindowLayout() // [SECTION] DemoWindowPopups() // [SECTION] DemoWindowTables() @@ -250,30 +250,6 @@ static void ShowExampleMenuFile(); // (because the link time of very large functions tends to grow non-linearly) static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data); static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data); -static void DemoWindowWidgetsBasic(); -static void DemoWindowWidgetsBullets(); -static void DemoWindowWidgetsCollapsingHeaders(); -static void DemoWindowWidgetsComboBoxes(); -static void DemoWindowWidgetsColorAndPickers(); -static void DemoWindowWidgetsDataTypes(); -static void DemoWindowWidgetsDisableBlocks(ImGuiDemoWindowData* demo_data); -static void DemoWindowWidgetsDragAndDrop(); -static void DemoWindowWidgetsDragsAndSliders(); -static void DemoWindowWidgetsImages(); -static void DemoWindowWidgetsListBoxes(); -static void DemoWindowWidgetsPlotting(); -static void DemoWindowWidgetsMultiComponents(); -static void DemoWindowWidgetsProgressBars(); -static void DemoWindowWidgetsQueryingStatuses(); -static void DemoWindowWidgetsSelectables(); -static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_data); -static void DemoWindowWidgetsTabs(); -static void DemoWindowWidgetsText(); -static void DemoWindowWidgetsTextFilter(); -static void DemoWindowWidgetsTextInput(); -static void DemoWindowWidgetsTooltips(); -static void DemoWindowWidgetsTreeNodes(); -static void DemoWindowWidgetsVerticalSliders(); static void DemoWindowLayout(); static void DemoWindowPopups(); static void DemoWindowTables(); @@ -816,56 +792,6 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) } } -//----------------------------------------------------------------------------- -// [SECTION] DemoWindowWidgets() -//----------------------------------------------------------------------------- - -static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) -{ - IMGUI_DEMO_MARKER("Widgets"); - //ImGui::SetNextItemOpen(true, ImGuiCond_Once); - if (!ImGui::CollapsingHeader("Widgets")) - return; - - const bool disable_all = demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom - if (disable_all) - ImGui::BeginDisabled(); - - DemoWindowWidgetsBasic(); - DemoWindowWidgetsBullets(); - DemoWindowWidgetsCollapsingHeaders(); - DemoWindowWidgetsComboBoxes(); - DemoWindowWidgetsColorAndPickers(); - DemoWindowWidgetsDataTypes(); - - if (disable_all) - ImGui::EndDisabled(); - DemoWindowWidgetsDisableBlocks(demo_data); - if (disable_all) - ImGui::BeginDisabled(); - - DemoWindowWidgetsDragAndDrop(); - DemoWindowWidgetsDragsAndSliders(); - DemoWindowWidgetsImages(); - DemoWindowWidgetsListBoxes(); - DemoWindowWidgetsMultiComponents(); - DemoWindowWidgetsPlotting(); - DemoWindowWidgetsProgressBars(); - DemoWindowWidgetsQueryingStatuses(); - DemoWindowWidgetsSelectables(); - DemoWindowWidgetsSelectionAndMultiSelect(demo_data); - DemoWindowWidgetsTabs(); - DemoWindowWidgetsText(); - DemoWindowWidgetsTextFilter(); - DemoWindowWidgetsTextInput(); - DemoWindowWidgetsTooltips(); - DemoWindowWidgetsTreeNodes(); - DemoWindowWidgetsVerticalSliders(); - - if (disable_all) - ImGui::EndDisabled(); -} - //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsBasic() //----------------------------------------------------------------------------- @@ -4183,6 +4109,56 @@ static void DemoWindowWidgetsVerticalSliders() } } +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgets() +//----------------------------------------------------------------------------- + +static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) +{ + IMGUI_DEMO_MARKER("Widgets"); + //ImGui::SetNextItemOpen(true, ImGuiCond_Once); + if (!ImGui::CollapsingHeader("Widgets")) + return; + + const bool disable_all = demo_data->DisableSections; // The Checkbox for that is inside the "Disabled" section at the bottom + if (disable_all) + ImGui::BeginDisabled(); + + DemoWindowWidgetsBasic(); + DemoWindowWidgetsBullets(); + DemoWindowWidgetsCollapsingHeaders(); + DemoWindowWidgetsComboBoxes(); + DemoWindowWidgetsColorAndPickers(); + DemoWindowWidgetsDataTypes(); + + if (disable_all) + ImGui::EndDisabled(); + DemoWindowWidgetsDisableBlocks(demo_data); + if (disable_all) + ImGui::BeginDisabled(); + + DemoWindowWidgetsDragAndDrop(); + DemoWindowWidgetsDragsAndSliders(); + DemoWindowWidgetsImages(); + DemoWindowWidgetsListBoxes(); + DemoWindowWidgetsMultiComponents(); + DemoWindowWidgetsPlotting(); + DemoWindowWidgetsProgressBars(); + DemoWindowWidgetsQueryingStatuses(); + DemoWindowWidgetsSelectables(); + DemoWindowWidgetsSelectionAndMultiSelect(demo_data); + DemoWindowWidgetsTabs(); + DemoWindowWidgetsText(); + DemoWindowWidgetsTextFilter(); + DemoWindowWidgetsTextInput(); + DemoWindowWidgetsTooltips(); + DemoWindowWidgetsTreeNodes(); + DemoWindowWidgetsVerticalSliders(); + + if (disable_all) + ImGui::EndDisabled(); +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowLayout() //----------------------------------------------------------------------------- From fcec08f7ae32656a00e5dde709ff390870a7a84b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 13:39:48 +0100 Subject: [PATCH 290/716] Demo: (Refactor) Moved ExampleTreeNode contents below ShowDemoWindow() so main entry point is more visible to casual reader. --- imgui_demo.cpp | 189 +++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 92 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 775e0c731309..beffe618db0f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -70,9 +70,9 @@ Index of this file: // [SECTION] Forward Declarations // [SECTION] Helpers -// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) // [SECTION] Demo Window / ShowDemoWindow() // [SECTION] DemoWindowMenuBar() +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) // [SECTION] DemoWindowWidgetsBasic() // [SECTION] DemoWindowWidgetsBullets() // [SECTION] DemoWindowWidgetsCollapsingHeaders() @@ -256,6 +256,11 @@ static void DemoWindowTables(); static void DemoWindowColumns(); static void DemoWindowInputs(); +// Helper tree functions used by Property Editor & Multi-Select demos +struct ExampleTreeNode; +static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent); +static void ExampleTree_DestroyNode(ExampleTreeNode* node); + //----------------------------------------------------------------------------- // [SECTION] Helpers //----------------------------------------------------------------------------- @@ -282,97 +287,6 @@ ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL; void* GImGuiDemoMarkerCallbackUserData = NULL; #define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0) -//----------------------------------------------------------------------------- -// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.) -//----------------------------------------------------------------------------- - -// Simple representation for a tree -// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.) -struct ExampleTreeNode -{ - // Tree structure - char Name[28] = ""; - int UID = 0; - ExampleTreeNode* Parent = NULL; - ImVector Childs; - unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily - - // Leaf Data - bool HasData = false; // All leaves have data - bool DataMyBool = true; - int DataMyInt = 128; - ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); -}; - -// Simple representation of struct metadata/serialization data. -// (this is a minimal version of what a typical advanced application may provide) -struct ExampleMemberInfo -{ - const char* Name; // Member name - ImGuiDataType DataType; // Member type - int DataCount; // Member count (1 when scalar) - int Offset; // Offset inside parent structure -}; - -// Metadata description of ExampleTreeNode struct. -static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] -{ - { "MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name) }, - { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) }, - { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) }, - { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) }, -}; - -static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent) -{ - ExampleTreeNode* node = IM_NEW(ExampleTreeNode); - snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); - node->UID = uid; - node->Parent = parent; - node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0; - if (parent) - parent->Childs.push_back(node); - return node; -} - -static void ExampleTree_DestroyNode(ExampleTreeNode* node) -{ - for (ExampleTreeNode* child_node : node->Childs) - ExampleTree_DestroyNode(child_node); - IM_DELETE(node); -} - -// Create example tree data -// (this allocates _many_ more times than most other code in either Dear ImGui or others demo) -static ExampleTreeNode* ExampleTree_CreateDemoTree() -{ - static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; - const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name); - char name_buf[NAME_MAX_LEN]; - int uid = 0; - ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); - const int root_items_multiplier = 2; - for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) - { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); - ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); - const int number_of_childs = (int)strlen(node_L1->Name); - for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) - { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1); - ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); - node_L2->HasData = true; - if (idx_L1 == 0) - { - snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0); - ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); - node_L3->HasData = true; - } - } - } - return node_L0; -} - //----------------------------------------------------------------------------- // [SECTION] Demo Window / ShowDemoWindow() //----------------------------------------------------------------------------- @@ -792,6 +706,97 @@ static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data) } } +//----------------------------------------------------------------------------- +// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos) +//----------------------------------------------------------------------------- + +// Simple representation for a tree +// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.) +struct ExampleTreeNode +{ + // Tree structure + char Name[28] = ""; + int UID = 0; + ExampleTreeNode* Parent = NULL; + ImVector Childs; + unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily + + // Leaf Data + bool HasData = false; // All leaves have data + bool DataMyBool = true; + int DataMyInt = 128; + ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f); +}; + +// Simple representation of struct metadata/serialization data. +// (this is a minimal version of what a typical advanced application may provide) +struct ExampleMemberInfo +{ + const char* Name; // Member name + ImGuiDataType DataType; // Member type + int DataCount; // Member count (1 when scalar) + int Offset; // Offset inside parent structure +}; + +// Metadata description of ExampleTreeNode struct. +static const ExampleMemberInfo ExampleTreeNodeMemberInfos[] +{ + { "MyName", ImGuiDataType_String, 1, offsetof(ExampleTreeNode, Name) }, + { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) }, + { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) }, + { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) }, +}; + +static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent) +{ + ExampleTreeNode* node = IM_NEW(ExampleTreeNode); + snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name); + node->UID = uid; + node->Parent = parent; + node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0; + if (parent) + parent->Childs.push_back(node); + return node; +} + +static void ExampleTree_DestroyNode(ExampleTreeNode* node) +{ + for (ExampleTreeNode* child_node : node->Childs) + ExampleTree_DestroyNode(child_node); + IM_DELETE(node); +} + +// Create example tree data +// (this allocates _many_ more times than most other code in either Dear ImGui or others demo) +static ExampleTreeNode* ExampleTree_CreateDemoTree() +{ + static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" }; + const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name); + char name_buf[NAME_MAX_LEN]; + int uid = 0; + ExampleTreeNode* node_L0 = ExampleTree_CreateNode("", ++uid, NULL); + const int root_items_multiplier = 2; + for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++) + { + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier); + ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0); + const int number_of_childs = (int)strlen(node_L1->Name); + for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++) + { + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1); + ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1); + node_L2->HasData = true; + if (idx_L1 == 0) + { + snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0); + ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2); + node_L3->HasData = true; + } + } + } + return node_L0; +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsBasic() //----------------------------------------------------------------------------- From 119dfbc6270cedf29e8655b296f9ca0f31cede32 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 15:04:26 +0100 Subject: [PATCH 291/716] Debug Tools: Tweaked layout of ID Stack Tool and always display full path. (#4631) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 50 ++++++++++++++++++++++++---------------------- imgui.h | 3 ++- imgui_internal.h | 1 + 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 78c6f09da0f7..a6110cd55197 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -110,6 +110,7 @@ Other changes: One case where it would manifest was calling Combo() with an out of range index. (#8450) - Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) +- Debug Tools: Tweaked layout of ID Stack Tool and always display full path. (#4631) - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors (busy/wait/hourglass shape, with or without an arrow cursor). - Demo: Reorganized "Widgets" section to be alphabetically ordered and split in more functions. diff --git a/imgui.cpp b/imgui.cpp index bae74db5f2c1..8963309133d9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16924,42 +16924,44 @@ void ImGui::ShowIDStackToolWindow(bool* p_open) // Display hovered/active status ImGuiIDStackTool* tool = &g.DebugIDStackTool; - const ImGuiID hovered_id = g.HoveredIdPreviousFrame; - const ImGuiID active_id = g.ActiveId; -#ifdef IMGUI_ENABLE_TEST_ENGINE - Text("HoveredId: 0x%08X (\"%s\"), ActiveId: 0x%08X (\"%s\")", hovered_id, hovered_id ? ImGuiTestEngine_FindItemDebugLabel(&g, hovered_id) : "", active_id, active_id ? ImGuiTestEngine_FindItemDebugLabel(&g, active_id) : ""); -#else - Text("HoveredId: 0x%08X, ActiveId: 0x%08X", hovered_id, active_id); -#endif + + // Build and display path + tool->ResultPathBuf.resize(0); + for (int stack_n = 0; stack_n < tool->Results.Size; stack_n++) + { + char level_desc[256]; + StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc)); + tool->ResultPathBuf.append(stack_n == 0 ? "//" : "/"); + for (int n = 0; level_desc[n]; n++) + { + if (level_desc[n] == '/') + tool->ResultPathBuf.append("\\"); + tool->ResultPathBuf.append(level_desc + n, level_desc + n + 1); + } + } + Text("0x%08X", tool->QueryId); SameLine(); MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details."); // CTRL+C to copy path const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime; - Checkbox("Ctrl+C: copy path to clipboard", &tool->CopyToClipboardOnCtrlC); + SameLine(); + PushStyleVarY(ImGuiStyleVar_FramePadding, 0.0f); Checkbox("Ctrl+C: copy path", &tool->CopyToClipboardOnCtrlC); PopStyleVar(); SameLine(); TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*"); if (tool->CopyToClipboardOnCtrlC && Shortcut(ImGuiMod_Ctrl | ImGuiKey_C, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused)) { tool->CopyToClipboardLastTime = (float)g.Time; - char* p = g.TempBuffer.Data; - char* p_end = p + g.TempBuffer.Size; - for (int stack_n = 0; stack_n < tool->Results.Size && p + 3 < p_end; stack_n++) - { - *p++ = '/'; - char level_desc[256]; - StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc)); - for (int n = 0; level_desc[n] && p + 2 < p_end; n++) - { - if (level_desc[n] == '/') - *p++ = '\\'; - *p++ = level_desc[n]; - } - } - *p = '\0'; - SetClipboardText(g.TempBuffer.Data); + SetClipboardText(tool->ResultPathBuf.c_str()); } + Text("- Path \"%s\"", tool->ResultPathBuf.c_str()); +#ifdef IMGUI_ENABLE_TEST_ENGINE + Text("- Label \"%s\"", tool->QueryId ? ImGuiTestEngine_FindItemDebugLabel(&g, tool->QueryId) : ""); +#endif + + Separator(); + // Display decorated stack tool->LastActiveFrame = g.FrameCount; if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders)) diff --git a/imgui.h b/imgui.h index 1cda94914594..2e6a67b336c3 100644 --- a/imgui.h +++ b/imgui.h @@ -2600,10 +2600,11 @@ struct ImGuiTextBuffer ImGuiTextBuffer() { } inline char operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } - const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator + const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() const { return Buf.Size <= 1; } void clear() { Buf.clear(); } + void resize(int size) { IM_ASSERT(size == 0); if (Buf.Size > 0) Buf.Data[0] = 0; Buf.resize(0); } // Similar to resize(0) on ImVector: empty string but don't free buffer. Only resize(0) supported for now. void reserve(int capacity) { Buf.reserve(capacity); } const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } IMGUI_API void append(const char* str, const char* str_end = NULL); diff --git a/imgui_internal.h b/imgui_internal.h index 40b854559c2c..455a9e0664d3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2030,6 +2030,7 @@ struct ImGuiIDStackTool ImVector Results; bool CopyToClipboardOnCtrlC; float CopyToClipboardLastTime; + ImGuiTextBuffer ResultPathBuf; ImGuiIDStackTool() { memset(this, 0, sizeof(*this)); CopyToClipboardLastTime = -FLT_MAX; } }; From 9f49292b357bacdf23f7131d0fa735672912f50e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 15:23:49 +0100 Subject: [PATCH 292/716] Internals: Menus: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00". --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 30 ++++++++++++++++++++++++------ imgui.h | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 4 ++-- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a6110cd55197..39d73571d3d3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,6 +62,9 @@ Breaking changes: - Backends: Vulkan: Added 'uint32_t api_version' argument to ImGui_ImplVulkan_LoadFunctions(). Note that it was also added to ImGui_ImplVulkan_InitInfo but for the later it is optional. (#8326, #8365, #8400) +- Internals: Menus: reworked mangling of menu windows to use "###Menu_00" etc. instead + of "##Menu_00", allowing them to also store the menu name before it. This shouldn't + affect code unless directly accessing menu window from their mangled name. Other changes: diff --git a/imgui.cpp b/imgui.cpp index 8963309133d9..b2738f1701dd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,6 +431,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/03/05 (1.91.9) - BeginMenu(): Internals: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238) - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); - new: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1)); @@ -7202,7 +7203,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // 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.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + if (g.NavWindowingListWindow != NULL && (flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB + window_title_visible_elsewhere = true; + if (flags & ImGuiWindowFlags_ChildMenu) window_title_visible_elsewhere = true; if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0) { @@ -11714,17 +11717,32 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags) } char name[20]; - if (extra_window_flags & ImGuiWindowFlags_ChildMenu) - ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuDepth); // Recycle windows based on depth - else - ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame + IM_ASSERT((extra_window_flags & ImGuiWindowFlags_ChildMenu) == 0); // Use BeginPopupMenuEx() + ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // No recycling, so we can close/open during the same frame bool is_open = Begin(name, NULL, extra_window_flags | ImGuiWindowFlags_Popup); if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) EndPopup(); - //g.CurrentWindow->FocusRouteParentWindow = g.CurrentWindow->ParentWindowInBeginStack; + return is_open; +} +bool ImGui::BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags extra_window_flags) +{ + ImGuiContext& g = *GImGui; + if (!IsPopupOpen(id, ImGuiPopupFlags_None)) + { + g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values + return false; + } + + char name[128]; + IM_ASSERT(extra_window_flags & ImGuiWindowFlags_ChildMenu); + ImFormatString(name, IM_ARRAYSIZE(name), "%s###Menu_%02d", label, g.BeginMenuDepth); // Recycle windows based on depth + bool is_open = Begin(name, NULL, extra_window_flags | ImGuiWindowFlags_Popup); + if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display) + EndPopup(); + //g.CurrentWindow->FocusRouteParentWindow = g.CurrentWindow->ParentWindowInBeginStack; return is_open; } diff --git a/imgui.h b/imgui.h index 2e6a67b336c3..f154efcb9b5f 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19186 +#define IMGUI_VERSION_NUM 19187 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 455a9e0664d3..a78ae9827c42 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3136,6 +3136,7 @@ namespace ImGui // Popups, Modals IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags); + IMGUI_API bool BeginPopupMenuEx(ImGuiID id, const char* label, ImGuiWindowFlags extra_window_flags); IMGUI_API void OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None); IMGUI_API void ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup); IMGUI_API void ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 76dabb8f9c55..b8b872b1ac8b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8867,7 +8867,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) if (g.MenusIdSubmittedThisFrame.contains(id)) { if (menu_is_open) - menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) else g.NextWindowData.ClearFlags(); // we behave like Begin() and need to consume those values return menu_is_open; @@ -9029,7 +9029,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) ImGuiLastItemData last_item_in_parent = g.LastItemData; SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos. PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding - menu_is_open = BeginPopupEx(id, window_flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) + menu_is_open = BeginPopupMenuEx(id, label, window_flags); // menu_is_open may be 'false' when the popup is completely clipped (e.g. zero size display) PopStyleVar(); if (menu_is_open) { From 377a387a427f152d63596de66bbaa590234a2b1c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 16:23:31 +0100 Subject: [PATCH 293/716] Add proper ImGuiTextBuffer::resize() support other than 0. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index f154efcb9b5f..2f6a18d2aa1a 100644 --- a/imgui.h +++ b/imgui.h @@ -2604,7 +2604,7 @@ struct ImGuiTextBuffer int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() const { return Buf.Size <= 1; } void clear() { Buf.clear(); } - void resize(int size) { IM_ASSERT(size == 0); if (Buf.Size > 0) Buf.Data[0] = 0; Buf.resize(0); } // Similar to resize(0) on ImVector: empty string but don't free buffer. Only resize(0) supported for now. + void resize(int size) { if (Buf.Size > size) Buf.Data[size] = 0; Buf.resize(size ? size + 1 : 0, 0); } // Similar to resize(0) on ImVector: empty string but don't free buffer. void reserve(int capacity) { Buf.reserve(capacity); } const char* c_str() const { return Buf.Data ? Buf.Data : EmptyString; } IMGUI_API void append(const char* str, const char* str_end = NULL); From 1ec99f4fd3a49bcd5479b4ab1a5fd52ce5195c02 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Mar 2025 11:09:02 +0100 Subject: [PATCH 294/716] Internals: added ImStrlen/ImMemchr #define to facilitate experimenting with variations. (#8421) --- imgui.cpp | 50 +++++++++++++++++++++++------------------------ imgui_draw.cpp | 13 ++++++------ imgui_internal.h | 2 ++ imgui_tables.cpp | 2 +- imgui_widgets.cpp | 42 +++++++++++++++++++-------------------- 5 files changed, 56 insertions(+), 53 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b2738f1701dd..cac29a932747 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1986,15 +1986,15 @@ void ImStrncpy(char* dst, const char* src, size_t count) char* ImStrdup(const char* str) { - size_t len = strlen(str); + size_t len = ImStrlen(str); void* buf = IM_ALLOC(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; + size_t dst_buf_size = p_dst_size ? *p_dst_size : ImStrlen(dst) + 1; + size_t src_size = ImStrlen(src) + 1; if (dst_buf_size < src_size) { IM_FREE(dst); @@ -2007,7 +2007,7 @@ char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) const char* ImStrchrRange(const char* str, const char* str_end, char c) { - const char* p = (const char*)memchr(str, (int)c, str_end - str); + const char* p = (const char*)ImMemchr(str, (int)c, str_end - str); return p; } @@ -2022,13 +2022,13 @@ int ImStrlenW(const ImWchar* str) // Find end-of-line. Return pointer will point to either first \n, either str_end. const char* ImStreolRange(const char* str, const char* str_end) { - const char* p = (const char*)memchr(str, '\n', str_end - str); + const char* p = (const char*)ImMemchr(str, '\n', str_end - str); return p ? p : str_end; } const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line { - IM_ASSERT_PARANOID(buf_mid_line >= buf_begin && buf_mid_line <= buf_begin + strlen(buf_begin)); + IM_ASSERT_PARANOID(buf_mid_line >= buf_begin && buf_mid_line <= buf_begin + ImStrlen(buf_begin)); while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n') buf_mid_line--; return buf_mid_line; @@ -2037,7 +2037,7 @@ const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find be const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) { if (!needle_end) - needle_end = needle + strlen(needle); + needle_end = needle + ImStrlen(needle); const char un0 = (char)ImToUpper(*needle); while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) @@ -2158,7 +2158,7 @@ void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, if (buf == NULL) buf = "(null)"; *out_buf = buf; - if (out_buf_end) { *out_buf_end = buf + strlen(buf); } + if (out_buf_end) { *out_buf_end = buf + ImStrlen(buf); } } else if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '*' && fmt[3] == 's' && fmt[4] == 0) { @@ -2567,11 +2567,11 @@ const char* ImTextFindPreviousUtf8Codepoint(const char* in_text_start, const cha int ImTextCountLines(const char* in_text, const char* in_text_end) { if (in_text_end == NULL) - in_text_end = in_text + strlen(in_text); // FIXME-OPT: Not optimal approach, discourage use for now. + in_text_end = in_text + ImStrlen(in_text); // FIXME-OPT: Not optimal approach, discourage use for now. int count = 0; while (in_text < in_text_end) { - const char* line_end = (const char*)memchr(in_text, '\n', in_text_end - in_text); + const char* line_end = (const char*)ImMemchr(in_text, '\n', in_text_end - in_text); in_text = line_end ? line_end + 1 : in_text_end; count++; } @@ -2852,7 +2852,7 @@ void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector 0) || (data == NULL && data_size == 0)); IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once); IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource() @@ -14378,7 +14378,7 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* } if (prefix) - LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here. + LogRenderedText(ref_pos, prefix, prefix + ImStrlen(prefix)); // Calculate end ourself to ensure "##" are included here. // Re-adjust padding if we have popped out of our starting depth if (g.LogDepthRef > window->DC.TreeDepth) @@ -14411,7 +14411,7 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* } if (suffix) - LogRenderedText(ref_pos, suffix, suffix + strlen(suffix)); + LogRenderedText(ref_pos, suffix, suffix + ImStrlen(suffix)); } // Start logging/capturing text output @@ -14677,7 +14677,7 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size) // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter). // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy.. if (ini_size == 0) - ini_size = strlen(ini_data); + ini_size = ImStrlen(ini_data); g.SettingsIniData.Buf.resize((int)ini_size + 1); char* const buf = g.SettingsIniData.Buf.Data; char* const buf_end = buf + ini_size; @@ -14778,7 +14778,7 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) if (const char* p = strstr(name, "###")) name = p; } - const size_t name_len = strlen(name); + const size_t name_len = ImStrlen(name); // Allocate chunk const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1; @@ -15070,7 +15070,7 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* t if (!main_clipboard) PasteboardCreate(kPasteboardClipboard, &main_clipboard); PasteboardClear(main_clipboard); - CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text)); + CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, ImStrlen(text)); if (cf_data) { PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0); @@ -15124,7 +15124,7 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const cha { ImGuiContext& g = *ctx; g.ClipboardHandlerData.clear(); - const char* text_end = text + strlen(text); + const char* text_end = text + ImStrlen(text); g.ClipboardHandlerData.resize((int)(text_end - text) + 1); memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text)); g.ClipboardHandlerData[(int)(text_end - text)] = 0; @@ -16894,7 +16894,7 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id); break; case ImGuiDataType_String: - ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id), (const char*)data_id); + ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)ImStrlen((const char*)data_id), (const char*)data_id); break; case ImGuiDataType_Pointer: ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 206c29ce5a06..efdddc8b1857 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -143,6 +143,7 @@ namespace IMGUI_STB_NAMESPACE #define STBTT_fabs(x) ImFabs(x) #define STBTT_ifloor(x) ((int)ImFloor(x)) #define STBTT_iceil(x) ((int)ImCeil(x)) +#define STBTT_strlen(x) ImStrlen(x) #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #else @@ -2672,7 +2673,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, { // Store a short copy of filename into into the font name for convenience const char* p; - for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} + for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); } return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); @@ -2707,7 +2708,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_d ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges) { - int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4; + int compressed_ttf_size = (((int)ImStrlen(compressed_ttf_data_base85) + 4) / 5) * 4; void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size); Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf); ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges); @@ -4029,7 +4030,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) { if (!text_end) - text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this. + text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this. const float line_height = size; const float scale = size / FontSize; @@ -4129,7 +4130,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im return; if (!text_end) - text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. + text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. const float scale = size / FontSize; const float line_height = FontSize * scale; @@ -4141,7 +4142,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im if (y + line_height < clip_rect.y) while (y + line_height < clip_rect.y && s < text_end) { - const char* line_end = (const char*)memchr(s, '\n', text_end - s); + const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s); if (word_wrap_enabled) { // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). @@ -4165,7 +4166,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im float y_end = y; while (y_end < clip_rect.w && s_end < text_end) { - s_end = (const char*)memchr(s_end, '\n', text_end - s_end); + s_end = (const char*)ImMemchr(s_end, '\n', text_end - s_end); s_end = s_end ? s_end + 1 : text_end; y_end += line_height; } diff --git a/imgui_internal.h b/imgui_internal.h index a78ae9827c42..b7395fcae087 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -372,6 +372,8 @@ static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } // Helpers: String +#define ImStrlen strlen +#define ImMemchr memchr IMGUI_API int ImStricmp(const char* str1, const char* str2); // Case insensitive compare. IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); // Case insensitive compare to a certain count. IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); // Copy to a certain count and always zero terminate (strncpy doesn't). diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f6aff8c026fb..6c79262363f2 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1648,7 +1648,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo if (label != NULL && label[0] != 0) { column->NameOffset = (ImS16)table->ColumnsNames.size(); - table->ColumnsNames.append(label, label + strlen(label) + 1); + table->ColumnsNames.append(label, label + ImStrlen(label) + 1); } } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b8b872b1ac8b..01e4e61872c9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -169,7 +169,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) // Calculate length const char* text_begin = text; if (text_end == NULL) - text_end = text + strlen(text); // FIXME-OPT + text_end = text + ImStrlen(text); // FIXME-OPT const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); const float wrap_pos_x = window->DC.TextWrapPos; @@ -209,7 +209,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) int lines_skipped = 0; while (line < text_end && lines_skipped < lines_skippable) { - const char* line_end = (const char*)memchr(line, '\n', text_end - line); + const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) @@ -230,7 +230,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) if (IsClippedEx(line_rect, 0)) break; - const char* line_end = (const char*)memchr(line, '\n', text_end - line); + const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; text_size.x = ImMax(text_size.x, CalcTextSize(line, line_end).x); @@ -245,7 +245,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags) int lines_skipped = 0; while (line < text_end) { - const char* line_end = (const char*)memchr(line, '\n', text_end - line); + const char* line_end = (const char*)ImMemchr(line, '\n', text_end - line); if (!line_end) line_end = text_end; if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0) @@ -2064,7 +2064,7 @@ static const char* Items_SingleStringGetter(void* data, int idx) { if (idx == items_count) break; - p += strlen(p) + 1; + p += ImStrlen(p) + 1; items_count++; } return *p ? p : NULL; @@ -2132,7 +2132,7 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open while (*p) { - p += strlen(p) + 1; + p += ImStrlen(p) + 1; items_count++; } bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items); @@ -3899,7 +3899,7 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** line_count++; if (s_eol == NULL) { - s = s + strlen(s); + s = s + ImStrlen(s); break; } s = s_eol + 1; @@ -4187,7 +4187,7 @@ void ImGuiInputTextState::OnCharPressed(unsigned int c) // The changes we had to make to stb_textedit_key made it very much UTF-8 specific which is not too great. char utf8[5]; ImTextCharToUtf8(utf8, c); - stb_textedit_text(this, Stb, utf8, (int)strlen(utf8)); + stb_textedit_text(this, Stb, utf8, (int)ImStrlen(utf8)); CursorFollow = true; CursorAnimReset(); } @@ -4238,7 +4238,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons // Grow internal buffer if needed const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; - const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text); + const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text); if (new_text_len + BufTextLen >= BufSize) { if (!is_resizable) @@ -4560,7 +4560,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool init_state = (init_make_active || user_scroll_active); if (init_reload_from_user_buf) { - int new_len = (int)strlen(buf); + int new_len = (int)ImStrlen(buf); IM_ASSERT(new_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); state->WantReloadUserBuf = false; InputTextReconcileUndoState(state, state->TextA.Data, state->TextLen, buf, new_len); @@ -4582,7 +4582,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Take a copy of the initial buffer value. // From the moment we focused we are normally ignoring the content of 'buf' (unless we are in read-only mode) - const int buf_len = (int)strlen(buf); + const int buf_len = (int)ImStrlen(buf); IM_ASSERT(buf_len + 1 <= buf_size && "Is your input buffer properly zero-terminated?"); state->TextToRevertTo.resize(buf_len + 1); // UTF-8. we use +1 to make sure that .Data is always pointing to at least an empty string. memcpy(state->TextToRevertTo.Data, buf, buf_len + 1); @@ -4667,7 +4667,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Read-only mode always ever read from source buffer. Refresh TextLen when active. if (is_readonly && state != NULL) - state->TextLen = (int)strlen(buf); + state->TextLen = (int)ImStrlen(buf); //if (is_readonly && state != NULL) // state->TextA.clear(); // Uncomment to facilitate debugging, but we otherwise prefer to keep/amortize th allocation. } @@ -4946,7 +4946,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (const char* clipboard = GetClipboardText()) { // Filter pasted buffer - const int clipboard_len = (int)strlen(clipboard); + const int clipboard_len = (int)ImStrlen(clipboard); ImVector clipboard_filtered; clipboard_filtered.reserve(clipboard_len + 1); for (const char* s = clipboard; *s != 0; ) @@ -4958,7 +4958,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ continue; char c_utf8[5]; ImTextCharToUtf8(c_utf8, c); - int out_len = (int)strlen(c_utf8); + int out_len = (int)ImStrlen(c_utf8); clipboard_filtered.resize(clipboard_filtered.Size + out_len); memcpy(clipboard_filtered.Data + clipboard_filtered.Size - out_len, c_utf8, out_len); } @@ -5088,7 +5088,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (buf_dirty) { // Callback may update buffer and thus set buf_dirty even in read-only mode. - IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! + IM_ASSERT(callback_data.BufTextLen == (int)ImStrlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text! InputTextReconcileUndoState(state, state->CallbackTextBackup.Data, state->CallbackTextBackup.Size - 1, callback_data.Buf, callback_data.BufTextLen); state->TextLen = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen() state->CursorAnimReset(); @@ -5187,7 +5187,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_displaying_hint) { buf_display = hint; - buf_display_end = hint + strlen(hint); + buf_display_end = hint + ImStrlen(hint); } // Render text. We currently only render selection when the widget is active or while scrolling. @@ -5220,7 +5220,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ int line_count = 1; if (is_multiline) { - for (const char* s = text_begin; (s = (const char*)memchr(s, '\n', (size_t)(text_end - s))) != NULL; s++) + for (const char* s = text_begin; (s = (const char*)ImMemchr(s, '\n', (size_t)(text_end - s))) != NULL; s++) { if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; } if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; } @@ -5298,7 +5298,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ break; if (rect_pos.y < clip_rect.y) { - p = (const char*)memchr((void*)p, '\n', text_selected_end - p); + p = (const char*)ImMemchr((void*)p, '\n', text_selected_end - p); p = p ? p + 1 : text_selected_end; } else @@ -5350,7 +5350,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else if (!is_displaying_hint && g.ActiveId == id) buf_display_end = buf_display + state->TextLen; else if (!is_displaying_hint) - buf_display_end = buf_display + strlen(buf_display); + buf_display_end = buf_display + ImStrlen(buf_display); if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length) { @@ -7184,7 +7184,7 @@ ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags f // Append to buffer const int buffer_max_len = IM_ARRAYSIZE(data->SearchBuffer) - 1; - int buffer_len = (int)strlen(data->SearchBuffer); + int buffer_len = (int)ImStrlen(data->SearchBuffer); bool select_request = false; for (ImWchar w : g.IO.InputQueueCharacters) { @@ -10111,7 +10111,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, else { tab->NameOffset = (ImS32)tab_bar->TabsNames.size(); - tab_bar->TabsNames.append(label, label + strlen(label) + 1); + tab_bar->TabsNames.append(label, label + ImStrlen(label) + 1); } // Update selected tab From 806731e37a27dab2abae14cc26a970d37ef9cd7d Mon Sep 17 00:00:00 2001 From: TheMode Date: Sun, 9 Mar 2025 06:28:36 +0100 Subject: [PATCH 295/716] Set IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS on 3DS sdk (#8477, #8476) --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cac29a932747..73bd2581ece2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15138,11 +15138,13 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const cha #if defined(__APPLE__) && TARGET_OS_IPHONE #define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS #endif - -#if defined(_WIN32) && defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#if defined(__3DS__) #define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS #endif +#if defined(_WIN32) && defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS #endif +#endif // #ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS #ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS #ifdef _WIN32 From 3c3d943fb13c7ae2ddecbfe5f73252c4820f3a9f Mon Sep 17 00:00:00 2001 From: fdsa <14tanks999@gmail.com> Date: Sat, 8 Mar 2025 01:28:48 -0800 Subject: [PATCH 296/716] Docs: Fix some typos (#8473) --- backends/imgui_impl_opengl3.cpp | 2 +- backends/imgui_impl_osx.mm | 2 +- backends/imgui_impl_vulkan.cpp | 2 +- docs/CHANGELOG.txt | 138 ++++++++++++++++---------------- docs/FAQ.md | 4 +- docs/TODO.txt | 4 +- imgui.cpp | 10 +-- imgui.h | 2 +- imgui_demo.cpp | 6 +- imgui_internal.h | 6 +- imgui_tables.cpp | 4 +- imgui_widgets.cpp | 2 +- 12 files changed, 91 insertions(+), 91 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 1311d1bc9f0e..7d0b53621960 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -54,7 +54,7 @@ // 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state. // 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state. // 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x) -// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader. +// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre-3.3 context which have the defines set by a loader. // 2020-07-10: OpenGL: Added support for glad2 OpenGL loader. // 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX. // 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 4726462cbec5..2d72d413ebde 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -39,7 +39,7 @@ // 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F20 function keys. Stopped mapping F13 into PrintScreen. // 2023-04-09: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_Pen. -// 2023-02-01: Fixed scroll wheel scaling for devices emitting events with hasPreciseScrollingDeltas==false (e.g. non-Apple mices). +// 2023-02-01: Fixed scroll wheel scaling for devices emitting events with hasPreciseScrollingDeltas==false (e.g. non-Apple mice). // 2022-11-02: Fixed mouse coordinates before clicking the host window. // 2022-10-06: Fixed mouse inputs on flipped views. // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported). diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 7379e000b741..e67b74c01455 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -53,7 +53,7 @@ // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2022-10-04: Vulkan: Added experimental ImGui_ImplVulkan_RemoveTexture() for api symmetry. (#914, #5738). // 2022-01-20: Vulkan: Added support for ImTextureID as VkDescriptorSet. User need to call ImGui_ImplVulkan_AddTexture(). Building for 32-bit targets requires '#define ImTextureID ImU64'. (#914). -// 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. +// 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likelihood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-03-22: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize. // 2021-02-18: Vulkan: Change blending equation to preserve alpha in output buffer. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 39d73571d3d3..ca5ab47e386b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -101,7 +101,7 @@ Other changes: - Default for selected tabs: TabCloseButtonMinWidthSelected = -1.0f (always visible) - Default for unselected tabs: TabCloseButtonMinWidthUnselected = 0.0f (visible when hovered) - Tabs: fixed middle-mouse-button to close tab not checking that close button - is hovered, merely it's visibility. (#8399, #8387) [@nicovanbentum] + is hovered, merely its visibility. (#8399, #8387) [@nicovanbentum] - TextLink(), TextLinkOpenURL(): fixed honoring text baseline alignment. (#8451, #7660) [@achabense] - TextLinkOpenURL(): fixed default Win32 io.PlatformOpenInShellFn handler to @@ -678,7 +678,7 @@ Other changes: by an extra pixel + rework the change so that contents doesn't overlap the bottom and right border in a scrolling table. (#6765, #3752, #7428) - Tables: fixed an issue resizing columns or querying hovered column/row when using multiple - synched instances that are layed out at different X positions. (#7933) + synced instances that are laid out at different X positions. (#7933) - Tabs: avoid queuing a refocus when tab is already focused, which would have the side-effect of e.g. closing popup on a mouse release. (#7914) - InputText: allow callback to update buffer while in read-only mode. (imgui_club/#46) @@ -911,7 +911,7 @@ Other changes: - Windows: BeginChild(): fixed a glitch when during a resize of a child window which is tightly close to the boundaries of its parent (e.g. with zero WindowPadding), the child position could have temporarily be moved around by erroneous padding application. (#7706) -- TabBar, Style: added ImGuiTabBarFlags_DrawSelectedOverline option to draw an horizontal +- TabBar, Style: added ImGuiTabBarFlags_DrawSelectedOverline option to draw a horizontal line over selected tabs to increase visibility. This is used by docking. Added corresponding ImGuiCol_TabSelectedOverline and ImGuiCol_TabDimmedSelectedOverline colors. - Tables: added TableGetHoveredColumn() to public API, as an alternative to testing for @@ -974,7 +974,7 @@ Other changes: - Scrollbar: made scrolling logic more standard: clicking above or below the grab scrolls by one page, holding mouse button repeats scrolling. (#7328, #150) - Scrollbar: fixed miscalculation of vertical scrollbar visibility when required - solely by the presence of an horizontal scrollbar. (#1574) + solely by the presence of a horizontal scrollbar. (#1574) - InputScalar, InputInt, InputFloat: added ImGuiInputTextFlags_ParseEmptyRefVal to parse an empty field as zero-value. (#7305) [@supermerill, @ocornut] - InputScalar, InputInt, InputFloat: added ImGuiInputTextFlags_DisplayEmptyRefVal @@ -1108,7 +1108,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking changes: -- TreeNode: Fixed a layout inconsistency when using a empty/hidden label followed +- TreeNode: Fixed a layout inconsistency when using an empty/hidden label followed by a SameLine() call. (#7505, #282) Before: TreeNode("##Hidden"); SameLine(); Text("Hello"); // This was actually incorrect! BUT appeared to look ok with the default style @@ -1207,7 +1207,7 @@ Other changes: Note that only simple polygons (no self-intersections, no holes) are supported. - DrawList: Allow AddText() to accept null ranges. (#3615, 7391) - Docs: added more wiki links to headers of imgui.h/imgui.cpp to facilitate discovery - of interesting resources, because github doesn't allow Wiki to be crawled by search engines. + of interesting resources, because GitHub doesn't allow Wiki to be crawled by search engines. - This is the main wiki: https://github.com/ocornut/imgui/wiki - This is the crawlable version: https://github-wiki-see.page/m/ocornut/imgui/wiki Adding a link to the crawlable version, even though it is not intended for humans, @@ -1359,7 +1359,7 @@ Other changes: - BeginChild(): Resize borders rendered even when ImGuiWindowFlags_NoBackground is specified. (#1710, #7194) - Fixed some auto-resizing path using style.WindowMinSize.x (instead of x/y) - for both axises since 1.90. (#7106) [@n0bodysec] + for both axes since 1.90. (#7106) [@n0bodysec] - Scrolling: internal scrolling value is rounded instead of truncated, as a way to reduce speed asymmetry when (incorrectly) attempting to scroll by non-integer amount. (#6677) - Navigation (Keyboard/gamepad): @@ -1517,7 +1517,7 @@ Other changes: - Combining this with also specifying ImGuiChildFlags_AlwaysAutoResize disables this optimization, meaning child contents will never be clipped (not recommended). - Please be considerate that child are full windows and carry significant overhead: - combining auto-resizing for both axises to create a non-scrolling child to merely draw + combining auto-resizing for both axes to create a non-scrolling child to merely draw a border would be better more optimally using BeginGroup(). (see #1496) (until we come up with new helpers for framed groups and work-rect adjustments). - BeginChild(): made it possible to use SetNextWindowSizeConstraints() rectangle, often @@ -1579,7 +1579,7 @@ Other changes: parent-menu would erroneously close the child-menu. (Regression from 1.88). (#6869) - MenuBar: Fixed an issue where layouting an item in the menu-bar would erroneously register contents size in a way that would affect the scrolling layer. - Was most often noticeable when using an horizontal scrollbar. (#6789) + Was most often noticeable when using a horizontal scrollbar. (#6789) - InputText: - InputTextMultiline: Fixed a crash pressing Down on last empty line of a multi-line buffer. (regression from 1.89.2, only happened in some states). (#6783, #6000) @@ -1785,7 +1785,7 @@ Breaking changes: - Moved io.HoverDelayShort/io.HoverDelayNormal to style.HoverDelayShort/style.HoverDelayNormal. As the fields were added in 1.89 and expected to be left unchanged by most users, or only - tweaked once during app initialisation, we are exceptionally accepting the breakage. + tweaked once during app initialization, we are exceptionally accepting the breakage. Majority of users should not even notice. - Overlapping items: (#6512, #3909, #517) - Added 'SetNextItemAllowOverlap()' (called before an item) as a replacement for using @@ -1885,7 +1885,7 @@ Breaking changes: - Commented out obsolete/redirecting functions that were marked obsolete more than two years ago: - ListBoxHeader() -> use BeginListBox() - ListBoxFooter() -> use EndListBox() - - Note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for refeence. + - Note how two variants of ListBoxHeader() existed. Check commented versions in imgui.h for reference. - Backends: SDL_Renderer: Renamed 'imgui_impl_sdlrenderer.h/cpp' to 'imgui_impl_sdlrenderer2.h/cpp', in order to accommodate for upcoming SDL3 and change in its SDL_Renderer API. (#6286) - Backends: GLUT: Removed call to ImGui::NewFrame() from ImGui_ImplGLUT_NewFrame(). @@ -2112,20 +2112,20 @@ Other changes: due to how unique table instance id was generated. (#6140) [@ocornut, @rodrigorc] - Inputs, Scrolling: Made horizontal scroll wheel and horizontal scroll direction consistent across backends/os. (#4019, #6096, #1463) [@PathogenDavid, @ocornut, @rokups] - - Clarified that 'wheel_y > 0.0f' scrolls Up, 'wheel_y > 0.0f' scrolls Down. - Clarified that 'wheel_x > 0.0f' scrolls Left, 'wheel_x > 0.0f' scrolls Right. + - Clarified that 'wheel_y > 0.0f' scrolls Up, 'wheel_y < 0.0f' scrolls Down. + Clarified that 'wheel_x > 0.0f' scrolls Left, 'wheel_x < 0.0f' scrolls Right. - Backends: Fixed horizontal scroll direction for Win32 and SDL backends. (#4019) - Shift+WheelY support on non-OSX machines was already correct. (#2424, #1463) (whereas on OSX machines Shift+WheelY turns into WheelX at the OS level). - If you use a custom backend, you should verify horizontal wheel direction. - - Axises are flipped by OSX for mouse & touch-pad when 'Natural Scrolling' is on. - - Axises are flipped by Windows for touch-pad when 'Settings->Touchpad->Down motion scrolls up' is on. + - Axes are flipped by OSX for mouse & touch-pad when 'Natural Scrolling' is on. + - Axes are flipped by Windows for touch-pad when 'Settings->Touchpad->Down motion scrolls up' is on. - You can use 'Demo->Tools->Debug Log->IO" to visualize values submitted to Dear ImGui. - Known issues remaining with Emscripten: - The magnitude of wheeling values on Emscripten was improved but isn't perfect. (#6096) - When running the Emscripten app on a Mac with a mouse, SHIFT+WheelY doesn't turn into WheelX. This is because we don't know that we are running on Mac and apply our own Shift+swapping - on top of OSX' own swapping, so wheel axises are swapped twice. Emscripten apps may need + on top of OSX's own swapping, so wheel axes are swapped twice. Emscripten apps may need to find a way to detect this and set io.ConfigMacOSXBehaviors manually (if you know a way let us know!), or offer the "OSX-style behavior" option to their user. - Window: Avoid rendering shapes for hidden resize grips. @@ -2151,7 +2151,7 @@ Other changes: values for io.DeltaTime, and browser features such as "privacy.resistFingerprinting=true" can exacerbate that. (#6114, #3644) - Backends: OSX: Fixed scroll/wheel scaling for devices emitting events with - hasPreciseScrollingDeltas==false (e.g. non-Apple mices). + hasPreciseScrollingDeltas==false (e.g. non-Apple mice). - Backends: Win32: flipping WM_MOUSEHWHEEL horizontal value to match other backends and offer consistent horizontal scrolling direction. (#4019) - Backends: SDL2: flipping SDL_MOUSEWHEEL horizontal value to match other backends and @@ -2355,7 +2355,7 @@ Other Changes: - Scrolling: Mitigated issue where multi-axis mouse-wheel inputs (usually from touch pad events) are incorrectly locking scrolling in a parent window. (#4559, #3795, #2604) - Scrolling: Exposed SetNextWindowScroll() in public API. Useful to remove a scrolling - delay in some situations where e.g. windows need to be synched. (#1526) + delay in some situations where e.g. windows need to be synced. (#1526) - InputText: added experimental io.ConfigInputTextEnterKeepActive feature to make pressing Enter keep the input active and select all text. - InputText: numerical fields automatically accept full-width characters (U+FF01..U+FF5E) @@ -2399,7 +2399,7 @@ Other Changes: - Menus: Fixed using IsItemHovered()/IsItemClicked() on BeginMenu(). (#5775) - Menus, Popups: Experimental fix for issue where clicking on an open BeginMenu() item called from a window which is neither a popup neither a menu used to incorrectly close and reopen the menu - (the fix may have side-effect and is labelld as experimental as we may need to revert). (#5775) + (the fix may have side-effect and is labelled as experimental as we may need to revert). (#5775) - Menus, Nav: Fixed keyboard/gamepad navigation occasionally erroneously landing on menu-item in parent window when the parent is not a popup. (#5730) - Menus, Nav: Fixed not being able to close a menu with Left arrow when parent is not a popup. (#5730) @@ -2537,7 +2537,7 @@ Other Changes: always lead to menu closure. Fixes using items that are not MenuItem() or BeginItem() at the root level of a popup with a child menu opened. - Menus: Menus emitted from the main/scrolling layer are not part of the same menu-set as menus emitted - from the menu-bar, avoiding accidental hovering from one to the other. (#3496, #4797) [@rokups] + from the menu-bar, avoiding accidental hovering from one to the other. (#3496, #4797) [@rokups] - Style: Adjust default value of GrabMinSize from 10.0f to 12.0f. - Stack Tool: Added option to copy item path to clipboard. (#4631) - Settings: Fixed out-of-bounds read when .ini file on disk is empty. (#5351) [@quantum5] @@ -2639,7 +2639,7 @@ Breaking Changes: io.AddKeyEvent(), io.AddKeyAnalogEvent(). - Added io.AddKeyAnalogEvent() function, obsoleting writing directly to io.NavInputs[] arrays. - Renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. (#2625) -- Removed support for legacy arithmetic operators (+,+-,*,/) when inputing text into a slider/drag. (#4917, #3184) +- Removed support for legacy arithmetic operators (+,+-,*,/) when inputting text into a slider/drag. (#4917, #3184) This doesn't break any api/code but a feature that was accessible by end-users (which seemingly no one used). (Instead you may implement custom expression evaluators to provide a better version of this). - Backends: GLFW: backend now uses glfwSetCursorPosCallback(). @@ -2695,7 +2695,7 @@ Other Changes: - Backends: GLFW: Retrieve mouse position using glfwSetCursorPosCallback() + fallback when focused but not hovered/captured. - Backends: GLFW: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4921) - Backends: GLFW: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing - callbacks after iniitializing backend. (#4981) + callbacks after initializing backend. (#4981) - Backends: Win32: Submit keys and key mods using io.AddKeyEvent(). (#2625, #4921) - Backends: Win32: Retrieve mouse position using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback when focused but not hovered/captured. - Backends: Win32: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921) @@ -2777,7 +2777,7 @@ Other Changes: - Menus: fixed sub-menu items inside a popups from closing the popup. - Menus: fixed top-level menu from not consistently using style.PopupRounding. (#4788) - InputText, Nav: fixed repeated calls to SetKeyboardFocusHere() preventing to use InputText(). (#4682) -- Inputtext, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761) +- InputText, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761) - InputText: made double-click select word, triple-line select line. Word delimitation logic differs slightly from the one used by CTRL+arrows. (#2244) - InputText: fixed ReadOnly flag preventing callbacks from receiving the text buffer. (#4762) [@actondev] @@ -2808,7 +2808,7 @@ Other Changes: - Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups] - CI: Add MinGW DLL build to test suite. [@rokups] - Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce - likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling + likelihood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame. (#4644) - Backends: OpenGL3: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers, and perhaps improve performances. (#4468, #4504, #2981, #3381) [@parbo] @@ -2884,7 +2884,7 @@ Other Changes: - Nav: Fixed vertical scoring offset when wrapping on Y in a decorated window. - Nav: Improve scrolling behavior when navigating to an item larger than view. - TreePush(): removed unnecessary/inconsistent legacy behavior where passing a NULL value to - the TreePush(const char*) and TreePush(const void*) functions would use an hard-coded replacement. + the TreePush(const char*) and TreePush(const void*) functions would use a hard-coded replacement. The only situation where that change would make a meaningful difference is TreePush((const char*)NULL) (_explicitly_ casting a null pointer to const char*), which is unlikely and will now crash. You may replace it with anything else. @@ -3007,9 +3007,9 @@ Other Changes: - Fonts: Functions with a 'float size_pixels' parameter can accept zero if it is set in ImFontSize::SizePixels. - Fonts: Prefer using U+FFFD character for fallback instead of '?', if available. (#4269) - Fonts: Use U+FF0E dot character to construct an ellipsis if U+002E '.' is not available. (#4269) -- Fonts: Added U+FFFD ("replacement character") to default asian glyphs ranges. (#4269) +- Fonts: Added U+FFFD ("replacement character") to default Asian glyphs ranges. (#4269) - Fonts: Fixed calling ClearTexData() (clearing CPU side font data) triggering an assert in NewFrame(). (#3487) -- DrawList: Fixed AddCircle/AddCircleFilled() with auto-tesselation not using accelerated paths for small circles. +- DrawList: Fixed AddCircle/AddCircleFilled() with auto-tessellation not using accelerated paths for small circles. Fixed AddCircle/AddCircleFilled() with 12 segments which had a broken edge. (#4419, #4421) [@thedmd] - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid @@ -3053,7 +3053,7 @@ Other Changes: - Examples: OSX+OpenGL2: Fix event forwarding (fix key remaining stuck when using shortcuts with Cmd/Super key). Other OSX examples were not affected. (#4253, #1873) [@rokups] - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg. -- Examples: SDL2: Accommodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. +- Examples: SDL2: Accommodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. ----------------------------------------------------------------------- @@ -3175,7 +3175,7 @@ Breaking Changes: - ImDrawList: clarified that PathArcTo()/PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would lead to counter-clockwise paths which and have an effect on anti-aliasing. - InputText: renamed ImGuiInputTextFlags_AlwaysInsertMode to ImGuiInputTextFlags_AlwaysOverwrite, old name was an - incorrect description of behavior. Was ostly used by memory editor. Kept inline redirection function. (#2863) + incorrect description of behavior. Was mostly used by memory editor. Kept inline redirection function. (#2863) - Moved 'misc/natvis/imgui.natvis' to 'misc/debuggers/imgui.natvis' as we will provide scripts for other debuggers. - Style: renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as its meaning changed. (#3808) [@thedmd] @@ -3273,7 +3273,7 @@ Other Changes: - For a Platform Monitor, the work area is generally the full area minus space used by task-bars. - All of this has been the case in 'docking' branch for a long time. What we've done is merely merging a small chunk of the multi-viewport logic into 'master' to standardize some concepts ahead of time. -- Tables: Fixed PopItemWidth() or multi-components items not restoring per-colum ItemWidth correctly. (#3760) +- Tables: Fixed PopItemWidth() or multi-components items not restoring per-column ItemWidth correctly. (#3760) - Window: Fixed minor title bar text clipping issue when FramePadding is small/zero and there are no close button in the window. (#3731) - SliderInt: Fixed click/drag when v_min==v_max from setting the value to zero. (#3774) [@erwincoumans] @@ -3310,7 +3310,7 @@ Other Changes: User needs to call ImGui_ImplVulkan_LoadFunctions() with their custom loader prior to other functions. - Backends: Metal: Fixed texture storage mode when building on Mac Catalyst. (#3748) [@Belinsky-L-V] - Backends: OSX: Fixed mouse position not being reported when mouse buttons other than left one are down. (#3762) [@rokups] -- Backends: WebGPU: Added enderer backend for WebGPU support (imgui_impl_wgpu.cpp) (#3632) [@bfierz] +- Backends: WebGPU: Added renderer backend for WebGPU support (imgui_impl_wgpu.cpp) (#3632) [@bfierz] Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break. - Examples: WebGPU: Added Emscripten+WebGPU example. (#3632) [@bfierz] - Backends: GLFW: Added ImGui_ImplGlfw_InitForOther() initialization call to use with non OpenGL API. (#3632) @@ -3509,12 +3509,12 @@ Other Changes: - Columns: Fix inverted ClipRect being passed to renderer when using certain primitives inside of a fully clipped column. (#3475) [@szreder] - Popups, Tooltips: Fix edge cases issues with positioning popups and tooltips when they are larger than - viewport on either or both axises. [@Rokups] + viewport on either or both axes. [@Rokups] - Fonts: AddFontDefault() adjust its vertical offset based on floor(size/13) instead of always +1. Was previously done by altering DisplayOffset.y but wouldn't work for DPI scaled font. - Metrics: Various tweaks, listing windows front-to-back, greying inactive items when possible. - Demo: Add simple InputText() callbacks demo (aside from the more elaborate ones in 'Examples->Console'). -- Backends: OpenGL3: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 contexts which have +- Backends: OpenGL3: Fix to avoid compiling/calling glBindSampler() on ES or pre-3.3 contexts which have the defines set by a loader. (#3467, #1985) [@jjwebb] - Backends: Vulkan: Some internal refactor aimed at allowing multi-viewport feature to create their own render pass. (#3455, #3459) [@FunMiles] @@ -3603,7 +3603,7 @@ Other Changes: and allowed to pass them to InvisibleButton(): ImGuiButtonFlags_MouseButtonLeft/Right/Middle. This is a small but rather important change because lots of multi-button behaviors could previously only be achieved using lower-level/internal API. Now also available via high-level InvisibleButton() - with is a de-facto versatile building block to creating custom widgets with the public API. + with is a de facto versatile building block to creating custom widgets with the public API. - Fonts: Fixed ImFontConfig::GlyphExtraSpacing and ImFontConfig::PixelSnapH settings being pulled from the merged/target font settings when merging fonts, instead of being pulled from the source font settings. @@ -3750,7 +3750,7 @@ Other Changes: ImGuiListClipper as the first thing after Begin() could largely break size calculations. (#3073) - Added optional support for Unicode plane 1-16 (#2538, #2541, #2815) [@cloudwu, @samhocevar] - Compile-time enable with '#define IMGUI_USE_WCHAR32' in imconfig.h. - - More onsistent handling of unsupported code points (0xFFFD). + - More consistent handling of unsupported code points (0xFFFD). - Surrogate pairs are supported when submitting UTF-16 data via io.AddInputCharacterUTF16(), allowing for more complete CJK input. - sizeof(ImWchar) goes from 2 to 4. IM_UNICODE_CODEPOINT_MAX goes from 0xFFFF to 0x10FFFF. @@ -3834,7 +3834,7 @@ Other Changes: - Inputs: Added ImGuiMouseButton enum for convenience (e.g. ImGuiMouseButton_Right=1). We forever guarantee that the existing value will not changes so existing code is free to use 0/1/2. -- Nav: Fixed a bug where the initial CTRL-Tab press while in a child window sometimes selected +- Nav: Fixed a bug where the initial CTRL+Tab press while in a child window sometimes selected the current root window instead of always selecting the previous root window. (#787) - ColorEdit: Fix label alignment when using ImGuiColorEditFlags_NoInputs. (#2955) [@rokups] - ColorEdit: In HSV display of a RGB stored value, attempt to locally preserve Saturation @@ -4007,7 +4007,7 @@ Other Changes: mostly for consistency. (#2159, #2160) [@goran-w] - Selectable: Added ImGuiSelectableFlags_AllowItemOverlap flag in public api (was previously internal only). - Style: Allow style.WindowMenuButtonPosition to be set to ImGuiDir_None to hide the collapse button. (#2634, #2639) -- Font: Better ellipsis ("...") drawing implementation. Instead of drawing three pixel-ey dots (which was glaringly +- Font: Better ellipsis ("...") drawing implementation. Instead of drawing three pixely dots (which was glaringly unfitting with many types of fonts) we first attempt to find a standard ellipsis glyphs within the loaded set. Otherwise we render ellipsis using '.' from the font from where we trim excessive spacing to make it as narrow as possible. (#2775) [@rokups] @@ -4343,7 +4343,7 @@ Other Changes: - InputText: Fixed an edge case crash that would happen if another widget sharing the same ID is being swapped with an InputText that has yet to be activated. - InputText: Fixed various display corruption related to swapping the underlying buffer while - a input widget is active (both for writable and read-only paths). Often they would manifest + an input widget is active (both for writable and read-only paths). Often they would manifest when manipulating the scrollbar of a multi-line input text. - ColorEdit, ColorPicker, ColorButton: Added ImGuiColorEditFlags_InputHSV to manipulate color values encoded as HSV (in order to avoid HSV<>RGB round trips and associated singularities). @@ -4354,7 +4354,7 @@ Other Changes: reading the 4th float in the array (value was read and discarded). (#2384) [@haldean] - MenuItem, Selectable: Fixed disabled widget interfering with navigation (fix c2db7f63 in 1.67). - Tabs: Fixed a crash when using many BeginTabBar() recursively (didn't affect docking). (#2371) -- Tabs: Added extra mis-usage error recovery. Past the assert, common mis-usage don't lead to +- Tabs: Added extra misusage error recovery. Past the assert, common misusage don't lead to hard crashes any more, facilitating integration with scripting languages. (#1651) - Tabs: Fixed ImGuiTabItemFlags_SetSelected being ignored if the tab is not visible (with scrolling policy enabled) or if is currently appearing. @@ -4397,7 +4397,7 @@ Breaking Changes: - Removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already). - Made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). - If for some reason your time step calculation gives you a zero value, replace it with a arbitrarily small value! + If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value! Other Changes: @@ -4495,7 +4495,7 @@ Other Changes: in the parent window, so there is no mismatch between the layout in parent and the position of the child window. - InputFloat: When using ImGuiInputTextFlags_ReadOnly the step buttons are disabled. (#2257) - DragFloat: Fixed broken mouse direction change with power!=1.0. (#2174, #2206) [@Joshhua5] -- Nav: Fixed an keyboard issue where holding Activate/Space for longer than two frames on a button would unnecessary +- Nav: Fixed a 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 @@ -4647,7 +4647,7 @@ Changes: then separate your changes into several patches that can more easily be applied to 1.64 on a per-file basis. What I found worked nicely for me, was to open the diff of the old patches in an interactive merge/diff tool, search for the corresponding function in the new code and apply the chunks manually. -- As a reminder, if you have any change to imgui.cpp it is a good habit to discuss them on the github, +- As a reminder, if you have any change to imgui.cpp it is a good habit to discuss them on the GitHub, so a solution applicable on the Master branch can be found. If your company has changes that you cannot disclose you may also contact me privately. @@ -4682,7 +4682,7 @@ Other Changes: - Nav: Added a CTRL+TAB window list and changed the highlight system accordingly. The change is motivated by upcoming Docking features. (#787) - Nav: Made CTRL+TAB skip menus + skip the current navigation window if is has the ImGuiWindow_NoNavFocus set. (#787) - While it was previously possible, you won't be able to CTRL-TAB out and immediately back in a window with the + While it was previously possible, you won't be able to CTRL+TAB out and immediately back in a window with the ImGuiWindow_NoNavFocus flag. - Window: Allow menu and popups windows from ignoring the style.WindowMinSize values so short menus/popups are not padded. (#1909) - Window: Added global io.ConfigResizeWindowsFromEdges option to enable resizing windows from their edges and from @@ -4717,7 +4717,7 @@ Other Changes: - Fixed assertion when transitioning from an active ID to another within a group, affecting ColorPicker (broken in 1.62). (#2023, #820, #956, #1875). - Fixed PushID() from keeping alive the new ID Stack top value (if a previously active widget shared the ID it would be erroneously kept alive). - Fixed horizontal mouse wheel not forwarding the request to the parent window if ImGuiWindowFlags_NoScrollWithMouse is set. (#1463, #1380, #1502) -- Fixed a include build issue for Cygwin in non-POSIX (Win32) mode. (#1917, #1319, #276) +- Fixed an include build issue for Cygwin in non-POSIX (Win32) mode. (#1917, #1319, #276) - ImDrawList: Improved handling for worst-case vertices reservation policy when large amount of text (e.g. 1+ million character strings) are being submitted in a single call. It would typically have crashed InputTextMultiline(). (#200) - OS/Windows: Fixed missing ImmReleaseContext() call in the default Win32 IME handler. (#1932) [@vby] @@ -4952,7 +4952,7 @@ Other Changes: - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays. - Basic controls: arrows to navigate, Alt to enter menus, Space to activate item, Enter to edit text, - Escape to cancel/close, Ctrl-Tab to focus windows, etc. + Escape to cancel/close, Ctrl+Tab to focus windows, etc. - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag will be set. - For more advanced uses, you may want to read from io.NavActive or io.NavVisible. Read imgui.cpp for more details. @@ -5002,7 +5002,7 @@ Other Changes: - Style: Exposed ImGuiStyleVar_WindowTitleAlign, ImGuiStyleVar_ScrollbarSize, ImGuiStyleVar_ScrollbarRounding, ImGuiStyleVar_GrabRounding + added an assert to reduce accidental breakage. (#1181) - Style: Added style.MouseCursorScale help when using the software mouse cursor facility. (#939). -- Style: Close button nows display a cross before hovering. Fixed cross positioning being a little off. Uses button colors for highlight when hovering. (#707) +- Style: Close buttons now display a cross before hovering. Fixed cross positioning being a little off. Uses button colors for highlight when hovering. (#707) - Popup: OpenPopup() Always reopen existing pop-ups. (Removed imgui_internal.h's OpenPopupEx() which was used for this.) (#1497, #1533). - Popup: BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick() all react on mouse release instead of mouse press. (~#439) - Popup: Better handling of user mistakenly calling OpenPopup() every frame (with the 'reopen_existing' option). @@ -5025,7 +5025,7 @@ Other Changes: - Drag and Drop: Increased payload type string to 32 characters instead of 8. (#143) - Drag and Drop: TreeNode as drop target displays rectangle over full frame. (#1597, #143) - DragFloat: Fix/workaround for backends which do not preserve a valid mouse position when dragged out of bounds. (#1559) -- InputFloat: Allow inputing value using scientific notation e.g. "1e+10". +- InputFloat: Allow inputting value using scientific notation e.g. "1e+10". - InputDouble: Added InputDouble() function. We use a format string instead of a 'decimal_precision' parameter to also for "%e" and variants. (#1011) - Slider, Combo: Use ImGuiCol_FrameBgHovered color when hovered. (#1456) [@stfx] @@ -5070,7 +5070,7 @@ Other Changes: - Demo: Improved Selectable() examples. (#1528) - Demo: Tweaked the Child demos, added a menu bar to the second child to test some navigation functions. - Demo: Console: Using ImGuiCol_Text to be more friendly to color changes. -- Demo: Using IM_COL32() instead of ImColor() in ImDrawList centric contexts. Trying to phase out use of the ImColor helper whenever possible. +- Demo: Using IM_COL32() instead of ImColor() in ImDrawList-centric contexts. Trying to phase out use of the ImColor helper whenever possible. - Examples: Files in examples/ now include their own changelog so it is easier to occasionally update your backends if needed. - Examples: Using Dark theme by default. (#707). Tweaked demo code. - Examples: Added support for horizontal mouse wheel for API that allows it. (#1463) [@tseeker] @@ -5188,7 +5188,7 @@ Other Changes: - Window: Added ImGuiWindowFlags_ResizeFromAnySide flag to resize from any borders or from the lower-left corner of a window. This requires your backend to honor GetMouseCursor() requests for full usability. (#822) -- Window: Sizing fixes when using SetNextWindowSize() on individual axises. +- Window: Sizing fixes when using SetNextWindowSize() on individual axes. - Window: Hide new window for one frame until they calculate their size. Also fixes SetNextWindowPos() given a non-zero pivot. (#1694) - Window: Made mouse wheel scrolling accommodate better to windows that are smaller than the scroll step. @@ -5490,7 +5490,7 @@ Other Changes: check the Demo window and comment for `ImGuiColorEditFlags_`. Some of the options it supports are: two color picker types (hue bar + sat/val rectangle, hue wheel + rotating sat/val triangle), display as u8 or float, lifting 0.0..1.0 constraints - (currently rgba only), context menus, alpha bar, background checkerboard options, preview tooltip, + (currently rgba only), context menus, alpha bar, background checkerboard options, preview tooltip, basic revert. For simple use, calling the existing `ColorEdit4()` function as you did before will be enough, as you can now open the color picker from there. - Added `SetColorEditOptions()` to set default color options (e.g. if you want HSV over RGBA, @@ -5592,7 +5592,7 @@ Other Changes: certain style settings and zero WindowMinSize). - EndGroup(): Made IsItemHovered() work when an item was activated within the group. (#849) - BulletText(): Fixed stopping to display formatted string after the '##' mark. -- Closing the focused window restore focus to the first active root window in descending z-order .(part of #727) +- Closing the focused window restore focus to the first active root window in descending z-order. (part of #727) - Word-wrapping: Fixed a bug where we never wrapped after a 1 character word. [@sronsse] - Word-wrapping: Fixed TextWrapped() overriding wrap position if one is already set. (#690) - Word-wrapping: Fixed incorrect testing for negative wrap coordinates, they are perfectly legal. (#706) @@ -5629,7 +5629,7 @@ Other Changes: - Demo: ShowStyleEditor: show font character map / grid in more details. - Demo: Console: Fixed a completion bug when multiple candidates are equals and match until the end. - Demo: Fixed 1-byte off overflow in the ShowStyleEditor() combo usage. (#783) [@bear24rw] -- Examples: Accessing ImVector fields directly, feel less stl-ey. (#810) +- Examples: Accessing ImVector fields directly, feel less stl-y. (#810) - Examples: OpenGL*: Saving/restoring existing scissor rectangle for completeness. (#807) - Examples: OpenGL*: Saving/restoring active texture number (the value modified by glActiveTexture). (#1087, #1088, #1116) - Examples: OpenGL*: Saving/restoring separate color/alpha blend functions correctly. (#1120) [@greggman] @@ -5793,7 +5793,7 @@ Other Changes: after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) - DragFloat(): Always apply value when mouse is held/widget active, so that an always-resetting variable (e.g. non saved local) can be passed. -- InputText(): OS X friendly behaviors: (@zhiayang), (#473) +- InputText(): OS X friendly behaviors: (@zhiayang), (#473) - Word movement uses ALT key; - Shortcuts uses CMD key; - Double-clicking text select a single word; @@ -5918,7 +5918,7 @@ Changes: - PlotHistogram(): improved rendering of histogram with a lot of values. - Dummy(): creates an item so functions such as IsItemHovered() can be used. - BeginChildFrame() helper: added the extra_flags parameter. -- Scrollbar: fixed rounding of background + child window consistenly have ChildWindowBg color under ScrollbarBg fill. (#355). +- Scrollbar: fixed rounding of background + child window consistently have ChildWindowBg color under ScrollbarBg fill. (#355). - Scrollbar: background color less translucent in default style so it works better when changing background color. - Scrollbar: fixed minor rendering offset when borders are enabled. (#365) - ImDrawList: fixed 1 leak per ImDrawList using the ChannelsSplit() API (via Columns). (#318) @@ -5934,7 +5934,7 @@ Changes: - Internal: Extracted a EndFrame() function out of Render() but kept it internal/private + clarified some asserts. (#335) - Internal: Added missing IMGUI_API definitions in imgui_internal.h (#326) - Internal: ImLoadFileToMemory() return void\* instead of taking void*\* + allow optional int\* file_size. -- Demo: Horizontal scrollbar demo allows to enable simultanaeous scrollbars on both axises. +- Demo: Horizontal scrollbar demo allows to enable simultaneous scrollbars on both axes. - Tools: binary_to_compressed_c.cpp: added -nocompress option. - Examples: Added example for the Marmalade platform. - Examples: Added batch files to build Windows examples with VS. @@ -5979,7 +5979,7 @@ Other Changes: - ImDrawList: Added an assert on overflowing index value (#292). - ImDrawList: Fixed issues with channels split/merge. Now functional without manually adding a draw cmd. Added comments. - ImDrawData: Added ScaleClipRects() helper useful when rendering scaled. (#287). -- Fixed Bullet() inconsistent layout behaviour when clipped. +- Fixed Bullet() inconsistent layout behavior when clipped. - Fixed IsWindowHovered() not taking account of window hoverability (may be disabled because of a popup). - Fixed InvisibleButton() not honoring negative size consistently with other widgets that do so. - Fixed OpenPopup() accessing current window, effectively opening "Debug" when called from an empty window stack. @@ -5991,7 +5991,7 @@ Other Changes: the first place so it's not really a useful default. - Begin(): Minor fixes with windows main clipping rectangle (e.g. child window with border). - Begin(): Window flags are only read on the first call of the frame. Subsequent calls ignore flags, which allows - appending to a window without worryin about flags. + appending to a window without worrying about flags. - InputText(): ignore character input when ctrl/alt are held. (Normally those text input are ignored by most wrappers.) (#279). - Demo: Fixed incorrectly formed string passed to Combo (#298). - Demo: Added simple Log demo. @@ -6025,7 +6025,7 @@ Other Changes: and more natural to extend ImGui. However please note that none of the content in imgui_internal.h is guaranteed for forward-compatibility and code using those types/functions may occasionally break. (#219) - All sample code is in imgui_demo.cpp. Please keep this file in your project and consider allowing your code to call - the ShowTestWindow() function as de-facto guide to ImGui features. It will be stripped out by the linker when unused. + the ShowTestWindow() function as de facto guide to ImGui features. It will be stripped out by the linker when unused. - Added GetContentRegionAvail() helper (basically GetContentRegionMax() - GetCursorPos()). - Added ImGuiWindowFlags_NoInputs for totally input-passthru window. - Button(): honor negative size consistently with other widgets that do so (width -100 to align the button 100 pixels @@ -6390,7 +6390,7 @@ Other Changes: - IsItemHovered() return false if another widget is active, aka we can't use what we are hovering now. - Added IsItemHoveredRect() if old behavior of IsItemHovered() is needed (e.g. for implementing the drop side of a drag'n drop operation). -- IsItemhovered() include space taken by label and behave consistently for all widgets (#145) +- IsItemHovered() include space taken by label and behave consistently for all widgets (#145) - Auto-filling child window feed their content size to parent (#170) - InputText() removed the odd ~ characters when clipping. - InputText() update its width in case of resize initiated programmatically while the widget is active. @@ -6454,7 +6454,7 @@ Other Changes: - Sliders: Fixed parsing of decimal precision back from format string when using %%. - Sliders: Fixed hovering bounding test excluding padding between outer frame and grab (there was a few pixels dead-zone). - Separator() logs itself as text when passing through text log. -- Optimisation: TreeNodeV() early out if SkipItems is set without formatting. +- Optimization: TreeNodeV() early out if SkipItems is set without formatting. - Moved various static buffers into state. Increase the formatted string buffer from 1K to 3K. - Examples: Example console keeps focus on input box at all times. - Examples: Updated to GLFW 3.1. Moved to examples/libs/ folder. @@ -6583,8 +6583,8 @@ Other Changes: Callback now passed an "EventFlag" parameter. - InputText: Added ImGuiInputTextFlags_CharsUppercase and ImGuiInputTextFlags_CharsNoBlank stock filters. - PushItemWidth() can take negative value to right-align items. -- Optimisation: Columns offsets cached to avoid unnecessary binary search. -- Optimisation: Optimized CalcTextSize() function by about 25% (they are often the bottleneck when +- Optimization: Columns offsets cached to avoid unnecessary binary search. +- Optimization: Optimized CalcTextSize() function by about 25% (they are often the bottleneck when submitting thousands of clipped items). - Added ImGuiCol_ChildWindowBg, ImGuiStyleVar_ChildWindowRounding for completeness and flexibility. - Added BeginChild() variant that takes an ImGuiID. @@ -6627,7 +6627,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- Big update! Initialisation had to be changed. You don't need to load PNG data anymore. Th +- Big update! Initialization had to be changed. You don't need to load PNG data anymore. The new system gives you uncompressed texture data. - This sequence: const void* png_data; @@ -6637,7 +6637,7 @@ Breaking Changes: - Became: unsigned char* pixels; int width, height; - // io.Fonts->AddFontFromFileTTF("myfontfile.ttf", 24.0f); // Optionally load another font + // io.Fonts->AddFontFromFileTTF("myfontfile.ttf", 24.0f); // Optionally load another font io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // io.Fonts->TexID = (your_texture_identifier); @@ -6659,7 +6659,7 @@ Other Changes: - Added IsItemActive() to tell if last widget is being held / modified (as opposed to just being hovered). Useful for custom dragging behaviors. - Style: Added FrameRounding setting for a more rounded look (default to 0 for now). -- Window: Fixed using multiple Begin/End pair on the same wnidow. +- Window: Fixed using multiple Begin/End pair on the same window. - Window: Fixed style.WindowMinSize not being honored properly. - Window: Added SetCursorScreenPos() helper (WindowPos+CursorPos = ScreenPos). - ColorEdit3: clicking on color square change the edition. The toggle button is hidden by default. @@ -6690,10 +6690,10 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - Dragging outside area of a widget while it is active doesn't trigger hover on other widgets. - Activating widget bring parent window to front if not already. - Checkbox and Radio buttons activate on click-release to be consistent with other widgets and most UI. -- InputText() nows consume input characters immediately so they cannot be reused if +- InputText() now consumes input characters immediately so they cannot be reused if ImGui::Update is called again with a call to ImGui::Render(). (fixes #105) - Examples: Console: added support for History callbacks + some cleanup. -- Various small optimisations. +- Various small optimizations. - Cleanup and other fixes. @@ -6896,7 +6896,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking Changes: -- The behaviour of PixelCenterOffset changed! You may need to change your value if you had set +- The behavior of PixelCenterOffset changed! You may need to change your value if you had set it to non-default in your code and/or offset your projection matrix by 0.5 pixels. It is likely that the default PixelCenterOffset value of 0.0 is now suitable unless your rendering uses some form of multisampling. @@ -6990,7 +6990,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v - OpenGL example now use the fixed function-pipeline + cleanups, down by 150 lines. - Added quick & dirty Makefiles for MacOSX and Linux. -- Simplified the DrawList system, ImDrawCmd include the clipping rectangle + some optimisations. +- Simplified the DrawList system, ImDrawCmd include the clipping rectangle + some optimizations. - Fixed warnings for more stringent compilation settings. diff --git a/docs/FAQ.md b/docs/FAQ.md index 6e8d6c26f7dd..5af2e9035e9e 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -543,7 +543,7 @@ The short answer is: obtain the desired DPI scale, load your fonts resized with Your application may want to detect DPI change and reload the fonts and reset style between frames. -Your ui code should avoid using hardcoded constants for size and positioning. Prefer to express values as multiple of reference values such as `ImGui::GetFontSize()` or `ImGui::GetFrameHeight()`. So e.g. instead of seeing a hardcoded height of 500 for a given item/window, you may want to use `30*ImGui::GetFontSize()` instead. +Your UI code should avoid using hardcoded constants for size and positioning. Prefer to express values as multiple of reference values such as `ImGui::GetFontSize()` or `ImGui::GetFrameHeight()`. So e.g. instead of seeing a hardcoded height of 500 for a given item/window, you may want to use `30*ImGui::GetFontSize()` instead. Down the line Dear ImGui will provide a variety of standardized reference values to facilitate using this. @@ -666,7 +666,7 @@ You may take a look at: Yes. People have written game editors, data browsers, debuggers, profilers, and all sorts of non-trivial tools with the library. In my experience, the simplicity of the API is very empowering. Your UI runs close to your live data. Make the tools always-on and everybody in the team will be inclined to create new tools (as opposed to more "offline" UI toolkits where only a fraction of your team effectively creates tools). The list of sponsors below is also an indicator that serious game teams have been using the library. -Dear ImGui is very programmer centric and the immediate-mode GUI paradigm might require you to readjust some habits before you can realize its full potential. Dear ImGui is about making things that are simple, efficient, and powerful. +Dear ImGui is very programmer-centric and the immediate-mode GUI paradigm might require you to readjust some habits before you can realize its full potential. Dear ImGui is about making things that are simple, efficient, and powerful. Dear ImGui is built to be efficient and scalable toward the needs for AAA-quality applications running all day. The IMGUI paradigm offers different opportunities for optimization than the more typical RMGUI paradigm. diff --git a/docs/TODO.txt b/docs/TODO.txt index 14a152a4bec0..aeef17592575 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -279,7 +279,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - nav: expose wrap around flags/logic to allow e.g. grid based layout (pressing NavRight on the right-most element would go to the next row, etc.). see internal's NavMoveRequestTryWrapping(). - nav: patterns to make it possible for arrows key to update selection (see JustMovedTo in range_select branch) - nav: restore/find nearest NavId when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name) - - nav: SetItemDefaultFocus() level of priority, so widget like Selectable when inside a popup could claim a low-priority default focus on the first selected iem + - nav: SetItemDefaultFocus() level of priority, so widgets like Selectable when inside a popup could claim a low-priority default focus on the first selected item - nav: holding space to repeat a button doesn't show button activated during hold. - nav: NavFlattened: init requests don't work properly on flattened siblings. - nav: NavFlattened: pageup/pagedown/home/end don't work properly on flattened siblings. @@ -329,7 +329,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - backends: opengl: explicitly disable GL_STENCIL_TEST in bindings. - backends: vulkan: viewport: support for synchronized swapping of multiple swap chains. - backends: bgfx: https://gist.github.com/RichardGale/6e2b74bc42b3005e08397236e4be0fd0 - - backends: emscriptem: with refactored examples, we could provide a direct imgui_impl_emscripten platform layer (see eg. https://github.com/floooh/sokol-samples/blob/master/html5/imgui-emsc.cc#L42) + - backends: emscripten: with refactored examples, we could provide a direct imgui_impl_emscripten platform layer (see eg. https://github.com/floooh/sokol-samples/blob/master/html5/imgui-emsc.cc#L42) - bindings: ways to use clang ast dump to generate bindings or helpers for bindings? (e.g. clang++ -Xclang -ast-dump=json imgui.h) (--> use https://github.com/dearimgui/dear_bindings) diff --git a/imgui.cpp b/imgui.cpp index 73bd2581ece2..86b0d5d46b0d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -655,7 +655,7 @@ CODE - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO. - 2022/01/20 (1.87) - inputs: reworded gamepad IO. - Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values. - - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used). + - 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputting text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used). - 2022/01/17 (1.87) - inputs: reworked mouse IO. - Backend writing to io.MousePos -> backend should call io.AddMousePosEvent() - Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent() @@ -4954,7 +4954,7 @@ void ImGui::StartMouseMovingWindow(ImGuiWindow* window) // Handle mouse moving window // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing() -// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId. +// FIXME: We don't have strong guarantee that g.MovingWindow stay synced with g.ActiveId == g.MovingWindow->MoveId. // This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs, // but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other. void ImGui::UpdateMouseMovingWindowNewFrame() @@ -6563,7 +6563,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si { // Auto-fit when double-clicking size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit); - ret_auto_fit_mask = 0x03; // Both axises + ret_auto_fit_mask = 0x03; // Both axes ClearActiveID(); } else if (held) @@ -9701,7 +9701,7 @@ void ImGui::UpdateMouseWheel() if (g.IO.MouseWheelRequestAxisSwap) wheel = ImVec2(wheel.y, 0.0f); - // Maintain a rough average of moving magnitude on both axises + // Maintain a rough average of moving magnitude on both axes // FIXME: should by based on wall clock time rather than frame-counter g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30); g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30); @@ -9714,7 +9714,7 @@ void ImGui::UpdateMouseWheel() // Mouse wheel scrolling: find target and apply // - don't renew lock if axis doesn't apply on the window. - // - select a main axis when both axises are being moved. + // - select a main axis when both axes are being moved. if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel))) if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs)) { diff --git a/imgui.h b/imgui.h index 2f6a18d2aa1a..4a14c82c28a1 100644 --- a/imgui.h +++ b/imgui.h @@ -544,7 +544,7 @@ namespace ImGui IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args) IM_FMTLIST(2); IMGUI_API void BulletText(const char* fmt, ...) IM_FMTARGS(1); // shortcut for Bullet()+Text() IMGUI_API void BulletTextV(const char* fmt, va_list args) IM_FMTLIST(1); - IMGUI_API void SeparatorText(const char* label); // currently: formatted text with an horizontal line + IMGUI_API void SeparatorText(const char* label); // currently: formatted text with a horizontal line // Widgets: Main // - Most widgets return true when the value has been changed or when pressed/selected diff --git a/imgui_demo.cpp b/imgui_demo.cpp index beffe618db0f..50eeed1073f6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8415,7 +8415,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::EndTooltip(); } ImGui::SameLine(); - HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically."); + HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically."); ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); @@ -8446,7 +8446,7 @@ void ImGui::ShowUserGuide() ImGui::BulletText("CTRL+Tab to select a window."); if (io.FontAllowUserScaling) ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); - ImGui::BulletText("While inputing text:\n"); + ImGui::BulletText("While inputting text:\n"); ImGui::Indent(); ImGui::BulletText("CTRL+Left/Right to word jump."); ImGui::BulletText("CTRL+A or double-click to select all."); @@ -8877,7 +8877,7 @@ struct ExampleAppConsole else { // Multiple matches. Complete as much as we can.. - // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. + // So inputting "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches. int match_len = (int)(word_end - word_start); for (;;) { diff --git a/imgui_internal.h b/imgui_internal.h index b7395fcae087..aaa2027df944 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2801,7 +2801,7 @@ struct IMGUI_API ImGuiTable { ImGuiID ID; ImGuiTableFlags Flags; - void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[] and RowCellData[] + void* RawData; // Single allocation to hold Columns[], DisplayOrderToIndex[], and RowCellData[] ImGuiTableTempData* TempData; // Transient data while table is active. Point within g.CurrentTableStack[] ImSpan Columns; // Point within RawData[] ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) @@ -2815,7 +2815,7 @@ struct IMGUI_API ImGuiTable int ColumnsCount; // Number of columns declared in BeginTable() int CurrentRow; int CurrentColumn; - ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched. + ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple tables with the same ID are multiple tables, they are just synced. ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with float RowPosY1; float RowPosY2; @@ -2847,7 +2847,7 @@ struct IMGUI_API ImGuiTable float AngledHeadersHeight; // Set by TableAngledHeadersRow(), used in TableUpdateLayout() float AngledHeadersSlope; // Set by TableAngledHeadersRow(), used in TableUpdateLayout() ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable(). - ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is + ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is " ImRect WorkRect; ImRect InnerClipRect; ImRect BgClipRect; // We use this to cpu-clip cell background color fill, evolve during the frame as we cross frozen rows boundaries diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 6c79262363f2..bc5862ee3703 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -977,7 +977,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // [Part 4] Apply final widths based on requested widths const ImRect work_rect = table->WorkRect; const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1); - const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synched tables with mismatching scrollbar state (#5920) + const float width_removed = (table->HasScrollbarYPrev && !table->InnerWindow->ScrollbarY) ? g.Style.ScrollbarSize : 0.0f; // To synchronize decoration width of synced tables with mismatching scrollbar state (#5920) const float width_avail = ImMax(1.0f, (((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth()) - width_removed); const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests; float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; @@ -1390,7 +1390,7 @@ void ImGui::EndTable() // Setup inner scrolling range // FIXME: This ideally should be done earlier, in BeginTable() SetNextWindowContentSize call, just like writing to inner_window->DC.CursorMaxPos.y, - // but since the later is likely to be impossible to do we'd rather update both axises together. + // but since the later is likely to be impossible to do we'd rather update both axes together. if (table->Flags & ImGuiTableFlags_ScrollX) { const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 01e4e61872c9..9ecdbae8e610 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -8898,7 +8898,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled) const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_NoAutoClosePopups; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { - // Menu inside an horizontal menu bar + // Menu inside a horizontal menu bar // Selectable extend their highlight by half ItemSpacing in each direction. // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin() popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight); From 88d4827b64f0453284252b2af344d770fb52da36 Mon Sep 17 00:00:00 2001 From: Zijie Wu Date: Sun, 9 Mar 2025 13:44:26 -0700 Subject: [PATCH 297/716] Update FAQ.md for SDL3 (#8480) --- docs/FAQ.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 5af2e9035e9e..8c08b4dd7873 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -562,7 +562,8 @@ Please note that if you are not using multi-viewports with multi-monitors using On Windows, in addition to scaling the font size (make sure to round to an integer) and using `style.ScaleAllSizes()`, you will need to inform Windows that your application is DPI aware. If this is not done, Windows will scale the application window and the UI text will be blurry. Potential solutions to indicate DPI awareness on Windows are: -- For SDL: the flag `SDL_WINDOW_ALLOW_HIGHDPI` needs to be passed to `SDL_CreateWindow()``. +- For SDL2: the flag `SDL_WINDOW_ALLOW_HIGHDPI` needs to be passed to `SDL_CreateWindow()`. +- For SDL3: the flag `SDL_WINDOW_HIGH_PIXEL_DENSITY` needs to be passed to `SDL_CreateWindow()`. - For GLFW: this is done automatically. - For other Windows projects with other backends, or wrapper projects: - We provide a `ImGui_ImplWin32_EnableDpiAwareness()` helper method in the Win32 backend. From a9e53829d2753b6eb3ef763e091f430ab507c722 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Mar 2025 16:29:59 +0100 Subject: [PATCH 298/716] Backends: Win32, SDL2, SDL3, GLFW: prioritize scancodes instead of translated keycodes when dealing with OEM keys + Added ImGuiKey_Oem102. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) --- backends/imgui_impl_glfw.cpp | 3 +++ backends/imgui_impl_sdl2.cpp | 34 ++++++++++++++++++++------- backends/imgui_impl_sdl3.cpp | 34 ++++++++++++++++++++------- backends/imgui_impl_win32.cpp | 43 +++++++++++++++++++++++++++-------- docs/CHANGELOG.txt | 12 ++++++++++ imgui.cpp | 4 ++-- imgui.h | 5 ++-- 7 files changed, 105 insertions(+), 30 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 874a0a440997..baa8541b0af0 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -28,6 +28,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn @@ -221,6 +222,8 @@ ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) case GLFW_KEY_EQUAL: return ImGuiKey_Equal; case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket; case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash; + case GLFW_KEY_WORLD_1: return ImGuiKey_Oem102; + case GLFW_KEY_WORLD_2: return ImGuiKey_Oem102; case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket; case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent; case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock; diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 6256b4dddec4..33f7fed06a2f 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. @@ -209,17 +210,17 @@ ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode sca case SDLK_SPACE: return ImGuiKey_Space; case SDLK_RETURN: return ImGuiKey_Enter; case SDLK_ESCAPE: return ImGuiKey_Escape; - case SDLK_QUOTE: return ImGuiKey_Apostrophe; + //case SDLK_QUOTE: return ImGuiKey_Apostrophe; case SDLK_COMMA: return ImGuiKey_Comma; - case SDLK_MINUS: return ImGuiKey_Minus; + //case SDLK_MINUS: return ImGuiKey_Minus; case SDLK_PERIOD: return ImGuiKey_Period; - case SDLK_SLASH: return ImGuiKey_Slash; + //case SDLK_SLASH: return ImGuiKey_Slash; case SDLK_SEMICOLON: return ImGuiKey_Semicolon; - case SDLK_EQUALS: return ImGuiKey_Equal; - case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket; - case SDLK_BACKSLASH: return ImGuiKey_Backslash; - case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket; - case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent; + //case SDLK_EQUALS: return ImGuiKey_Equal; + //case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket; + //case SDLK_BACKSLASH: return ImGuiKey_Backslash; + //case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket; + //case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent; case SDLK_CAPSLOCK: return ImGuiKey_CapsLock; case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock; case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock; @@ -315,6 +316,23 @@ ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode sca case SDLK_AC_FORWARD: return ImGuiKey_AppForward; default: break; } + + // Fallback to scancode + switch (scancode) + { + case SDL_SCANCODE_GRAVE: return ImGuiKey_GraveAccent; + case SDL_SCANCODE_MINUS: return ImGuiKey_Minus; + case SDL_SCANCODE_EQUALS: return ImGuiKey_Equal; + case SDL_SCANCODE_LEFTBRACKET: return ImGuiKey_LeftBracket; + case SDL_SCANCODE_RIGHTBRACKET: return ImGuiKey_RightBracket; + case SDL_SCANCODE_NONUSBACKSLASH: return ImGuiKey_Oem102; + case SDL_SCANCODE_BACKSLASH: return ImGuiKey_Backslash; + case SDL_SCANCODE_SEMICOLON: return ImGuiKey_Semicolon; + case SDL_SCANCODE_APOSTROPHE: return ImGuiKey_Apostrophe; + case SDL_SCANCODE_COMMA: return ImGuiKey_Comma; + case SDL_SCANCODE_PERIOD: return ImGuiKey_Period; + case SDL_SCANCODE_SLASH: return ImGuiKey_Slash; + } return ImGuiKey_None; } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 2d8027184b60..6720899ef23f 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. @@ -207,17 +208,17 @@ ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode sca case SDLK_SPACE: return ImGuiKey_Space; case SDLK_RETURN: return ImGuiKey_Enter; case SDLK_ESCAPE: return ImGuiKey_Escape; - case SDLK_APOSTROPHE: return ImGuiKey_Apostrophe; + //case SDLK_APOSTROPHE: return ImGuiKey_Apostrophe; case SDLK_COMMA: return ImGuiKey_Comma; - case SDLK_MINUS: return ImGuiKey_Minus; + //case SDLK_MINUS: return ImGuiKey_Minus; case SDLK_PERIOD: return ImGuiKey_Period; - case SDLK_SLASH: return ImGuiKey_Slash; + //case SDLK_SLASH: return ImGuiKey_Slash; case SDLK_SEMICOLON: return ImGuiKey_Semicolon; - case SDLK_EQUALS: return ImGuiKey_Equal; - case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket; - case SDLK_BACKSLASH: return ImGuiKey_Backslash; - case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket; - case SDLK_GRAVE: return ImGuiKey_GraveAccent; + //case SDLK_EQUALS: return ImGuiKey_Equal; + //case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket; + //case SDLK_BACKSLASH: return ImGuiKey_Backslash; + //case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket; + //case SDLK_GRAVE: return ImGuiKey_GraveAccent; case SDLK_CAPSLOCK: return ImGuiKey_CapsLock; case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock; case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock; @@ -296,6 +297,23 @@ ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode sca case SDLK_AC_FORWARD: return ImGuiKey_AppForward; default: break; } + + // Fallback to scancode + switch (scancode) + { + case SDL_SCANCODE_GRAVE: return ImGuiKey_GraveAccent; + case SDL_SCANCODE_MINUS: return ImGuiKey_Minus; + case SDL_SCANCODE_EQUALS: return ImGuiKey_Equal; + case SDL_SCANCODE_LEFTBRACKET: return ImGuiKey_LeftBracket; + case SDL_SCANCODE_RIGHTBRACKET: return ImGuiKey_RightBracket; + case SDL_SCANCODE_NONUSBACKSLASH: return ImGuiKey_Oem102; + case SDL_SCANCODE_BACKSLASH: return ImGuiKey_Backslash; + case SDL_SCANCODE_SEMICOLON: return ImGuiKey_Semicolon; + case SDL_SCANCODE_APOSTROPHE: return ImGuiKey_Apostrophe; + case SDL_SCANCODE_COMMA: return ImGuiKey_Comma; + case SDL_SCANCODE_PERIOD: return ImGuiKey_Period; + case SDL_SCANCODE_SLASH: return ImGuiKey_Slash; + } return ImGuiKey_None; } diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 49948c529441..2c749515d221 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. @@ -431,6 +432,8 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED)) return ImGuiKey_KeypadEnter; + const int scancode = (int)LOBYTE(HIWORD(lParam)); + //IMGUI_DEBUG_LOG("scancode %3d, keycode = 0x%02X\n", scancode, wParam); switch (wParam) { case VK_TAB: return ImGuiKey_Tab; @@ -448,17 +451,17 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) case VK_SPACE: return ImGuiKey_Space; case VK_RETURN: return ImGuiKey_Enter; case VK_ESCAPE: return ImGuiKey_Escape; - case VK_OEM_7: return ImGuiKey_Apostrophe; + //case VK_OEM_7: return ImGuiKey_Apostrophe; case VK_OEM_COMMA: return ImGuiKey_Comma; - case VK_OEM_MINUS: return ImGuiKey_Minus; + //case VK_OEM_MINUS: return ImGuiKey_Minus; case VK_OEM_PERIOD: return ImGuiKey_Period; - case VK_OEM_2: return ImGuiKey_Slash; - case VK_OEM_1: return ImGuiKey_Semicolon; - case VK_OEM_PLUS: return ImGuiKey_Equal; - case VK_OEM_4: return ImGuiKey_LeftBracket; - case VK_OEM_5: return ImGuiKey_Backslash; - case VK_OEM_6: return ImGuiKey_RightBracket; - case VK_OEM_3: return ImGuiKey_GraveAccent; + //case VK_OEM_2: return ImGuiKey_Slash; + //case VK_OEM_1: return ImGuiKey_Semicolon; + //case VK_OEM_PLUS: return ImGuiKey_Equal; + //case VK_OEM_4: return ImGuiKey_LeftBracket; + //case VK_OEM_5: return ImGuiKey_Backslash; + //case VK_OEM_6: return ImGuiKey_RightBracket; + //case VK_OEM_3: return ImGuiKey_GraveAccent; case VK_CAPITAL: return ImGuiKey_CapsLock; case VK_SCROLL: return ImGuiKey_ScrollLock; case VK_NUMLOCK: return ImGuiKey_NumLock; @@ -550,8 +553,28 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) case VK_F24: return ImGuiKey_F24; case VK_BROWSER_BACK: return ImGuiKey_AppBack; case VK_BROWSER_FORWARD: return ImGuiKey_AppForward; - default: return ImGuiKey_None; + default: break; } + + // Fallback to scancode + // https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names + switch (scancode) + { + case 41: return ImGuiKey_GraveAccent; // VK_OEM_8 in EN-UK, VK_OEM_3 in EN-US, VK_OEM_7 in FR, VK_OEM_5 in DE, etc. + case 12: return ImGuiKey_Minus; + case 13: return ImGuiKey_Equal; + case 26: return ImGuiKey_LeftBracket; + case 27: return ImGuiKey_RightBracket; + case 86: return ImGuiKey_Oem102; + case 43: return ImGuiKey_Backslash; + case 39: return ImGuiKey_Semicolon; + case 40: return ImGuiKey_Apostrophe; + case 51: return ImGuiKey_Comma; + case 52: return ImGuiKey_Period; + case 53: return ImGuiKey_Slash; + } + + return ImGuiKey_None; } // Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ca5ab47e386b..07a9801bc1cb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -121,6 +121,18 @@ Other changes: by showing the filter inside the combo contents. (#718) - Examples: SDL3: Added comments to clarify setup for users of the unfortunate SDL_MAIN_USE_CALLBACKS feature. (#8455) +- IO: Added ImGuiKey_Oem102 to ImGuiKey enum. (#7136, #7201, #7206, #7306, #8468) +- Backends: reworked key handlers to use/prioritize untranslated scancodes instead of + translated keycodes when dealing with OEM keys. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) + Not that only ImGuiKey value (NOT the characters used for text input) are affected. + - Win32, SDL2, SDL3: Use scancodes for OEM keys. + - GLFW: GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 are emitting ImGuiKey_Oem102. + - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboad layouts. + - Makes emitted ImGuiKey values more consistent regardless of keyboard mapping. + - OEM keys are: ImGuiKey_Apostrophe, ImGuiKey_Comma, ImGuiKey_Minus, ImGuiKey_Period, + ImGuiKey_Slash, ImGuiKey_Semicolon, ImGuiKey_Equal, ImGuiKey_LeftBracket, + ImGuiKey_RightBracket, ImGuiKey_Backslash, ImGuiKey_GraveAccent, which are difficult + to find a reliable translated mapping on all keyboard layouts. - Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. (#8452) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn diff --git a/imgui.cpp b/imgui.cpp index 86b0d5d46b0d..26d055dd21ff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8772,7 +8772,7 @@ ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key) return &g.IO.KeysData[key - ImGuiKey_NamedKey_BEGIN]; } -// Those names a provided for debugging purpose and are not meant to be saved persistently not compared. +// Those names are provided for debugging purpose and are not meant to be saved persistently nor compared. static const char* const GKeyNames[] = { "Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDown", @@ -8787,7 +8787,7 @@ static const char* const GKeyNames[] = "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", - "AppBack", "AppForward", + "AppBack", "AppForward", "Oem102", "GamepadStart", "GamepadBack", "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown", "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown", diff --git a/imgui.h b/imgui.h index 4a14c82c28a1..7cecf064a289 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19187 +#define IMGUI_VERSION_NUM 19188 #define IMGUI_HAS_TABLE /* @@ -975,7 +975,7 @@ namespace ImGui IMGUI_API bool IsKeyReleased(ImGuiKey key); // was key released (went from Down to !Down)? IMGUI_API bool IsKeyChordPressed(ImGuiKeyChord key_chord); // was key chord (mods + key) pressed, e.g. you can pass 'ImGuiMod_Ctrl | ImGuiKey_S' as a key-chord. This doesn't do any routing or focus check, please consider using Shortcut() function instead. IMGUI_API int GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate - IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared. + IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names are provided for debugging purpose and are not meant to be saved persistently nor compared. IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call. // Inputs Utilities: Shortcut Testing & Routing [BETA] @@ -1493,6 +1493,7 @@ enum ImGuiKey : int ImGuiKey_KeypadEqual, ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back" ImGuiKey_AppForward, + ImGuiKey_Oem102, // Non-US backslash. // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) From 39585aa90d43c26a12a0d754d16b407f0c1ca62d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Mar 2025 18:13:45 +0100 Subject: [PATCH 299/716] Amend Changelog to talk about OEM keys. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) + more consistently use Ctrl+XXX instead of Ctrl-XXX. --- docs/CHANGELOG.txt | 20 +++++++++++--------- imgui.h | 2 +- imgui_widgets.cpp | 6 +++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 07a9801bc1cb..5975e9155305 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -123,16 +123,18 @@ Other changes: SDL_MAIN_USE_CALLBACKS feature. (#8455) - IO: Added ImGuiKey_Oem102 to ImGuiKey enum. (#7136, #7201, #7206, #7306, #8468) - Backends: reworked key handlers to use/prioritize untranslated scancodes instead of - translated keycodes when dealing with OEM keys. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) - Not that only ImGuiKey value (NOT the characters used for text input) are affected. + translated keycodes when dealing with OEM keys which are too difficult to find a reliable + translated mapping on all systems, backends and keyboard layout. + (#7136, #7201, #7206, #7306, #7670, #7672, #8468) + - The affected keys are: ImGuiKey_Apostrophe, ImGuiKey_Comma, ImGuiKey_Minus, ImGuiKey_Period, + ImGuiKey_Slash, ImGuiKey_Semicolon, ImGuiKey_Equal, ImGuiKey_LeftBracket, ImGuiKey_RightBracket, + ImGuiKey_Backslash, ImGuiKey_GraveAccent, and newly introduced ImGuiKey_Oem102. + - This is NOT affecting characters used the text inputs. + - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboad layouts. + - Makes emitted ImGuiKey values more consistent regardless of keyboard mapping, + but you may be getting different values as before. - Win32, SDL2, SDL3: Use scancodes for OEM keys. - GLFW: GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 are emitting ImGuiKey_Oem102. - - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboad layouts. - - Makes emitted ImGuiKey values more consistent regardless of keyboard mapping. - - OEM keys are: ImGuiKey_Apostrophe, ImGuiKey_Comma, ImGuiKey_Minus, ImGuiKey_Period, - ImGuiKey_Slash, ImGuiKey_Semicolon, ImGuiKey_Equal, ImGuiKey_LeftBracket, - ImGuiKey_RightBracket, ImGuiKey_Backslash, ImGuiKey_GraveAccent, which are difficult - to find a reliable translated mapping on all keyboard layouts. - Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. (#8452) - Backends: SDL2, SDL3: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn @@ -2061,7 +2063,7 @@ Other changes: - Public API: PushTabStop(false) / PopTabStop() - Internal: PushItemFlag(ImGuiItemFlags_NoTabStop, true); - Internal: Directly pass ImGuiItemFlags_NoTabStop to ItemAdd() for custom widgets. -- Nav: Tabbing/Shift-Tabbing can more reliably be used to step out of an item that is not +- Nav: Tabbing/Shift+Tabbing can more reliably be used to step out of an item that is not tab-stoppable. (#3092, #5759, #787) - Nav: Made Enter key submit the same type of Activation event as Space key, allowing to press buttons with Enter. (#5606) diff --git a/imgui.h b/imgui.h index 7cecf064a289..429bb7480b58 100644 --- a/imgui.h +++ b/imgui.h @@ -2436,7 +2436,7 @@ struct ImGuiIO bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds. bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window. bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system. - bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a ctrl-click that spawned a simulated right click + bool MouseCtrlLeftAsRightClick; // (OSX) Set to true when the current click was a Ctrl+click that spawned a simulated right click float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked) float MouseDownDurationPrev[5]; // Previous time the mouse button has been down float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9ecdbae8e610..fef30d273781 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2642,7 +2642,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { - // Tabbing or CTRL-clicking on Drag turns it into an InputText + // Tabbing or CTRL+click on Drag turns it into an InputText const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id); const bool double_clicked = (hovered && g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft, id)); const bool make_active = (clicked || double_clicked || g.NavActivateId == id); @@ -3246,7 +3246,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { - // Tabbing or CTRL-clicking on Slider turns it into an input box + // Tabbing or CTRL+click on Slider turns it into an input box const bool clicked = hovered && IsMouseClicked(0, ImGuiInputFlags_None, id); const bool make_active = (clicked || g.NavActivateId == id); if (make_active && clicked) @@ -5495,7 +5495,7 @@ static void ColorEditRestoreHS(const float* col, float* H, float* S, float* V) // Edit colors components (each component in 0.0f..1.0f range). // See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set. -// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item. +// With typical options: Left-click on color square to open color picker. Right-click to open option menu. CTRL+Click over input fields to edit them and TAB to go to next item. bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags) { ImGuiWindow* window = GetCurrentWindow(); From 51e4cba909e7a442eed3fcb1080c7d757ea031de Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Mar 2025 12:05:23 +0100 Subject: [PATCH 300/716] Backends: Fixed zealous warnings. --- backends/imgui_impl_sdl2.cpp | 2 +- backends/imgui_impl_sdl3.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 33f7fed06a2f..0be2f2c6e360 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -192,7 +192,6 @@ static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImG ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode); ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode) { - IM_UNUSED(scancode); switch (keycode) { case SDLK_TAB: return ImGuiKey_Tab; @@ -332,6 +331,7 @@ ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode sca case SDL_SCANCODE_COMMA: return ImGuiKey_Comma; case SDL_SCANCODE_PERIOD: return ImGuiKey_Period; case SDL_SCANCODE_SLASH: return ImGuiKey_Slash; + default: break; } return ImGuiKey_None; } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 6720899ef23f..cfe8bbd4e8b1 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -313,6 +313,7 @@ ImGuiKey ImGui_ImplSDL3_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode sca case SDL_SCANCODE_COMMA: return ImGuiKey_Comma; case SDL_SCANCODE_PERIOD: return ImGuiKey_Period; case SDL_SCANCODE_SLASH: return ImGuiKey_Slash; + default: break; } return ImGuiKey_None; } From 6da230636b4cb64aa8a30c9110c5a52862a5c2c0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Mar 2025 12:20:33 +0100 Subject: [PATCH 301/716] Examples: Updated all .vcxproj from VS2015 to VS2019 (toolset v140 to v142), Windows SDK 8.1 to 10. --- docs/CHANGELOG.txt | 6 ++++++ examples/example_allegro5/example_allegro5.vcxproj | 10 +++++----- .../example_glfw_opengl2.vcxproj | 10 +++++----- .../example_glfw_opengl3.vcxproj | 10 +++++----- .../example_glfw_vulkan/example_glfw_vulkan.vcxproj | 10 +++++----- .../example_glut_opengl2.vcxproj | 10 +++++----- .../example_sdl2_directx11.vcxproj | 10 +++++----- .../example_sdl2_opengl2.vcxproj | 10 +++++----- .../example_sdl2_opengl3.vcxproj | 10 +++++----- .../example_sdl2_sdlrenderer2.vcxproj | 12 ++++++------ .../example_sdl2_vulkan/example_sdl2_vulkan.vcxproj | 12 ++++++------ .../example_sdl3_opengl3.vcxproj | 10 +++++----- .../example_sdl3_sdlgpu3.vcxproj | 12 ++++++------ .../example_sdl3_sdlrenderer3.vcxproj | 10 +++++----- .../example_sdl3_vulkan/example_sdl3_vulkan.vcxproj | 10 +++++----- .../example_win32_directx10.vcxproj | 10 +++++----- .../example_win32_directx11.vcxproj | 9 +++++---- .../example_win32_directx12.vcxproj | 10 +++++----- .../example_win32_directx9.vcxproj | 10 +++++----- .../example_win32_opengl3.vcxproj | 10 +++++----- .../example_win32_vulkan.vcxproj | 9 +++++---- 21 files changed, 109 insertions(+), 101 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5975e9155305..2a55e24131bd 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,6 +68,10 @@ Breaking changes: Other changes: +- This is the last release we are thoroughly testing with VS2015 + Windows SDK 8.1. + Example projects have been transitioned to VS2019 + Windows SDK 10. The library + as of today still compiles and works fine with VS2015, but onward we may break + support more often. - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) - Windows: Fixed an issue where BeginChild() inside a collapsed Begin() @@ -121,6 +125,8 @@ Other changes: by showing the filter inside the combo contents. (#718) - Examples: SDL3: Added comments to clarify setup for users of the unfortunate SDL_MAIN_USE_CALLBACKS feature. (#8455) +- Examples: Updated all .vcxproj from VS2015 to VS2019 (toolset v140 to v142), + and from Windows SDK 8.1 to Windows SDK 10 ("latest" setting). - IO: Added ImGuiKey_Oem102 to ImGuiKey enum. (#7136, #7201, #7206, #7306, #8468) - Backends: reworked key handlers to use/prioritize untranslated scancodes instead of translated keycodes when dealing with OEM keys which are too difficult to find a reliable diff --git a/examples/example_allegro5/example_allegro5.vcxproj b/examples/example_allegro5/example_allegro5.vcxproj index 02f6a4741239..220095e78eca 100644 --- a/examples/example_allegro5/example_allegro5.vcxproj +++ b/examples/example_allegro5/example_allegro5.vcxproj @@ -21,34 +21,34 @@ {73F235B5-7D31-4FC6-8682-DDC5A097B9C1} example_allegro5 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj index 2aa25506e2f3..6d373337c01c 100644 --- a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj +++ b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj @@ -21,34 +21,34 @@ {9CDA7840-B7A5-496D-A527-E95571496D18} example_glfw_opengl2 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj index 4bd503afe335..40000775720f 100644 --- a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj +++ b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj @@ -21,34 +21,34 @@ {4a1fb5ea-22f5-42a8-ab92-1d2df5d47fb9} example_glfw_opengl3 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj index a81d328df976..d2ff07e9b9f2 100644 --- a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj +++ b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj @@ -21,34 +21,34 @@ {57E2DF5A-6FC8-45BB-99DD-91A18C646E80} example_glfw_vulkan - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj index c56452b26c5a..5c773c8188e6 100644 --- a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj +++ b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj @@ -21,34 +21,34 @@ {F90D0333-5FB1-440D-918D-DD39A1B5187E} example_glut_opengl2 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj index c23800c9e4a4..5a8daf1bd3c9 100644 --- a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj +++ b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj @@ -21,7 +21,7 @@ {9E1987E3-1F19-45CA-B9C9-D31E791836D8} example_sdl2_directx11 - 8.1 + 10.0 example_sdl2_directx11 @@ -29,27 +29,27 @@ Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj index 036463f96bf1..b033c322f542 100644 --- a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj +++ b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj @@ -21,34 +21,34 @@ {2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741} example_sdl2_opengl2 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj index 6a81c67704bc..faf5874b3181 100644 --- a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj +++ b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj @@ -21,34 +21,34 @@ {BBAEB705-1669-40F3-8567-04CF6A991F4C} example_sdl2_opengl3 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj index cf2c890bba17..7d3cd4eb5178 100644 --- a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj +++ b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj @@ -21,7 +21,7 @@ {0C0B2BEA-311F-473C-9652-87923EF639E3} example_sdl2_sdlrenderer2 - 8.1 + 10.0 example_sdl2_sdlrenderer2 @@ -29,27 +29,27 @@ Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 @@ -184,4 +184,4 @@ - + \ No newline at end of file diff --git a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj index bcf99a46c002..07a60ac7239a 100644 --- a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj +++ b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj @@ -21,34 +21,34 @@ {BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3} example_sdl2_vulkan - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 @@ -187,4 +187,4 @@ - + \ No newline at end of file diff --git a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj index 051f87d764fc..2f14fdf80a48 100644 --- a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj +++ b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj @@ -21,34 +21,34 @@ {84AAA301-84FE-428B-9E3E-817BC8123C0C} example_sdl3_opengl3 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj index 3d034f52c0a5..01a38f336701 100644 --- a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj +++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj @@ -21,34 +21,34 @@ {c22cb6f8-39a5-4dda-90ed-4aca4e81e1e5} example_sdl3_sdlgpu3 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 @@ -186,4 +186,4 @@ - + \ No newline at end of file diff --git a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj index 8b71324cc750..4793e537c5a8 100644 --- a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj +++ b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj @@ -21,34 +21,34 @@ {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA} example_sdl3_opengl3 - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj index d48e4aff3051..29437778450b 100644 --- a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj +++ b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj @@ -21,34 +21,34 @@ {663A7E89-1E42-4222-921C-177F5B5910DF} example_sdl3_vulkan - 8.1 + 10.0 Application true MultiByte - v140 + v142 Application true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 Application false true MultiByte - v140 + v142 diff --git a/examples/example_win32_directx10/example_win32_directx10.vcxproj b/examples/example_win32_directx10/example_win32_directx10.vcxproj index d11aed88387a..8fe6d10b5622 100644 --- a/examples/example_win32_directx10/example_win32_directx10.vcxproj +++ b/examples/example_win32_directx10/example_win32_directx10.vcxproj @@ -21,34 +21,34 @@ {345A953E-A004-4648-B442-DC5F9F11068C} example_win32_directx10 - 8.1 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 diff --git a/examples/example_win32_directx11/example_win32_directx11.vcxproj b/examples/example_win32_directx11/example_win32_directx11.vcxproj index bace6a2c8361..79cdbaea7a0a 100644 --- a/examples/example_win32_directx11/example_win32_directx11.vcxproj +++ b/examples/example_win32_directx11/example_win32_directx11.vcxproj @@ -21,33 +21,34 @@ {9F316E83-5AE5-4939-A723-305A94F48005} example_win32_directx11 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj b/examples/example_win32_directx12/example_win32_directx12.vcxproj index bb98c4141ca1..c4b81e76f5fc 100644 --- a/examples/example_win32_directx12/example_win32_directx12.vcxproj +++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj @@ -21,34 +21,34 @@ {b4cf9797-519d-4afe-a8f4-5141a6b521d3} example_win32_directx12 - 10.0.20348.0 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 diff --git a/examples/example_win32_directx9/example_win32_directx9.vcxproj b/examples/example_win32_directx9/example_win32_directx9.vcxproj index 8c3f99589bb0..346ec1efcc7f 100644 --- a/examples/example_win32_directx9/example_win32_directx9.vcxproj +++ b/examples/example_win32_directx9/example_win32_directx9.vcxproj @@ -21,34 +21,34 @@ {4165A294-21F2-44CA-9B38-E3F935ABADF5} example_win32_directx9 - 8.1 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 diff --git a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj index 98fc38fd34d9..9848d62c66d9 100644 --- a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj +++ b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj @@ -21,34 +21,34 @@ {C624E5FF-D4FE-4D35-9164-B8A91864F98E} example_win32_opengl2 - 8.1 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj index dab8afd4ed71..604f8a817137 100644 --- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj @@ -21,33 +21,34 @@ {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88} example_win32_directx11 + 10.0 Application true Unicode - v140 + v142 Application true Unicode - v140 + v142 Application false true Unicode - v140 + v142 Application false true Unicode - v140 + v142 From 557c77e4556a776058c099881f4b32d5416b27c6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Mar 2025 18:38:45 +0100 Subject: [PATCH 302/716] Added ImGuiKey_AbntC1, ImGuiKey_AbntC2 + Backends: GLFW, Win32: added support. (#8468) --- backends/imgui_impl_glfw.cpp | 12 +++++++++--- backends/imgui_impl_win32.cpp | 6 ++++-- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 2 +- imgui.h | 2 ++ 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index baa8541b0af0..d4629493261e 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -28,7 +28,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. +// 2025-03-11: Added support for ImGuiKey_Oem102, ImGuiKey_AbntC1, ImGuiKey_AbntC2. // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn @@ -195,7 +195,6 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode); ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) { - IM_UNUSED(scancode); switch (keycode) { case GLFW_KEY_TAB: return ImGuiKey_Tab; @@ -317,8 +316,15 @@ ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) case GLFW_KEY_F22: return ImGuiKey_F22; case GLFW_KEY_F23: return ImGuiKey_F23; case GLFW_KEY_F24: return ImGuiKey_F24; - default: return ImGuiKey_None; + default: break; + } + switch (scancode) + { + case 115: return ImGuiKey_AbntC1; + case 126: return ImGuiKey_AbntC2; + default: break; } + return ImGuiKey_None; } // X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 2c749515d221..da007c1d83ed 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,7 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) +// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) + Added support for ImGuiKey_Oem102, ImGuiKey_AbntC1, ImGuiKey_AbntC2. // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. @@ -565,13 +565,15 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) case 13: return ImGuiKey_Equal; case 26: return ImGuiKey_LeftBracket; case 27: return ImGuiKey_RightBracket; - case 86: return ImGuiKey_Oem102; case 43: return ImGuiKey_Backslash; case 39: return ImGuiKey_Semicolon; case 40: return ImGuiKey_Apostrophe; case 51: return ImGuiKey_Comma; case 52: return ImGuiKey_Period; case 53: return ImGuiKey_Slash; + case 86: return ImGuiKey_Oem102; + case 115: return ImGuiKey_AbntC1; + case 126: return ImGuiKey_AbntC2; } return ImGuiKey_None; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2a55e24131bd..f5ce04a88f40 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -128,6 +128,7 @@ Other changes: - Examples: Updated all .vcxproj from VS2015 to VS2019 (toolset v140 to v142), and from Windows SDK 8.1 to Windows SDK 10 ("latest" setting). - IO: Added ImGuiKey_Oem102 to ImGuiKey enum. (#7136, #7201, #7206, #7306, #8468) +- IO: Added ImGuiKey_AbntC1, ImGuiKey_AbntC2 to ImGuiKey enum. (#8468) - Backends: reworked key handlers to use/prioritize untranslated scancodes instead of translated keycodes when dealing with OEM keys which are too difficult to find a reliable translated mapping on all systems, backends and keyboard layout. @@ -139,7 +140,8 @@ Other changes: - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboad layouts. - Makes emitted ImGuiKey values more consistent regardless of keyboard mapping, but you may be getting different values as before. - - Win32, SDL2, SDL3: Use scancodes for OEM keys. + - Win32: Use scancodes for OEM keys. Added support for the 3 new keys. + - SDL2, SDL3: Use scancodes for OEM keys. Added support for the Oem102 new key. - GLFW: GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 are emitting ImGuiKey_Oem102. - Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. (#8452) diff --git a/imgui.cpp b/imgui.cpp index 26d055dd21ff..ae81cc64acd9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8787,7 +8787,7 @@ static const char* const GKeyNames[] = "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", - "AppBack", "AppForward", "Oem102", + "AppBack", "AppForward", "Oem102", "AbntC1", "AbntC2", "GamepadStart", "GamepadBack", "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown", "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown", diff --git a/imgui.h b/imgui.h index 429bb7480b58..512e9a6c7298 100644 --- a/imgui.h +++ b/imgui.h @@ -1494,6 +1494,8 @@ enum ImGuiKey : int ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back" ImGuiKey_AppForward, ImGuiKey_Oem102, // Non-US backslash. + ImGuiKey_AbntC1, // Brazil ABNT extra keys + ImGuiKey_AbntC2, // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) From 09654f4e8caae1ae2c25f246e007ec0fd97eb6b8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Mar 2025 18:42:12 +0100 Subject: [PATCH 303/716] Revert "Examples: Updated all .vcxproj from VS2015 to VS2019 (toolset v140 to v142), Windows SDK 8.1 to 10." This reverts commit 6da230636b4cb64aa8a30c9110c5a52862a5c2c0. --- docs/CHANGELOG.txt | 6 ------ examples/example_allegro5/example_allegro5.vcxproj | 10 +++++----- .../example_glfw_opengl2.vcxproj | 10 +++++----- .../example_glfw_opengl3.vcxproj | 10 +++++----- .../example_glfw_vulkan/example_glfw_vulkan.vcxproj | 10 +++++----- .../example_glut_opengl2.vcxproj | 10 +++++----- .../example_sdl2_directx11.vcxproj | 10 +++++----- .../example_sdl2_opengl2.vcxproj | 10 +++++----- .../example_sdl2_opengl3.vcxproj | 10 +++++----- .../example_sdl2_sdlrenderer2.vcxproj | 12 ++++++------ .../example_sdl2_vulkan/example_sdl2_vulkan.vcxproj | 12 ++++++------ .../example_sdl3_opengl3.vcxproj | 10 +++++----- .../example_sdl3_sdlgpu3.vcxproj | 12 ++++++------ .../example_sdl3_sdlrenderer3.vcxproj | 10 +++++----- .../example_sdl3_vulkan/example_sdl3_vulkan.vcxproj | 10 +++++----- .../example_win32_directx10.vcxproj | 10 +++++----- .../example_win32_directx11.vcxproj | 9 ++++----- .../example_win32_directx12.vcxproj | 10 +++++----- .../example_win32_directx9.vcxproj | 10 +++++----- .../example_win32_opengl3.vcxproj | 10 +++++----- .../example_win32_vulkan.vcxproj | 9 ++++----- 21 files changed, 101 insertions(+), 109 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f5ce04a88f40..cc5964f073e9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,10 +68,6 @@ Breaking changes: Other changes: -- This is the last release we are thoroughly testing with VS2015 + Windows SDK 8.1. - Example projects have been transitioned to VS2019 + Windows SDK 10. The library - as of today still compiles and works fine with VS2015, but onward we may break - support more often. - Fixed IsItemDeactivatedAfterEdit() signal being broken for Checkbox(), RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) - Windows: Fixed an issue where BeginChild() inside a collapsed Begin() @@ -125,8 +121,6 @@ Other changes: by showing the filter inside the combo contents. (#718) - Examples: SDL3: Added comments to clarify setup for users of the unfortunate SDL_MAIN_USE_CALLBACKS feature. (#8455) -- Examples: Updated all .vcxproj from VS2015 to VS2019 (toolset v140 to v142), - and from Windows SDK 8.1 to Windows SDK 10 ("latest" setting). - IO: Added ImGuiKey_Oem102 to ImGuiKey enum. (#7136, #7201, #7206, #7306, #8468) - IO: Added ImGuiKey_AbntC1, ImGuiKey_AbntC2 to ImGuiKey enum. (#8468) - Backends: reworked key handlers to use/prioritize untranslated scancodes instead of diff --git a/examples/example_allegro5/example_allegro5.vcxproj b/examples/example_allegro5/example_allegro5.vcxproj index 220095e78eca..02f6a4741239 100644 --- a/examples/example_allegro5/example_allegro5.vcxproj +++ b/examples/example_allegro5/example_allegro5.vcxproj @@ -21,34 +21,34 @@ {73F235B5-7D31-4FC6-8682-DDC5A097B9C1} example_allegro5 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj index 6d373337c01c..2aa25506e2f3 100644 --- a/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj +++ b/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj @@ -21,34 +21,34 @@ {9CDA7840-B7A5-496D-A527-E95571496D18} example_glfw_opengl2 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj index 40000775720f..4bd503afe335 100644 --- a/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj +++ b/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj @@ -21,34 +21,34 @@ {4a1fb5ea-22f5-42a8-ab92-1d2df5d47fb9} example_glfw_opengl3 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj index d2ff07e9b9f2..a81d328df976 100644 --- a/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj +++ b/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj @@ -21,34 +21,34 @@ {57E2DF5A-6FC8-45BB-99DD-91A18C646E80} example_glfw_vulkan - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj index 5c773c8188e6..c56452b26c5a 100644 --- a/examples/example_glut_opengl2/example_glut_opengl2.vcxproj +++ b/examples/example_glut_opengl2/example_glut_opengl2.vcxproj @@ -21,34 +21,34 @@ {F90D0333-5FB1-440D-918D-DD39A1B5187E} example_glut_opengl2 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj index 5a8daf1bd3c9..c23800c9e4a4 100644 --- a/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj +++ b/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj @@ -21,7 +21,7 @@ {9E1987E3-1F19-45CA-B9C9-D31E791836D8} example_sdl2_directx11 - 10.0 + 8.1 example_sdl2_directx11 @@ -29,27 +29,27 @@ Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj index b033c322f542..036463f96bf1 100644 --- a/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj +++ b/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj @@ -21,34 +21,34 @@ {2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741} example_sdl2_opengl2 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj index faf5874b3181..6a81c67704bc 100644 --- a/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj +++ b/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj @@ -21,34 +21,34 @@ {BBAEB705-1669-40F3-8567-04CF6A991F4C} example_sdl2_opengl3 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj index 7d3cd4eb5178..cf2c890bba17 100644 --- a/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj +++ b/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj @@ -21,7 +21,7 @@ {0C0B2BEA-311F-473C-9652-87923EF639E3} example_sdl2_sdlrenderer2 - 10.0 + 8.1 example_sdl2_sdlrenderer2 @@ -29,27 +29,27 @@ Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 @@ -184,4 +184,4 @@ - \ No newline at end of file + diff --git a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj index 07a60ac7239a..bcf99a46c002 100644 --- a/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj +++ b/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj @@ -21,34 +21,34 @@ {BAE3D0B5-9695-4EB1-AD0F-75890EB4A3B3} example_sdl2_vulkan - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 @@ -187,4 +187,4 @@ - \ No newline at end of file + diff --git a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj index 2f14fdf80a48..051f87d764fc 100644 --- a/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj +++ b/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj @@ -21,34 +21,34 @@ {84AAA301-84FE-428B-9E3E-817BC8123C0C} example_sdl3_opengl3 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj index 01a38f336701..3d034f52c0a5 100644 --- a/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj +++ b/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj @@ -21,34 +21,34 @@ {c22cb6f8-39a5-4dda-90ed-4aca4e81e1e5} example_sdl3_sdlgpu3 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 @@ -186,4 +186,4 @@ - \ No newline at end of file + diff --git a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj index 4793e537c5a8..8b71324cc750 100644 --- a/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj +++ b/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj @@ -21,34 +21,34 @@ {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA} example_sdl3_opengl3 - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj index 29437778450b..d48e4aff3051 100644 --- a/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj +++ b/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj @@ -21,34 +21,34 @@ {663A7E89-1E42-4222-921C-177F5B5910DF} example_sdl3_vulkan - 10.0 + 8.1 Application true MultiByte - v142 + v140 Application true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 Application false true MultiByte - v142 + v140 diff --git a/examples/example_win32_directx10/example_win32_directx10.vcxproj b/examples/example_win32_directx10/example_win32_directx10.vcxproj index 8fe6d10b5622..d11aed88387a 100644 --- a/examples/example_win32_directx10/example_win32_directx10.vcxproj +++ b/examples/example_win32_directx10/example_win32_directx10.vcxproj @@ -21,34 +21,34 @@ {345A953E-A004-4648-B442-DC5F9F11068C} example_win32_directx10 - 10.0 + 8.1 Application true Unicode - v142 + v140 Application true Unicode - v142 + v140 Application false true Unicode - v142 + v140 Application false true Unicode - v142 + v140 diff --git a/examples/example_win32_directx11/example_win32_directx11.vcxproj b/examples/example_win32_directx11/example_win32_directx11.vcxproj index 79cdbaea7a0a..bace6a2c8361 100644 --- a/examples/example_win32_directx11/example_win32_directx11.vcxproj +++ b/examples/example_win32_directx11/example_win32_directx11.vcxproj @@ -21,34 +21,33 @@ {9F316E83-5AE5-4939-A723-305A94F48005} example_win32_directx11 - 10.0 Application true Unicode - v142 + v140 Application true Unicode - v142 + v140 Application false true Unicode - v142 + v140 Application false true Unicode - v142 + v140 diff --git a/examples/example_win32_directx12/example_win32_directx12.vcxproj b/examples/example_win32_directx12/example_win32_directx12.vcxproj index c4b81e76f5fc..bb98c4141ca1 100644 --- a/examples/example_win32_directx12/example_win32_directx12.vcxproj +++ b/examples/example_win32_directx12/example_win32_directx12.vcxproj @@ -21,34 +21,34 @@ {b4cf9797-519d-4afe-a8f4-5141a6b521d3} example_win32_directx12 - 10.0 + 10.0.20348.0 Application true Unicode - v142 + v140 Application true Unicode - v142 + v140 Application false true Unicode - v142 + v140 Application false true Unicode - v142 + v140 diff --git a/examples/example_win32_directx9/example_win32_directx9.vcxproj b/examples/example_win32_directx9/example_win32_directx9.vcxproj index 346ec1efcc7f..8c3f99589bb0 100644 --- a/examples/example_win32_directx9/example_win32_directx9.vcxproj +++ b/examples/example_win32_directx9/example_win32_directx9.vcxproj @@ -21,34 +21,34 @@ {4165A294-21F2-44CA-9B38-E3F935ABADF5} example_win32_directx9 - 10.0 + 8.1 Application true Unicode - v142 + v140 Application true Unicode - v142 + v140 Application false true Unicode - v142 + v140 Application false true Unicode - v142 + v140 diff --git a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj index 9848d62c66d9..98fc38fd34d9 100644 --- a/examples/example_win32_opengl3/example_win32_opengl3.vcxproj +++ b/examples/example_win32_opengl3/example_win32_opengl3.vcxproj @@ -21,34 +21,34 @@ {C624E5FF-D4FE-4D35-9164-B8A91864F98E} example_win32_opengl2 - 10.0 + 8.1 Application true Unicode - v142 + v140 Application true Unicode - v142 + v140 Application false true Unicode - v142 + v140 Application false true Unicode - v142 + v140 diff --git a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj index 604f8a817137..dab8afd4ed71 100644 --- a/examples/example_win32_vulkan/example_win32_vulkan.vcxproj +++ b/examples/example_win32_vulkan/example_win32_vulkan.vcxproj @@ -21,34 +21,33 @@ {0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88} example_win32_directx11 - 10.0 Application true Unicode - v142 + v140 Application true Unicode - v142 + v140 Application false true Unicode - v142 + v140 Application false true Unicode - v142 + v140 From de4f77b0ac9a41fa4a77ffc5d3a2c4a106880068 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Mar 2025 15:47:37 +0100 Subject: [PATCH 304/716] Backends: DX12: comment about using SrvDescriptorAllocFn/SrvDescriptorFreeFn. Amend 40b2286d16e92ea017347a62cb91e63f378ff455 --- backends/imgui_impl_dx12.cpp | 2 +- backends/imgui_impl_dx12.h | 2 +- examples/example_win32_directx12/main.cpp | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index e9a2c119c4b6..202bac3b09d9 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -748,7 +748,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - IM_ASSERT(bd->LegacySingleDescriptorUsed == false); + IM_ASSERT(bd->LegacySingleDescriptorUsed == false && "Only 1 simultaneous texture allowed with legacy ImGui_ImplDX12_Init() signature!"); *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor; *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor; bd->LegacySingleDescriptorUsed = true; diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 736e9f5c2e3e..a79de7b13565 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -34,7 +34,7 @@ struct ImGui_ImplDX12_InitInfo void* UserData; // Allocating SRV descriptors for textures is up to the application, so we provide callbacks. - // (current version of the backend will only allocate one descriptor, future versions will need to allocate more) + // (current version of the backend will only allocate one descriptor, from 1.92 the backend will need to allocate more) ID3D12DescriptorHeap* SrvDescriptorHeap; void (*SrvDescriptorAllocFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle); void (*SrvDescriptorFreeFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle); diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index e83ce7dcbbc9..5f6cd51dd845 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -154,6 +154,9 @@ int main(int, char**) init_info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle) { return g_pd3dSrvDescHeapAlloc.Free(cpu_handle, gpu_handle); }; ImGui_ImplDX12_Init(&init_info); + // Before 1.91.6: our signature was using a single descriptor. From 1.92, specifying SrvDescriptorAllocFn/SrvDescriptorFreeFn will be required to benefit from new features. + //ImGui_ImplDX12_Init(g_pd3dDevice, APP_NUM_FRAMES_IN_FLIGHT, DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); + // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. From 6e30c4210181aebb6137f6c10fdfc572ea1202f2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Mar 2025 19:29:41 +0100 Subject: [PATCH 305/716] Tables: fixed an issue with TableSetupColumn() overriding ini data. (#7934) Amend 05742f9b6f --- imgui_tables.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index bc5862ee3703..5464ba688f28 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1637,7 +1637,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo if (table->IsInitializing) { ImGuiTableFlags init_flags = ~0; - if (column->WidthRequest >= 0.0f && column->StretchWeight >= 0.0f) + if (column->WidthRequest >= 0.0f || column->StretchWeight >= 0.0f) init_flags &= ~ImGuiTableFlags_Resizable; TableInitColumnDefaults(table, column, init_flags); } From d9dad2f4a15aa49c7464b9b3eef2588f14437e22 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 12 Mar 2025 14:15:51 +0100 Subject: [PATCH 306/716] Scrollbar: stabilize visibility of ScrollbarX when detecting a feedback loop. (#8488, #3285, #4539) --- docs/CHANGELOG.txt | 8 ++++++++ imgui.cpp | 14 ++++++++++++++ imgui_internal.h | 9 ++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cc5964f073e9..bbf9255c34d8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -82,6 +82,14 @@ Other changes: visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] - Scrollbar: Rework logic that fades-out scrollbar when it becomes too small, which amusingly made it disappear when using very big font/frame size. +- Scrollbar: Automatically stabilize ScrollbarX visibility when detecting a + feedback loop manifesting with ScrollbarX visibility toggling on and off + repeatedly. (#8488, #3285, #4539) + (feedback loops of this sort can manifest in various situations, but combining + horizontal + vertical scrollbar + using a clipper with varying width items is + one frequent cause. The better solution is to, either: (1) enforce visibility + by using ImGuiWindowFlags_AlwaysHorizontalScrollbar or (2) declare stable + contents width with SetNextWindowContentSize(), if you can compute it.) - Tables: fixed calling SetNextWindowScroll() on clipped scrolling table to not leak the value into a subsequent window. (#8196) - Tables: fixed an issue where Columns Visible/Width state wouldn't be correctly diff --git a/imgui.cpp b/imgui.cpp index ae81cc64acd9..093ba637528d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7456,9 +7456,23 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; + bool scrollbar_x_prev = window->ScrollbarX; //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); + + // Track when ScrollbarX visibility keeps toggling, which is a sign of a feedback loop, and stabilize by enforcing visibility (#3285, #8488) + // (Feedback loops of this sort can manifest in various situations, but combining horizontal + vertical scrollbar + using a clipper with varying width items is one frequent cause. + // The better solution is to, either (1) enforce visibility by using ImGuiWindowFlags_AlwaysHorizontalScrollbar or (2) declare stable contents width with SetNextWindowContentSize(), if you can compute it) + window->ScrollbarXStabilizeToggledHistory <<= 1; + window->ScrollbarXStabilizeToggledHistory |= (scrollbar_x_prev != window->ScrollbarX) ? 0x01 : 0x00; + const bool scrollbar_x_stabilize = (window->ScrollbarXStabilizeToggledHistory != 0) && ImCountSetBits(window->ScrollbarXStabilizeToggledHistory) >= 4; // 4 == half of bits in our U8 history. + if (scrollbar_x_stabilize) + window->ScrollbarX = true; + //if (scrollbar_x_stabilize && !window->ScrollbarXStabilizeEnabled) + // IMGUI_DEBUG_LOG("[scroll] Stabilize ScrollbarX for Window '%s'\n", window->Name); + window->ScrollbarXStabilizeEnabled = scrollbar_x_stabilize; + if (window->ScrollbarX && !window->ScrollbarY) window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); diff --git a/imgui_internal.h b/imgui_internal.h index aaa2027df944..6d9120a9e007 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -367,9 +367,10 @@ static inline void ImQsort(void* base, size_t count, size_t size_of_element IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b); // Helpers: Bit manipulation -static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } -static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } -static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } +static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } +static inline bool ImIsPowerOfTwo(ImU64 v) { return v != 0 && (v & (v - 1)) == 0; } +static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } +static inline unsigned int ImCountSetBits(unsigned int v) { unsigned int count = 0; while (v > 0) { v = v & (v - 1); count++; } return count; } // Helpers: String #define ImStrlen strlen @@ -2514,6 +2515,8 @@ struct IMGUI_API ImGuiWindow ImVec2 ScrollTargetEdgeSnapDist; // 0.0f = no snapping, >0.0f snapping threshold ImVec2 ScrollbarSizes; // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar. bool ScrollbarX, ScrollbarY; // Are scrollbars visible? + bool ScrollbarXStabilizeEnabled; // Was ScrollbarX previously auto-stabilized? + ImU8 ScrollbarXStabilizeToggledHistory; // Used to stabilize scrollbar visibility in case of feedback loops bool Active; // Set to true on Begin(), unless Collapsed bool WasActive; bool WriteAccessed; // Set to true when any widget access the current window From 79bba34c5f453640bf6f4a17741ad2e3e7b5abfe Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 16:32:50 +0100 Subject: [PATCH 307/716] Revert "Added ImGuiKey_AbntC1, ImGuiKey_AbntC2 + Backends: GLFW, Win32: added support. (#8468)" This reverts commit 557c77e4556a776058c099881f4b32d5416b27c6. --- backends/imgui_impl_glfw.cpp | 12 +++--------- backends/imgui_impl_win32.cpp | 6 ++---- docs/CHANGELOG.txt | 4 +--- imgui.cpp | 2 +- imgui.h | 2 -- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index d4629493261e..baa8541b0af0 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -28,7 +28,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-03-11: Added support for ImGuiKey_Oem102, ImGuiKey_AbntC1, ImGuiKey_AbntC2. +// 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn @@ -195,6 +195,7 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode); ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) { + IM_UNUSED(scancode); switch (keycode) { case GLFW_KEY_TAB: return ImGuiKey_Tab; @@ -316,15 +317,8 @@ ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) case GLFW_KEY_F22: return ImGuiKey_F22; case GLFW_KEY_F23: return ImGuiKey_F23; case GLFW_KEY_F24: return ImGuiKey_F24; - default: break; - } - switch (scancode) - { - case 115: return ImGuiKey_AbntC1; - case 126: return ImGuiKey_AbntC2; - default: break; + default: return ImGuiKey_None; } - return ImGuiKey_None; } // X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index da007c1d83ed..2c749515d221 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,7 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) + Added support for ImGuiKey_Oem102, ImGuiKey_AbntC1, ImGuiKey_AbntC2. +// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. @@ -565,15 +565,13 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) case 13: return ImGuiKey_Equal; case 26: return ImGuiKey_LeftBracket; case 27: return ImGuiKey_RightBracket; + case 86: return ImGuiKey_Oem102; case 43: return ImGuiKey_Backslash; case 39: return ImGuiKey_Semicolon; case 40: return ImGuiKey_Apostrophe; case 51: return ImGuiKey_Comma; case 52: return ImGuiKey_Period; case 53: return ImGuiKey_Slash; - case 86: return ImGuiKey_Oem102; - case 115: return ImGuiKey_AbntC1; - case 126: return ImGuiKey_AbntC2; } return ImGuiKey_None; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bbf9255c34d8..f184ddc8f785 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -130,7 +130,6 @@ Other changes: - Examples: SDL3: Added comments to clarify setup for users of the unfortunate SDL_MAIN_USE_CALLBACKS feature. (#8455) - IO: Added ImGuiKey_Oem102 to ImGuiKey enum. (#7136, #7201, #7206, #7306, #8468) -- IO: Added ImGuiKey_AbntC1, ImGuiKey_AbntC2 to ImGuiKey enum. (#8468) - Backends: reworked key handlers to use/prioritize untranslated scancodes instead of translated keycodes when dealing with OEM keys which are too difficult to find a reliable translated mapping on all systems, backends and keyboard layout. @@ -142,8 +141,7 @@ Other changes: - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboad layouts. - Makes emitted ImGuiKey values more consistent regardless of keyboard mapping, but you may be getting different values as before. - - Win32: Use scancodes for OEM keys. Added support for the 3 new keys. - - SDL2, SDL3: Use scancodes for OEM keys. Added support for the Oem102 new key. + - Win32, SDL2, SDL3: Use scancodes for OEM keys. - GLFW: GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 are emitting ImGuiKey_Oem102. - Backends: GLFW: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. (#8452) diff --git a/imgui.cpp b/imgui.cpp index 093ba637528d..a2d90caeda6e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8801,7 +8801,7 @@ static const char* const GKeyNames[] = "Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply", "KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", - "AppBack", "AppForward", "Oem102", "AbntC1", "AbntC2", + "AppBack", "AppForward", "Oem102", "GamepadStart", "GamepadBack", "GamepadFaceLeft", "GamepadFaceRight", "GamepadFaceUp", "GamepadFaceDown", "GamepadDpadLeft", "GamepadDpadRight", "GamepadDpadUp", "GamepadDpadDown", diff --git a/imgui.h b/imgui.h index 512e9a6c7298..429bb7480b58 100644 --- a/imgui.h +++ b/imgui.h @@ -1494,8 +1494,6 @@ enum ImGuiKey : int ImGuiKey_AppBack, // Available on some keyboard/mouses. Often referred as "Browser Back" ImGuiKey_AppForward, ImGuiKey_Oem102, // Non-US backslash. - ImGuiKey_AbntC1, // Brazil ABNT extra keys - ImGuiKey_AbntC2, // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) From b758b8223fc789c8f1962be08ce234aaa4ccd4f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 19:30:42 +0100 Subject: [PATCH 308/716] InputText: Pasting a multi-line buffer into a single-line edit replaces carriage return by spaces. (#8459) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f184ddc8f785..8d4f0bec7579 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,8 @@ Other changes: inner/outer padding applied to hit-testing of windows borders and detection of hovered window. - InputText: Allow CTRL+Shift+Z to redo even outside of OSX. (#8389) [@tanksdude] +- InputText: Pasting a multi-line buffer into a single-line edit replaces + carriage return by spaces. (#8459) - InputTextWithHint(): Fixed buffer-overflow (luckily often with no visible effect) when a user callback modified the buffer contents in a way that altered the visibility of the preview/hint buffer. (#8368) [@m9710797, @ocornut] diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fef30d273781..602bdb9e1c9d 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4294,7 +4294,13 @@ static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, Im if (c < 0x20) { bool pass = false; - pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) + pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; // Note that an Enter KEY will emit \r and be ignored (we poll for KEY in InputText() code) + if (c == '\n' && input_source_is_clipboard && (flags & ImGuiInputTextFlags_Multiline) == 0) // In single line mode, replace \n with a space + { + c = *p_char = ' '; + pass = true; + } + pass |= (c == '\n') && (flags & ImGuiInputTextFlags_Multiline) != 0; pass |= (c == '\t') && (flags & ImGuiInputTextFlags_AllowTabInput) != 0; if (!pass) return false; From ea2a12112df50975f3582b121c63d65fcdebd330 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 14 Mar 2025 17:13:04 +0100 Subject: [PATCH 309/716] Misc: Various zealous warning fixes for newer version of Clang. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 4 +++- imgui_demo.cpp | 2 ++ imgui_draw.cpp | 1 + imgui_tables.cpp | 2 ++ imgui_widgets.cpp | 2 ++ 6 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8d4f0bec7579..3c6c4f234960 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -124,6 +124,7 @@ Other changes: - Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) - Debug Tools: Tweaked layout of ID Stack Tool and always display full path. (#4631) +- Misc: Various zealous warning fixes for newer version of Clang. - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors (busy/wait/hourglass shape, with or without an arrow cursor). - Demo: Reorganized "Widgets" section to be alphabetically ordered and split in more functions. diff --git a/imgui.cpp b/imgui.cpp index a2d90caeda6e..60340c022423 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1145,17 +1145,19 @@ CODE #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. +#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. #pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is. #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness -#pragma clang diagnostic ignored "-Wformat-pedantic" // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type 'int' #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 #pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double. #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) // We disable -Wpragmas because GCC doesn't provide a has_warning equivalent and some forks/patches may not follow the warning/version association. #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 50eeed1073f6..0423c49f27e0 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -159,6 +159,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning: 'xx' is deprecated: The POSIX name for this.. // for strdup used in demo code (so user can copy & paste the code) #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning: cast to 'void *' from smaller integer type +#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' #pragma clang diagnostic ignored "-Wformat-security" // warning: format string is not a string literal #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals. #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. @@ -167,6 +168,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wreserved-id-macro" // warning: macro name is a reserved identifier #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe diff --git a/imgui_draw.cpp b/imgui_draw.cpp index efdddc8b1857..a1111b08fbed 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -68,6 +68,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type #pragma clang diagnostic ignored "-Wcast-qual" // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5464ba688f28..5cdee0433e3b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -221,6 +221,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" // warning: zero as null pointer constant // some standard header variations use #define NULL 0 @@ -230,6 +231,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 602bdb9e1c9d..880232965036 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -70,6 +70,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning: unknown warning group 'xxx' #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. #pragma clang diagnostic ignored "-Wfloat-equal" // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok. +#pragma clang diagnostic ignored "-Wformat" // warning: format specifies type 'int' but the argument has type 'unsigned int' #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning: format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code. #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used // we define snprintf/vsnprintf on Windows so they are available, but not always used. @@ -80,6 +81,7 @@ Index of this file: #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // warning: 'xxx' is an unsafe pointer used for buffer access #pragma clang diagnostic ignored "-Wnontrivial-memaccess" // warning: first argument in call to 'memset' is a pointer to non-trivially copyable type +#pragma clang diagnostic ignored "-Wswitch-default" // warning: 'switch' missing 'default' label #elif defined(__GNUC__) #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind #pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe From 97428e8ac99e339ce05eee531cf55b77b29ea709 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 14 Mar 2025 16:30:39 +0100 Subject: [PATCH 310/716] Version 1.91.9 --- docs/CHANGELOG.txt | 11 +++++++---- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3c6c4f234960..c9a68c7b2cf1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,9 +36,11 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.9 WIP (In Progress) + VERSION 1.91.9 (Released 2025-03-14) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.9 + Breaking changes: - Image: removed 'tint_col' and 'border_col' parameter from Image() function. (#8131, #8238) @@ -72,7 +74,7 @@ Other changes: RadioButton(), Selectable(). Regression from 2025/01/13. (#8370) - Windows: Fixed an issue where BeginChild() inside a collapsed Begin() wouldn't inherit the SkipItems flag, resulting in missing coarse clipping - opportunity for code not checking the BeginChild() return value. + opportunities for code not checking the BeginChild() return value. - Windows, Style: Added style.WindowBorderHoverPadding setting to configure inner/outer padding applied to hit-testing of windows borders and detection of hovered window. @@ -141,7 +143,7 @@ Other changes: ImGuiKey_Slash, ImGuiKey_Semicolon, ImGuiKey_Equal, ImGuiKey_LeftBracket, ImGuiKey_RightBracket, ImGuiKey_Backslash, ImGuiKey_GraveAccent, and newly introduced ImGuiKey_Oem102. - This is NOT affecting characters used the text inputs. - - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboad layouts. + - Fixes many cases of keys not emitting a ImGuiKey value with certain keyboard layouts. - Makes emitted ImGuiKey values more consistent regardless of keyboard mapping, but you may be getting different values as before. - Win32, SDL2, SDL3: Use scancodes for OEM keys. @@ -155,7 +157,8 @@ Other changes: - Backends: SDL2, SDL3: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. (#8425, #8407) [@TheMode] - Backends: SDL2, SDL3: Only start SDL_CaptureMouse() when mouse is being dragged, - to mitigate issues with e.g. Linux debuggers not claiming capture back. (#6410, #3650) + to mitigate issues with e.g. Linux debuggers not claiming capture back on debug + break. (#6410, #3650) - Backends: OpenGL3: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) - Backends: DirectX12: Fixed an issue where pre-1.91.5 legacy ImGui_ImplDX12_Init() diff --git a/imgui.cpp b/imgui.cpp index 60340c022423..8ec001178734 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 429bb7480b58..4ca9c83724dc 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.9 WIP" -#define IMGUI_VERSION_NUM 19188 +#define IMGUI_VERSION "1.91.9" +#define IMGUI_VERSION_NUM 19190 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0423c49f27e0..ead800f4b639 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a1111b08fbed..aa0a7feec1bd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 6d9120a9e007..6cb9be406c32 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 5cdee0433e3b..e67a8364978a 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 880232965036..fc358534eaa8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 WIP +// dear imgui, v1.91.9 // (widgets code) /* From d6493aab028139538c9bcf2141ae02574b12aa75 Mon Sep 17 00:00:00 2001 From: Wizard <74285801+wizard00000@users.noreply.github.com> Date: Sun, 16 Mar 2025 18:56:59 -0400 Subject: [PATCH 311/716] Fix typo in comment (#8494) --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index fc358534eaa8..d671cbbda950 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6207,7 +6207,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (g.Style.FrameBorderSize > 0.0f) RenderFrameBorder(bb.Min, bb.Max, rounding); else - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border } // Drag and Drop Source From 4d4f1fd364ebb770766a6fd4dd0d17c39865e7b2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 11:50:32 +0100 Subject: [PATCH 312/716] Docs: retroactively document ConfigData->Sources renaming. (#8495) Amend 4c0604e --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c9a68c7b2cf1..36ceb7cdbdeb 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,6 +64,8 @@ Breaking changes: - Backends: Vulkan: Added 'uint32_t api_version' argument to ImGui_ImplVulkan_LoadFunctions(). Note that it was also added to ImGui_ImplVulkan_InitInfo but for the later it is optional. (#8326, #8365, #8400) +- Internals: Fonts: ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[], +- Internals: Fonts: ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. - Internals: Menus: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. diff --git a/imgui.cpp b/imgui.cpp index 8ec001178734..af7ce4ce7667 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -441,6 +441,7 @@ CODE - old behavior altered border size (and therefore layout) based on border color's alpha, which caused variety of problems + old behavior a fixed 1.0f for border size which was not tweakable. - kept legacy signature (will obsolete), which mimics the old behavior, but uses Max(1.0f, style.ImageBorderSize) when border_col is specified. - added ImageWithBg() function which has both 'bg_col' (which was missing) and 'tint_col'. It was impossible to add 'bg_col' to Image() with a parameter order consistent with other functions, so we decided to remove 'tint_col' and introduce ImageWithBg(). + - 2025/02/25 (1.91.9) - internals: fonts: ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]. ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. - 2025/02/06 (1.91.9) - renamed ImFontConfig::GlyphExtraSpacing.x to ImFontConfig::GlyphExtraAdvanceX. - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. From 2737dbb1e1cd206fc874a5ca17ee672a68523182 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 11:51:57 +0100 Subject: [PATCH 313/716] Docs: Fixed typo. Very oops. (#8495) --- docs/CHANGELOG.txt | 2 +- imgui.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 36ceb7cdbdeb..e369f1957760 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -65,7 +65,7 @@ Breaking changes: Note that it was also added to ImGui_ImplVulkan_InitInfo but for the later it is optional. (#8326, #8365, #8400) - Internals: Fonts: ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[], -- Internals: Fonts: ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. +- Internals: Fonts: ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourcesCount. - Internals: Menus: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. diff --git a/imgui.cpp b/imgui.cpp index af7ce4ce7667..78774c2b48ea 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -441,7 +441,7 @@ CODE - old behavior altered border size (and therefore layout) based on border color's alpha, which caused variety of problems + old behavior a fixed 1.0f for border size which was not tweakable. - kept legacy signature (will obsolete), which mimics the old behavior, but uses Max(1.0f, style.ImageBorderSize) when border_col is specified. - added ImageWithBg() function which has both 'bg_col' (which was missing) and 'tint_col'. It was impossible to add 'bg_col' to Image() with a parameter order consistent with other functions, so we decided to remove 'tint_col' and introduce ImageWithBg(). - - 2025/02/25 (1.91.9) - internals: fonts: ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]. ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. + - 2025/02/25 (1.91.9) - internals: fonts: ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]. ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourcesCount. - 2025/02/06 (1.91.9) - renamed ImFontConfig::GlyphExtraSpacing.x to ImFontConfig::GlyphExtraAdvanceX. - 2025/01/22 (1.91.8) - removed ImGuiColorEditFlags_AlphaPreview (made value 0): it is now the default behavior. prior to 1.91.8: alpha was made opaque in the preview by default _unless_ using ImGuiColorEditFlags_AlphaPreview. We now display the preview as transparent by default. You can use ImGuiColorEditFlags_AlphaOpaque to use old behavior. From bfaef8ca1783a26aa7eba766dacf87a85ed13ede Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 19:08:58 +0100 Subject: [PATCH 314/716] Version 1.92.0 WIP --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e369f1957760..62c7c548a9c4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.92.0 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.91.9 (Released 2025-03-14) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 78774c2b48ea..932f433fdc5c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 4ca9c83724dc..7bbdf8225583 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.9" -#define IMGUI_VERSION_NUM 19190 +#define IMGUI_VERSION "1.92.0 WIP" +#define IMGUI_VERSION_NUM 19191 #define IMGUI_HAS_TABLE /* diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ead800f4b639..996694268739 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index aa0a7feec1bd..1404b8d61fcf 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 6cb9be406c32..870360264922 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e67a8364978a..0ac6ec89661d 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d671cbbda950..0aa121e774a2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9 +// dear imgui, v1.92.0 WIP // (widgets code) /* From a7dc1847728171e8940671d8e34a8ecb050f00fa Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 19:07:24 +0100 Subject: [PATCH 315/716] Moved ImDrawIdx definition lower in imgui.h. Moved ImTextureID slightly below in its own section. --- imgui.h | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/imgui.h b/imgui.h index 7bbdf8225583..0db50aec1825 100644 --- a/imgui.h +++ b/imgui.h @@ -37,6 +37,7 @@ Index of this file: // [SECTION] Header mess // [SECTION] Forward declarations and basic types +// [SECTION] Texture identifier (ImTextureID) // [SECTION] Dear ImGui end-user API functions // [SECTION] Flags & Enumerations // [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) @@ -250,22 +251,6 @@ typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: f typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild() -// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] -// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. -// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. -// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators. -// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings) -#ifndef ImTextureID -typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) -#endif - -// ImDrawIdx: vertex index. [Compile-time configurable type] -// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). -// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. -#ifndef ImDrawIdx -typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) -#endif - // Character types // (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display) typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings. @@ -315,6 +300,19 @@ struct ImVec4 }; IM_MSVC_RUNTIME_CHECKS_RESTORE +//----------------------------------------------------------------------------- +// [SECTION] Texture identifier (ImTextureID) +//----------------------------------------------------------------------------- + +// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] +// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. +// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators. +// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings) +#ifndef ImTextureID +typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +#endif + //----------------------------------------------------------------------------- // [SECTION] Dear ImGui end-user API functions // (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) @@ -2957,6 +2955,13 @@ struct ImGuiSelectionExternalStorage #define IM_DRAWLIST_TEX_LINES_WIDTH_MAX (32) #endif +// ImDrawIdx: vertex index. [Compile-time configurable type] +// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended). +// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file. +#ifndef ImDrawIdx +typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends) +#endif + // ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h] // NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering, // you can poke into the draw list for that! Draw callback may be useful for example to: From 93b446a96281ceec9b226ef624cdc428efd44c60 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 19:39:52 +0100 Subject: [PATCH 316/716] Backtrack of version tagging 1.92.0 > 1.91.9b for publishing a hotfix (#8496) --- docs/CHANGELOG.txt | 2 +- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 62c7c548a9c4..a2a55e1f2bd2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,7 +36,7 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.92.0 WIP (In Progress) + VERSION 1.91.9b WIP (In Progress) ----------------------------------------------------------------------- Breaking changes: diff --git a/imgui.cpp b/imgui.cpp index 932f433fdc5c..7ec192278971 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91.9b // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 0db50aec1825..75750ae10904 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91.9b // (headers) // Help: @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.0 WIP" +#define IMGUI_VERSION "1.91.9b" #define IMGUI_VERSION_NUM 19191 #define IMGUI_HAS_TABLE diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 996694268739..10fa434dca7f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91.9b // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1404b8d61fcf..273101529189 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91.9b // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 870360264922..ddf9ea3e9afd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91.9b // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 0ac6ec89661d..74eec5797078 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91b // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0aa121e774a2..c997e17b61c6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.91b // (widgets code) /* From cfed7a3a5446cd6b36a161d02e89fc816deab69b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 19:51:46 +0100 Subject: [PATCH 317/716] Tables: fixed assert/issues loading settings. (#8496, #7934) Not sure what I did with 05742f9b6ff but I missed on the primary filter. --- docs/CHANGELOG.txt | 4 ++++ imgui_tables.cpp | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a2a55e1f2bd2..d32fa1c43fa9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,10 @@ Breaking changes: Other changes: +- Tables: Fixed assert when loading .ini settings of reordered columns. (#8496, #7934) +- Tables: Fixed issues when loading .ini settings for a table with columns using + ImGuiTableColumnFlags_DefaultHide or ImGuiTableColumnFlags_DefaultSort. (#8496, #7934) + ----------------------------------------------------------------------- VERSION 1.91.9 (Released 2025-03-14) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 74eec5797078..c98aea2d1cc7 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1638,9 +1638,9 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo column->InitStretchWeightOrWidth = init_width_or_weight; if (table->IsInitializing) { - ImGuiTableFlags init_flags = ~0; - if (column->WidthRequest >= 0.0f || column->StretchWeight >= 0.0f) - init_flags &= ~ImGuiTableFlags_Resizable; + ImGuiTableFlags init_flags = ~table->SettingsLoadedFlags; + if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) + init_flags |= ImGuiTableFlags_Resizable; TableInitColumnDefaults(table, column, init_flags); } From f5befd2d29e66809cd1110a152e375a7f1981f06 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 20:17:26 +0100 Subject: [PATCH 318/716] Version 1.91.9b --- docs/CHANGELOG.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d32fa1c43fa9..db1fb0cea5ab 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,14 +36,12 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.91.9b WIP (In Progress) + VERSION 1.91.9b (Released 2025-03-17) ----------------------------------------------------------------------- -Breaking changes: - -Other changes: +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.91.9b -- Tables: Fixed assert when loading .ini settings of reordered columns. (#8496, #7934) +- Tables: Fixed assert when loading .ini settings with reordered columns. (#8496, #7934) - Tables: Fixed issues when loading .ini settings for a table with columns using ImGuiTableColumnFlags_DefaultHide or ImGuiTableColumnFlags_DefaultSort. (#8496, #7934) From 5679de60c567fc62c091004ee80a738757e6d3b6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 18 Mar 2025 17:35:43 +0100 Subject: [PATCH 319/716] Error Handling: added better report and recovery for extraneous EndPopup() call. (#1651, #8499) --- docs/CHANGELOG.txt | 12 ++++++++++++ imgui.cpp | 7 +++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index db1fb0cea5ab..17327ee24e0a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,18 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.92.0 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + +- Error Handling: added better error report and recovery for extraneous + EndPopup() call. (#1651, #8499) + + ----------------------------------------------------------------------- VERSION 1.91.9b (Released 2025-03-17) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 7ec192278971..3b9d25e54e6f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11818,8 +11818,11 @@ void ImGui::EndPopup() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls - IM_ASSERT(g.BeginPopupStack.Size > 0); + if ((window->Flags & ImGuiWindowFlags_Popup) == 0 || g.BeginPopupStack.Size == 0) + { + IM_ASSERT_USER_ERROR(0, "Calling EndPopup() too many times or in wrong window!"); + return; + } // Make all menus and popups wrap around for now, may need to expose that policy (e.g. focus scope could include wrap/loop policy flags used by new move requests) if (g.NavWindow == window) From ee48ffe0215fa639254372f303d4539ef047f7c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 17:42:19 +0100 Subject: [PATCH 320/716] Added comments about line/rect thickness needing scaling. (#7031) --- imgui.cpp | 4 ++-- imgui_widgets.cpp | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3b9d25e54e6f..b8ffe463f85b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5617,7 +5617,7 @@ static void ImGui::RenderDimmedBackgrounds() if (window->DrawList->CmdBuffer.Size == 0) window->DrawList->AddDrawCmd(); window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size); - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), window->WindowRounding, 0, 3.0f); // FIXME-DPI window->DrawList->PopClipRect(); } } @@ -14307,7 +14307,7 @@ void ImGui::RenderDragDropTargetRect(const ImRect& bb, const ImRect& item_clip_r bool push_clip_rect = !window->ClipRect.Contains(bb_display); if (push_clip_rect) window->DrawList->PushClipRectFullScreen(); - window->DrawList->AddRect(bb_display.Min, bb_display.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); + window->DrawList->AddRect(bb_display.Min, bb_display.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f); // FIXME-DPI if (push_clip_rect) window->DrawList->PopClipRect(); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c997e17b61c6..1eea8cb50bbf 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -867,11 +867,12 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos) if (hovered) window->DrawList->AddRectFilled(bb.Min, bb.Max, bg_col); RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact); - ImU32 cross_col = GetColorU32(ImGuiCol_Text); - ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); - float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; - window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f); - window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f); + const ImU32 cross_col = GetColorU32(ImGuiCol_Text); + const ImVec2 cross_center = bb.GetCenter() - ImVec2(0.5f, 0.5f); + const float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f; + const float cross_thickness = 1.0f; // FIXME-DPI + window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, +cross_extent), cross_center + ImVec2(-cross_extent, -cross_extent), cross_col, cross_thickness); + window->DrawList->AddLine(cross_center + ImVec2(+cross_extent, -cross_extent), cross_center + ImVec2(-cross_extent, +cross_extent), cross_col, cross_thickness); return pressed; } @@ -1478,7 +1479,7 @@ bool ImGui::TextLink(const char* label) } float line_y = bb.Max.y + ImFloor(g.Font->Descent * g.FontScale * 0.20f); - window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode. + window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); RenderText(bb.Min, label, label_end); @@ -5339,7 +5340,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) - draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text)); + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text), 1.0f); // FIXME-DPI: Cursor thickness (#7031) + Color // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (!is_readonly) @@ -6207,7 +6208,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl if (g.Style.FrameBorderSize > 0.0f) RenderFrameBorder(bb.Min, bb.Max, rounding); else - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color buttons are often in need of some sort of border // FIXME-DPI } // Drag and Drop Source @@ -7486,7 +7487,7 @@ void ImGui::EndBoxSelect(const ImRect& scope_rect, ImGuiMultiSelectFlags ms_flag ImRect box_select_r = bs->BoxSelectRectCurr; box_select_r.ClipWith(scope_rect); window->DrawList->AddRectFilled(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_SeparatorHovered, 0.30f)); // FIXME-MULTISELECT: Styling - window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT: Styling + window->DrawList->AddRect(box_select_r.Min, box_select_r.Max, GetColorU32(ImGuiCol_NavCursor)); // FIXME-MULTISELECT FIXME-DPI: Styling // Scroll const bool enable_scroll = (ms_flags & ImGuiMultiSelectFlags_ScopeWindow) && (ms_flags & ImGuiMultiSelectFlags_BoxSelectNoScroll) == 0; From 0ecb2bbe74b8e86e9f1acf4a0a7a508d0b8b9b52 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 17:45:20 +0100 Subject: [PATCH 321/716] Version 1.92.0 WIP --- docs/CHANGELOG.txt | 2 +- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 17327ee24e0a..5ebedf819d8a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,7 +43,7 @@ Breaking changes: Other changes: -- Error Handling: added better error report and recovery for extraneous +- Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) diff --git a/imgui.cpp b/imgui.cpp index b8ffe463f85b..3918f6433857 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9b +// dear imgui, v1.92.0 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 75750ae10904..0db50aec1825 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9b +// dear imgui, v1.92.0 WIP // (headers) // Help: @@ -28,7 +28,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.91.9b" +#define IMGUI_VERSION "1.92.0 WIP" #define IMGUI_VERSION_NUM 19191 #define IMGUI_HAS_TABLE diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 10fa434dca7f..996694268739 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9b +// dear imgui, v1.92.0 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 273101529189..1404b8d61fcf 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9b +// dear imgui, v1.92.0 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index ddf9ea3e9afd..870360264922 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.91.9b +// dear imgui, v1.92.0 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index c98aea2d1cc7..0954784bb37a 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91b +// dear imgui, v1.92.0 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1eea8cb50bbf..eb805640a389 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.91b +// dear imgui, v1.92.0 WIP // (widgets code) /* From d467950a5e167e06abc278803fa230e3461fce09 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 17:50:40 +0100 Subject: [PATCH 322/716] Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 1 + imgui.h | 1 + imgui_draw.cpp | 3 +++ imgui_widgets.cpp | 2 +- 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5ebedf819d8a..1a668bf73c65 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) +- Style, InputText: added ImGuiCol_InputTextCursor to configure color of + the InputText cursor/caret. (#7031) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index 3918f6433857..b0e197590522 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3544,6 +3544,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_ResizeGrip: return "ResizeGrip"; case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered"; case ImGuiCol_ResizeGripActive: return "ResizeGripActive"; + case ImGuiCol_InputTextCursor: return "InputTextCursor"; case ImGuiCol_TabHovered: return "TabHovered"; case ImGuiCol_Tab: return "Tab"; case ImGuiCol_TabSelected: return "TabSelected"; diff --git a/imgui.h b/imgui.h index 0db50aec1825..a45348ad370b 100644 --- a/imgui.h +++ b/imgui.h @@ -1648,6 +1648,7 @@ enum ImGuiCol_ ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows. ImGuiCol_ResizeGripHovered, ImGuiCol_ResizeGripActive, + ImGuiCol_InputTextCursor, // InputText cursor/caret ImGuiCol_TabHovered, // Tab background, when hovered ImGuiCol_Tab, // Tab background, when tab-bar is focused & tab is unselected ImGuiCol_TabSelected, // Tab background, when tab-bar is focused & tab is selected diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1404b8d61fcf..67dfbdeccbd0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -217,6 +217,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); @@ -280,6 +281,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f); + colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f); colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); @@ -344,6 +346,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f); colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f); colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); + colors[ImGuiCol_InputTextCursor] = colors[ImGuiCol_Text]; colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f); colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index eb805640a389..df12c0066cb9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5340,7 +5340,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll); ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f); if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect)) - draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text), 1.0f); // FIXME-DPI: Cursor thickness (#7031) + Color + draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031) // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) if (!is_readonly) From 979c7d76abdddc086cb1a21e4d36fff6bebd5a17 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Mar 2025 15:42:47 +0100 Subject: [PATCH 323/716] Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) --- backends/imgui_impl_android.cpp | 2 +- backends/imgui_impl_android.h | 2 +- backends/imgui_impl_glfw.cpp | 2 +- backends/imgui_impl_osx.h | 2 +- backends/imgui_impl_osx.mm | 5 ++--- backends/imgui_impl_sdl2.cpp | 6 ++---- backends/imgui_impl_sdl2.h | 2 +- backends/imgui_impl_sdl3.cpp | 6 ++---- backends/imgui_impl_sdl3.h | 2 +- backends/imgui_impl_win32.cpp | 4 +--- backends/imgui_impl_win32.h | 2 +- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- 13 files changed, 17 insertions(+), 22 deletions(-) diff --git a/backends/imgui_impl_android.cpp b/backends/imgui_impl_android.cpp index 1c2d62476002..a76de1c260b5 100644 --- a/backends/imgui_impl_android.cpp +++ b/backends/imgui_impl_android.cpp @@ -6,7 +6,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // Missing features or Issues: // [ ] Platform: Clipboard support. -// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [ ] Platform: Gamepad support. // [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. diff --git a/backends/imgui_impl_android.h b/backends/imgui_impl_android.h index 3eaeca7253ae..f6e41039a2ba 100644 --- a/backends/imgui_impl_android.h +++ b/backends/imgui_impl_android.h @@ -6,7 +6,7 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // Missing features or Issues: // [ ] Platform: Clipboard support. -// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [ ] Platform: Gamepad support. // [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // Important: // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index baa8541b0af0..6beb97f6c2e1 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -789,7 +789,7 @@ static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0 static void ImGui_ImplGlfw_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs, but see #8075 return; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 5d4dd8d41b7f..b4d7bf8d7d61 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -7,7 +7,7 @@ // [X] Platform: Clipboard support is part of core Dear ImGui (no specific code in this backend). // [X] Platform: Mouse support. Can discriminate Mouse/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // Missing features or Issues: diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 2d72d413ebde..86e8b17a68e2 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -7,7 +7,7 @@ // [X] Platform: Clipboard support is part of core Dear ImGui (no specific code in this backend). // [X] Platform: Mouse support. Can discriminate Mouse/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy kVK_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. // Missing features or Issues: @@ -31,6 +31,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-01-20: Removed notification observer when shutting down. (#8331) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: // - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn @@ -552,8 +553,6 @@ static void ImGui_ImplOSX_UpdateMouseCursor() static void ImGui_ImplOSX_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - return; #if APPLE_HAS_CONTROLLER GCController* controller = GCController.current; diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 0be2f2c6e360..54f9599cce5d 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -7,7 +7,7 @@ // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. @@ -755,9 +756,6 @@ static void ImGui_ImplSDL2_UpdateGamepads() bd->WantUpdateGamepadsList = false; } - // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) - return; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; if (bd->Gamepads.Size == 0) return; diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 3c477569777c..9f7b551fc168 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -6,7 +6,7 @@ // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index cfe8bbd4e8b1..d2be43620164 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -6,7 +6,7 @@ // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) // 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode. @@ -724,9 +725,6 @@ static void ImGui_ImplSDL3_UpdateGamepads() SDL_free(sdl_gamepads); } - // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) - return; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; if (bd->Gamepads.Size == 0) return; diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 5b8973738201..a822a259bf72 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -6,7 +6,7 @@ // [X] Platform: Clipboard support. // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 2c749515d221..ab7c8ab9ff1f 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -5,7 +5,7 @@ // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -335,8 +335,6 @@ static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) { #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io); - //if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - // return; // Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow. // Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE. diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index 083fe385f6fa..5ae399e0e24b 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -5,7 +5,7 @@ // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5] -// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. +// [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1a668bf73c65..c7be9a949c18 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,8 @@ Other changes: EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) +- Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad + regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) ----------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index a45348ad370b..ddd6645c4ab9 100644 --- a/imgui.h +++ b/imgui.h @@ -3288,7 +3288,7 @@ struct ImFontConfig float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. - float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display. IMPORTANT: If you increase this it is expected that you increase font scale accordingly, otherwise quality may look lowered. + float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] From 102f3f3a0de607ba444b4a0932f23a9de84de139 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Mar 2025 16:18:36 +0100 Subject: [PATCH 324/716] IO: variations in analog-only components of gamepad events do not interfere with trickling of mouse position events (#4921, #8508) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 12 ++++++++---- imgui.h | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c7be9a949c18..cf423eeb16d4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- IO: variations in analog-only components of gamepad events do not interfere + with trickling of mouse position events (#4921, #8508) - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of diff --git a/imgui.cpp b/imgui.cpp index b0e197590522..8339697241d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9868,12 +9868,16 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs) if (trickle_interleaved_nonchar_keys_and_text && (text_inputted && !key_is_potentially_for_char_input)) break; + if (key_data->Down != e->Key.Down) // Analog change only do not trigger this, so it won't block e.g. further mouse pos events testing key_changed. + { + key_changed = true; + key_changed_mask.SetBit(key_data_index); + if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input) + key_changed_nonchar = true; + } + key_data->Down = e->Key.Down; key_data->AnalogValue = e->Key.AnalogValue; - key_changed = true; - key_changed_mask.SetBit(key_data_index); - if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input) - key_changed_nonchar = true; } else if (e->Type == ImGuiInputEventType_Text) { diff --git a/imgui.h b/imgui.h index ddd6645c4ab9..8e456e130dd3 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19191 +#define IMGUI_VERSION_NUM 19192 #define IMGUI_HAS_TABLE /* From f5003aff69ed8ee6c8b3ec07206ae266eb948b17 Mon Sep 17 00:00:00 2001 From: tanksdude <58898485+tanksdude@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:23:09 -0700 Subject: [PATCH 325/716] Docs: Fix some typos (#8505) --- backends/imgui_impl_osx.mm | 2 +- backends/imgui_impl_sdlgpu3.h | 2 +- docs/CHANGELOG.txt | 2 +- examples/libs/usynergy/uSynergy.h | 2 +- imgui.cpp | 18 +++++++++--------- imgui.h | 4 ++-- imgui_demo.cpp | 10 +++++----- imgui_draw.cpp | 4 ++-- imgui_widgets.cpp | 8 ++++---- misc/fonts/binary_to_compressed_c.cpp | 4 ++-- misc/freetype/imgui_freetype.h | 2 +- 11 files changed, 29 insertions(+), 29 deletions(-) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 86e8b17a68e2..e681d176b347 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -537,7 +537,7 @@ static void ImGui_ImplOSX_UpdateMouseCursor() else { NSCursor* desired = bd->MouseCursors[imgui_cursor] ?: bd->MouseCursors[ImGuiMouseCursor_Arrow]; - // -[NSCursor set] generates measureable overhead if called unconditionally. + // -[NSCursor set] generates measurable overhead if called unconditionally. if (desired != NSCursor.currentCursor) { [desired set]; diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 865139e26a0f..7d28f7a36d2b 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -17,7 +17,7 @@ // - Introduction, links and more at the top of imgui.cpp // Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. -// - Unline other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// - Unlike other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. #pragma once diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cf423eeb16d4..2e57ee00569d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -633,7 +633,7 @@ Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v Breaking changes: - - Internals: using multiple overlayed ButtonBehavior() with same ID will now have the + - Internals: using multiple overlaid ButtonBehavior() with same ID will now have the io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030) It was one of the rare case where using same ID is legal. Workarounds: - use single ButtonBehavior() call with multiple _MouseButton flags diff --git a/examples/libs/usynergy/uSynergy.h b/examples/libs/usynergy/uSynergy.h index 2d7f9fa15543..2b4d779b6384 100644 --- a/examples/libs/usynergy/uSynergy.h +++ b/examples/libs/usynergy/uSynergy.h @@ -336,7 +336,7 @@ typedef struct uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */ uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */ - /* State data, used internall by client, initialized by uSynergyInit() */ + /* State data, used internally by client, initialized by uSynergyInit() */ uSynergyBool m_connected; /* Is our socket connected? */ uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */ uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */ diff --git a/imgui.cpp b/imgui.cpp index 8339697241d0..d9a6c2b0f75e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -477,7 +477,7 @@ CODE - 2024/10/03 (1.91.3) - drags: treat v_min==v_max as a valid clamping range when != 0.0f. Zero is a still special value due to legacy reasons, unless using ImGuiSliderFlags_ClampZeroRange. (#7968, #3361, #76) - drags: extended behavior of ImGuiSliderFlags_AlwaysClamp to include _ClampZeroRange. It considers v_min==v_max==0.0f as a valid clamping range (aka edits not allowed). although unlikely, it you wish to only clamp on text input but want v_min==v_max==0.0f to mean unclamped drags, you can use _ClampOnInput instead of _AlwaysClamp. (#7968, #3361, #76) - - 2024/09/10 (1.91.2) - internals: using multiple overlayed ButtonBehavior() with same ID will now have io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030) + - 2024/09/10 (1.91.2) - internals: using multiple overlaid ButtonBehavior() with same ID will now have io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030) it was one of the rare case where using same ID is legal. workarounds: (1) use single ButtonBehavior() call with multiple _MouseButton flags, or (2) surround the calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag() - 2024/08/23 (1.91.1) - renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. kept inline redirection flag. - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure: @@ -667,7 +667,7 @@ CODE - 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(), ImGui::IsKeyDown(). Removed GetKeyIndex(), now unnecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details. - IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX) - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX) - - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes). + - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to still function with legacy key codes). - Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiMod_XXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiMod_XXX values.* - one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert. - inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper. @@ -876,7 +876,7 @@ CODE - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete). - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete). - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency. - - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. + - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix. - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type. - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely. - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete). @@ -1748,7 +1748,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) // On MacOS X: Convert Ctrl(Super)+Left click into Right-click: handle held button. if (ConfigMacOSXBehaviors && mouse_button == 0 && MouseCtrlLeftAsRightClick) { - // Order of both statements matterns: this event will still release mouse button 1 + // Order of both statements matters: this event will still release mouse button 1 mouse_button = 1; if (!down) MouseCtrlLeftAsRightClick = false; @@ -3637,7 +3637,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end // Default clip_rect uses (pos_min,pos_max) // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges) -// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especally for text above draw_list->DrawList. +// FIXME-OPT: Since we have or calculate text_size we could coarse clip whole block immediately, especially for text above draw_list->DrawList. // Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take // better advantage of the render function taking size into account for coarse clipping. void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect) @@ -5525,7 +5525,7 @@ static void InitViewportDrawData(ImGuiViewportP* viewport) // - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): // some frequently called functions which to modify both channels and clipping simultaneously tend to use the // more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds. -// - This is analoguous to PushFont()/PopFont() in the sense that are a mixing a global stack and a window stack, +// - This is analogous to PushFont()/PopFont() in the sense that are a mixing a global stack and a window stack, // which in the case of ClipRect is not so problematic but tends to be more restrictive for fonts. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { @@ -5717,7 +5717,7 @@ void ImGui::EndFrame() } // Prepare the data for rendering so you can call GetDrawData() -// (As with anything within the ImGui:: namspace this doesn't touch your GPU or graphics API at all: +// (As with anything within the ImGui:: namespace this doesn't touch your GPU or graphics API at all: // it is the role of the ImGui_ImplXXXX_RenderDrawData() function provided by the renderer backend) void ImGui::Render() { @@ -7870,7 +7870,7 @@ void ImGui::SetCurrentFont(ImFont* font) g.DrawListSharedData.FontScale = g.FontScale; } -// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authorative against window-local ImDrawList. +// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authoritative against window-local ImDrawList. // - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls. // - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... // - Some code paths never really fully worked with multiple atlas textures. @@ -11360,7 +11360,7 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext // - offset visibility to increase visibility around mouse. // - never clamp within outer viewport boundary. // We call SetNextWindowPos() to enforce position and disable clamping. - // See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones). + // See FindBestWindowPosForPopup() for positioning logic of other tooltips (not drag and drop ones). //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding; const bool is_touchscreen = (g.IO.MouseSource == ImGuiMouseSource_TouchScreen); if ((g.NextWindowData.HasFlags & ImGuiNextWindowDataFlags_HasPos) == 0) diff --git a/imgui.h b/imgui.h index 8e456e130dd3..2b6dd083dd36 100644 --- a/imgui.h +++ b/imgui.h @@ -696,7 +696,7 @@ namespace ImGui // - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label. // - If you don't need a label you can probably simply use BeginChild() with the ImGuiChildFlags_FrameStyle flag for the same result. // - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items. - // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. + // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analogous to how Combos are created. // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region @@ -1022,7 +1022,7 @@ namespace ImGui IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); // IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired mouse cursor shape - IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse); // Override io.WantCaptureMouse flag next frame (said flag is left for your application to handle, typical when true it instucts your app to ignore inputs). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse;" after the next NewFrame() call. + IMGUI_API void SetNextFrameWantCaptureMouse(bool want_capture_mouse); // Override io.WantCaptureMouse flag next frame (said flag is left for your application to handle, typical when true it instructs your app to ignore inputs). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse;" after the next NewFrame() call. // Clipboard Utilities // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 996694268739..7bf2879d7187 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2388,7 +2388,7 @@ static const char* ExampleNames[] = struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage { // Find which item should be Focused after deletion. - // Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it. + // Call _before_ item submission. Return an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it. // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection. // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data. // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility. @@ -5399,7 +5399,7 @@ struct MyItem return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1; } - // qsort() is instable so always return a way to differenciate items. + // qsort() is instable so always return a way to differentiate items. // Your own compare function may want to avoid fallback on implicit sort specs. // e.g. a Name compare if it wasn't already part of the sort specs. return (a->ID - b->ID); @@ -7762,7 +7762,7 @@ static void DemoWindowInputs() ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); // 2: InputText also polling for CTRL+A: it always uses _RouteFocused internally (gets priority when active) - // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h) + // (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) //char str[16] = "Press CTRL+A"; //ImGui::Spacing(); //ImGui::InputText("InputTextB", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly); @@ -7789,7 +7789,7 @@ static void DemoWindowInputs() { ImGui::Text("(in PopupF)"); ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags) ? "PRESSED" : "..."); - // (Commmented because the owner-aware version of Shortcut() is still in imgui_internal.h) + // (Commented because the owner-aware version of Shortcut() is still in imgui_internal.h) //ImGui::InputText("InputTextG", str, IM_ARRAYSIZE(str), ImGuiInputTextFlags_ReadOnly); //ImGui::Text("IsWindowFocused: %d, Shortcut: %s", ImGui::IsWindowFocused(), ImGui::Shortcut(key_chord, flags, ImGui::GetItemID()) ? "PRESSED" : "..."); ImGui::EndPopup(); @@ -10368,7 +10368,7 @@ struct ExampleAssetsBrowser Selection.Clear(); } - // Logic would be written in the main code BeginChild() and outputing to local variables. + // Logic would be written in the main code BeginChild() and outputting to local variables. // We extracted it into a function so we can call it easily from multiple places. void UpdateLayoutSizes(float avail_width) { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 67dfbdeccbd0..95d5eaba1f9c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -856,7 +856,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area dm_y *= half_draw_size; - // Add temporary vertexes for the outer edges + // Add temporary vertices for the outer edges 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; @@ -883,7 +883,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 idx1 = idx2; } - // Add vertexes for each point on the line + // Add vertices for each point on the line if (use_texture) { // If we're using textures we only need to emit the left/right edge vertices diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index df12c0066cb9..883a2648d0b9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -494,7 +494,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args) // And better standardize how widgets use 'GetColor32((held && hovered) ? ... : hovered ? ...)' vs 'GetColor32(held ? ... : hovered ? ...);' // For mouse feedback we typically prefer the 'held && hovered' test, but for nav feedback not always. Outputting hovered=true on Activation may be misleading. // - Since v1.91.2 (Sept 2024) we included io.ConfigDebugHighlightIdConflicts feature. -// One idiom which was previously valid which will now emit a warning is when using multiple overlayed ButtonBehavior() +// One idiom which was previously valid which will now emit a warning is when using multiple overlaid ButtonBehavior() // with same ID and different MouseButton (see #8030). You can fix it by: // (1) switching to use a single ButtonBehavior() with multiple _MouseButton flags. // or (2) surrounding those calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag() @@ -3891,7 +3891,7 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, si return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data); } -// This is only used in the path where the multiline widget is inactivate. +// This is only used in the path where the multiline widget is inactive. static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end) { int line_count = 0; @@ -4648,7 +4648,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (g.ActiveId == id) { // Declare some inputs, the other are registered and polled via Shortcut() routing system. - // FIXME: The reason we don't use Shortcut() is we would need a routing flag to specify multiple mods, or to all mods combinaison into individual shortcuts. + // FIXME: The reason we don't use Shortcut() is we would need a routing flag to specify multiple mods, or to all mods combination into individual shortcuts. const ImGuiKey always_owned_keys[] = { ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_Enter, ImGuiKey_KeypadEnter, ImGuiKey_Delete, ImGuiKey_Backspace, ImGuiKey_Home, ImGuiKey_End }; for (ImGuiKey key : always_owned_keys) SetKeyOwner(key, id); @@ -7691,7 +7691,7 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect() if (ms->IsFocused) { // We currently don't allow user code to modify RangeSrcItem by writing to BeginIO's version, but that would be an easy change here. - if (ms->IO.RangeSrcReset || (ms->RangeSrcPassedBy == false && ms->IO.RangeSrcItem != ImGuiSelectionUserData_Invalid)) // Can't read storage->RangeSrcItem here -> we want the state at begining of the scope (see tests for easy failure) + if (ms->IO.RangeSrcReset || (ms->RangeSrcPassedBy == false && ms->IO.RangeSrcItem != ImGuiSelectionUserData_Invalid)) // Can't read storage->RangeSrcItem here -> we want the state at beginning of the scope (see tests for easy failure) { IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset RangeSrcItem.\n"); // Will set be to NavId. storage->RangeSrcItem = ImGuiSelectionUserData_Invalid; diff --git a/misc/fonts/binary_to_compressed_c.cpp b/misc/fonts/binary_to_compressed_c.cpp index b0a243a710df..da9883191993 100644 --- a/misc/fonts/binary_to_compressed_c.cpp +++ b/misc/fonts/binary_to_compressed_c.cpp @@ -5,8 +5,8 @@ // The data is first compressed with stb_compress() to reduce source code size. // Then stored in a C array: // - Base85: ~5 bytes of source code for 4 bytes of input data. 5 bytes stored in binary (suggested by @mmalex). -// - As int: ~11 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Endianness dependant, need swapping on big-endian CPU. -// - As char: ~12 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Not endianness dependant. +// - As int: ~11 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Endianness dependent, need swapping on big-endian CPU. +// - As char: ~12 bytes of source code for 4 bytes of input data. 4 bytes stored in binary. Not endianness dependent. // Load compressed TTF fonts with ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF() // Build with, e.g: diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 6572b1547bf8..9d367074e0c2 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -21,7 +21,7 @@ struct ImFontBuilderIO; // - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h // - The Default hinting mode usually looks good, but may distort glyphs in an unusual way. // - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. -// You can set those flags globaly in ImFontAtlas::FontBuilderFlags +// You can set those flags globally in ImFontAtlas::FontBuilderFlags // You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags enum ImGuiFreeTypeBuilderFlags { From ca3ba287683a1c60339e54edfe58da1175c9f79c Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Mar 2025 17:21:22 +0100 Subject: [PATCH 326/716] Internals: made MousePos an argument of UpdateHoveredWindowAndCaptureFlags(). (#8431, #1152) --- imgui.cpp | 6 +++--- imgui_internal.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d9a6c2b0f75e..ea813cd92d8b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5058,7 +5058,7 @@ static bool IsWindowActiveAndVisible(ImGuiWindow* window) } // The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) -void ImGui::UpdateHoveredWindowAndCaptureFlags() +void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) { ImGuiContext& g = *GImGui; ImGuiIO& io = g.IO; @@ -5072,7 +5072,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags() // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame. // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms. bool clear_hovered_windows = false; - FindHoveredWindowEx(g.IO.MousePos, false, &g.HoveredWindow, &g.HoveredWindowUnderMovingWindow); + FindHoveredWindowEx(mouse_pos, false, &g.HoveredWindow, &g.HoveredWindowUnderMovingWindow); g.HoveredWindowBeforeClear = g.HoveredWindow; // Modal windows prevents mouse from hovering behind them. @@ -5343,7 +5343,7 @@ void ImGui::NewFrame() // Find hovered window // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) // (currently needs to be done after the WasActive=Active loop and FindHoveredWindowEx uses ->Active) - UpdateHoveredWindowAndCaptureFlags(); + UpdateHoveredWindowAndCaptureFlags(g.IO.MousePos); // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering) UpdateMouseMovingWindowNewFrame(); diff --git a/imgui_internal.h b/imgui_internal.h index 870360264922..d2abe4588e69 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3049,7 +3049,7 @@ namespace ImGui // NewFrame IMGUI_API void UpdateInputEvents(bool trickle_fast_inputs); - IMGUI_API void UpdateHoveredWindowAndCaptureFlags(); + IMGUI_API void UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos); IMGUI_API void FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_viewport, ImGuiWindow** out_hovered_window, ImGuiWindow** out_hovered_window_under_moving_window); IMGUI_API void StartMouseMovingWindow(ImGuiWindow* window); IMGUI_API void UpdateMouseMovingWindowNewFrame(); From a806d2f9b8f18209e436ffb33815b2d0a8d7ad4f Mon Sep 17 00:00:00 2001 From: puugz Date: Fri, 21 Mar 2025 20:05:32 +0100 Subject: [PATCH 327/716] Backends: SDLGPU: Fixed typo in function name Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData(). (#8509, 8163, #7998, #7988) --- backends/imgui_impl_sdlgpu3.cpp | 9 +++++---- backends/imgui_impl_sdlgpu3.h | 4 ++-- docs/CHANGELOG.txt | 2 ++ examples/example_sdl3_sdlgpu3/main.cpp | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 74b966227ddd..94d81551cab7 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -17,10 +17,11 @@ // - Introduction, links and more at the top of imgui.cpp // Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. -// - Unlike other backends, the user must call the function Imgui_ImplSDLGPU3_PrepareDrawData() BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU3_RenderDrawData. +// - Unlike other backends, the user must call the function ImGui_ImplSDLGPU3_PrepareDrawData() BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU3_RenderDrawData. // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2025-03-21: Fixed typo in function name Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData(). // 2025-01-16: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device. // 2025-01-09: SDL_GPU: Added the SDL_GPU3 backend. @@ -134,7 +135,7 @@ static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer, uint32_t* old_size, uin // SDL_GPU doesn't allow copy passes to occur while a render or compute pass is bound! // The only way to allow a user to supply their own RenderPass (to render to a texture instead of the window for example), // is to split the upload part of ImGui_ImplSDLGPU3_RenderDrawData() to another function that needs to be called by the user before rendering. -void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer) +void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); @@ -366,7 +367,7 @@ void ImGui_ImplSDLGPU3_DestroyFontsTexture() io.Fonts->SetTexID(0); } -static void Imgui_ImplSDLGPU3_CreateShaders() +static void ImGui_ImplSDLGPU3_CreateShaders() { // Create the shader modules ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); @@ -431,7 +432,7 @@ static void ImGui_ImplSDLGPU3_CreateGraphicsPipeline() { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - Imgui_ImplSDLGPU3_CreateShaders(); + ImGui_ImplSDLGPU3_CreateShaders(); SDL_GPUVertexBufferDescription vertex_buffer_desc[1]; vertex_buffer_desc[0].slot = 0; diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 7d28f7a36d2b..c6d5a8e5d0f3 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -17,7 +17,7 @@ // - Introduction, links and more at the top of imgui.cpp // Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. -// - Unlike other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// - Unlike other backends, the user must call the function ImGui_ImplSDLGPU_PrepareDrawData BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. #pragma once @@ -38,7 +38,7 @@ struct ImGui_ImplSDLGPU3_InitInfo IMGUI_IMPL_API bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_NewFrame(); -IMGUI_IMPL_API void Imgui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateDeviceObjects(); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2e57ee00569d..6052c430080d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -49,6 +49,8 @@ Other changes: EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) +- Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] + - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 630639f3fefb..3deeeafd56ee 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -7,7 +7,7 @@ // - Introduction, links and more at the top of imgui.cpp // Important note to the reader who wish to integrate imgui_impl_sdlgpu3.cpp/.h in their own engine/app. -// - Unlike other backends, the user must call the function Imgui_ImplSDLGPU_PrepareDrawData() BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. +// - Unlike other backends, the user must call the function ImGui_ImplSDLGPU_PrepareDrawData() BEFORE issuing a SDL_GPURenderPass containing ImGui_ImplSDLGPU_RenderDrawData. // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. #include "imgui.h" @@ -178,8 +178,8 @@ int main(int, char**) if (swapchain_texture != nullptr && !is_minimized) { - // This is mandatory: call Imgui_ImplSDLGPU3_PrepareDrawData() to upload the vertex/index buffer! - Imgui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer); + // This is mandatory: call ImGui_ImplSDLGPU3_PrepareDrawData() to upload the vertex/index buffer! + ImGui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer); // Setup and start a render pass SDL_GPUColorTargetInfo target_info = {}; From 702a67807bbba83986a955376995cd277984ff57 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Mar 2025 20:17:49 +0100 Subject: [PATCH 328/716] Move Changelog entry. (#8509) --- docs/CHANGELOG.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6052c430080d..4d35191a5e5d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,9 @@ HOW TO UPDATE? Breaking changes: +- Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] + - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() + Other changes: - IO: variations in analog-only components of gamepad events do not interfere @@ -49,8 +52,6 @@ Other changes: EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) -- Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] - - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) From dbd9ae287a40e773a6fff364bdd8816ddae9b92b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 23 Mar 2025 12:55:59 +0100 Subject: [PATCH 329/716] Windows: fixed SetNextWindowCollapsed()/SetWindowCollapsed() breaking codepath that preserve last contents size when collapsed. (#7691) --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4d35191a5e5d..0574bfe36839 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,10 @@ Other changes: - IO: variations in analog-only components of gamepad events do not interfere with trickling of mouse position events (#4921, #8508) +- Windows: fixed SetNextWindowCollapsed()/SetWindowCollapsed() breaking + codepath that preserve last contents size when collapsed, resulting in + programmatically uncollapsing auto-sizing windows having them flicker size + for a frame. (#7691) [@achabense] - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of diff --git a/imgui.cpp b/imgui.cpp index ea813cd92d8b..ba3271c545ec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8228,8 +8228,10 @@ void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond co return; window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing); - // Set - window->Collapsed = collapsed; + // Queue applying in Begin() + if (window->WantCollapseToggle) + window->Collapsed ^= 1; + window->WantCollapseToggle = (window->Collapsed != collapsed); } void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size) From 7674cbc9b25668dcbcc0ffd35b126b094c978e89 Mon Sep 17 00:00:00 2001 From: gan74 Date: Fri, 21 Mar 2025 20:40:38 +0100 Subject: [PATCH 330/716] Added extra operators to ImVec4. (#8510) --- docs/CHANGELOG.txt | 1 + imgui.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0574bfe36839..469483be3687 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other changes: EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) +- Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) diff --git a/imgui.h b/imgui.h index 2b6dd083dd36..fec015c775a0 100644 --- a/imgui.h +++ b/imgui.h @@ -2731,6 +2731,7 @@ struct ImGuiListClipper #ifdef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF +// ImVec2 operators static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } @@ -2746,9 +2747,14 @@ static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } static inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } static inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } +// ImVec4 operators +static inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } +static inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +static inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } static inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } IM_MSVC_RUNTIME_CHECKS_RESTORE From 5c9fb8f0648ed8b7be9c8f571157eefbf7ba1c88 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Sat, 29 Mar 2025 21:04:17 +0100 Subject: [PATCH 331/716] Backends: SDL3: Update for API changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) see https://github.com/libsdl-org/SDL/pull/10390 --- backends/imgui_impl_sdl3.cpp | 4 ++-- docs/CHANGELOG.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index d2be43620164..ac2e841e69e1 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) @@ -133,8 +134,7 @@ static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*) ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); - const char* sdl_clipboard_text = SDL_GetClipboardText(); - bd->ClipboardTextData = sdl_clipboard_text ? SDL_strdup(sdl_clipboard_text) : nullptr; + bd->ClipboardTextData = SDL_GetClipboardText(); return bd->ClipboardTextData; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 469483be3687..4a691a20a3e5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,8 @@ Other changes: - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) +- Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() + memory ownership change. (#8530, #7801) [@Green-Sky] ----------------------------------------------------------------------- From 187acb86093503bdf0af6aff069495671d8b607e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 30 Mar 2025 14:46:07 +0200 Subject: [PATCH 332/716] Nav: polling gamepad for ImGuiKey_NavGamepadMenu use routing-friendly Shortcut() so Ctrl+Tab equivalent may be hijacked. (#8525, #4828, #3255, #5641) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ba3271c545ec..d8cbbf9f1709 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13779,7 +13779,7 @@ static void ImGui::NavUpdateWindowing() const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0; const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways, owner_id); - const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_None); + const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && Shortcut(ImGuiKey_NavGamepadMenu, ImGuiInputFlags_RouteAlways, owner_id); const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard! bool just_started_windowing_from_null_focus = false; if (start_windowing_with_gamepad || start_windowing_with_keyboard) @@ -13802,7 +13802,8 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingTimer += io.DeltaTime; if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) { - // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise + // Highlight only appears after a brief time holding the button, so that a fast tap on ImGuiKey_NavGamepadMenu (to toggle NavLayer) doesn't add visual noise + // However inputs are accepted immediately, so you press ImGuiKey_NavGamepadMenu + L1/R1 fast. g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // Select window to focus From 8bbdfefe056bfb2d778b144fbfdfc49642c367a1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 30 Mar 2025 15:05:27 +0200 Subject: [PATCH 333/716] Nav: added bool ConfigNavWindowingWithGamepad to disable windowing with gamepad. (#8525, #4828, #3255, #5641) --- imgui.cpp | 27 ++++++++++++++++----------- imgui_internal.h | 1 + 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d8cbbf9f1709..53537baa0b12 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4016,6 +4016,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac... // FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this.. + ConfigNavWindowingWithGamepad = true; ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab); ConfigNavWindowingKeyPrev = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab); NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; @@ -13799,19 +13800,22 @@ static void ImGui::NavUpdateWindowing() } // Gamepad update - g.NavWindowingTimer += io.DeltaTime; if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) { - // Highlight only appears after a brief time holding the button, so that a fast tap on ImGuiKey_NavGamepadMenu (to toggle NavLayer) doesn't add visual noise - // However inputs are accepted immediately, so you press ImGuiKey_NavGamepadMenu + L1/R1 fast. - g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); - - // Select window to focus - const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1); - if (focus_change_dir != 0 && !just_started_windowing_from_null_focus) + if (g.ConfigNavWindowingWithGamepad) { - NavUpdateWindowingTarget(focus_change_dir); - g.NavWindowingHighlightAlpha = 1.0f; + // Highlight only appears after a brief time holding the button, so that a fast tap on ImGuiKey_NavGamepadMenu (to toggle NavLayer) doesn't add visual noise + // However inputs are accepted immediately, so you press ImGuiKey_NavGamepadMenu + L1/R1 fast. + g.NavWindowingTimer += io.DeltaTime; + g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); + + // Select window to focus + const int focus_change_dir = (int)IsKeyPressed(ImGuiKey_GamepadL1) - (int)IsKeyPressed(ImGuiKey_GamepadR1); + if (focus_change_dir != 0 && !just_started_windowing_from_null_focus) + { + NavUpdateWindowingTarget(focus_change_dir); + g.NavWindowingHighlightAlpha = 1.0f; + } } // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most) @@ -13820,7 +13824,7 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. if (g.NavWindowingToggleLayer && g.NavWindow) apply_toggle_layer = true; - else if (!g.NavWindowingToggleLayer) + else if (!g.NavWindowingToggleLayer && g.ConfigNavWindowingWithGamepad) apply_focus_window = g.NavWindowingTarget; g.NavWindowingTarget = NULL; } @@ -13832,6 +13836,7 @@ static void ImGui::NavUpdateWindowing() // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise ImGuiKeyChord shared_mods = ((g.ConfigNavWindowingKeyNext ? g.ConfigNavWindowingKeyNext : ImGuiMod_Mask_) & (g.ConfigNavWindowingKeyPrev ? g.ConfigNavWindowingKeyPrev : ImGuiMod_Mask_)) & ImGuiMod_Mask_; IM_ASSERT(shared_mods != 0); // Next/Prev shortcut currently needs a shared modifier to "hold", otherwise Prev actions would keep cycling between two windows. + g.NavWindowingTimer += io.DeltaTime; g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f if ((keyboard_next_window || keyboard_prev_window) && !just_started_windowing_from_null_focus) NavUpdateWindowingTarget(keyboard_next_window ? -1 : +1); diff --git a/imgui_internal.h b/imgui_internal.h index d2abe4588e69..ec9c6047c452 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2240,6 +2240,7 @@ struct ImGuiContext bool NavJustMovedToHasSelectionData; // Copy of move result's ItemFlags & ImGuiItemFlags_HasSelectionUserData). Maybe we should just store ImGuiNavItemData. // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize) + bool ConfigNavWindowingWithGamepad; // = true. Enable CTRL+TAB by holding ImGuiKey_GamepadFaceLeft (== ImGuiKey_NavGamepadMenu). When false, the button may still be used to toggle Menu layer. ImGuiKeyChord ConfigNavWindowingKeyNext; // = ImGuiMod_Ctrl | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiKey_Tab on OS X). For reconfiguration (see #4828) ImGuiKeyChord ConfigNavWindowingKeyPrev; // = ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab (or ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab on OS X) ImGuiWindow* NavWindowingTarget; // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most! From a26fcf58cc2d0cfeee8b98ad8517af998f75c27e Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 30 Mar 2025 16:40:36 +0200 Subject: [PATCH 334/716] Nav: fixed assertion when holding gamepad FaceLeft/West button + pressing a keyboard key. (#8525) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 19 +++++++++++-------- imgui_internal.h | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4a691a20a3e5..b333f109e7a8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,8 @@ Other changes: codepath that preserve last contents size when collapsed, resulting in programmatically uncollapsing auto-sizing windows having them flicker size for a frame. (#7691) [@achabense] +- Nav: fixed assertion when holding gamepad FaceLeft/West button to open + CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of diff --git a/imgui.cpp b/imgui.cpp index 53537baa0b12..b9088378aa9b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4020,6 +4020,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab); ConfigNavWindowingKeyPrev = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab); NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL; + NavWindowingInputSource = ImGuiInputSource_None; NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f; NavWindowingToggleLayer = false; NavWindowingToggleKey = ImGuiKey_None; @@ -13786,11 +13787,12 @@ static void ImGui::NavUpdateWindowing() if (start_windowing_with_gamepad || start_windowing_with_keyboard) if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) { - g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location + if (start_windowing_with_keyboard || g.ConfigNavWindowingWithGamepad) + g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f); g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer - g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; + g.NavWindowingInputSource = g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad; if (g.NavWindow == NULL) just_started_windowing_from_null_focus = true; @@ -13800,9 +13802,9 @@ static void ImGui::NavUpdateWindowing() } // Gamepad update - if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad) + if ((g.NavWindowingTarget || g.NavWindowingToggleLayer) && g.NavWindowingInputSource == ImGuiInputSource_Gamepad) { - if (g.ConfigNavWindowingWithGamepad) + if (g.NavWindowingTarget != NULL) { // Highlight only appears after a brief time holding the button, so that a fast tap on ImGuiKey_NavGamepadMenu (to toggle NavLayer) doesn't add visual noise // However inputs are accepted immediately, so you press ImGuiKey_NavGamepadMenu + L1/R1 fast. @@ -13824,14 +13826,15 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore. if (g.NavWindowingToggleLayer && g.NavWindow) apply_toggle_layer = true; - else if (!g.NavWindowingToggleLayer && g.ConfigNavWindowingWithGamepad) + else if (!g.NavWindowingToggleLayer) apply_focus_window = g.NavWindowingTarget; g.NavWindowingTarget = NULL; + g.NavWindowingToggleLayer = false; } } // Keyboard: Focus - if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard) + if (g.NavWindowingTarget && g.NavWindowingInputSource == ImGuiInputSource_Keyboard) { // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise ImGuiKeyChord shared_mods = ((g.ConfigNavWindowingKeyNext ? g.ConfigNavWindowingKeyNext : ImGuiMod_Mask_) & (g.ConfigNavWindowingKeyPrev ? g.ConfigNavWindowingKeyPrev : ImGuiMod_Mask_)) & ImGuiMod_Mask_; @@ -13854,10 +13857,10 @@ static void ImGui::NavUpdateWindowing() windowing_toggle_layer_start = true; g.NavWindowingToggleLayer = true; g.NavWindowingToggleKey = windowing_toggle_key; - g.NavInputSource = ImGuiInputSource_Keyboard; + g.NavWindowingInputSource = g.NavInputSource = ImGuiInputSource_Keyboard; break; } - if (g.NavWindowingToggleLayer && g.NavInputSource == ImGuiInputSource_Keyboard) + if (g.NavWindowingToggleLayer && g.NavWindowingInputSource == ImGuiInputSource_Keyboard) { // We cancel toggling nav layer when any text has been typed (generally while holding Alt). (See #370) // We cancel toggling nav layer when other modifiers are pressed. (See #4439) diff --git a/imgui_internal.h b/imgui_internal.h index ec9c6047c452..ff1a8d8aca00 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2248,6 +2248,7 @@ struct ImGuiContext ImGuiWindow* NavWindowingListWindow; // Internal window actually listing the CTRL+Tab contents float NavWindowingTimer; float NavWindowingHighlightAlpha; + ImGuiInputSource NavWindowingInputSource; bool NavWindowingToggleLayer; ImGuiKey NavWindowingToggleKey; ImVec2 NavWindowingAccumDeltaPos; From b6786595a43651a6214f036a5ce999138c37cd3b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 14:43:17 +0200 Subject: [PATCH 335/716] Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. (#8534) --- backends/imgui_impl_sdlgpu3.cpp | 69 ++++++++++++++++----------------- docs/CHANGELOG.txt | 2 + 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 94d81551cab7..f3a7adc85ff1 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -21,6 +21,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2025-03-30: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. // 2025-03-21: Fixed typo in function name Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData(). // 2025-01-16: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device. // 2025-01-09: SDL_GPU: Added the SDL_GPU3 backend. @@ -35,10 +36,12 @@ // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU3_RenderDrawData() struct ImGui_ImplSDLGPU3_FrameData { - SDL_GPUBuffer* VertexBuffer = nullptr; - SDL_GPUBuffer* IndexBuffer = nullptr; - uint32_t VertexBufferSize = 0; - uint32_t IndexBufferSize = 0; + SDL_GPUBuffer* VertexBuffer = nullptr; + SDL_GPUTransferBuffer* VertexTransferBuffer = nullptr; + uint32_t VertexBufferSize = 0; + SDL_GPUBuffer* IndexBuffer = nullptr; + SDL_GPUTransferBuffer* IndexTransferBuffer = nullptr; + uint32_t IndexBufferSize = 0; }; struct ImGui_ImplSDLGPU3_Data @@ -114,14 +117,15 @@ static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGra SDL_PushGPUVertexUniformData(command_buffer, 0, &ubo, sizeof(UBO)); } -static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer, uint32_t* old_size, uint32_t new_size, SDL_GPUBufferUsageFlags usage) +static void CreateOrResizeBuffers(SDL_GPUBuffer** buffer, SDL_GPUTransferBuffer** transferbuffer, uint32_t* old_size, uint32_t new_size, SDL_GPUBufferUsageFlags usage) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - // Even though this is fairly rarely called. + // FIXME-OPT: Not optimal, but this is fairly rarely called. SDL_WaitForGPUIdle(v->Device); SDL_ReleaseGPUBuffer(v->Device, *buffer); + SDL_ReleaseGPUTransferBuffer(v->Device, *transferbuffer); SDL_GPUBufferCreateInfo buffer_info = {}; buffer_info.usage = usage; @@ -130,6 +134,12 @@ static void CreateOrResizeBuffer(SDL_GPUBuffer** buffer, uint32_t* old_size, uin *buffer = SDL_CreateGPUBuffer(v->Device, &buffer_info); *old_size = new_size; IM_ASSERT(*buffer != nullptr && "Failed to create GPU Buffer, call SDL_GetError() for more information"); + + SDL_GPUTransferBufferCreateInfo transferbuffer_info = {}; + transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + transferbuffer_info.size = new_size; + *transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &transferbuffer_info); + IM_ASSERT(*transferbuffer != nullptr && "Failed to create GPU Transfer Buffer, call SDL_GetError() for more information"); } // SDL_GPU doesn't allow copy passes to occur while a render or compute pass is bound! @@ -150,25 +160,12 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff uint32_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); uint32_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); if (fd->VertexBuffer == nullptr || fd->VertexBufferSize < vertex_size) - CreateOrResizeBuffer(&fd->VertexBuffer, &fd->VertexBufferSize, vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX); + CreateOrResizeBuffers(&fd->VertexBuffer, &fd->VertexTransferBuffer, &fd->VertexBufferSize, vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX); if (fd->IndexBuffer == nullptr || fd->IndexBufferSize < index_size) - CreateOrResizeBuffer(&fd->IndexBuffer, &fd->IndexBufferSize, index_size, SDL_GPU_BUFFERUSAGE_INDEX); - - // FIXME: It feels like more code could be shared there. - SDL_GPUTransferBufferCreateInfo vertex_transferbuffer_info = {}; - vertex_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - vertex_transferbuffer_info.size = vertex_size; - SDL_GPUTransferBufferCreateInfo index_transferbuffer_info = {}; - index_transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - index_transferbuffer_info.size = index_size; - - SDL_GPUTransferBuffer* vertex_transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &vertex_transferbuffer_info); - IM_ASSERT(vertex_transferbuffer != nullptr && "Failed to create the vertex transfer buffer, call SDL_GetError() for more information"); - SDL_GPUTransferBuffer* index_transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &index_transferbuffer_info); - IM_ASSERT(index_transferbuffer != nullptr && "Failed to create the index transfer buffer, call SDL_GetError() for more information"); - - ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->Device, vertex_transferbuffer, true); - ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->Device, index_transferbuffer, true); + CreateOrResizeBuffers(&fd->IndexBuffer, &fd->IndexTransferBuffer, &fd->IndexBufferSize, index_size, SDL_GPU_BUFFERUSAGE_INDEX); + + ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->Device, fd->VertexTransferBuffer, true); + ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->Device, fd->IndexTransferBuffer, true); for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* draw_list = draw_data->CmdLists[n]; @@ -177,15 +174,15 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff vtx_dst += draw_list->VtxBuffer.Size; idx_dst += draw_list->IdxBuffer.Size; } - SDL_UnmapGPUTransferBuffer(v->Device, vertex_transferbuffer); - SDL_UnmapGPUTransferBuffer(v->Device, index_transferbuffer); + SDL_UnmapGPUTransferBuffer(v->Device, fd->VertexTransferBuffer); + SDL_UnmapGPUTransferBuffer(v->Device, fd->IndexTransferBuffer); SDL_GPUTransferBufferLocation vertex_buffer_location = {}; vertex_buffer_location.offset = 0; - vertex_buffer_location.transfer_buffer = vertex_transferbuffer; + vertex_buffer_location.transfer_buffer = fd->VertexTransferBuffer; SDL_GPUTransferBufferLocation index_buffer_location = {}; index_buffer_location.offset = 0; - index_buffer_location.transfer_buffer = index_transferbuffer; + index_buffer_location.transfer_buffer = fd->IndexTransferBuffer; SDL_GPUBufferRegion vertex_buffer_region = {}; vertex_buffer_region.buffer = fd->VertexBuffer; @@ -201,8 +198,6 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff SDL_UploadToGPUBuffer(copy_pass, &vertex_buffer_location, &vertex_buffer_region, true); SDL_UploadToGPUBuffer(copy_pass, &index_buffer_location, &index_buffer_region, true); SDL_EndGPUCopyPass(copy_pass); - SDL_ReleaseGPUTransferBuffer(v->Device, index_transferbuffer); - SDL_ReleaseGPUTransferBuffer(v->Device, vertex_transferbuffer); } void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline) @@ -547,12 +542,14 @@ void ImGui_ImplSDLGPU3_DestroyFrameData() ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - SDL_ReleaseGPUBuffer(v->Device, bd->MainWindowFrameData.VertexBuffer); - SDL_ReleaseGPUBuffer(v->Device, bd->MainWindowFrameData.IndexBuffer); - bd->MainWindowFrameData.VertexBuffer = nullptr; - bd->MainWindowFrameData.IndexBuffer = nullptr; - bd->MainWindowFrameData.VertexBufferSize = 0; - bd->MainWindowFrameData.IndexBufferSize = 0; + ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData; + SDL_ReleaseGPUBuffer(v->Device, fd->VertexBuffer); + SDL_ReleaseGPUBuffer(v->Device, fd->IndexBuffer); + SDL_ReleaseGPUTransferBuffer(v->Device, fd->VertexTransferBuffer); + SDL_ReleaseGPUTransferBuffer(v->Device, fd->IndexTransferBuffer); + fd->VertexBuffer = fd->IndexBuffer = nullptr; + fd->VertexTransferBuffer = fd->IndexTransferBuffer = nullptr; + fd->VertexBufferSize = fd->IndexBufferSize = 0; } void ImGui_ImplSDLGPU3_DestroyDeviceObjects() diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b333f109e7a8..216a1c4a6044 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,8 @@ Other changes: regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] +- Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers + which were unusually slow to recreate every frame. Much faster now. (#8534) ----------------------------------------------------------------------- From 4bdb0ac68539f3812dd1abb4b080624d22b46fe6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 15:12:28 +0200 Subject: [PATCH 336/716] Comments --- docs/CHANGELOG.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 216a1c4a6044..2ad53ed61dbe 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,8 +63,8 @@ Other changes: regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] -- Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers - which were unusually slow to recreate every frame. Much faster now. (#8534) +- Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which + were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] ----------------------------------------------------------------------- @@ -530,7 +530,7 @@ Other changes: - Set io.ConfigNavCursorVisibleAuto = true (default) to enable automatic toggling of cursor visibility (mouse click hide the cursor, arrow keys makes it visible). - Set io.ConfigNavCursorVisibleAlways to keep cursor always visible. - - Nav: added NavSetCursorVisible(bool visible) function to manipulate visibility of + - Nav: added SetNavCursorVisible(bool visible) function to manipulate visibility of navigation cursor (e.g. set default state, or after some actions). (#1074, #2048, #7237, #8059) - Nav: added io.ConfigNavEscapeClearFocusItem and io.ConfigNavEscapeClearFocusWindow to change how pressing Escape affects navigation. (#8059, #2048, #1074, #3200) From 8098d79ca2e7787b082189623c5ffbba2cca6d4d Mon Sep 17 00:00:00 2001 From: Shixian Sheng Date: Tue, 1 Apr 2025 03:10:30 -0400 Subject: [PATCH 337/716] Docs: fixed link typo (#8538) --- docs/EXAMPLES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 0df73059bda2..2826a5ad7946 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -58,7 +58,7 @@ Allegro 5 example.
Android + OpenGL3 (ES) example.
= main.cpp + imgui_impl_android.cpp + imgui_impl_opengl3.cpp -[example_apple_metal/](https://github.com/ocornut/imgui/blob/master/examples/example_metal/)
+[example_apple_metal/](https://github.com/ocornut/imgui/tree/master/examples/example_apple_metal/)
OSX & iOS + Metal example.
= main.m + imgui_impl_osx.mm + imgui_impl_metal.mm
It is based on the "cross-platform" game template provided with Xcode as of Xcode 9. From fcab22f80f48495e70a24430f3a03a495e807fca Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 1 Apr 2025 22:53:00 +0200 Subject: [PATCH 338/716] Fonts: fixed CalcWordWrapPositionA() fallback when width is too small to wrap with multibyte codepoints.. (#8540) --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2ad53ed61dbe..3872fe5071f0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,8 @@ Other changes: CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) +- Fonts: fixed CalcWordWrapPositionA() fallback when width is too small to wrap: + would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 95d5eaba1f9c..df044e9b6be4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4027,7 +4027,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity. // +1 may not be a character start point in UTF-8 but it's ok because caller loops use (text >= word_wrap_eol). if (s == text && text < text_end) - return s + 1; + return s + ImTextCountUtf8BytesFromChar(s, text_end); return s; } From b4bd596a393f09eb39c8fa9cf1b4430dbe6272b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 1 Apr 2025 22:56:59 +0200 Subject: [PATCH 339/716] Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) --- docs/CHANGELOG.txt | 1 + imgui_draw.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3872fe5071f0..6a6c08bdd404 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,7 @@ Other changes: CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) +- Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) - Fonts: fixed CalcWordWrapPositionA() fallback when width is too small to wrap: would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of diff --git a/imgui_draw.cpp b/imgui_draw.cpp index df044e9b6be4..06da4ef2d589 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4009,7 +4009,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } // Allow wrapping after punctuation. - inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"'); + inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"' && c != 0x3001 && c != 0x3002); } // We ignore blank width at the end of the line (they can be skipped) From 9701810bc36577d443422b2894ba1a580faef13b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Apr 2025 11:41:21 +0200 Subject: [PATCH 340/716] TreeNode: adding ImGuiTreeNodeFlags_NoNavFocus in imgui_internal.h (#8551) --- imgui_internal.h | 1 + imgui_widgets.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/imgui_internal.h b/imgui_internal.h index ff1a8d8aca00..a5bb47e03c51 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -994,6 +994,7 @@ enum ImGuiSelectableFlagsPrivate_ // Extend ImGuiTreeNodeFlags_ enum ImGuiTreeNodeFlagsPrivate_ { + ImGuiTreeNodeFlags_NoNavFocus = 1 << 27,// Don't claim nav focus when interacting with this item (#8551) ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader() ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, for reversed trees (#6517) ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow, diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 883a2648d0b9..e882d85eefe1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6691,6 +6691,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; else button_flags |= ImGuiButtonFlags_PressedOnClickRelease; + if (flags & ImGuiTreeNodeFlags_NoNavFocus) + button_flags |= ImGuiButtonFlags_NoNavFocus; bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; const bool was_selected = selected; From 91652c317e8b231318afed60b4b506a8888837fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Apr 2025 16:38:05 +0200 Subject: [PATCH 341/716] Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) # Conflicts: # backends/imgui_impl_vulkan.cpp # docs/CHANGELOG.txt --- backends/imgui_impl_vulkan.cpp | 13 +++++++++++++ docs/CHANGELOG.txt | 3 +++ 2 files changed, 16 insertions(+) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index e67b74c01455..b44513a2bdf7 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-07: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) // 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). // 2025-02-13: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326) // 2025-01-09: Vulkan: Added IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE to clarify how many image sampler descriptors are expected to be available in descriptor pool. (#6642) @@ -1174,6 +1175,16 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + if (bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) + { + // Deep copy buffer to reduce error-rate for end user (#8282) + VkFormat* formats_copy = (VkFormat*)IM_ALLOC(sizeof(VkFormat) * v->PipelineRenderingCreateInfo.colorAttachmentCount); + memcpy(formats_copy, v->PipelineRenderingCreateInfo.pColorAttachmentFormats, sizeof(VkFormat) * v->PipelineRenderingCreateInfo.colorAttachmentCount); + v->PipelineRenderingCreateInfo.pColorAttachmentFormats = formats_copy; + } +#endif ImGui_ImplVulkan_CreateDeviceObjects(); @@ -1187,6 +1198,8 @@ void ImGui_ImplVulkan_Shutdown() ImGuiIO& io = ImGui::GetIO(); ImGui_ImplVulkan_DestroyDeviceObjects(); + IM_FREE((void*)bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats); + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6a6c08bdd404..c6cb312214ac 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -68,6 +68,9 @@ Other changes: memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] +- Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's + pColorAttachmentFormats buffer when set, in order to reduce common user-error of + specifying a pointer to data that gets out of scope. (#8282) ----------------------------------------------------------------------- From 974bf58a215cbc71af2f16432fc65a3f50e0d6d1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Apr 2025 17:38:28 +0200 Subject: [PATCH 342/716] Backends: Vulkan: Build and warning fixes. (#8282) --- backends/imgui_impl_vulkan.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index b44513a2bdf7..398b81f2035f 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1175,9 +1175,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) { // Deep copy buffer to reduce error-rate for end user (#8282) VkFormat* formats_copy = (VkFormat*)IM_ALLOC(sizeof(VkFormat) * v->PipelineRenderingCreateInfo.colorAttachmentCount); @@ -1198,7 +1198,9 @@ void ImGui_ImplVulkan_Shutdown() ImGuiIO& io = ImGui::GetIO(); ImGui_ImplVulkan_DestroyDeviceObjects(); +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING IM_FREE((void*)bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats); +#endif io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; From faa03031b4cdf34fe9174c4e73dd769a5b41fda5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Apr 2025 18:16:23 +0200 Subject: [PATCH 343/716] Windows: loosened code to handle ImGuiButtonFlags_FlattenChildren so that master matches docking. (#8554) This essentially merges 059560d2 back into master. --- docs/CHANGELOG.txt | 3 +++ imgui_widgets.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c6cb312214ac..17f856c3a851 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,9 @@ Other changes: codepath that preserve last contents size when collapsed, resulting in programmatically uncollapsing auto-sizing windows having them flicker size for a frame. (#7691) [@achabense] +- Windows: loosened code to allow hovering of resize grips, borders, and table + borders while hovering a sibling child window, so that the code in master matches + one in docking (they accidentally diverged). (#8554) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index e882d85eefe1..0067bae01ec8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -518,7 +518,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool flags |= (item_flags & ImGuiItemFlags_ButtonRepeat) ? ImGuiButtonFlags_PressedOnClick : ImGuiButtonFlags_PressedOnDefault_; ImGuiWindow* backup_hovered_window = g.HoveredWindow; - const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; + const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window->RootWindow; if (flatten_hovered_children) g.HoveredWindow = window; From e5b218e6d1e1943ca211522be322cbcf57db4477 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Jul 2024 19:03:25 +0200 Subject: [PATCH 344/716] TreeNode: added ImGuiTreeNodeFlags_DrawTreeXXX flags. (#2920) # Conflicts: # docs/CHANGELOG.txt --- docs/CHANGELOG.txt | 12 +++++++++ imgui.cpp | 7 ++++- imgui.h | 12 ++++++++- imgui_demo.cpp | 64 +++++++++++++++++++++++++++++++++++++++++++--- imgui_draw.cpp | 3 +++ imgui_internal.h | 10 +++++--- imgui_tables.cpp | 2 ++ imgui_widgets.cpp | 61 +++++++++++++++++++++++++++++++++++++------ 8 files changed, 154 insertions(+), 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 17f856c3a851..42721adac935 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -55,6 +55,18 @@ Other changes: - Windows: loosened code to allow hovering of resize grips, borders, and table borders while hovering a sibling child window, so that the code in master matches one in docking (they accidentally diverged). (#8554) +- TreeNode: added flags to draw tree hierarchy outlines linking parent + and tree nodes: (#2920) + - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn. + - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. + - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. + - Added style.TreeLinesFlags which stores the default setting, + which may be overriden in individual TreeNode() calls. + - Added style.TreeLinesSize (default to 1.0f). + - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). + The color for a given hierarchy level is latched in TreeNode(), + allowing advanced tree drawing code to potentially alter it. + - The feature adds a little cost as extra data needs to be stored. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index b9088378aa9b..f0b633cf2b6f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1360,6 +1360,8 @@ ImGuiStyle::ImGuiStyle() TabBarOverlineSize = 1.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar. TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees). TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell + TreeLinesFlags = ImGuiTreeNodeFlags_DrawLinesNone; + TreeLinesSize = 1.0f; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. @@ -3415,6 +3417,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] = { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize @@ -3563,6 +3566,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt"; case ImGuiCol_TextLink: return "TextLink"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; + case ImGuiCol_TreeLines: return "TreeLines"; case ImGuiCol_DragDropTarget: return "DragDropTarget"; case ImGuiCol_NavCursor: return "NavCursor"; case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; @@ -10243,6 +10247,7 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.Style.WindowBorderHoverPadding > 0.0f && "Invalid style setting!"); // Required otherwise cannot resize from borders. IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right); IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right); + IM_ASSERT(g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesNone || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesFull || g.Style.TreeLinesFlags == ImGuiTreeNodeFlags_DrawLinesToNodes); // Error handling: we do not accept 100% silent recovery! Please contact me if you feel this is getting in your way. if (g.IO.ConfigErrorRecovery) @@ -12794,7 +12799,7 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) } // Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere -void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data) +void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, const ImGuiTreeNodeStackData* tree_node_data) { ImGuiContext& g = *GImGui; g.NavMoveScoringItems = false; diff --git a/imgui.h b/imgui.h index fec015c775a0..a3efff402713 100644 --- a/imgui.h +++ b/imgui.h @@ -1214,6 +1214,12 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 17, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, + // [EXPERIMENTAL] Draw lines connecting TreeNode hierarchy. Discuss in GitHub issue #2920. + // Default value is pulled from style.TreeLinesFlags. May be overridden in TreeNode calls. + ImGuiTreeNodeFlags_DrawLinesNone = 1 << 18, // No lines drawn + ImGuiTreeNodeFlags_DrawLinesFull = 1 << 19, // Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. + ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. A little bit slower. + #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth,// Renamed in 1.90.7 @@ -1666,7 +1672,8 @@ enum ImGuiCol_ ImGuiCol_TableRowBg, // Table row background (even rows) ImGuiCol_TableRowBgAlt, // Table row background (odd rows) ImGuiCol_TextLink, // Hyperlink color - ImGuiCol_TextSelectedBg, + ImGuiCol_TextSelectedBg, // Selected text inside an InputText + ImGuiCol_TreeLines, // Tree node hierarchy outlines when using ImGuiTreeNodeFlags_DrawLines ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target ImGuiCol_NavCursor, // Color of keyboard/gamepad navigation cursor/rectangle, when visible ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB @@ -1722,6 +1729,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign + ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize @@ -2181,6 +2189,8 @@ struct ImGuiStyle float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar. float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell + ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. + float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7bf2879d7187..205551fbfce8 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3920,6 +3920,7 @@ static void DemoWindowWidgetsTreeNodes() IMGUI_DEMO_MARKER("Widgets/Tree Nodes"); if (ImGui::TreeNode("Tree Nodes")) { + // See see "Examples -> Property Editor" (ShowExampleAppPropertyEditor() function) for a fancier, data-driven tree. IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Basic trees"); if (ImGui::TreeNode("Basic trees")) { @@ -3946,6 +3947,35 @@ static void DemoWindowWidgetsTreeNodes() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Hierarchy lines"); + if (ImGui::TreeNode("Hierarchy lines")) + { + static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DefaultOpen; + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); + + if (ImGui::TreeNodeEx("Parent", base_flags)) + { + if (ImGui::TreeNodeEx("Child 1", base_flags)) + { + ImGui::Button("Button for Child 1"); + ImGui::TreePop(); + } + if (ImGui::TreeNodeEx("Child 2", base_flags)) + { + ImGui::Button("Button for Child 2"); + ImGui::TreePop(); + } + ImGui::Text("Remaining contents"); + ImGui::Text("Remaining contents"); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes"); if (ImGui::TreeNode("Advanced, with Selectable nodes")) { @@ -3964,6 +3994,12 @@ static void DemoWindowWidgetsTreeNodes() ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere); + + HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesFull", &base_flags, ImGuiTreeNodeFlags_DrawLinesFull); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesToNodes", &base_flags, ImGuiTreeNodeFlags_DrawLinesToNodes); + ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position); ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop); ImGui::Text("Hello!"); @@ -4607,10 +4643,11 @@ static void DemoWindowLayout() ImGui::SmallButton("SmallButton()"); // Tree + // (here the node appears after a button and has odd intent, so we use ImGuiTreeNodeFlags_DrawLinesNone to disable hierarchy outline) const float spacing = ImGui::GetStyle().ItemInnerSpacing.x; ImGui::Button("Button##1"); ImGui::SameLine(0.0f, spacing); - if (ImGui::TreeNode("Node##1")) + if (ImGui::TreeNodeEx("Node##1", ImGuiTreeNodeFlags_DrawLinesNone)) { // Placeholder tree data for (int i = 0; i < 6; i++) @@ -6592,7 +6629,7 @@ static void DemoWindowTables() { static ImGuiTableFlags table_flags = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; - static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns; + static ImGuiTreeNodeFlags tree_node_flags_base = ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_DrawLinesFull; ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanFullWidth); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanLabelWidth", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanLabelWidth); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &tree_node_flags_base, ImGuiTreeNodeFlags_SpanAllColumns); @@ -8139,6 +8176,14 @@ bool ImGui::ShowStyleSelector(const char* label) return false; } +static const char* GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags) +{ + if (flags == ImGuiTreeNodeFlags_DrawLinesNone) return "DrawLinesNone"; + if (flags == ImGuiTreeNodeFlags_DrawLinesFull) return "DrawLinesFull"; + if (flags == ImGuiTreeNodeFlags_DrawLinesToNodes) return "DrawLinesToNodes"; + return ""; +} + void ImGui::ShowStyleEditor(ImGuiStyle* ref) { IMGUI_DEMO_MARKER("Tools/Style Editor"); @@ -8233,6 +8278,15 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); ImGui::SeparatorText("Widgets"); + if (ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags))) + { + const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes }; + for (ImGuiTreeNodeFlags option : options) + if (ImGui::Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option)) + style.TreeLinesFlags = option; + ImGui::EndCombo(); + } + ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 1.0f, "%.0f"); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); @@ -9285,8 +9339,10 @@ struct ExampleAppPropertyEditor ImGui::TableNextColumn(); ImGui::PushID(node->UID); ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None; - tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards - tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support + tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;// Standard opening mode as we are likely to want to add selection afterwards + tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support + tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach + tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines if (node == VisibleNode) tree_flags |= ImGuiTreeNodeFlags_Selected; if (node->Childs.Size == 0) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 06da4ef2d589..07145751aef3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -236,6 +236,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); @@ -300,6 +301,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f); colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); @@ -365,6 +367,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f); colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive]; colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); + colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); diff --git a/imgui_internal.h b/imgui_internal.h index a5bb47e03c51..5703cd0e3443 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -998,6 +998,7 @@ enum ImGuiTreeNodeFlagsPrivate_ ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader() ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, for reversed trees (#6517) ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow, + ImGuiTreeNodeFlags_DrawLinesMask_ = ImGuiTreeNodeFlags_DrawLinesNone | ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes, }; enum ImGuiSeparatorFlags_ @@ -1291,8 +1292,11 @@ struct ImGuiTreeNodeStackData { ImGuiID ID; ImGuiTreeNodeFlags TreeFlags; - ImGuiItemFlags ItemFlags; // Used for nav landing - ImRect NavRect; // Used for nav landing + ImGuiItemFlags ItemFlags; // Used for nav landing + ImRect NavRect; // Used for nav landing + ImU32 DrawLinesCol; + float DrawLinesX1; + float DrawLinesY2; }; // sizeof() = 20 @@ -3178,7 +3182,7 @@ namespace ImGui IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); - IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data); + IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, const ImGuiTreeNodeStackData* tree_node_data); IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 0954784bb37a..a3d4a886b57a 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -451,6 +451,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG // But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable(). table->WorkRect = table->OuterRect = table->InnerRect = outer_rect; table->HasScrollbarYPrev = table->HasScrollbarYCurr = false; + table->InnerWindow->DC.TreeDepth++; // This is designed to always linking ImGuiTreeNodeFlags_DrawLines linking accross a table } // Push a standardized ID for both child-using and not-child-using tables @@ -1510,6 +1511,7 @@ void ImGui::EndTable() } else { + table->InnerWindow->DC.TreeDepth--; ItemSize(table->OuterRect.GetSize()); ItemAdd(table->OuterRect, 0); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0067bae01ec8..3491ce8aaddf 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6390,6 +6390,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl // - TreeNodeV() // - TreeNodeEx() // - TreeNodeExV() +// - TreeNodeStoreStackData() [Internal] // - TreeNodeBehavior() [Internal] // - TreePush() // - TreePop() @@ -6548,17 +6549,27 @@ bool ImGui::TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags) // Store ImGuiTreeNodeStackData for just submitted node. // Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase. -static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags) +static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; g.TreeNodeStack.resize(g.TreeNodeStack.Size + 1); - ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.back(); + ImGuiTreeNodeStackData* tree_node_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; tree_node_data->ID = g.LastItemData.ID; tree_node_data->TreeFlags = flags; tree_node_data->ItemFlags = g.LastItemData.ItemFlags; tree_node_data->NavRect = g.LastItemData.NavRect; + if (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) + { + tree_node_data->DrawLinesCol = ImGui::GetColorU32(ImGuiCol_TreeLines); + tree_node_data->DrawLinesX1 = x1; + tree_node_data->DrawLinesY2 = -FLT_MAX; + } + else + { + tree_node_data->DrawLinesCol = 0; + } window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6634,18 +6645,28 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). // It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle. bool store_tree_node_stack_data = false; - if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) + flags |= g.Style.TreeLinesFlags; + const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y);// && (g.Style.TreeLinesSize > 0.0f); + if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { - if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && is_open && !g.NavIdIsAlive) + if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !g.NavIdIsAlive) if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) store_tree_node_stack_data = true; + if (draw_tree_lines) + store_tree_node_stack_data = true; } const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; if (!is_visible) { - if (store_tree_node_stack_data && is_open) - TreeNodeStoreStackData(flags); // Call before TreePushOverrideID() + if (draw_tree_lines && (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeHasStackDataDepthMask & (1 << window->DC.TreeDepth))) + { + ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. + } + if (is_open && store_tree_node_stack_data) + TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0)); @@ -6807,6 +6828,18 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l LogSetNextTextDecoration(">", NULL); } + if (draw_tree_lines && (window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1)))) + { + // Draw horizontal line from our parent node + ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float x2 = text_pos.x - text_offset_x; + float y = text_pos.y + ImTrunc(g.FontSize * 0.5f); + parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); + if (x1 < x2) + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), parent_data->DrawLinesCol, g.Style.TreeLinesSize); + } + if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); @@ -6821,7 +6854,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } if (store_tree_node_stack_data && is_open) - TreeNodeStoreStackData(flags); // Call before TreePushOverrideID() + TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); // Could use TreePush(label) but this avoid computing twice @@ -6865,7 +6898,7 @@ void ImGui::TreePop() if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) // Only set during request { - ImGuiTreeNodeStackData* data = &g.TreeNodeStack.back(); + const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; IM_ASSERT(data->ID == window->IDStack.back()); if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) { @@ -6873,6 +6906,18 @@ void ImGui::TreePop() if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data); } + if (data->DrawLinesCol != 0 && window->DC.CursorPos.y >= window->ClipRect.Min.y) + { + // Draw vertical line of the hierarchy + float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y); + float y2 = (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesToNodes) ? data->DrawLinesY2 : ImTrunc(window->DC.CursorPos.y - g.Style.ItemSpacing.y - g.FontSize * 0.5f); + y2 = ImMin(y2, window->ClipRect.Max.y); + if (y1 < y2) + { + float x = data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), data->DrawLinesCol, g.Style.TreeLinesSize); + } + } g.TreeNodeStack.pop_back(); window->DC.TreeHasStackDataDepthMask &= ~tree_depth_mask; } From 39f34e1e5846f064f5457645d205b4d69d598b2f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 8 Apr 2025 19:56:14 +0200 Subject: [PATCH 345/716] TreeNode: Don't latch GetColorU32(ImGuiCol_TreeLines). (#2920) Trade off doesn't seem worth it for large trees. User who really needs to alter colors can do it by adjusting Push/Pop locations. --- docs/CHANGELOG.txt | 2 -- imgui_internal.h | 1 - imgui_widgets.cpp | 20 +++++++------------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 42721adac935..5fe43da867f5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -64,8 +64,6 @@ Other changes: which may be overriden in individual TreeNode() calls. - Added style.TreeLinesSize (default to 1.0f). - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). - The color for a given hierarchy level is latched in TreeNode(), - allowing advanced tree drawing code to potentially alter it. - The feature adds a little cost as extra data needs to be stored. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) diff --git a/imgui_internal.h b/imgui_internal.h index 5703cd0e3443..0b2b0e6a01a6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1294,7 +1294,6 @@ struct ImGuiTreeNodeStackData ImGuiTreeNodeFlags TreeFlags; ImGuiItemFlags ItemFlags; // Used for nav landing ImRect NavRect; // Used for nav landing - ImU32 DrawLinesCol; float DrawLinesX1; float DrawLinesY2; }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3491ce8aaddf..6323e2271701 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6560,16 +6560,10 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) tree_node_data->TreeFlags = flags; tree_node_data->ItemFlags = g.LastItemData.ItemFlags; tree_node_data->NavRect = g.LastItemData.NavRect; - if (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) - { - tree_node_data->DrawLinesCol = ImGui::GetColorU32(ImGuiCol_TreeLines); - tree_node_data->DrawLinesX1 = x1; - tree_node_data->DrawLinesY2 = -FLT_MAX; - } - else - { - tree_node_data->DrawLinesCol = 0; - } + + // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large trees. + tree_node_data->DrawLinesX1 = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) ? x1 : +FLT_MAX; + tree_node_data->DrawLinesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6837,7 +6831,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l float y = text_pos.y + ImTrunc(g.FontSize * 0.5f); parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); if (x1 < x2) - window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), parent_data->DrawLinesCol, g.Style.TreeLinesSize); + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } if (span_all_columns && !span_all_columns_label) @@ -6906,7 +6900,7 @@ void ImGui::TreePop() if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data); } - if (data->DrawLinesCol != 0 && window->DC.CursorPos.y >= window->ClipRect.Min.y) + if (data->DrawLinesX1 != +FLT_MAX && window->DC.CursorPos.y >= window->ClipRect.Min.y) { // Draw vertical line of the hierarchy float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y); @@ -6915,7 +6909,7 @@ void ImGui::TreePop() if (y1 < y2) { float x = data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f - window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), data->DrawLinesCol, g.Style.TreeLinesSize); + window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } } g.TreeNodeStack.pop_back(); From 789de09dda710a8826cf3bdfba29a4c1f72c6097 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 12:04:09 +0200 Subject: [PATCH 346/716] TreeNode: extracted TreeNodeDrawLineToChildNode() for usage by custom widgets (#2920) --- docs/CHANGELOG.txt | 8 ++++++-- imgui.cpp | 4 ++-- imgui.h | 2 +- imgui_internal.h | 1 + imgui_widgets.cpp | 30 +++++++++++++++++++----------- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5fe43da867f5..312b6de3e6d8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,14 +57,18 @@ Other changes: one in docking (they accidentally diverged). (#8554) - TreeNode: added flags to draw tree hierarchy outlines linking parent and tree nodes: (#2920) - - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn. + - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn (default value in style.TreeLinesFlags). - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. - Added style.TreeLinesFlags which stores the default setting, which may be overriden in individual TreeNode() calls. - Added style.TreeLinesSize (default to 1.0f). - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). - - The feature adds a little cost as extra data needs to be stored. + - Caveats: + - Tree nodes may be used in many creative ways (manually positioning openable + nodes in unusual ways, using indent to create tree-looking structures, etc.) + and the feature may not accurately represent them in every cases. + - The feature adds a little cost as extra data needs to be stored. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index f0b633cf2b6f..b32874ec5199 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16578,9 +16578,9 @@ void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int wi ImFormatString(buf, IM_ARRAYSIZE(buf), "[%04d] Window", window->BeginOrderWithinContext); //BulletText("[%04d] Window '%s'", window->BeginOrderWithinContext, window->Name); DebugNodeWindow(window, buf); - Indent(); + TreePush(buf); DebugNodeWindowsListByBeginStackParent(windows + i + 1, windows_size - i - 1, window); - Unindent(); + TreePop(); } } diff --git a/imgui.h b/imgui.h index a3efff402713..d5e24f09e5bc 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19192 +#define IMGUI_VERSION_NUM 19193 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 0b2b0e6a01a6..b4c2a429ecd2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3467,6 +3467,7 @@ namespace ImGui // Widgets: Tree Nodes IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); + IMGUI_API void TreeNodeDrawLineToChildNode(const ImVec2& target_pos); IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6323e2271701..56134d641dea 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6822,17 +6822,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l LogSetNextTextDecoration(">", NULL); } - if (draw_tree_lines && (window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1)))) - { - // Draw horizontal line from our parent node - ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f - float x2 = text_pos.x - text_offset_x; - float y = text_pos.y + ImTrunc(g.FontSize * 0.5f); - parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); - if (x1 < x2) - window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); - } + if (draw_tree_lines) + TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x, text_pos.y + g.FontSize * 0.5f)); if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); @@ -6856,6 +6847,23 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l return is_open; } +// Draw horizontal line from our parent node +// This is only called for visible child nodes so we are not too fussy anymore about performances +void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if ((window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1))) == 0) + return; + + ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; + float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float y = ImTrunc(target_pos.y); + parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); + if (x1 < target_pos.x) + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(target_pos.x, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); +} + void ImGui::TreePush(const char* str_id) { ImGuiWindow* window = GetCurrentWindow(); From 74e453cf15c08cd1c34128a2cb020fe732efe61c Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Wed, 9 Apr 2025 14:56:54 +0200 Subject: [PATCH 347/716] Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) --- backends/imgui_impl_sdl2.cpp | 41 ++++++++++++++++++++---------------- backends/imgui_impl_sdl3.cpp | 41 ++++++++++++++++++++---------------- docs/CHANGELOG.txt | 3 +++ 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 54f9599cce5d..b2dacc48e309 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650) @@ -142,6 +143,7 @@ struct ImGui_ImplSDL2_Data SDL_Cursor* MouseLastCursor; int MouseLastLeaveFrame; bool MouseCanUseGlobalState; + bool MouseCanUseCapture; // Gamepad handling ImVector Gamepads; @@ -474,17 +476,6 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); - // Check and store if we are on a SDL backend that supports global mouse position - // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) - bool mouse_can_use_global_state = false; -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - const char* sdl_backend = SDL_GetCurrentVideoDriver(); - const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; - for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) - if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) - mouse_can_use_global_state = true; -#endif - // Setup backend capabilities flags ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)(); io.BackendPlatformUserData = (void*)bd; @@ -495,7 +486,18 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->Window = window; bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; - bd->MouseCanUseGlobalState = mouse_can_use_global_state; + + // Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse() + // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) + bd->MouseCanUseGlobalState = false; + bd->MouseCanUseCapture = false; +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + const char* sdl_backend = SDL_GetCurrentVideoDriver(); + const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; + for (const char* item : capture_and_global_state_whitelist) + if (strncmp(sdl_backend, item, strlen(item)) == 0) + bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true; +#endif ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText; @@ -630,12 +632,15 @@ static void ImGui_ImplSDL2_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE // - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside. - // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture. - bool want_capture = false; - for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) - if (ImGui::IsMouseDragging(button_n, 1.0f)) - want_capture = true; - SDL_CaptureMouse(want_capture ? SDL_TRUE : SDL_FALSE); + // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue we wait until mouse has moved to begin capture. + if (bd->MouseCanUseCapture) + { + bool want_capture = false; + for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) + if (ImGui::IsMouseDragging(button_n, 1.0f)) + want_capture = true; + SDL_CaptureMouse(want_capture ? SDL_TRUE : SDL_FALSE); + } SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->Window == focused_window); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index ac2e841e69e1..c2dd810853b4 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) @@ -110,6 +111,7 @@ struct ImGui_ImplSDL3_Data SDL_Cursor* MouseLastCursor; int MousePendingLeaveFrame; bool MouseCanUseGlobalState; + bool MouseCanUseCapture; // Gamepad handling ImVector Gamepads; @@ -461,17 +463,6 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); IM_UNUSED(sdl_gl_context); // Unused in this branch - // Check and store if we are on a SDL backend that supports global mouse position - // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) - bool mouse_can_use_global_state = false; -#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE - const char* sdl_backend = SDL_GetCurrentVideoDriver(); - const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; - for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++) - if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0) - mouse_can_use_global_state = true; -#endif - // Setup backend capabilities flags ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)(); io.BackendPlatformUserData = (void*)bd; @@ -482,7 +473,18 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void bd->Window = window; bd->WindowID = SDL_GetWindowID(window); bd->Renderer = renderer; - bd->MouseCanUseGlobalState = mouse_can_use_global_state; + + // Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse() + // ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list) + bd->MouseCanUseGlobalState = false; + bd->MouseCanUseCapture = false; +#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE + const char* sdl_backend = SDL_GetCurrentVideoDriver(); + const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" }; + for (const char* item : capture_and_global_state_whitelist) + if (strncmp(sdl_backend, item, strlen(item)) == 0) + bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true; +#endif ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText; @@ -596,12 +598,15 @@ static void ImGui_ImplSDL3_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE // - SDL_CaptureMouse() let the OS know e.g. that our drags can extend outside of parent boundaries (we want updated position) and shouldn't trigger other operations outside. - // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to migitate the issue we wait until mouse has moved to begin capture. - bool want_capture = false; - for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) - if (ImGui::IsMouseDragging(button_n, 1.0f)) - want_capture = true; - SDL_CaptureMouse(want_capture); + // - Debuggers under Linux tends to leave captured mouse on break, which may be very inconvenient, so to mitigate the issue we wait until mouse has moved to begin capture. + if (bd->MouseCanUseCapture) + { + bool want_capture = false; + for (int button_n = 0; button_n < ImGuiMouseButton_COUNT && !want_capture; button_n++) + if (ImGui::IsMouseDragging(button_n, 1.0f)) + want_capture = true; + SDL_CaptureMouse(want_capture); + } SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (bd->Window == focused_window); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 312b6de3e6d8..b45cc1e3af66 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,6 +81,9 @@ Other changes: - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) +- Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't + call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use + the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which From 5e7174dec6d7d708dbfd857c32c15671619babc2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:39:22 +0200 Subject: [PATCH 348/716] TreeNode: removed TreeLinesSize > 0.0f optimization check. (#2920) This is desirable but we'd need to avoid exposing 0.0f in style editor + assert on it. --- imgui_demo.cpp | 2 +- imgui_widgets.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 205551fbfce8..ac51635cfb25 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8286,7 +8286,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) style.TreeLinesFlags = option; ImGui::EndCombo(); } - ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 1.0f, "%.0f"); + ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f"); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 56134d641dea..5122fef7d3be 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6641,7 +6641,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l bool store_tree_node_stack_data = false; if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) flags |= g.Style.TreeLinesFlags; - const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y);// && (g.Style.TreeLinesSize > 0.0f); + const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !g.NavIdIsAlive) From bcbbfdaad4b98249cedcfd4914c70b01c4cb3243 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:43:48 +0200 Subject: [PATCH 349/716] TreeNode: DrawLines: latch X1 offset during TreePush(). (#2920) --- imgui_widgets.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 5122fef7d3be..b61817b9c55b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6562,7 +6562,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) tree_node_data->NavRect = g.LastItemData.NavRect; // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large trees. - tree_node_data->DrawLinesX1 = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) ? x1 : +FLT_MAX; + tree_node_data->DrawLinesX1 = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; tree_node_data->DrawLinesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6857,11 +6857,12 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) return; ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - float x1 = parent_data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float x1 = ImTrunc(parent_data->DrawLinesX1); + float x2 = ImTrunc(target_pos.x); float y = ImTrunc(target_pos.y); parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); - if (x1 < target_pos.x) - window->DrawList->AddLine(ImVec2(x1, y), ImVec2(target_pos.x, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + if (x1 < x2) + window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } void ImGui::TreePush(const char* str_id) @@ -6916,7 +6917,7 @@ void ImGui::TreePop() y2 = ImMin(y2, window->ClipRect.Max.y); if (y1 < y2) { - float x = data->DrawLinesX1 + ImTrunc(g.FontSize * 0.5f + g.Style.FramePadding.x); // GetTreeNodeToLabelSpacing() * 0.5f + float x = ImTrunc(data->DrawLinesX1); window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } } From 43caca05c27aebaa8f8fc3064d47042dce6c7f8b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:58:23 +0200 Subject: [PATCH 350/716] TreeNode: DrawLines: tweak X2 offset to avoid losing line when ItemSpacing is large. (#2920) --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b61817b9c55b..c1d1f54ba34c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6823,7 +6823,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l } if (draw_tree_lines) - TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x, text_pos.y + g.FontSize * 0.5f)); + TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.5f)); if (span_all_columns && !span_all_columns_label) TablePopBackgroundChannel(); @@ -6858,7 +6858,7 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; float x1 = ImTrunc(parent_data->DrawLinesX1); - float x2 = ImTrunc(target_pos.x); + float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); float y = ImTrunc(target_pos.y); parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); if (x1 < x2) From bbb0f0ade4d716be73c5c4b2552e124e54c63681 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 14:08:10 +0200 Subject: [PATCH 351/716] TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. --- docs/CHANGELOG.txt | 1 + imgui_widgets.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b45cc1e3af66..5ab36ed187f2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,7 @@ Other changes: nodes in unusual ways, using indent to create tree-looking structures, etc.) and the feature may not accurately represent them in every cases. - The feature adds a little cost as extra data needs to be stored. +- TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c1d1f54ba34c..bd56f509b1a4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6794,6 +6794,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header); RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding); RenderNavCursor(frame_bb, id, nav_render_cursor_flags); + if (span_all_columns && !span_all_columns_label) + TablePopBackgroundChannel(); if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) @@ -6814,6 +6816,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false); } RenderNavCursor(frame_bb, id, nav_render_cursor_flags); + if (span_all_columns && !span_all_columns_label) + TablePopBackgroundChannel(); if (flags & ImGuiTreeNodeFlags_Bullet) RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col); else if (!is_leaf) @@ -6825,9 +6829,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (draw_tree_lines) TreeNodeDrawLineToChildNode(ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.5f)); - if (span_all_columns && !span_all_columns_label) - TablePopBackgroundChannel(); - // Label if (display_frame) RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); From ed50bb167671f716358c8bd7bb5a6fadde39fae3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 14:47:08 +0200 Subject: [PATCH 352/716] TreeNode, Tables: fixed ImGuiTreeNodeFlags_DrawLinesXXX feature when TreePop() is called from a different column. (#2920) --- imgui_internal.h | 13 ++++++++----- imgui_tables.cpp | 31 ++++++++++++++++++++++++++++++- imgui_widgets.cpp | 8 +++++++- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index b4c2a429ecd2..070a75e6f5db 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -206,6 +206,10 @@ typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // F typedef int ImGuiTypingSelectFlags; // -> enum ImGuiTypingSelectFlags_ // Flags: for GetTypingSelectRequest() typedef int ImGuiWindowRefreshFlags; // -> enum ImGuiWindowRefreshFlags_ // Flags: for SetNextWindowRefreshPolicy() +// Table column indexing +typedef ImS16 ImGuiTableColumnIdx; +typedef ImU16 ImGuiTableDrawChannelIdx; + //----------------------------------------------------------------------------- // [SECTION] Context pointer // See implementation of this variable in imgui.cpp for comments and details. @@ -1296,6 +1300,7 @@ struct ImGuiTreeNodeStackData ImRect NavRect; // Used for nav landing float DrawLinesX1; float DrawLinesY2; + ImGuiTableColumnIdx DrawLinesTableColumn; }; // sizeof() = 20 @@ -2704,11 +2709,7 @@ struct IMGUI_API ImGuiTabBar //----------------------------------------------------------------------------- #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. -#define IMGUI_TABLE_MAX_COLUMNS 512 // May be further lifted - -// Our current column maximum is 64 but we may raise that in the future. -typedef ImS16 ImGuiTableColumnIdx; -typedef ImU16 ImGuiTableDrawChannelIdx; +#define IMGUI_TABLE_MAX_COLUMNS 512 // Arbitrary "safety" maximum, may be lifted in the future if needed. Must fit in ImGuiTableColumnIdx/ImGuiTableDrawChannelIdx. // [Internal] sizeof() ~ 112 // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. @@ -3344,6 +3345,8 @@ namespace ImGui IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); IMGUI_API void TablePushBackgroundChannel(); IMGUI_API void TablePopBackgroundChannel(); + IMGUI_API void TablePushColumnChannel(int column_n); + IMGUI_API void TablePopColumnChannel(); IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count); // Tables: Internals diff --git a/imgui_tables.cpp b/imgui_tables.cpp index a3d4a886b57a..6d4d673a1da6 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2193,6 +2193,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) g.LastItemData.StatusFlags = 0; } + // Also see TablePushColumnChannel() if (table->Flags & ImGuiTableFlags_NoClip) { // FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed. @@ -2466,10 +2467,38 @@ void ImGui::TablePopBackgroundChannel() ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; ImGuiTable* table = g.CurrentTable; - ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; // Optimization: avoid PopClipRect() + SetCurrentChannel() SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, table->Columns[table->CurrentColumn].DrawChannelCurrent); +} + +// Also see TableBeginCell() +void ImGui::TablePushColumnChannel(int column_n) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + // Optimization: avoid SetCurrentChannel() + PushClipRect() + if (table->Flags & ImGuiTableFlags_NoClip) + return; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiTableColumn* column = &table->Columns[column_n]; + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); + table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); +} + +void ImGui::TablePopColumnChannel() +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + + // Optimization: avoid PopClipRect() + SetCurrentChannel() + if (table->Flags & ImGuiTableFlags_NoClip) + return; + ImGuiWindow* window = g.CurrentWindow; + const ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; + SetWindowClipRectBeforeSetChannel(window, column->ClipRect); table->DrawSplitter->SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); } diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index bd56f509b1a4..8d98dab6e833 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6562,7 +6562,9 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) tree_node_data->NavRect = g.LastItemData.NavRect; // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large trees. - tree_node_data->DrawLinesX1 = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; + const bool draw_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) != 0; + tree_node_data->DrawLinesX1 = draw_lines ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; + tree_node_data->DrawLinesTableColumn = draw_lines && g.CurrentTable ? (ImGuiTableColumnIdx)g.CurrentTable->CurrentColumn : -1; tree_node_data->DrawLinesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6919,7 +6921,11 @@ void ImGui::TreePop() if (y1 < y2) { float x = ImTrunc(data->DrawLinesX1); + if (data->DrawLinesTableColumn != -1) + TablePushColumnChannel(data->DrawLinesTableColumn); window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + if (data->DrawLinesTableColumn != -1) + TablePopColumnChannel(); } } g.TreeNodeStack.pop_back(); From 531125346847d26f87e5a0dde9fa74b50d5725f9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 16:03:39 +0200 Subject: [PATCH 353/716] TreeNode: ImGuiTreeNodeFlags_DrawLinesFull uses ToNodes Y2 when they are close (using a threshold). (#2920) --- imgui.h | 4 ++-- imgui_internal.h | 2 +- imgui_widgets.cpp | 14 ++++++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index d5e24f09e5bc..98761113f49d 100644 --- a/imgui.h +++ b/imgui.h @@ -1217,8 +1217,8 @@ enum ImGuiTreeNodeFlags_ // [EXPERIMENTAL] Draw lines connecting TreeNode hierarchy. Discuss in GitHub issue #2920. // Default value is pulled from style.TreeLinesFlags. May be overridden in TreeNode calls. ImGuiTreeNodeFlags_DrawLinesNone = 1 << 18, // No lines drawn - ImGuiTreeNodeFlags_DrawLinesFull = 1 << 19, // Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. A little bit slower. + ImGuiTreeNodeFlags_DrawLinesFull = 1 << 19, // Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. Faster (for large trees). + ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. Slower (for large trees). #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 diff --git a/imgui_internal.h b/imgui_internal.h index 070a75e6f5db..3100bd4ac6b3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1299,7 +1299,7 @@ struct ImGuiTreeNodeStackData ImGuiItemFlags ItemFlags; // Used for nav landing ImRect NavRect; // Used for nav landing float DrawLinesX1; - float DrawLinesY2; + float DrawLinesToNodesY2; ImGuiTableColumnIdx DrawLinesTableColumn; }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 8d98dab6e833..42741b227194 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6565,7 +6565,7 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) const bool draw_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) != 0; tree_node_data->DrawLinesX1 = draw_lines ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; tree_node_data->DrawLinesTableColumn = draw_lines && g.CurrentTable ? (ImGuiTableColumnIdx)g.CurrentTable->CurrentColumn : -1; - tree_node_data->DrawLinesY2 = -FLT_MAX; + tree_node_data->DrawLinesToNodesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); } @@ -6659,7 +6659,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (draw_tree_lines && (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeHasStackDataDepthMask & (1 << window->DC.TreeDepth))) { ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; - parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. + parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. } if (is_open && store_tree_node_stack_data) TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() @@ -6863,7 +6863,7 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) float x1 = ImTrunc(parent_data->DrawLinesX1); float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); float y = ImTrunc(target_pos.y); - parent_data->DrawLinesY2 = ImMax(parent_data->DrawLinesY2, y); + parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, y); if (x1 < x2) window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } @@ -6916,7 +6916,13 @@ void ImGui::TreePop() { // Draw vertical line of the hierarchy float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y); - float y2 = (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesToNodes) ? data->DrawLinesY2 : ImTrunc(window->DC.CursorPos.y - g.Style.ItemSpacing.y - g.FontSize * 0.5f); + float y2 = data->DrawLinesToNodesY2; + if (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesFull) + { + float y2_full = ImTrunc(window->DC.CursorPos.y - g.Style.ItemSpacing.y - g.FontSize * 0.5f); + if (y2 + g.Style.ItemSpacing.y < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y + y2 = y2_full; + } y2 = ImMin(y2, window->ClipRect.Max.y); if (y1 < y2) { From 8c977bf7b3a74ac3a9bea4ad003676ffd2a3d940 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 16:26:38 +0200 Subject: [PATCH 354/716] TreeNode, Tables: fixed ImGuiTreeNodeFlags_DrawLinesXXX feature when TreePop() is called in table: in no column or at top of row. (#2920) --- docs/CHANGELOG.txt | 9 +++++++-- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 5 ++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5ab36ed187f2..1e67668421b5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -55,8 +55,8 @@ Other changes: - Windows: loosened code to allow hovering of resize grips, borders, and table borders while hovering a sibling child window, so that the code in master matches one in docking (they accidentally diverged). (#8554) -- TreeNode: added flags to draw tree hierarchy outlines linking parent - and tree nodes: (#2920) +- TreeNode: added experimental flags to draw tree hierarchy outlines linking + parent and tree nodes: (#2920) - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn (default value in style.TreeLinesFlags). - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. @@ -69,6 +69,11 @@ Other changes: nodes in unusual ways, using indent to create tree-looking structures, etc.) and the feature may not accurately represent them in every cases. - The feature adds a little cost as extra data needs to be stored. + (ImGuiTreeNodeFlags_DrawLinesToNodes is slower than ImGuiTreeNodeFlags_DrawLinesFull + which may be meaningful on very large trees, as it needs to record bottom-most + Y position even for clipped nodes). + - The feature is unlikely to ever work properly when using a coarse clipper + such as ImGuiListClipper. - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 6d4d673a1da6..b8b869301c47 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -2494,7 +2494,7 @@ void ImGui::TablePopColumnChannel() ImGuiTable* table = g.CurrentTable; // Optimization: avoid PopClipRect() + SetCurrentChannel() - if (table->Flags & ImGuiTableFlags_NoClip) + if ((table->Flags & ImGuiTableFlags_NoClip) || (table->CurrentColumn == -1)) // Calling TreePop() after TableNextRow() is supported. return; ImGuiWindow* window = g.CurrentWindow; const ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 42741b227194..6933fdcb6603 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6919,7 +6919,10 @@ void ImGui::TreePop() float y2 = data->DrawLinesToNodesY2; if (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesFull) { - float y2_full = ImTrunc(window->DC.CursorPos.y - g.Style.ItemSpacing.y - g.FontSize * 0.5f); + float y2_full = window->DC.CursorPos.y; + if (g.CurrentTable) + y2_full = ImMax(g.CurrentTable->RowPosY2, y2_full); + y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5f); if (y2 + g.Style.ItemSpacing.y < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y y2 = y2_full; } From ee0d96ac0d7c0a2d79ad1650eb4c12f9c7cd739a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 17:00:17 +0200 Subject: [PATCH 355/716] TreeNode: extract code out of TreePop() into TreeNodeDrawLineToTreePop(). (#2920) --- imgui_internal.h | 1 + imgui_widgets.cpp | 60 ++++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 3100bd4ac6b3..d5155e4258cb 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3471,6 +3471,7 @@ namespace ImGui // Widgets: Tree Nodes IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL); IMGUI_API void TreeNodeDrawLineToChildNode(const ImVec2& target_pos); + IMGUI_API void TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data); IMGUI_API void TreePushOverrideID(ImGuiID id); IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6933fdcb6603..13c1362b1c7a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6868,6 +6868,33 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); } +// Draw vertical line of the hierarchy +void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) +{ + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y); + float y2 = data->DrawLinesToNodesY2; + if (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesFull) + { + float y2_full = window->DC.CursorPos.y; + if (g.CurrentTable) + y2_full = ImMax(g.CurrentTable->RowPosY2, y2_full); + y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5f); + if (y2 + g.Style.ItemSpacing.y < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y + y2 = y2_full; + } + y2 = ImMin(y2, window->ClipRect.Max.y); + if (y2 <= y1) + return; + float x = ImTrunc(data->DrawLinesX1); + if (data->DrawLinesTableColumn != -1) + TablePushColumnChannel(data->DrawLinesTableColumn); + window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + if (data->DrawLinesTableColumn != -1) + TablePopColumnChannel(); +} + void ImGui::TreePush(const char* str_id) { ImGuiWindow* window = GetCurrentWindow(); @@ -6906,37 +6933,16 @@ void ImGui::TreePop() { const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; IM_ASSERT(data->ID == window->IDStack.back()); + + // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) - { - // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data); - } + + // Draw hierarchy lines if (data->DrawLinesX1 != +FLT_MAX && window->DC.CursorPos.y >= window->ClipRect.Min.y) - { - // Draw vertical line of the hierarchy - float y1 = ImMax(data->NavRect.Max.y, window->ClipRect.Min.y); - float y2 = data->DrawLinesToNodesY2; - if (data->TreeFlags & ImGuiTreeNodeFlags_DrawLinesFull) - { - float y2_full = window->DC.CursorPos.y; - if (g.CurrentTable) - y2_full = ImMax(g.CurrentTable->RowPosY2, y2_full); - y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5f); - if (y2 + g.Style.ItemSpacing.y < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y - y2 = y2_full; - } - y2 = ImMin(y2, window->ClipRect.Max.y); - if (y1 < y2) - { - float x = ImTrunc(data->DrawLinesX1); - if (data->DrawLinesTableColumn != -1) - TablePushColumnChannel(data->DrawLinesTableColumn); - window->DrawList->AddLine(ImVec2(x, y1), ImVec2(x, y2), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); - if (data->DrawLinesTableColumn != -1) - TablePopColumnChannel(); - } - } + TreeNodeDrawLineToTreePop(data); + g.TreeNodeStack.pop_back(); window->DC.TreeHasStackDataDepthMask &= ~tree_depth_mask; } From 9943137d1e926d4e4901c5721fea249c8ee4355f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 17:25:06 +0200 Subject: [PATCH 356/716] TreeNode: fixed non-opened clipped child node not moving Y2 marker. (#2920) --- imgui.cpp | 2 +- imgui_internal.h | 3 ++- imgui_widgets.cpp | 8 ++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b32874ec5199..c7566494b17e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7649,7 +7649,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.MenuBarAppending = false; window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user); window->DC.TreeDepth = 0; - window->DC.TreeHasStackDataDepthMask = 0x00; + window->DC.TreeHasStackDataDepthMask = window->DC.TreeRecordsClippedNodesY2Mask = 0x00; window->DC.ChildWindows.resize(0); window->DC.StateStorage = &window->StateStorage; window->DC.CurrentColumns = NULL; diff --git a/imgui_internal.h b/imgui_internal.h index d5155e4258cb..65de255f5dcd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2474,7 +2474,8 @@ struct IMGUI_API ImGuiWindowTempData ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs. ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items measurement int TreeDepth; // Current tree depth. - ImU32 TreeHasStackDataDepthMask; // Store whether given depth has ImGuiTreeNodeStackData data. Could be turned into a ImU64 if necessary. + ImU32 TreeHasStackDataDepthMask; // Store whether given depth has ImGuiTreeNodeStackData data. Could be turned into a ImU64 if necessary. + ImU32 TreeRecordsClippedNodesY2Mask; // Store whether we should keep recording Y2. Cleared when passing clip max. Equivalent TreeHasStackDataDepthMask value should always be set. ImVector ChildWindows; ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state) ImGuiOldColumns* CurrentColumns; // Current columns set diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 13c1362b1c7a..140ceb9e12f9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6564,9 +6564,11 @@ static void TreeNodeStoreStackData(ImGuiTreeNodeFlags flags, float x1) // Initially I tried to latch value for GetColorU32(ImGuiCol_TreeLines) but it's not a good trade-off for very large trees. const bool draw_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) != 0; tree_node_data->DrawLinesX1 = draw_lines ? (x1 + g.FontSize * 0.5f + g.Style.FramePadding.x) : +FLT_MAX; - tree_node_data->DrawLinesTableColumn = draw_lines && g.CurrentTable ? (ImGuiTableColumnIdx)g.CurrentTable->CurrentColumn : -1; + tree_node_data->DrawLinesTableColumn = (draw_lines && g.CurrentTable) ? (ImGuiTableColumnIdx)g.CurrentTable->CurrentColumn : -1; tree_node_data->DrawLinesToNodesY2 = -FLT_MAX; window->DC.TreeHasStackDataDepthMask |= (1 << window->DC.TreeDepth); + if (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) + window->DC.TreeRecordsClippedNodesY2Mask |= (1 << window->DC.TreeDepth); } // When using public API, currently 'id == storage_id' is always true, but we separate the values to facilitate advanced user code doing storage queries outside of UI loop. @@ -6656,10 +6658,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; if (!is_visible) { - if (draw_tree_lines && (flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeHasStackDataDepthMask & (1 << window->DC.TreeDepth))) + if ((flags & ImGuiTreeNodeFlags_DrawLinesToNodes) && (window->DC.TreeRecordsClippedNodesY2Mask & (1 << (window->DC.TreeDepth - 1)))) { ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, window->DC.CursorPos.y); // Don't need to aim to mid Y position as we are clipped anyway. + if (frame_bb.Min.y >= window->ClipRect.Max.y) + window->DC.TreeRecordsClippedNodesY2Mask &= ~(1 << (window->DC.TreeDepth - 1)); // Done } if (is_open && store_tree_node_stack_data) TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() From 3ab50c334a0b89480c00cca3bca414cea9d02d05 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Apr 2025 19:26:29 +0200 Subject: [PATCH 357/716] TreeNode, Style: added style.TreeLinesRounding support. (#2920) --- docs/CHANGELOG.txt | 3 ++- imgui.cpp | 3 +++ imgui.h | 4 +++- imgui_demo.cpp | 24 +++++++++++++++--------- imgui_widgets.cpp | 19 ++++++++++++++++--- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1e67668421b5..e4e8dc0db1c4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,9 +60,10 @@ Other changes: - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn (default value in style.TreeLinesFlags). - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. - - Added style.TreeLinesFlags which stores the default setting, + - Added style.TreeLinesFlags which stores the default setting, which may be overriden in individual TreeNode() calls. - Added style.TreeLinesSize (default to 1.0f). + - Added style.TreeLinesRadius (default to 0.0f). - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). - Caveats: - Tree nodes may be used in many creative ways (manually positioning openable diff --git a/imgui.cpp b/imgui.cpp index c7566494b17e..a8d67f9bf172 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1362,6 +1362,7 @@ ImGuiStyle::ImGuiStyle() TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell TreeLinesFlags = ImGuiTreeNodeFlags_DrawLinesNone; TreeLinesSize = 1.0f; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + TreeLinesRounding = 0.0f; // Radius of lines connecting child nodes to the vertical line. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. @@ -1416,6 +1417,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : TabCloseButtonMinWidthSelected; TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : TabCloseButtonMinWidthUnselected; TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor); + TreeLinesRounding = ImTrunc(TreeLinesRounding * scale_factor); SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor); @@ -3418,6 +3420,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] = { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize diff --git a/imgui.h b/imgui.h index 98761113f49d..0ddef9510efa 100644 --- a/imgui.h +++ b/imgui.h @@ -1730,6 +1730,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize + ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize @@ -2190,7 +2191,8 @@ struct ImGuiStyle float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. - float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ac51635cfb25..fbf65aa1d4e4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8270,15 +8270,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SeparatorText("Windows"); - ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); - int window_menu_button_position = style.WindowMenuButtonPosition + 1; - if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) - style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); - - ImGui::SeparatorText("Widgets"); - if (ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags))) + ImGui::SeparatorText("Trees"); + bool combo_open = ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)); + ImGui::SameLine(); + HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode."); + if (combo_open) { const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes }; for (ImGuiTreeNodeFlags option : options) @@ -8287,6 +8283,16 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::EndCombo(); } ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f"); + ImGui::SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f"); + + ImGui::SeparatorText("Windows"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); + int window_menu_button_position = style.WindowMenuButtonPosition + 1; + if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) + style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); + + ImGui::SeparatorText("Widgets"); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 140ceb9e12f9..64f07a41b9c8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6867,9 +6867,22 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) float x1 = ImTrunc(parent_data->DrawLinesX1); float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); float y = ImTrunc(target_pos.y); - parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, y); - if (x1 < x2) + float rounding = (g.Style.TreeLinesRounding > 0.0f) ? ImMin(x2 - x1, g.Style.TreeLinesRounding) : 0.0f; + parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, y - rounding); + if (x1 >= x2) + return; + if (rounding > 0.0f) + { + x1 += 0.5f + rounding; + window->DrawList->PathArcToFast(ImVec2(x1, y - rounding), rounding, 6, 3); + if (x1 < x2) + window->DrawList->PathLineTo(ImVec2(x2, y)); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_TreeLines), ImDrawFlags_None, g.Style.TreeLinesSize); + } + else + { window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + } } // Draw vertical line of the hierarchy @@ -6885,7 +6898,7 @@ void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) if (g.CurrentTable) y2_full = ImMax(g.CurrentTable->RowPosY2, y2_full); y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5f); - if (y2 + g.Style.ItemSpacing.y < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y + if (y2 + (g.Style.ItemSpacing.y + g.Style.TreeLinesRounding) < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y y2 = y2_full; } y2 = ImMin(y2, window->ClipRect.Max.y); From d3bb3336f5359dd3bf4af9bb32c2164b31414eac Mon Sep 17 00:00:00 2001 From: 519q Date: Sat, 12 Apr 2025 17:54:10 +0300 Subject: [PATCH 358/716] Backends: OSX: remove duplicate variable. (#8565) --- backends/imgui_impl_osx.mm | 2 -- 1 file changed, 2 deletions(-) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index e681d176b347..558ed9f2ade3 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -788,8 +788,6 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) default: return io.WantCaptureKeyboard; } - - NSEventModifierFlags modifier_flags = [event modifierFlags]; io.AddKeyEvent(key, (modifier_flags & mask) != 0); io.SetKeyEventNativeData(key, key_code, -1); // To support legacy indexing (<1.87 user code) } From b23a216ecddedcc1bf3c1241b5428d39399b622a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Apr 2025 13:28:57 +0200 Subject: [PATCH 359/716] Examples: added SDL2+Vulkan, SDL3+Vulkan, GLFW+Vulkan makefiles. Amend ignore list. (#2480) --- .gitignore | 8 +- examples/example_glfw_vulkan/Makefile | 83 +++++++++++++++++++++ examples/example_glfw_vulkan/main.cpp | 2 +- examples/example_sdl2_vulkan/Makefile | 80 ++++++++++++++++++++ examples/example_sdl2_vulkan/main.cpp | 2 +- examples/example_sdl3_opengl3/Makefile | 5 +- examples/example_sdl3_sdlrenderer3/Makefile | 7 +- examples/example_sdl3_vulkan/Makefile | 77 +++++++++++++++++++ examples/example_sdl3_vulkan/main.cpp | 2 +- 9 files changed, 257 insertions(+), 9 deletions(-) create mode 100644 examples/example_glfw_vulkan/Makefile create mode 100644 examples/example_sdl2_vulkan/Makefile create mode 100644 examples/example_sdl3_vulkan/Makefile diff --git a/.gitignore b/.gitignore index 15a908273eae..c920ba6491d7 100644 --- a/.gitignore +++ b/.gitignore @@ -56,9 +56,15 @@ cmake-build-* examples/example_glfw_metal/example_glfw_metal examples/example_glfw_opengl2/example_glfw_opengl2 examples/example_glfw_opengl3/example_glfw_opengl3 +examples/example_glfw_vulkan/example_glfw_vulkan examples/example_glut_opengl2/example_glut_opengl2 examples/example_null/example_null examples/example_sdl2_metal/example_sdl2_metal examples/example_sdl2_opengl2/example_sdl2_opengl2 examples/example_sdl2_opengl3/example_sdl2_opengl3 -examples/example_sdl2_sdlrenderer/example_sdl2_sdlrenderer +examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2 +examples/example_sdl2_vulkan/example_sdl2_vulkan +examples/example_sdl3_opengl3/example_sdl3_opengl3 +examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3 +examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3 +examples/example_sdl3_vulkan/example_sdl3_vulkan diff --git a/examples/example_glfw_vulkan/Makefile b/examples/example_glfw_vulkan/Makefile new file mode 100644 index 000000000000..1a84082d1e19 --- /dev/null +++ b/examples/example_glfw_vulkan/Makefile @@ -0,0 +1,83 @@ +# +# Cross Platform Makefile +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X +# +# You will need GLFW (http://www.glfw.org): +# Linux: +# apt-get install libglfw-dev +# Mac OS X: +# brew install glfw +# MSYS2: +# pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-glfw +# + +#CXX = g++ +#CXX = clang++ + +EXE = example_glfw_vulkan +IMGUI_DIR = ../.. +SOURCES = main.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_vulkan.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) +UNAME_S := $(shell uname -s) +LINUX_GL_LIBS = -lGL + +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = + +##--------------------------------------------------------------------- +## BUILD FLAGS PER PLATFORM +##--------------------------------------------------------------------- + +ifeq ($(UNAME_S), Linux) #LINUX + ECHO_MESSAGE = "Linux" + LIBS += $(LINUX_GL_LIBS) `pkg-config --static --libs glfw3 vulkan` + + CXXFLAGS += `pkg-config --cflags glfw3 vulkan` + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(UNAME_S), Darwin) #APPLE + ECHO_MESSAGE = "Mac OS X" + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo + LIBS += `pkg-config --libs glfw3 vulkan` + LIBS += -L/usr/local/lib -L/opt/local/lib -L/opt/homebrew/lib + #LIBS += -lglfw3 + + LIBS += `pkg-config --cflags glfw3 vulkan` + CXXFLAGS += -I/usr/local/include -I/opt/local/include -I/opt/homebrew/include + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(OS), Windows_NT) + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -limm32 + LIBS += `pkg-config --libs glfw3 vulkan` + + CXXFLAGS += `pkg-config --cflags glfw3 vulkan` + CFLAGS = $(CXXFLAGS) +endif + +##--------------------------------------------------------------------- +## BUILD RULES +##--------------------------------------------------------------------- + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +all: $(EXE) + @echo Build complete for $(ECHO_MESSAGE) + +$(EXE): $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +clean: + rm -f $(EXE) $(OBJS) diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index ce7fcde5e127..3d2181e89302 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -38,6 +38,7 @@ //#define APP_USE_UNLIMITED_FRAME_RATE #ifdef _DEBUG #define APP_USE_VULKAN_DEBUG_REPORT +static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; #endif // Data @@ -47,7 +48,6 @@ static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; static VkDevice g_Device = VK_NULL_HANDLE; static uint32_t g_QueueFamily = (uint32_t)-1; static VkQueue g_Queue = VK_NULL_HANDLE; -static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; diff --git a/examples/example_sdl2_vulkan/Makefile b/examples/example_sdl2_vulkan/Makefile new file mode 100644 index 000000000000..e722ab0357ad --- /dev/null +++ b/examples/example_sdl2_vulkan/Makefile @@ -0,0 +1,80 @@ +# +# Cross Platform Makefile +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X +# +# You will need SDL2 (http://www.libsdl.org): +# Linux: +# apt-get install libsdl2-dev +# Mac OS X: +# brew install sdl2 +# MSYS2: +# pacman -S mingw-w64-i686-SDL2 +# + +#CXX = g++ +#CXX = clang++ + +EXE = example_sdl2_vulkan +IMGUI_DIR = ../.. +SOURCES = main.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl2.cpp $(IMGUI_DIR)/backends/imgui_impl_vulkan.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) +UNAME_S := $(shell uname -s) + +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = + +##--------------------------------------------------------------------- +## BUILD FLAGS PER PLATFORM +##--------------------------------------------------------------------- + +ifeq ($(UNAME_S), Linux) #LINUX + ECHO_MESSAGE = "Linux" + LIBS += -lGL -ldl + LIBS += `pkg-config --libs sdl2 vulkan` + CXXFLAGS += `pkg-config --cflags sdl2 vulkan` + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(UNAME_S), Darwin) #APPLE + ECHO_MESSAGE = "Mac OS X" + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo + LIBS += `pkg-config --libs sdl2 vulkan` + LIBS += -L/usr/local/lib -L/opt/local/lib + + CXXFLAGS += `pkg-config --cflags sdl2 vulkan` + CXXFLAGS += -I/usr/local/include -I/opt/local/include + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(OS), Windows_NT) + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2 vulkan` + + CXXFLAGS += `pkg-config --cflags sdl2 vulkan` + CFLAGS = $(CXXFLAGS) +endif + +##--------------------------------------------------------------------- +## BUILD RULES +##--------------------------------------------------------------------- + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +all: $(EXE) + @echo Build complete for $(ECHO_MESSAGE) + +$(EXE): $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +clean: + rm -f $(EXE) $(OBJS) diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 0c29154bcabb..c62222577b5b 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -30,6 +30,7 @@ //#define APP_USE_UNLIMITED_FRAME_RATE #ifdef _DEBUG #define APP_USE_VULKAN_DEBUG_REPORT +static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; #endif // Data @@ -39,7 +40,6 @@ static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; static VkDevice g_Device = VK_NULL_HANDLE; static uint32_t g_QueueFamily = (uint32_t)-1; static VkQueue g_Queue = VK_NULL_HANDLE; -static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; diff --git a/examples/example_sdl3_opengl3/Makefile b/examples/example_sdl3_opengl3/Makefile index c2ef3ba556c3..d9c6eac9e0e0 100644 --- a/examples/example_sdl3_opengl3/Makefile +++ b/examples/example_sdl3_opengl3/Makefile @@ -45,10 +45,11 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" - LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` + LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo + LIBS += `pkg-config --libs sdl3` LIBS += -L/usr/local/lib -L/opt/local/lib - CXXFLAGS += `pkg-config sdl3 --cflags` + CXXFLAGS += `pkg-config --cflags sdl3` CXXFLAGS += -I/usr/local/include -I/opt/local/include CFLAGS = $(CXXFLAGS) endif diff --git a/examples/example_sdl3_sdlrenderer3/Makefile b/examples/example_sdl3_sdlrenderer3/Makefile index 1976fa924c0f..c278f7830116 100644 --- a/examples/example_sdl3_sdlrenderer3/Makefile +++ b/examples/example_sdl3_sdlrenderer3/Makefile @@ -26,7 +26,7 @@ LIBS = ifeq ($(UNAME_S), Linux) #LINUX ECHO_MESSAGE = "Linux" - LIBS += -ldl `pkg-config sdl3 --libs` + LIBS += -ldl `pkg-config sdl3 --libs` CXXFLAGS += `pkg-config sdl3 --cflags` CFLAGS = $(CXXFLAGS) @@ -34,10 +34,11 @@ endif ifeq ($(UNAME_S), Darwin) #APPLE ECHO_MESSAGE = "Mac OS X" - LIBS += -framework Cocoa -framework IOKit -framework CoreVideo `sdl3-config --libs` + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo + LIBS += `pkg-config --libs sdl3` LIBS += -L/usr/local/lib -L/opt/local/lib - CXXFLAGS += `pkg-config sdl3 --cflags` + CXXFLAGS += `pkg-config --cflags sdl3` CXXFLAGS += -I/usr/local/include -I/opt/local/include CFLAGS = $(CXXFLAGS) endif diff --git a/examples/example_sdl3_vulkan/Makefile b/examples/example_sdl3_vulkan/Makefile new file mode 100644 index 000000000000..e1956ff67847 --- /dev/null +++ b/examples/example_sdl3_vulkan/Makefile @@ -0,0 +1,77 @@ +# +# Cross Platform Makefile +# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X +# +# You will need SDL3 (http://www.libsdl.org) which is still unreleased/unpackaged. +# Mac OS X: +# brew install sdl3 + +#CXX = g++ +#CXX = clang++ + +EXE = example_sdl3_vulkan +IMGUI_DIR = ../.. +SOURCES = main.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_vulkan.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) +UNAME_S := $(shell uname -s) + +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = + + +##--------------------------------------------------------------------- +## BUILD FLAGS PER PLATFORM +##--------------------------------------------------------------------- + +ifeq ($(UNAME_S), Linux) #LINUX + ECHO_MESSAGE = "Linux" + LIBS += -ldl + LIBS += `pkg-config --libs sdl3 vulkan` + + CXXFLAGS += `pkg-config --cflags sdl3 vulkan` + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(UNAME_S), Darwin) #APPLE + ECHO_MESSAGE = "Mac OS X" + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo + LIBS += `pkg-config --libs sdl3 vulkan` + LIBS += -L/usr/local/lib -L/opt/local/lib + + CXXFLAGS += `pkg-config --cflags sdl3 vulkan` + CXXFLAGS += -I/usr/local/include -I/opt/local/include + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(OS), Windows_NT) + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -limm32 `pkg-config --static --libs sdl3 vulkan` + + CXXFLAGS += `pkg-config --cflags sdl3 vulkan` + CFLAGS = $(CXXFLAGS) +endif + +##--------------------------------------------------------------------- +## BUILD RULES +##--------------------------------------------------------------------- + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +all: $(EXE) + @echo Build complete for $(ECHO_MESSAGE) + +$(EXE): $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +clean: + rm -f $(EXE) $(OBJS) diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 170eae45b01b..618fd34a8e3e 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -35,6 +35,7 @@ //#define APP_USE_UNLIMITED_FRAME_RATE #ifdef _DEBUG #define APP_USE_VULKAN_DEBUG_REPORT +static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; #endif // Data @@ -44,7 +45,6 @@ static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE; static VkDevice g_Device = VK_NULL_HANDLE; static uint32_t g_QueueFamily = (uint32_t)-1; static VkQueue g_Queue = VK_NULL_HANDLE; -static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE; static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE; static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE; From 7ab4728a36cfa99c9a5cffde758f86248accb5b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Apr 2025 18:12:53 +0200 Subject: [PATCH 360/716] Error Handling: added better error report and recovery when calling EndFrame() or Render() without NewFrame(). --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e4e8dc0db1c4..51229ac8396e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -80,6 +80,8 @@ Other changes: CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) +- Error Handling: added better error report and recovery when calling EndFrame() + or Render() without NewFrame(). Was previously only an assert. - Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) - Fonts: fixed CalcWordWrapPositionA() fallback when width is too small to wrap: would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) diff --git a/imgui.cpp b/imgui.cpp index a8d67f9bf172..0d882da04f07 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5641,7 +5641,11 @@ void ImGui::EndFrame() // Don't process EndFrame() multiple times. if (g.FrameCountEnded == g.FrameCount) return; - IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); + if (!g.WithinFrameScope) + { + IM_ASSERT_USER_ERROR(g.WithinFrameScope, "Forgot to call ImGui::NewFrame()?"); + return; + } CallContextHooks(&g, ImGuiContextHookType_EndFramePre); From faea1938001d9667e0e98bedef4104cd73325236 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Apr 2025 19:18:10 +0200 Subject: [PATCH 361/716] Internals: minor refactor of TabItemLabelAndCloseButton(), should be no-op. (minor thing toward #7024) --- imgui_widgets.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 64f07a41b9c8..52e6236b5e42 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -10466,13 +10466,13 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, #endif // Render text label (with clipping + alpha gradient) + unsaved marker - ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); - ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; + ImRect text_ellipsis_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); + float text_pixel_clip_bb_max_x = text_ellipsis_clip_bb.Max.x; // Return clipped state ignoring the close button if (out_text_clipped) { - *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x; + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb_max_x; //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); } @@ -10518,15 +10518,15 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // This is all rather complicated // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. - float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f; + float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb_max_x : bb.Max.x - 1.0f; if (close_button_visible || unsaved_marker_visible) { - text_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); + text_pixel_clip_bb_max_x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; - ellipsis_max_x = text_pixel_clip_bb.Max.x; + ellipsis_max_x = text_pixel_clip_bb_max_x; } LogSetNextTextDecoration("/", "\\"); - RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size); + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb_max_x, ellipsis_max_x, label, NULL, &label_size); #if 0 if (!is_contents_visible) From e4a865177ee7276d63e2d33789010722232b73fc Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Apr 2025 20:21:23 +0200 Subject: [PATCH 362/716] ImFont: added cpu clip fine option for ImFont::RenderChar() (which is technically internal). (toward #7024) --- imgui.h | 2 +- imgui_draw.cpp | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 0ddef9510efa..989ae5ebca03 100644 --- a/imgui.h +++ b/imgui.h @@ -3532,7 +3532,7 @@ struct ImFont // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width); - IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c); + IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); // [Internal] Don't use! diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 07145751aef3..13130a242870 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4113,7 +4113,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c) +void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip) { const ImFontGlyph* glyph = FindGlyph(c); if (!glyph || !glyph->Visible) @@ -4123,8 +4123,31 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; float x = IM_TRUNC(pos.x); float y = IM_TRUNC(pos.y); + + float x1 = x + glyph->X0 * scale; + float x2 = x + glyph->X1 * scale; + if (cpu_fine_clip && (x1 > cpu_fine_clip->z || x2 < cpu_fine_clip->x)) + return; + float y1 = y + glyph->Y0 * scale; + float y2 = y + glyph->Y1 * scale; + float u1 = glyph->U0; + float v1 = glyph->V0; + float u2 = glyph->U1; + float v2 = glyph->V1; + + // Always CPU fine clip. Code extracted from RenderText(). + // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads. + if (cpu_fine_clip != NULL) + { + if (x1 < cpu_fine_clip->x) { u1 = u1 + (1.0f - (x2 - cpu_fine_clip->x) / (x2 - x1)) * (u2 - u1); x1 = cpu_fine_clip->x; } + if (y1 < cpu_fine_clip->y) { v1 = v1 + (1.0f - (y2 - cpu_fine_clip->y) / (y2 - y1)) * (v2 - v1); y1 = cpu_fine_clip->y; } + if (x2 > cpu_fine_clip->z) { u2 = u1 + ((cpu_fine_clip->z - x1) / (x2 - x1)) * (u2 - u1); x2 = cpu_fine_clip->z; } + if (y2 > cpu_fine_clip->w) { v2 = v1 + ((cpu_fine_clip->w - y1) / (y2 - y1)) * (v2 - v1); y2 = cpu_fine_clip->w; } + if (y1 >= y2) + return; + } draw_list->PrimReserve(6, 4); - draw_list->PrimRectUV(ImVec2(x + glyph->X0 * scale, y + glyph->Y0 * scale), ImVec2(x + glyph->X1 * scale, y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col); + draw_list->PrimRectUV(ImVec2(x1, y1), ImVec2(x2, y2), ImVec2(u1, v1), ImVec2(u2, v2), col); } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. From 97d85338e8cb3c865649aead7842ec32367281aa Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Apr 2025 20:27:23 +0200 Subject: [PATCH 363/716] Tabs: adjust handling of ellipsis now that Close Button visibility changed. (#8387) Internals: remove extra parameter to RenderTextEllipsis(). This requires RenderTextEllipsis() to use fine CPU-side clippoing. Users of RenderTextEllipsis(): #7024, #6236, #5267, #5745, #4269, #2775 --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 20 ++++++++++---------- imgui_internal.h | 2 +- imgui_tables.cpp | 4 ++-- imgui_widgets.cpp | 22 ++++++++++++++-------- 5 files changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 51229ac8396e..23093c963656 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other changes: - The feature is unlikely to ever work properly when using a coarse clipper such as ImGuiListClipper. - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. +- Tabs: fixes small issues with how "..." ellipsis moved depending on visibility + of Close Button or Unsaved Document marker. (#8387) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index 0d882da04f07..0f7618edc38d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3691,18 +3691,18 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons } // Another overly complex function until we reorganize everything into a nice all-in-one helper. -// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display. +// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) from 'ellipsis_max_x' which may be beyond it. // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. -void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) +void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) { ImGuiContext& g = *GImGui; if (text_end_full == NULL) text_end_full = FindRenderedTextEnd(text); const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f); - //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255)); - //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255)); - //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255)); + //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 6), IM_COL32(0, 0, 255, 255)); + //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y - 2), ImVec2(ellipsis_max_x, pos_max.y + 3), IM_COL32(0, 255, 0, 255)); + // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels. if (text_size.x > pos_max.x - pos_min.x) { @@ -3734,15 +3734,15 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con } // Render text, render ellipsis - RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); + ImVec4 cpu_fine_clip_rect(pos_min.x, pos_min.y, pos_max.x, pos_max.y); ImVec2 ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); - if (ellipsis_pos.x + ellipsis_width <= ellipsis_max_x) - for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) - font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar); + for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) + font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar, &cpu_fine_clip_rect); } else { - RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); + RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_full, &text_size, ImVec2(0.0f, 0.0f)); } if (g.LogEnabled) diff --git a/imgui_internal.h b/imgui_internal.h index 65de255f5dcd..1d217553b0ad 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3424,7 +3424,7 @@ namespace ImGui IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL); - IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); + IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known); IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders = true, float rounding = 0.0f); IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f); IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index b8b869301c47..077d54b14c04 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3275,7 +3275,7 @@ void ImGui::TableHeader(const char* label) // Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will // be merged into a single draw call. //window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, label, label_end, &label_size); const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); if (text_clipped && hovered && g.ActiveId == 0) @@ -3427,7 +3427,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ImRect clip_r(window->ClipRect.Min, window->ClipRect.Min + ImVec2(clip_width, clip_height)); int vtx_idx_begin = draw_list->_VtxCurrentIdx; PushStyleColor(ImGuiCol_Text, request->TextColor); - RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, clip_r.Max.x, label_name, label_name_eol, &label_size); + RenderTextEllipsis(draw_list, clip_r.Min, clip_r.Max, clip_r.Max.x, label_name, label_name_eol, &label_size); PopStyleColor(); int vtx_idx_end = draw_list->_VtxCurrentIdx; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 52e6236b5e42..984bf5f06102 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1690,7 +1690,7 @@ void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness); if (g.LogEnabled) LogSetNextTextDecoration("---", NULL); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, label, label_end, &label_size); } else { @@ -10467,12 +10467,11 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // Render text label (with clipping + alpha gradient) + unsaved marker ImRect text_ellipsis_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y); - float text_pixel_clip_bb_max_x = text_ellipsis_clip_bb.Max.x; // Return clipped state ignoring the close button if (out_text_clipped) { - *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb_max_x; + *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_ellipsis_clip_bb.Max.x; //draw_list->AddCircle(text_ellipsis_clip_bb.Min, 3.0f, *out_text_clipped ? IM_COL32(255, 0, 0, 255) : IM_COL32(0, 255, 0, 255)); } @@ -10518,15 +10517,22 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, // This is all rather complicated // (the main idea is that because the close button only appears on hover, we don't want it to alter the ellipsis position) // FIXME: if FramePadding is noticeably large, ellipsis_max_x will be wrong here (e.g. #3497), maybe for consistency that parameter of RenderTextEllipsis() shouldn't exist.. - float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb_max_x : bb.Max.x - 1.0f; + float ellipsis_max_x = text_ellipsis_clip_bb.Max.x; if (close_button_visible || unsaved_marker_visible) { - text_pixel_clip_bb_max_x -= close_button_visible ? (button_sz) : (button_sz * 0.80f); - text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f; - ellipsis_max_x = text_pixel_clip_bb_max_x; + const bool visible_without_hover = unsaved_marker_visible || (is_contents_visible ? g.Style.TabCloseButtonMinWidthSelected : g.Style.TabCloseButtonMinWidthUnselected) < 0.0f; + if (visible_without_hover) + { + text_ellipsis_clip_bb.Max.x -= button_sz * 0.90f; + ellipsis_max_x -= button_sz * 0.90f; + } + else + { + text_ellipsis_clip_bb.Max.x -= button_sz * 1.00f; + } } LogSetNextTextDecoration("/", "\\"); - RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb_max_x, ellipsis_max_x, label, NULL, &label_size); + RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, ellipsis_max_x, label, NULL, &label_size); #if 0 if (!is_contents_visible) From 69d572bb107c2e2dde3b0ce9d4bb583ac628be6b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 16 Apr 2025 20:30:00 +0200 Subject: [PATCH 364/716] Fonts: reworked text ellipsis logic to ensure a "..." is always displayed instead of a single character. (#7024) Requires 97d85338e8 and e4a865177e --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 6 ------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 23093c963656..197fe9bb0fa5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -84,6 +84,8 @@ Other changes: EndPopup() call. (#1651, #8499) - Error Handling: added better error report and recovery when calling EndFrame() or Render() without NewFrame(). Was previously only an assert. +- Fonts: reworked text ellipsis logic to ensure a "..." is always displayed instead + of a single character. (#7024) - Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) - Fonts: fixed CalcWordWrapPositionA() fallback when width is too small to wrap: would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) diff --git a/imgui.cpp b/imgui.cpp index 0f7618edc38d..90d4bbfa9b4a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3720,12 +3720,6 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con // We can now claim the space between pos_max.x and ellipsis_max.x const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x; - if (text == text_end_ellipsis && text_end_ellipsis < text_end_full) - { - // Always display at least 1 character if there's no room for character + ellipsis - text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full); - text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x; - } while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1])) { // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text) From af987eb1176fb4c11a6f0a4f2550d9907d113df5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 20 Apr 2025 11:24:30 +0200 Subject: [PATCH 365/716] Backends: DX12: build fix for Clang. (#8582) --- backends/imgui_impl_dx12.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 202bac3b09d9..b6425cf52a4b 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -535,7 +535,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() return false; } - PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature"); + PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)(void*)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature"); if (D3D12SerializeRootSignatureFn == nullptr) return false; From bf0f586b69ec9f082164c8fe39068952beadf304 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Apr 2025 11:21:02 +0200 Subject: [PATCH 366/716] Platform IME: added ImGuiPlatformImeData::WantTextInput, ViewportId. Backends: SDL3: honor WantTextInput. (#8584, #7492, #6341) --- backends/imgui_impl_sdl3.cpp | 6 ++++-- docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 4 +++- imgui.h | 12 +++++++----- imgui_internal.h | 4 ++-- imgui_widgets.cpp | 8 +++++--- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index c2dd810853b4..e4e64721a2f5 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. @@ -150,7 +151,7 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle; SDL_Window* window = SDL_GetWindowFromID(window_id); - if ((data->WantVisible == false || bd->ImeWindow != window) && bd->ImeWindow != nullptr) + if ((!(data->WantVisible || data->WantTextInput) || bd->ImeWindow != window) && bd->ImeWindow != nullptr) { SDL_StopTextInput(bd->ImeWindow); bd->ImeWindow = nullptr; @@ -163,9 +164,10 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view r.w = 1; r.h = (int)data->InputLineHeight; SDL_SetTextInputArea(window, &r, 0); - SDL_StartTextInput(window); bd->ImeWindow = window; } + if (data->WantVisible || data->WantTextInput) + SDL_StartTextInput(window); } // Not static to allow third-party code to use that if they want to (but undocumented) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 197fe9bb0fa5..d78e8104f9c8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -91,6 +91,10 @@ Other changes: would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) +- Platform IME: added ImGuiPlatformImeData::ViewportId info (backported from Docking branch). +- Platform IME: added ImGuiPlatformImeData::WantTextInput which might set independently + of WantVisible. This is set in the same structure because activating text input generally + requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) @@ -99,6 +103,8 @@ Other changes: the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] +- Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative + way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] - Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's diff --git a/imgui.cpp b/imgui.cpp index 90d4bbfa9b4a..ad9132f23df7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5362,7 +5362,7 @@ void ImGui::NewFrame() // Platform IME data: reset for the frame g.PlatformImeDataPrev = g.PlatformImeData; - g.PlatformImeData.WantVisible = false; + g.PlatformImeData.WantVisible = g.PlatformImeData.WantTextInput = false; // Mouse wheel scrolling, scale UpdateMouseWheel(); @@ -5654,9 +5654,11 @@ void ImGui::EndFrame() if (g.PlatformIO.Platform_SetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0) { IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y); + IM_ASSERT(ime_data->ViewportId == IMGUI_VIEWPORT_DEFAULT_ID); // master branch ImGuiViewport* viewport = GetMainViewport(); g.PlatformIO.Platform_SetImeDataFn(&g, viewport, ime_data); } + g.WantTextInputNextFrame = ime_data->WantTextInput ? 1 : 0; // Hide implicit/fallback "Debug" window if it hasn't been used g.WithinFrameScopeWithImplicitWindow = false; diff --git a/imgui.h b/imgui.h index 989ae5ebca03..af72083e361b 100644 --- a/imgui.h +++ b/imgui.h @@ -3626,14 +3626,16 @@ struct ImGuiPlatformIO void* Renderer_RenderState; }; -// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. +// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). struct ImGuiPlatformImeData { - bool WantVisible; // A widget wants the IME to be visible - ImVec2 InputPos; // Position of the input cursor - float InputLineHeight; // Line height + bool WantVisible; // A widget wants the IME to be visible. + bool WantTextInput; // A widget wants text input, not necessarily IME to be visible. This is automatically set to the upcoming value of io.WantTextInput. + ImVec2 InputPos; // Position of input cursor (for IME). + float InputLineHeight; // Line height (for IME). + ImGuiID ViewportId; // ID of platform window/viewport. - ImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); } + ImGuiPlatformImeData() { memset(this, 0, sizeof(*this)); } }; //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index 1d217553b0ad..2c147e397e41 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2360,7 +2360,7 @@ struct ImGuiContext ImGuiTypingSelectState TypingSelectState; // State for GetTypingSelectRequest() // Platform support - ImGuiPlatformImeData PlatformImeData; // Data updated by current frame + ImGuiPlatformImeData PlatformImeData; // Data updated by current frame. Will be applied at end of the frame. For some backends, this is required to have WantVisible=true in order to receive text message. ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the platform_io.Platform_SetImeDataFn() handler. // Settings @@ -2428,7 +2428,7 @@ struct ImGuiContext float FramerateSecPerFrameAccum; int WantCaptureMouseNextFrame; // Explicit capture override via SetNextFrameWantCaptureMouse()/SetNextFrameWantCaptureKeyboard(). Default to -1. int WantCaptureKeyboardNextFrame; // " - int WantTextInputNextFrame; + int WantTextInputNextFrame; // Copied in EndFrame() from g.PlatformImeData.WanttextInput. Needs to be set for some backends (SDL3) to emit character inputs. ImVector TempBuffer; // Temporary text buffer char TempKeychordName[64]; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 984bf5f06102..c0a34db34b3c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5161,8 +5161,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Otherwise request text input ahead for next frame. if (g.ActiveId == id && clear_active_id) ClearActiveID(); - else if (g.ActiveId == id) - g.WantTextInputNextFrame = 1; // Render frame if (!is_multiline) @@ -5343,11 +5341,15 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031) // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.) - if (!is_readonly) + // This is required for some backends (SDL3) to start emitting character/text inputs. + // As per #6341, make sure we don't set that on the deactivating frame. + if (!is_readonly && g.ActiveId == id) { g.PlatformImeData.WantVisible = true; + g.PlatformImeData.WantTextInput = true; g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); g.PlatformImeData.InputLineHeight = g.FontSize; + g.PlatformImeData.ViewportId = window->Viewport->ID; } } } From 7c6ce12fa487c7684ac56be8e40c2a1c57c39602 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Apr 2025 11:24:02 +0200 Subject: [PATCH 367/716] Platform IME: minor amend to bf0f586 (#8584) --- imgui_widgets.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c0a34db34b3c..6a6d1e6ad74c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5345,11 +5345,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // As per #6341, make sure we don't set that on the deactivating frame. if (!is_readonly && g.ActiveId == id) { - g.PlatformImeData.WantVisible = true; - g.PlatformImeData.WantTextInput = true; - g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); - g.PlatformImeData.InputLineHeight = g.FontSize; - g.PlatformImeData.ViewportId = window->Viewport->ID; + ImGuiPlatformImeData* ime_data = &g.PlatformImeData; // (this is a public struct, passed to io.Platform_SetImeDataFn() handler) + ime_data->WantVisible = true; + ime_data->WantTextInput = true; + ime_data->InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize); + ime_data->InputLineHeight = g.FontSize; + ime_data->ViewportId = window->Viewport->ID; } } } From dcf0d8cab68bcf90156077211740836d95d683ad Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Apr 2025 18:34:56 +0200 Subject: [PATCH 368/716] Tables: fixed TableHeader() eager vertical clipping of text. (#6236) --- docs/CHANGELOG.txt | 2 ++ imgui_tables.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d78e8104f9c8..a3892a06b520 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other changes: - The feature is unlikely to ever work properly when using a coarse clipper such as ImGuiListClipper. - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. +- Tables: fixed TableHeader() eager vertical clipping of text which may be noticeable + with FramePadding.y was too small. (#6236) - Tabs: fixes small issues with how "..." ellipsis moved depending on visibility of Close Button or Unsaved Document marker. (#8387) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 077d54b14c04..6a84dba3671b 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3275,7 +3275,7 @@ void ImGui::TableHeader(const char* label) // Render clipped label. Clipping here ensure that in the majority of situations, all our header cells will // be merged into a single draw call. //window->DrawList->AddCircleFilled(ImVec2(ellipsis_max, label_pos.y), 40, IM_COL32_WHITE); - RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, label, label_end, &label_size); + RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, bb.Max.y), ellipsis_max, label, label_end, &label_size); const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); if (text_clipped && hovered && g.ActiveId == 0) From 6a42d6b339e0c86cdf0bce866bf390496155df69 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 23 Apr 2025 14:39:59 +0200 Subject: [PATCH 369/716] Added wp TextAligned() TextAlignedV(), TextAlignedExV() to internal API. (#7024) --- imgui.h | 2 +- imgui_internal.h | 7 ++++++- imgui_widgets.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index af72083e361b..64049bed6379 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19193 +#define IMGUI_VERSION_NUM 19194 #define IMGUI_HAS_TABLE /* diff --git a/imgui_internal.h b/imgui_internal.h index 2c147e397e41..cc5c488ba2be 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3443,8 +3443,13 @@ namespace ImGui IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding); IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, const ImRect& outer, const ImRect& inner, ImU32 col, float rounding); - // Widgets + // Widgets: Text IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); + IMGUI_API void TextAligned(float align_x, const char* fmt, ...); // FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) + IMGUI_API void TextAlignedV(float align_x, const char* fmt, va_list args); + IMGUI_API void TextAlignedExV(float align_x, float avail_x, const char* fmt, va_list args); + + // Widgets IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6a6d1e6ad74c..6e19c22ed66b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -339,6 +339,52 @@ void ImGui::TextWrappedV(const char* fmt, va_list args) PopTextWrapPos(); } +void ImGui::TextAligned(float align_x, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + TextAlignedV(align_x, fmt, args); + va_end(args); +} + +// align_x: 0.0f = left, 0.5f = center, 1.0f = right. +// FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) +void ImGui::TextAlignedV(float align_x, const char* fmt, va_list args) +{ + TextAlignedExV(align_x, GetContentRegionAvail().x, fmt, args); +} + +void ImGui::TextAlignedExV(float align_x, float avail_x, const char* fmt, va_list args) +{ + ImGuiWindow* window = GetCurrentWindow(); + if (window->SkipItems) + return; + + const char* text, *text_end; + ImFormatStringToTempBufferV(&text, &text_end, fmt, args); + const ImVec2 text_size = CalcTextSize(text, text_end); + + ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); + ImVec2 pos_max(pos.x + avail_x, window->ClipRect.Max.y); + ImVec2 size(ImMin(avail_x, text_size.x), text_size.y); + window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, pos.x + text_size.x); + window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, pos.x + text_size.x); + if (align_x > 0.0f && text_size.x < avail_x) + { + pos.x += ImTrunc((avail_x - text_size.x) * align_x); + window->DC.CursorPos = pos; + } + RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, text_end, &text_size); + + const ImVec2 backup_max_pos = window->DC.CursorMaxPos; + ItemSize(size); + ItemAdd(ImRect(pos, pos + size), 0); + window->DC.CursorMaxPos.x = backup_max_pos.x; // Cancel out extending content size because right-aligned text would otherwise mess it up. + + if (avail_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip)) + SetTooltip("%.*s", (int)(text_end - text), text); +} + void ImGui::LabelText(const char* label, const char* fmt, ...) { va_list args; From aed1bcc12c3260b0e4e202cfbb6625d2127fa6c0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 23 Apr 2025 14:52:29 +0200 Subject: [PATCH 370/716] Rework TextAligned() api to take size input. (#7024) --- imgui_internal.h | 5 ++--- imgui_widgets.cpp | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index cc5c488ba2be..1c60ddf1807c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3445,9 +3445,8 @@ namespace ImGui // Widgets: Text IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0); - IMGUI_API void TextAligned(float align_x, const char* fmt, ...); // FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) - IMGUI_API void TextAlignedV(float align_x, const char* fmt, va_list args); - IMGUI_API void TextAlignedExV(float align_x, float avail_x, const char* fmt, va_list args); + IMGUI_API void TextAligned(float align_x, float size_x, const char* fmt, ...); // FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) + IMGUI_API void TextAlignedV(float align_x, float size_x, const char* fmt, va_list args); // Widgets IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6e19c22ed66b..435a89b64747 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -339,39 +339,39 @@ void ImGui::TextWrappedV(const char* fmt, va_list args) PopTextWrapPos(); } -void ImGui::TextAligned(float align_x, const char* fmt, ...) +void ImGui::TextAligned(float align_x, float size_x, const char* fmt, ...) { va_list args; va_start(args, fmt); - TextAlignedV(align_x, fmt, args); + TextAlignedV(align_x, size_x, fmt, args); va_end(args); } // align_x: 0.0f = left, 0.5f = center, 1.0f = right. +// size_x : 0.0f = shortcut for GetContentRegionAvail().x // FIXME-WIP: Works but API is likely to be reworked. This is designed for 1 item on the line. (#7024) -void ImGui::TextAlignedV(float align_x, const char* fmt, va_list args) -{ - TextAlignedExV(align_x, GetContentRegionAvail().x, fmt, args); -} - -void ImGui::TextAlignedExV(float align_x, float avail_x, const char* fmt, va_list args) +void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list args) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) return; + // ~CalcItemSize() + if (size_x <= 0.0f) + size_x = GetContentRegionAvail().x + size_x; // <-- Remember that size_x is negative here + const char* text, *text_end; ImFormatStringToTempBufferV(&text, &text_end, fmt, args); const ImVec2 text_size = CalcTextSize(text, text_end); ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); - ImVec2 pos_max(pos.x + avail_x, window->ClipRect.Max.y); - ImVec2 size(ImMin(avail_x, text_size.x), text_size.y); + ImVec2 pos_max(pos.x + size_x, window->ClipRect.Max.y); + ImVec2 size(ImMin(size_x, text_size.x), text_size.y); window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, pos.x + text_size.x); window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, pos.x + text_size.x); - if (align_x > 0.0f && text_size.x < avail_x) + if (align_x > 0.0f && text_size.x < size_x) { - pos.x += ImTrunc((avail_x - text_size.x) * align_x); + pos.x += ImTrunc((size_x - text_size.x) * align_x); window->DC.CursorPos = pos; } RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, text_end, &text_size); @@ -381,7 +381,7 @@ void ImGui::TextAlignedExV(float align_x, float avail_x, const char* fmt, va_lis ItemAdd(ImRect(pos, pos + size), 0); window->DC.CursorMaxPos.x = backup_max_pos.x; // Cancel out extending content size because right-aligned text would otherwise mess it up. - if (avail_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip)) + if (size_x < text_size.x && IsItemHovered(ImGuiHoveredFlags_NoNavOverride | ImGuiHoveredFlags_AllowWhenDisabled | ImGuiHoveredFlags_ForTooltip)) SetTooltip("%.*s", (int)(text_end - text), text); } From 0fc4967ebc6a2d40b7b048296ff5e0cc24f91f26 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 23 Apr 2025 15:08:57 +0200 Subject: [PATCH 371/716] Rework TextAligned() api to fix issues with baseline alignment + use standard CalcItemSize(). (#7024) --- imgui_widgets.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 435a89b64747..1204a45990dd 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -356,13 +356,10 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a if (window->SkipItems) return; - // ~CalcItemSize() - if (size_x <= 0.0f) - size_x = GetContentRegionAvail().x + size_x; // <-- Remember that size_x is negative here - const char* text, *text_end; ImFormatStringToTempBufferV(&text, &text_end, fmt, args); const ImVec2 text_size = CalcTextSize(text, text_end); + size_x = CalcItemSize(ImVec2(size_x, 0.0f), 0.0f, text_size.y).x; ImVec2 pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset); ImVec2 pos_max(pos.x + size_x, window->ClipRect.Max.y); @@ -370,10 +367,7 @@ void ImGui::TextAlignedV(float align_x, float size_x, const char* fmt, va_list a window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, pos.x + text_size.x); window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, pos.x + text_size.x); if (align_x > 0.0f && text_size.x < size_x) - { pos.x += ImTrunc((size_x - text_size.x) * align_x); - window->DC.CursorPos = pos; - } RenderTextEllipsis(window->DrawList, pos, pos_max, pos_max.x, text, text_end, &text_size); const ImVec2 backup_max_pos = window->DC.CursorMaxPos; From 75964a9860d497ce3a4b0c482a093e664971466c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Apr 2025 14:39:17 +0200 Subject: [PATCH 372/716] CI: run on ubuntu-latest. --- .github/workflows/build.yml | 6 +++--- .github/workflows/static-analysis.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f95ff43c8a9c..86872d21cb85 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -218,7 +218,7 @@ jobs: run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release' Linux: - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -516,7 +516,7 @@ jobs: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_ios CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO Emscripten: - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -557,7 +557,7 @@ jobs: cmake --build build Android: - runs-on: ubuntu-24.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 69df5cdf8031..53db047646c8 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -10,7 +10,7 @@ on: jobs: PVS-Studio: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: From cbb8edb0b775f0abba3ea16d73eaabcbac10fc33 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 26 Apr 2025 15:41:08 +0200 Subject: [PATCH 373/716] Tables: fixed an assert when combining Tables, Frozen Rows, Clipper and BeginMultiSelect() in a certain order. (#8595, #8250) The table->CurrentColumn != -1 test in BeginMultiSelect() was affected. It would have been possible to amend the test with table->IsInsideRow but this seems generally saner. Docs: fixed typo. (#8592) --- docs/CHANGELOG.txt | 2 ++ docs/README.md | 2 +- imgui_tables.cpp | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a3892a06b520..0f4418fd689a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -78,6 +78,8 @@ Other changes: - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. - Tables: fixed TableHeader() eager vertical clipping of text which may be noticeable with FramePadding.y was too small. (#6236) +- Tables: fixed an assert when combining Tables, Frozen Rows, Clipper and BeginMultiSelect() + in a certain order. (#8595, #8250) - Tabs: fixes small issues with how "..." ellipsis moved depending on visibility of Close Button or Unsaved Document marker. (#8387) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open diff --git a/docs/README.md b/docs/README.md index 9b437311af12..701016a6a31d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -120,7 +120,7 @@ See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) On most platforms and when using C++, **you should be able to use a combination of the [imgui_impl_xxxx](https://github.com/ocornut/imgui/tree/master/backends) backends without modification** (e.g. `imgui_impl_win32.cpp` + `imgui_impl_dx11.cpp`). If your engine supports multiple platforms, consider using more imgui_impl_xxxx files instead of rewriting them: this will be less work for you, and you can get Dear ImGui running immediately. You can _later_ decide to rewrite a custom backend using your custom engine functions if you wish so. -Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles, which is essentially what Backends are doing. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that: setting up a window and using backends. If you follow the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide it should in theory takes you less than an hour to integrate Dear ImGui. **Make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** +Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles, which is essentially what Backends are doing. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that: setting up a window and using backends. If you follow the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide it should in theory take you less than an hour to integrate Dear ImGui. **Make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** Officially maintained backends/bindings (in repository): - Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 6a84dba3671b..e1813110dc9e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1953,7 +1953,10 @@ void ImGui::TableEndRow(ImGuiTable* table) IM_ASSERT(table->IsInsideRow); if (table->CurrentColumn != -1) + { TableEndCell(table); + table->CurrentColumn = -1; + } // Logging if (g.LogEnabled) From b3c96bde8c4e2ce0465d4c02d80f3d8173f2164c Mon Sep 17 00:00:00 2001 From: Ryan Jensen Date: Sat, 26 Apr 2025 09:10:00 -0500 Subject: [PATCH 374/716] Demo: use IM_ARRAYSIZE more consistently InputText calls in demo window (#8596) --- imgui_demo.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fbf65aa1d4e4..c7d3a31bc18e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3659,13 +3659,13 @@ static void DemoWindowWidgetsTextInput() } }; - static char buf1[32] = ""; ImGui::InputText("default", buf1, 32); - static char buf2[32] = ""; ImGui::InputText("decimal", buf2, 32, ImGuiInputTextFlags_CharsDecimal); - static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, 32, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); - static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, 32, ImGuiInputTextFlags_CharsUppercase); - static char buf5[32] = ""; ImGui::InputText("no blank", buf5, 32, ImGuiInputTextFlags_CharsNoBlank); - static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. - static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, 32, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. + static char buf1[32] = ""; ImGui::InputText("default", buf1, IM_ARRAYSIZE(buf1)); + static char buf2[32] = ""; ImGui::InputText("decimal", buf2, IM_ARRAYSIZE(buf2), ImGuiInputTextFlags_CharsDecimal); + static char buf3[32] = ""; ImGui::InputText("hexadecimal", buf3, IM_ARRAYSIZE(buf3), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase); + static char buf4[32] = ""; ImGui::InputText("uppercase", buf4, IM_ARRAYSIZE(buf4), ImGuiInputTextFlags_CharsUppercase); + static char buf5[32] = ""; ImGui::InputText("no blank", buf5, IM_ARRAYSIZE(buf5), ImGuiInputTextFlags_CharsNoBlank); + static char buf6[32] = ""; ImGui::InputText("casing swap", buf6, IM_ARRAYSIZE(buf6), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterCasingSwap); // Use CharFilter callback to replace characters. + static char buf7[32] = ""; ImGui::InputText("\"imgui\"", buf7, IM_ARRAYSIZE(buf7), ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters); // Use CharFilter callback to disable some characters. ImGui::TreePop(); } @@ -3721,20 +3721,20 @@ static void DemoWindowWidgetsTextInput() } }; static char buf1[64]; - ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); + ImGui::InputText("Completion", buf1, IM_ARRAYSIZE(buf1), ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback); ImGui::SameLine(); HelpMarker( "Here we append \"..\" each time Tab is pressed. " "See 'Examples>Console' for a more meaningful demonstration of using this callback."); static char buf2[64]; - ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); + ImGui::InputText("History", buf2, IM_ARRAYSIZE(buf2), ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback); ImGui::SameLine(); HelpMarker( "Here we replace and select text each time Up/Down are pressed. " "See 'Examples>Console' for a more meaningful demonstration of using this callback."); static char buf3[64]; static int edit_count = 0; - ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); + ImGui::InputText("Edit", buf3, IM_ARRAYSIZE(buf3), ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count); ImGui::SameLine(); HelpMarker( "Here we toggle the casing of the first character on every edit + count edits."); ImGui::SameLine(); ImGui::Text("(%d)", edit_count); From 75ddd9a6cd85db455ed2ee5ea8f4dfe1a9f96c7a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 28 Apr 2025 23:10:29 +0200 Subject: [PATCH 375/716] Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) --- backends/imgui_impl_sdlgpu3.cpp | 8 +++++++- docs/CHANGELOG.txt | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index f3a7adc85ff1..b277512ccf19 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -21,6 +21,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2025-04-28: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2025-03-30: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. // 2025-03-21: Fixed typo in function name Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData(). // 2025-01-16: Renamed ImGui_ImplSDLGPU3_InitInfo::GpuDevice to Device. @@ -232,7 +233,12 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != nullptr) { - pcmd->UserCallback(draw_list, pcmd); + // User callback, registered via ImDrawList::AddCallback() + // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height); + else + pcmd->UserCallback(draw_list, pcmd); } else { diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0f4418fd689a..e52537692a83 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -111,6 +111,7 @@ Other changes: way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] +- Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) - Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) From 3f8033324fbe5dbd3a47e91b02556c91b7d6ce1f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Apr 2025 11:10:54 +0200 Subject: [PATCH 376/716] Demo: Dual List Box: fix sorting function, in theory should return 0 when equal. (#8601) --- imgui_demo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c7d3a31bc18e..24ea67fa2542 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2491,7 +2491,7 @@ struct ExampleDualListBox { const int* a = (const int*)lhs; const int* b = (const int*)rhs; - return (*a - *b) > 0 ? +1 : -1; + return (*a - *b); } void SortItems(int n) { @@ -2499,7 +2499,7 @@ struct ExampleDualListBox } void Show() { - //ImGui::Checkbox("Sorted", &OptKeepSorted); + //if (ImGui::Checkbox("Sorted", &OptKeepSorted) && OptKeepSorted) { SortItems(0); SortItems(1); } if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None)) { ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side From 20066a8964a069b51de24eb0fe412d8539448266 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Apr 2025 11:30:06 +0200 Subject: [PATCH 377/716] Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) Amend ec1d2be96f. (#2496, #3907, #6308, #7615) This technically prevents multi-viewports from working with io.ConfigViewportsNoDefaultParent=true but this is a more fringe case to handle for our example app, better tradeoff imho to use IsIconic(). --- docs/CHANGELOG.txt | 2 ++ examples/example_win32_directx12/main.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e52537692a83..852380a8c975 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -115,6 +115,8 @@ Other changes: - Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) +- Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to + get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] ----------------------------------------------------------------------- diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 5f6cd51dd845..2df2751c58c6 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -196,7 +196,7 @@ int main(int, char**) break; // Handle window screen locked - if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) + if ((g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) || ::IsIconic(hwnd)) { ::Sleep(10); continue; From c0dfd65d6790b9b96872b64fa232f1fa80fcd3b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Apr 2025 16:23:58 +0200 Subject: [PATCH 378/716] Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594) --- backends/imgui_impl_win32.cpp | 6 +++++- docs/CHANGELOG.txt | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index ab7c8ab9ff1f..cd5e2dbf20b1 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-04-30: Inputs: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594) // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768) @@ -682,7 +683,10 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; } if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; } if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; } - if (bd->MouseButtonsDown == 0 && ::GetCapture() == nullptr) + HWND hwnd_with_capture = ::GetCapture(); + if (bd->MouseButtonsDown != 0 && hwnd_with_capture != hwnd) // Did we externally lost capture? + bd->MouseButtonsDown = 0; + if (bd->MouseButtonsDown == 0 && hwnd_with_capture == nullptr) ::SetCapture(hwnd); // Allow us to read mouse coordinates when dragging mouse outside of our window bounds. bd->MouseButtonsDown |= 1 << button; io.AddMouseSourceEvent(mouse_source); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 852380a8c975..9a221b94911c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -100,6 +100,8 @@ Other changes: of WantVisible. This is set in the same structure because activating text input generally requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] +- Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) + would fail to claim it again the next subsequent click. (#8594) - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) - Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't From e3bfaab3f70755af84f47300dbe448d5a52dcd7a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 May 2025 17:12:06 +0200 Subject: [PATCH 379/716] Examples: update xcode projects. --- .gitignore | 1 + .../project.pbxproj | 39 ++++++++++++++----- .../project.pbxproj | 4 +- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index c920ba6491d7..5a5c8cda371c 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ cmake-build-* .vscode ## Unix executables from our example Makefiles +examples/example_apple_metal/example_apple_metal examples/example_glfw_metal/example_glfw_metal examples/example_glfw_opengl2/example_glfw_opengl2 examples/example_glfw_opengl3/example_glfw_opengl3 diff --git a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj index 5f657eab9495..bf3c80d6e91a 100644 --- a/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj +++ b/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 48; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -209,7 +209,8 @@ 8307E7B620E9F9C700473790 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1200; + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1530; ORGANIZATIONNAME = "Warren Moore"; TargetAttributes = { 8307E7C320E9F9C900473790 = { @@ -327,9 +328,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -383,9 +386,11 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -405,8 +410,11 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios"; PRODUCT_NAME = example_apple_metal; SDKROOT = iphoneos; @@ -422,8 +430,11 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios"; PRODUCT_NAME = example_apple_metal; SDKROOT = iphoneos; @@ -439,10 +450,14 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos"; PRODUCT_NAME = example_apple_metal; SDKROOT = macosx; @@ -456,10 +471,14 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.12; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos"; PRODUCT_NAME = example_apple_metal; SDKROOT = macosx; diff --git a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj index a168373d49e0..9770e4396cfe 100644 --- a/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj +++ b/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj @@ -289,7 +289,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = ../..; }; @@ -299,7 +299,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - MACOSX_DEPLOYMENT_TARGET = 10.12; + MACOSX_DEPLOYMENT_TARGET = 10.13; PRODUCT_NAME = "$(TARGET_NAME)"; USER_HEADER_SEARCH_PATHS = ../..; }; From c5e2bb7cd1c577f701cb67a2e04d319b5ecacc9d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 May 2025 19:19:33 +0200 Subject: [PATCH 380/716] Backends: SDLGPU3: Fixed creating atlas texture earlier than other backends. # Conflicts: # backends/imgui_impl_sdlgpu3.cpp --- backends/imgui_impl_sdlgpu3.cpp | 4 ++-- docs/CHANGELOG.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index b277512ccf19..4bcc5bdfc4c0 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -589,8 +589,6 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) bd->InitInfo = *info; - ImGui_ImplSDLGPU3_CreateDeviceObjects(); - return true; } @@ -612,6 +610,8 @@ void ImGui_ImplSDLGPU3_NewFrame() ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLGPU3_Init()?"); + if (!bd->FontSampler) + ImGui_ImplSDLGPU3_CreateDeviceObjects(); if (!bd->FontTexture) ImGui_ImplSDLGPU3_CreateFontsTexture(); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9a221b94911c..ceb7bfcf7dc4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -111,6 +111,8 @@ Other changes: memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) +- Backends: SDLGPU3: Fixed creating atlas texture earlier than other backends, preventing + to load fonts between the Init and NewFrames calls. - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] - Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) From afd3a36f6989d09fa785bb27ffb9537c23333ea9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 May 2025 19:39:56 +0200 Subject: [PATCH 381/716] Demo: added basic Fonts section under main demo (same as Metrics one) for visibility. --- imgui.cpp | 24 ++++++++++++++++++++---- imgui_demo.cpp | 20 ++++++++++++++++++++ imgui_internal.h | 1 + 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ad9132f23df7..cb36ac536c5c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15491,6 +15491,18 @@ static void MetricsHelpMarker(const char* desc) // [DEBUG] List fonts in a font atlas and display its texture void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { + ImGuiContext& g = *GImGui; + + Text("Read "); + SameLine(0, 0); + TextLinkOpenURL("https://www.dearimgui.com/faq/"); + SameLine(0, 0); + Text(" for details on font loading."); + + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + Checkbox("Show font preview", &cfg->ShowFontPreview); + + // Font list for (ImFont* font : atlas->Fonts) { PushID(font); @@ -15499,7 +15511,6 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) } if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) { - ImGuiContext& g = *GImGui; PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); ImageWithBg(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); PopStyleVar(); @@ -16290,6 +16301,8 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co // [DEBUG] Display details for a single font, called by ShowStyleEditor(). void ImGui::DebugNodeFont(ImFont* font) { + ImGuiContext& g = *GImGui; + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)", font->Sources ? font->Sources[0].Name : "", font->FontSize, font->Glyphs.Size, font->SourcesCount); @@ -16297,9 +16310,12 @@ void ImGui::DebugNodeFont(ImFont* font) if (!opened) Indent(); Indent(); - PushFont(font); - Text("The quick brown fox jumps over the lazy dog"); - PopFont(); + if (cfg->ShowFontPreview) + { + PushFont(font); + Text("The quick brown fox jumps over the lazy dog"); + PopFont(); + } if (!opened) { Unindent(); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 24ea67fa2542..091a5256932d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -82,6 +82,7 @@ Index of this file: // [SECTION] DemoWindowWidgetsDisableBlocks() // [SECTION] DemoWindowWidgetsDragAndDrop() // [SECTION] DemoWindowWidgetsDragsAndSliders() +// [SECTION] DemoWindowWidgetsFonts() // [SECTION] DemoWindowWidgetsImages() // [SECTION] DemoWindowWidgetsListBoxes() // [SECTION] DemoWindowWidgetsMultiComponents() @@ -1719,6 +1720,24 @@ static void DemoWindowWidgetsDragsAndSliders() } } +//----------------------------------------------------------------------------- +// [SECTION] DemoWindowWidgetsFonts() +//----------------------------------------------------------------------------- + +// Forward declare ShowFontAtlas() which isn't worth putting in public API yet +namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } + +static void DemoWindowWidgetsFonts() +{ + IMGUI_DEMO_MARKER("Widgets/Fonts"); + if (ImGui::TreeNode("Fonts")) + { + ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImGui::ShowFontAtlas(atlas); + ImGui::TreePop(); + } +} + //----------------------------------------------------------------------------- // [SECTION] DemoWindowWidgetsImages() //----------------------------------------------------------------------------- @@ -4182,6 +4201,7 @@ static void DemoWindowWidgets(ImGuiDemoWindowData* demo_data) DemoWindowWidgetsDragAndDrop(); DemoWindowWidgetsDragsAndSliders(); + DemoWindowWidgetsFonts(); DemoWindowWidgetsImages(); DemoWindowWidgetsListBoxes(); DemoWindowWidgetsMultiComponents(); diff --git a/imgui_internal.h b/imgui_internal.h index 1c60ddf1807c..996eb82a29dc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2020,6 +2020,7 @@ struct ImGuiMetricsConfig int ShowTablesRectsType = -1; int HighlightMonitorIdx = -1; ImGuiID HighlightViewportID = 0; + bool ShowFontPreview = true; }; struct ImGuiStackLevelInfo From 46235e91f602b663f9b0f1f1a300177b61b193f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 May 2025 20:04:12 +0200 Subject: [PATCH 382/716] Examples: SDL3: specify SDL_WINDOW_HIGH_PIXEL_DENSITY and make centering consistent + call SDL_RenderScale(). --- examples/example_sdl3_opengl3/main.cpp | 4 ++-- examples/example_sdl3_sdlgpu3/main.cpp | 5 ++++- examples/example_sdl3_sdlrenderer3/main.cpp | 4 ++-- examples/example_sdl3_vulkan/main.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index d8666061dac6..46eeb59b59dd 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -68,14 +68,13 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+OpenGL3 example", 1280, 720, window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); return -1; } - SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_GLContext gl_context = SDL_GL_CreateContext(window); if (gl_context == nullptr) { @@ -85,6 +84,7 @@ int main(int, char**) SDL_GL_MakeCurrent(window, gl_context); SDL_GL_SetSwapInterval(1); // Enable vsync + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); SDL_ShowWindow(window); // Setup Dear ImGui context diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 3deeeafd56ee..4178f94b5e5b 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -34,12 +34,15 @@ int main(int, char**) } // Create SDL window graphics context - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", 1280, 720, SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY); + SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", 1280, 720, window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); return -1; } + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_ShowWindow(window); // Create GPU Device SDL_GPUDevice* gpu_device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB,true,nullptr); diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index ad05a0f919c2..9a2732b45cab 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -32,7 +32,7 @@ int main(int, char**) } // Create window with SDL_Renderer graphics context - Uint32 window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags); if (window == nullptr) { @@ -164,7 +164,7 @@ int main(int, char**) // Rendering ImGui::Render(); - //SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); + SDL_SetRenderScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); SDL_SetRenderDrawColorFloat(renderer, clear_color.x, clear_color.y, clear_color.z, clear_color.w); SDL_RenderClear(renderer); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 618fd34a8e3e..183965a84a0e 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -353,7 +353,7 @@ int main(int, char**) } // Create window with Vulkan graphics context - SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_HIDDEN); + SDL_WindowFlags window_flags = SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Vulkan example", 1280, 720, window_flags); if (window == nullptr) { From d1dc2a329893cdfe9bf9b7c20602b0a77d42c9ad Mon Sep 17 00:00:00 2001 From: ChrisTom-94 Date: Wed, 7 May 2025 11:47:58 +0200 Subject: [PATCH 383/716] Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) # Conflicts: # backends/imgui_impl_vulkan.cpp # docs/CHANGELOG.txt --- backends/imgui_impl_vulkan.cpp | 17 +++++++++++++---- docs/CHANGELOG.txt | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 398b81f2035f..2cebb6c251ee 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-05-07: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) // 2025-04-07: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) // 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). // 2025-02-13: Vulkan: Added ApiVersion field in ImGui_ImplVulkan_InitInfo. Default to header version if unspecified. Dynamic rendering path loads "vkCmdBeginRendering/vkCmdEndRendering" (without -KHR suffix) on API 1.3. (#8326) @@ -1085,9 +1086,17 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { - // Manually load those two (see #5446, #8326, #8365) - ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func(api_version < VK_API_VERSION_1_3 ? "vkCmdBeginRenderingKHR" : "vkCmdBeginRendering", user_data)); - ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func(api_version < VK_API_VERSION_1_3 ? "vkCmdEndRenderingKHR" : "vkCmdEndRendering", user_data)); + // Manually load those two (see #5446, #8326, #8365, #8600) + // - Try loading core (non-KHR) versions first (this will work for Vulkan 1.3+ and the device supports dynamic rendering) + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRendering", user_data)); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRendering", user_data)); + + // - Fallback to KHR versions if core not available (this will work if KHR extension is available and enabled and also the device supports dynamic rendering) + if (ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR == nullptr || ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR == nullptr) + { + ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRenderingKHR", user_data)); + ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR = reinterpret_cast(loader_func("vkCmdEndRenderingKHR", user_data)); + } } #endif @@ -1142,7 +1151,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) { #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #ifndef IMGUI_IMPL_VULKAN_USE_LOADER - ImGui_ImplVulkan_LoadDynamicRenderingFunctions(info->ApiVersion, [](const char* function_name, void* user_data) { return vkGetInstanceProcAddr((VkInstance)user_data, function_name); }, (void*)info->Instance); + ImGui_ImplVulkan_LoadDynamicRenderingFunctions(info->ApiVersion, [](const char* function_name, void* user_data) { return vkGetDeviceProcAddr((VkDevice)user_data, function_name); }, (void*)info->Device); #endif IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR != nullptr); IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR != nullptr); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ceb7bfcf7dc4..2ec521434b9a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -119,9 +119,28 @@ Other changes: - Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) +- Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + + try both non-KHR and KHR versions. (#8600, #8326, #8365) [@ChrisTom-94] - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] +Docking+Viewports Branch: + +- Backends: Win32: Viewports: fixed an issue when closing a window from + the OS close button (with io.ConfigViewportsNoDecoration=false) while + user code is discarding the 'bool *p_open=false output' from Begin(). + Because we allowed the Win32 window to close early, Windows destroyed + it and our imgui window became not visible even though user code was + still submitting it. +- Backends: SDLGPU3 for SDL3: added multi-viewport support. (#8573) [@Lekoopapaul] +- Backends: SDL2, SDL3: revert updating monitors and work areas info every + frame. Only do it on Windows to detect task-bar resize until we get an + adequate event for it. (#8415, #8558) +- Backends: SDL3: macOS: Fixed secondary-viewports not appearing on a different + monitor than the main viewport. Because SDL_SetWindowParent() seems to restrict it. +- Backends: GLFW: Disable multi-viewports under Wayland (require GLFW 3.4). (#8587) +>>>>>>> 6f2d429592 (Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365)) + ----------------------------------------------------------------------- VERSION 1.91.9b (Released 2025-03-17) From 64a5e274860ccf3771d35df1487812cdd790f0d0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 May 2025 14:22:19 +0200 Subject: [PATCH 384/716] Docs: bad merge error. --- docs/CHANGELOG.txt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2ec521434b9a..ff5a8b90a3b4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -124,23 +124,6 @@ Other changes: - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] -Docking+Viewports Branch: - -- Backends: Win32: Viewports: fixed an issue when closing a window from - the OS close button (with io.ConfigViewportsNoDecoration=false) while - user code is discarding the 'bool *p_open=false output' from Begin(). - Because we allowed the Win32 window to close early, Windows destroyed - it and our imgui window became not visible even though user code was - still submitting it. -- Backends: SDLGPU3 for SDL3: added multi-viewport support. (#8573) [@Lekoopapaul] -- Backends: SDL2, SDL3: revert updating monitors and work areas info every - frame. Only do it on Windows to detect task-bar resize until we get an - adequate event for it. (#8415, #8558) -- Backends: SDL3: macOS: Fixed secondary-viewports not appearing on a different - monitor than the main viewport. Because SDL_SetWindowParent() seems to restrict it. -- Backends: GLFW: Disable multi-viewports under Wayland (require GLFW 3.4). (#8587) ->>>>>>> 6f2d429592 (Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365)) - ----------------------------------------------------------------------- VERSION 1.91.9b (Released 2025-03-17) From bbc89b6391a0f89dc48c8c223b221820a3feceec Mon Sep 17 00:00:00 2001 From: ChrisTom-94 Date: Wed, 7 May 2025 15:19:45 +0200 Subject: [PATCH 385/716] Backends: Vulkan: fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) --- backends/imgui_impl_vulkan.cpp | 79 ++++++++++++++++++++++++++++++++++ docs/CHANGELOG.txt | 3 ++ 2 files changed, 82 insertions(+) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 2cebb6c251ee..78d09221714e 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -26,6 +26,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-05-07- Vulkan: Fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) // 2025-05-07: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) // 2025-04-07: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) // 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). @@ -1086,6 +1087,8 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING static void ImGui_ImplVulkan_LoadDynamicRenderingFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data) { + IM_UNUSED(api_version); + // Manually load those two (see #5446, #8326, #8365, #8600) // - Try loading core (non-KHR) versions first (this will work for Vulkan 1.3+ and the device supports dynamic rendering) ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR = reinterpret_cast(loader_func("vkCmdBeginRendering", user_data)); @@ -1667,6 +1670,82 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic (void)instance; ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count); ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator); + + // FIXME: to submit the command buffer, we need a queue. In the examples folder, the ImGui_ImplVulkanH_CreateOrResizeWindow function is called + // before the ImGui_ImplVulkan_Init function, so we don't have access to the queue yet. Here we have the queue_family that we can use to grab + // a queue from the device and submit the command buffer. It would be better to have access to the queue as suggested in the FIXME below. + VkCommandPool command_pool; + VkCommandPoolCreateInfo pool_info = {}; + pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + pool_info.queueFamilyIndex = queue_family; + pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + VkResult err = vkCreateCommandPool(device, &pool_info, allocator, &command_pool); + check_vk_result(err); + + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + VkFence fence; + err = vkCreateFence(device, &fence_info, allocator, &fence); + check_vk_result(err); + + VkCommandBufferAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.commandPool = command_pool; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + VkCommandBuffer command_buffer; + err = vkAllocateCommandBuffers(device, &alloc_info, &command_buffer); + check_vk_result(err); + + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(command_buffer, &begin_info); + check_vk_result(err); + + // Transition the images to the correct layout for rendering + for (uint32_t i = 0; i < wd->ImageCount; i++) + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = wd->Frames[i].Backbuffer; + barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier); + } + + err = vkEndCommandBuffer(command_buffer); + check_vk_result(err); + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &command_buffer; + + VkQueue queue; + vkGetDeviceQueue(device, queue_family, 0, &queue); + err = vkQueueSubmit(queue, 1, &submit_info, fence); + check_vk_result(err); + err = vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX); + check_vk_result(err); + err = vkResetFences(device, 1, &fence); + check_vk_result(err); + + err = vkResetCommandPool(device, command_pool, 0); + check_vk_result(err); + + // Destroy command buffer and fence and command pool + vkFreeCommandBuffers(device, command_pool, 1, &command_buffer); + vkDestroyCommandPool(device, command_pool, allocator); + vkDestroyFence(device, fence, allocator); + command_pool = VK_NULL_HANDLE; + command_buffer = VK_NULL_HANDLE; + fence = VK_NULL_HANDLE; + queue = VK_NULL_HANDLE; } void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ff5a8b90a3b4..9074f906ccd6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -121,6 +121,9 @@ Other changes: specifying a pointer to data that gets out of scope. (#8282) - Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) [@ChrisTom-94] +- Backends: Vulkan: fixed validation errors in window create/resize helpers used by examples + and by multi-viewports implementation, which would typically trigger errors while detaching + secondary viewports. (#8600, #8176) [@ChrisTom-94] - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] From bf68040dc592f9eaf9abc2c268db5d97493325b0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 7 May 2025 15:42:23 +0200 Subject: [PATCH 386/716] Backends: Vulkan: fixed build with VK_NO_PROTOTYPES. Amend bbc89b6 (#8600) --- backends/imgui_impl_vulkan.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 78d09221714e..10648c3a41f5 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -177,6 +177,7 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeDescriptorSets) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkFreeMemory) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetBufferMemoryRequirements) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetDeviceQueue) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetImageMemoryRequirements) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceProperties) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceMemoryProperties) \ @@ -189,8 +190,10 @@ static bool g_FunctionsLoaded = true; IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetFences) \ IMGUI_VULKAN_FUNC_MAP_MACRO(vkUnmapMemory) \ - IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) + IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) \ + IMGUI_VULKAN_FUNC_MAP_MACRO(vkWaitForFences) // Define function pointers #define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func; From ba513ba804c87635f7bcb3a054a463598a0a332d Mon Sep 17 00:00:00 2001 From: WSSDude <41929176+WSSDude@users.noreply.github.com> Date: Wed, 19 Feb 2025 14:00:06 +0100 Subject: [PATCH 387/716] Backends: DX10, DX11, DX12: honor FramebufferScale. (#8412) # Conflicts: # backends/imgui_impl_dx11.cpp # backends/imgui_impl_dx12.cpp --- backends/imgui_impl_dx10.cpp | 10 ++++++---- backends/imgui_impl_dx11.cpp | 10 ++++++---- backends/imgui_impl_dx12.cpp | 10 ++++++---- docs/CHANGELOG.txt | 3 +++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 801983211aba..dd06e0e7fdea 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -15,6 +15,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-10-07: DirectX10: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. @@ -88,8 +89,8 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* // Setup viewport D3D10_VIEWPORT vp = {}; - vp.Width = (UINT)draw_data->DisplaySize.x; - vp.Height = (UINT)draw_data->DisplaySize.y; + vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; @@ -246,6 +247,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) int global_vtx_offset = 0; int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; + ImVec2 clip_scale = draw_data->FramebufferScale; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* draw_list = draw_data->CmdLists[n]; @@ -264,8 +266,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) else { // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); - ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 9f39588810eb..f6a7f35f6ccf 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler. // 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -91,8 +92,8 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC // Setup viewport D3D11_VIEWPORT vp = {}; - vp.Width = draw_data->DisplaySize.x; - vp.Height = draw_data->DisplaySize.y; + vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; + vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0; @@ -260,6 +261,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) int global_idx_offset = 0; int global_vtx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; + ImVec2 clip_scale = draw_data->FramebufferScale; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* draw_list = draw_data->CmdLists[n]; @@ -278,8 +280,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) else { // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); - ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index b6425cf52a4b..84ec37f494eb 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -19,6 +19,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-02-24: DirectX12: Fixed an issue where ImGui_ImplDX12_Init() signature change from 2024-11-15 combined with change from 2025-01-15 made legacy ImGui_ImplDX12_Init() crash. (#8429) // 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. // 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat. @@ -138,8 +139,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic // Setup viewport D3D12_VIEWPORT vp = {}; - vp.Width = draw_data->DisplaySize.x; - vp.Height = draw_data->DisplaySize.y; + vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x; + vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = vp.TopLeftY = 0.0f; @@ -274,6 +275,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL int global_vtx_offset = 0; int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; + ImVec2 clip_scale = draw_data->FramebufferScale; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* draw_list = draw_data->CmdLists[n]; @@ -292,8 +294,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL else { // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); - ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9074f906ccd6..4c6dfe706f93 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -116,6 +116,9 @@ Other changes: - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] - Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) +- Backends: DirectX10, DirectX11, DirectX12: Honor FramebufferScale to allow for custom + platform backends and experiments using it (consistently with other renderer backends, + even though in normal condition it is not set under Windows). (#8412) [@WSSDude] - Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) From f484af34c2014e98a64410e6cd81e1a5ab434bfd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 May 2025 18:05:05 +0200 Subject: [PATCH 388/716] Font: rename ImFont::AddRemapChar() parameters for clarity. (#609) --- imgui.h | 2 +- imgui_draw.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index 64049bed6379..b9b8bf6adff2 100644 --- a/imgui.h +++ b/imgui.h @@ -3540,7 +3540,7 @@ struct ImFont IMGUI_API void ClearOutputData(); IMGUI_API void GrowIndex(int new_size); IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); - IMGUI_API void AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. + IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , bool overwrite_dst = true); // Makes 'from_codepoint' character points to 'to_codepoint' character. Currently needs to be called AFTER fonts have been built. IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 13130a242870..dbc659d254b6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3885,19 +3885,19 @@ void ImFont::AddGlyph(const ImFontConfig* src, ImWchar codepoint, float x0, floa MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad); } -void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst) +void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) { IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. unsigned int index_size = (unsigned int)IndexLookup.Size; - if (dst < index_size && IndexLookup.Data[dst] == (ImU16)-1 && !overwrite_dst) // 'dst' already exists + if (from_codepoint < index_size && IndexLookup.Data[from_codepoint] == (ImU16)-1 && !overwrite_dst) // 'from_codepoint' already exists return; - if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op + if (to_codepoint >= index_size && from_codepoint >= index_size) // both 'from_codepoint' and 'to_codepoint' don't exist -> no-op return; - GrowIndex(dst + 1); - IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImU16)-1; - IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f; + GrowIndex(from_codepoint + 1); + IndexLookup[from_codepoint] = (to_codepoint < index_size) ? IndexLookup.Data[to_codepoint] : (ImU16)-1; + IndexAdvanceX[from_codepoint] = (to_codepoint < index_size) ? IndexAdvanceX.Data[to_codepoint] : 1.0f; } // Find glyph, return fallback if missing From b9ac32a0d5011db31f40f639f99b8db30a4848b6 Mon Sep 17 00:00:00 2001 From: tamas-rabel Date: Sun, 11 May 2025 23:04:44 +0100 Subject: [PATCH 389/716] Backends: DirectX12: Make sure texture sampling in the dx12 backend is not limited to the highest mip. (#8631) --- backends/imgui_impl_dx12.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 84ec37f494eb..a373e8eec4cf 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -499,7 +499,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; staticSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; staticSampler.MinLOD = 0.f; - staticSampler.MaxLOD = 0.f; + staticSampler.MaxLOD = D3D12_FLOAT32_MAX; staticSampler.ShaderRegister = 0; staticSampler.RegisterSpace = 0; staticSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; From 4a6ba9539216c5cd78696e4b90a665709aa275b9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 May 2025 19:19:23 +0200 Subject: [PATCH 390/716] Backends: SDL3: Comments (#6146) --- backends/imgui_impl_sdl3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index e4e64721a2f5..cacce7e10e79 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -782,7 +782,7 @@ void ImGui_ImplSDL3_NewFrame() if (w > 0 && h > 0) io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); - // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) + // Setup time step (we could also use SDL_GetTicksNS() available since SDL3) // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) static Uint64 frequency = SDL_GetPerformanceFrequency(); Uint64 current_time = SDL_GetPerformanceCounter(); From 08689c51a9c9ff9eea44b5bf0b0ae11242487d1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 13 May 2025 15:48:00 +0200 Subject: [PATCH 391/716] Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. # Conflicts: # backends/imgui_impl_sdl2.cpp # backends/imgui_impl_sdl3.cpp --- backends/imgui_impl_glfw.cpp | 5 ++++- backends/imgui_impl_sdl2.cpp | 16 +++++++++++++--- backends/imgui_impl_sdl3.cpp | 8 +++++++- docs/CHANGELOG.txt | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 6beb97f6c2e1..ba75699709b4 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -117,6 +117,7 @@ #ifndef _WIN32 #include // for usleep() #endif +#include // for snprintf() #ifdef __EMSCRIPTEN__ #include @@ -157,6 +158,7 @@ struct ImGui_ImplGlfw_Data ImVec2 LastValidMousePos; bool InstalledCallbacks; bool CallbacksChainForAllWindows; + char BackendPlatformName[32]; #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 const char* CanvasSelector; #endif @@ -593,8 +595,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw // Setup backend capabilities flags ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)(); + snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_glfw (%d)", GLFW_VERSION_COMBINED); io.BackendPlatformUserData = (void*)bd; - io.BackendPlatformName = "imgui_impl_glfw"; + io.BackendPlatformName = bd->BackendPlatformName; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index b2dacc48e309..3d82bc348b7f 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -109,6 +109,7 @@ // SDL #include #include +#include // for snprintf() #ifdef __APPLE__ #include #endif @@ -135,6 +136,7 @@ struct ImGui_ImplSDL2_Data SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; + char BackendPlatformName[40]; // Mouse handling Uint32 MouseWindowID; @@ -476,12 +478,20 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void IMGUI_CHECKVERSION(); IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); + // Obtain compiled and runtime versions + SDL_version ver_compiled; + SDL_version ver_runtime; + SDL_VERSION(&ver_compiled); + SDL_GetVersion(&ver_runtime); + // Setup backend capabilities flags ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)(); + snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl2 (%u.%u.%u, %u.%u.%u)", + ver_compiled.major, ver_compiled.minor, ver_compiled.patch, ver_runtime.major, ver_runtime.minor, ver_runtime.patch); io.BackendPlatformUserData = (void*)bd; - io.BackendPlatformName = "imgui_impl_sdl2"; - io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) - io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + io.BackendPlatformName = bd->BackendPlatformName; + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) bd->Window = window; bd->WindowID = SDL_GetWindowID(window); diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index cacce7e10e79..41511140c46f 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -69,6 +69,7 @@ // SDL #include +#include // for snprintf() #if defined(__APPLE__) #include #endif @@ -101,6 +102,7 @@ struct ImGui_ImplSDL3_Data SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; + char BackendPlatformName[40]; // IME handling SDL_Window* ImeWindow; @@ -465,10 +467,14 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!"); IM_UNUSED(sdl_gl_context); // Unused in this branch + const int ver_linked = SDL_GetVersion(); + // Setup backend capabilities flags ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)(); + snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl3 (%u.%u.%u; %u.%u.%u)", + SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, SDL_VERSIONNUM_MAJOR(ver_linked), SDL_VERSIONNUM_MINOR(ver_linked), SDL_VERSIONNUM_MICRO(ver_linked)); io.BackendPlatformUserData = (void*)bd; - io.BackendPlatformName = "imgui_impl_sdl3"; + io.BackendPlatformName = bd->BackendPlatformName; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4c6dfe706f93..197a97da451f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,7 @@ Other changes: - Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] +- Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative From 61242e2e6a9c58337faff50afe8298e113901720 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 May 2025 11:35:38 +0200 Subject: [PATCH 392/716] InputText: fixed cursor positioning issue using up/down keys on non-ASCII text. (#8635, #7925) Bug introduced in abd07f6d30736c00fba899d41043a78a5de0f765. Ref https://github.com/nothings/stb/issues/188 --- docs/CHANGELOG.txt | 2 ++ imgui.h | 2 +- imstb_textedit.h | 12 ++++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 197a97da451f..1d37496b5967 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,8 @@ Other changes: - The feature is unlikely to ever work properly when using a coarse clipper such as ImGuiListClipper. - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. +- InputText: fixed cursor positioning issue using up/down keys near end of lines while + editing non-ASCII text. (Regression from 1.91.2) (#8635, #7925) - Tables: fixed TableHeader() eager vertical clipping of text which may be noticeable with FramePadding.y was too small. (#6236) - Tables: fixed an assert when combining Tables, Frozen Rows, Clipper and BeginMultiSelect() diff --git a/imgui.h b/imgui.h index b9b8bf6adff2..633f9f6dc7d0 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19194 +#define IMGUI_VERSION_NUM 19195 #define IMGUI_HAS_TABLE /* diff --git a/imstb_textedit.h b/imstb_textedit.h index b7a761c85381..ecdc7d39d746 100644 --- a/imstb_textedit.h +++ b/imstb_textedit.h @@ -918,7 +918,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat state->cursor = start; STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); x = row.x0; - for (i=0; i < row.num_chars; ++i) { + for (i=0; i < row.num_chars; ) { float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE) @@ -927,7 +927,9 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat x += dx; if (x > goal_x) break; - state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + int next_cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + i += next_cursor - state->cursor; + state->cursor = next_cursor; } stb_textedit_clamp(str, state); @@ -980,7 +982,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat state->cursor = find.prev_first; STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor); x = row.x0; - for (i=0; i < row.num_chars; ++i) { + for (i=0; i < row.num_chars; ) { float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE) @@ -989,7 +991,9 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat x += dx; if (x > goal_x) break; - state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + int next_cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); + i += next_cursor - state->cursor; + state->cursor = next_cursor; } stb_textedit_clamp(str, state); From 5c3ac9333596374d08eddef1292a196948ecb223 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 May 2025 13:14:31 +0200 Subject: [PATCH 393/716] stb_textedit: minor edits to match PR submitted upstream. --- imstb_textedit.h | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/imstb_textedit.h b/imstb_textedit.h index ecdc7d39d746..f97a20747876 100644 --- a/imstb_textedit.h +++ b/imstb_textedit.h @@ -400,6 +400,16 @@ typedef struct #define IMSTB_TEXTEDIT_memmove memmove #endif +// [DEAR IMGUI] +// Functions must be implemented for UTF8 support +// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit. +// There is not necessarily a '[DEAR IMGUI]' at the usage sites. +#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX +#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(OBJ, IDX) ((IDX) - 1) +#endif +#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX +#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(OBJ, IDX) ((IDX) + 1) +#endif ///////////////////////////////////////////////////////////////////////////// // @@ -648,17 +658,6 @@ static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditSt } } -// [DEAR IMGUI] -// Functions must be implemented for UTF8 support -// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit. -// There is not necessarily a '[DEAR IMGUI]' at the usage sites. -#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX -#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1) -#endif -#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX -#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1) -#endif - #ifdef STB_TEXTEDIT_IS_SPACE static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx ) { @@ -920,6 +919,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat x = row.x0; for (i=0; i < row.num_chars; ) { float dx = STB_TEXTEDIT_GETWIDTH(str, start, i); + int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE) break; @@ -927,9 +927,8 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat x += dx; if (x > goal_x) break; - int next_cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); - i += next_cursor - state->cursor; - state->cursor = next_cursor; + i += next - state->cursor; + state->cursor = next; } stb_textedit_clamp(str, state); @@ -984,6 +983,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat x = row.x0; for (i=0; i < row.num_chars; ) { float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i); + int next = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); #ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE) break; @@ -991,9 +991,8 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat x += dx; if (x > goal_x) break; - int next_cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); - i += next_cursor - state->cursor; - state->cursor = next_cursor; + i += next - state->cursor; + state->cursor = next; } stb_textedit_clamp(str, state); From 1387d356aab85d8104fbb2837037fe5cd7783bf5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 May 2025 13:37:30 +0200 Subject: [PATCH 394/716] stb_textedit: subsequent fixes for next/prev word impl (not used by imgui) + PageUp/Home/End (no side effect but more correct) (#8635, #7925) --- imstb_textedit.h | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/imstb_textedit.h b/imstb_textedit.h index f97a20747876..56d9d1151a2b 100644 --- a/imstb_textedit.h +++ b/imstb_textedit.h @@ -667,9 +667,9 @@ static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx ) #ifndef STB_TEXTEDIT_MOVEWORDLEFT static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c ) { - --c; // always move at least one character - while( c >= 0 && !is_word_boundary( str, c ) ) - --c; + c = IMSTB_TEXTEDIT_GETPREVCHARINDEX( str, c ); // always move at least one character + while (c >= 0 && !is_word_boundary(str, c)) + c = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, c); if( c < 0 ) c = 0; @@ -683,9 +683,9 @@ static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c ) { const int len = STB_TEXTEDIT_STRINGLEN(str); - ++c; // always move at least one character + c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c); // always move at least one character while( c < len && !is_word_boundary( str, c ) ) - ++c; + c = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, c); if( c > len ) c = len; @@ -1005,8 +1005,13 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat // go to previous line // (we need to scan previous line the hard way. maybe we could expose this as a new API function?) prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0; - while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE) - --prev_scan; + while (prev_scan > 0) + { + int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, prev_scan); + if (STB_TEXTEDIT_GETCHAR(str, prev) == STB_TEXTEDIT_NEWLINE) + break; + prev_scan = prev; + } find.first_char = find.prev_first; find.prev_first = prev_scan; } @@ -1085,7 +1090,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat if (state->single_line) state->cursor = 0; else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) - --state->cursor; + state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor); state->has_preferred_x = 0; break; @@ -1097,9 +1102,9 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat stb_textedit_clamp(str, state); stb_textedit_move_to_first(state); if (state->single_line) - state->cursor = n; + state->cursor = n; else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) - ++state->cursor; + state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); state->has_preferred_x = 0; break; } @@ -1113,7 +1118,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat if (state->single_line) state->cursor = 0; else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE) - --state->cursor; + state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor); state->select_end = state->cursor; state->has_preferred_x = 0; break; @@ -1128,7 +1133,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat if (state->single_line) state->cursor = n; else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE) - ++state->cursor; + state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor); state->select_end = state->cursor; state->has_preferred_x = 0; break; From 4e487cfa9985b8db8430096d283cf2763b0507d2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 May 2025 14:05:19 +0200 Subject: [PATCH 395/716] stb_textedit: subsequent comments to match ocornut/stb branch. (#8635, #7925) --- imstb_textedit.h | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/imstb_textedit.h b/imstb_textedit.h index 56d9d1151a2b..33eef7095b5d 100644 --- a/imstb_textedit.h +++ b/imstb_textedit.h @@ -141,6 +141,7 @@ // with previous char) // STB_TEXTEDIT_KEYTOTEXT(k) maps a keyboard input to an insertable character // (return type is int, -1 means not valid to insert) +// (not supported if you want to use UTF-8, see below) // STB_TEXTEDIT_GETCHAR(obj,i) returns the i'th character of obj, 0-based // STB_TEXTEDIT_NEWLINE the character returned by _GETCHAR() we recognize // as manually wordwrapping for end-of-line positioning @@ -178,6 +179,13 @@ // STB_TEXTEDIT_K_TEXTSTART2 secondary keyboard input to move cursor to start of text // STB_TEXTEDIT_K_TEXTEND2 secondary keyboard input to move cursor to end of text // +// To support UTF-8: +// +// STB_TEXTEDIT_GETPREVCHARINDEX returns index of previous character +// STB_TEXTEDIT_GETNEXTCHARINDEX returns index of next character +// Do NOT define STB_TEXTEDIT_KEYTOTEXT. +// Instead, call stb_textedit_text() directly for text contents. +// // Keyboard input must be encoded as a single integer value; e.g. a character code // and some bitflags that represent shift states. to simplify the interface, SHIFT must // be a bitflag, so we can test the shifted state of cursor movements to allow selection, @@ -250,8 +258,10 @@ // if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are // transformed into text and stb_textedit_text() is automatically called. // -// text: [DEAR IMGUI] added 2024-09 -// call this to text inputs sent to the textfield. +// text: (added 2025) +// call this to directly send text input the textfield, which is required +// for UTF-8 support, because stb_textedit_key() + STB_TEXTEDIT_KEYTOTEXT() +// cannot infer text length. // // // When rendering, you can read the cursor position and selection state from @@ -738,6 +748,7 @@ static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditS #define STB_TEXTEDIT_KEYTYPE int #endif +// API key: process text input // [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility. static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len) { @@ -752,8 +763,7 @@ static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* sta state->cursor += text_len; state->has_preferred_x = 0; } - } - else { + } else { stb_textedit_delete_selection(str, state); // implicitly clamps if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) { stb_text_makeundo_insert(state, state->cursor, text_len); @@ -770,6 +780,7 @@ static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *stat switch (key) { default: { #ifdef STB_TEXTEDIT_KEYTOTEXT + // This is not suitable for UTF-8 support. int c = STB_TEXTEDIT_KEYTOTEXT(key); if (c > 0) { IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c; From 2fd474132d4af57c61b3474af0fc9fd7bbe12f93 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 14 May 2025 16:53:36 +0200 Subject: [PATCH 396/716] Update pull_request_template.md --- .github/pull_request_template.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 638545bd6d3f..796ec0b9e165 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,5 +2,7 @@ 1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md) -2. Clear this template before submitting your PR. +2. Make sure you're using a special branch just for this pull request. (Sometimes people unknowingly use a default branch, then later update that branch, which updates the pull request with the other changes if it hasn't been merged yet.) + +3. Clear this template before submitting your PR. From 2df9e9b103d2d2c5d14bddf5ecc8099c248b2f03 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Wed, 14 May 2025 17:27:26 +0200 Subject: [PATCH 397/716] Examples: Apple: add Makefile for example_apple_metal, example_apple_opengl2. (#8637) - Works only for macOS: use XCode for iOS - It will produce a raw exe. It will not a produce an macOS application bundle (i.e a folder that includes exe and resources). To get app bundles, use the XCode project. - An adjustment was required in main.mm (for macOS only), to ensure that the exe can run without any plist or storyboard under macOS --- examples/example_apple_metal/Makefile | 25 +++++++++++++++++++++++++ examples/example_apple_metal/main.mm | 15 +++++++++++++-- examples/example_apple_opengl2/Makefile | 25 +++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 examples/example_apple_metal/Makefile create mode 100644 examples/example_apple_opengl2/Makefile diff --git a/examples/example_apple_metal/Makefile b/examples/example_apple_metal/Makefile new file mode 100644 index 000000000000..a15fc431ca4a --- /dev/null +++ b/examples/example_apple_metal/Makefile @@ -0,0 +1,25 @@ +# Makefile for example_apple_metal, for macOS only (**not iOS**) +TARGET := example_apple_metal +CXX := clang++ +CXXFLAGS := -std=c++17 -ObjC++ -fobjc-arc -Wall -Wextra \ + -I../../ \ + -I../../backends +FRAMEWORKS := -framework AppKit -framework Metal -framework MetalKit -framework QuartzCore -framework GameController +IMGUI_SRC := ../../imgui.cpp ../../imgui_draw.cpp ../../imgui_demo.cpp \ + ../../imgui_tables.cpp ../../imgui_widgets.cpp +BACKENDS := ../../backends/imgui_impl_metal.mm ../../backends/imgui_impl_osx.mm +SRC := main.mm $(IMGUI_SRC) $(BACKENDS) + +.PHONY: all run clean + + +all: $(TARGET) + +$(TARGET): $(SRC) + $(CXX) $(CXXFLAGS) $^ $(FRAMEWORKS) -o $@ + +run: all + ./$(TARGET) + +clean: + rm -f $(TARGET) *.o diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 830f1aed33b6..3ad7cff4685a 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -319,9 +319,20 @@ -(BOOL)application:(UIApplication *)application #if TARGET_OS_OSX -int main(int argc, const char * argv[]) +int main(int, const char**) { - return NSApplicationMain(argc, argv); + @autoreleasepool + { + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + AppDelegate *appDelegate = [[AppDelegate alloc] init]; // creates window + [NSApp setDelegate:appDelegate]; + + [NSApp activateIgnoringOtherApps:YES]; + [NSApp run]; + } + return 0; } #else diff --git a/examples/example_apple_opengl2/Makefile b/examples/example_apple_opengl2/Makefile new file mode 100644 index 000000000000..02b4fba5806f --- /dev/null +++ b/examples/example_apple_opengl2/Makefile @@ -0,0 +1,25 @@ +IMGUI_DIR = ../../ +CXX = clang++ +CXXFLAGS = -std=c++17 -ObjC++ -Wall -Wextra -g -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +FRAMEWORKS = -framework Cocoa -framework OpenGL -framework GameController + +SOURCES = \ + main.mm \ + $(IMGUI_DIR)/backends/imgui_impl_osx.mm \ + $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp \ + $(IMGUI_DIR)/imgui.cpp \ + $(IMGUI_DIR)/imgui_draw.cpp \ + $(IMGUI_DIR)/imgui_demo.cpp \ + $(IMGUI_DIR)/imgui_tables.cpp \ + $(IMGUI_DIR)/imgui_widgets.cpp + +TARGET = imgui_example_apple_opengl2 + +all: $(TARGET) + +$(TARGET): $(SOURCES) + $(CXX) $(CXXFLAGS) $(SOURCES) -o imgui_example_apple_opengl2 $(FRAMEWORKS) + +clean: + rm -f $(TARGET) + rm -rf $(TARGET).dSYM From b5a73033ab54009186bb8e4c711e03e6b939cb91 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 14 May 2025 18:05:23 +0200 Subject: [PATCH 398/716] Examples: Apple: Amend build scripts and gitignore, fix misc OSX warnings. (#8637) # Conflicts: # backends/imgui_impl_metal.mm --- .gitignore | 4 +++- backends/imgui_impl_osx.mm | 2 +- docs/CHANGELOG.txt | 1 + examples/example_apple_metal/Makefile | 28 ++++++++++------------ examples/example_apple_opengl2/Makefile | 32 +++++++++++-------------- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 5a5c8cda371c..6cadd63b48d1 100644 --- a/.gitignore +++ b/.gitignore @@ -32,9 +32,10 @@ JSON/ ## Commonly used CMake directories build*/ -## Xcode artifacts +## Xcode & macOS artifacts project.xcworkspace xcuserdata +examples/*/*.dSYM ## Emscripten artifacts examples/*.o.tmp @@ -54,6 +55,7 @@ cmake-build-* ## Unix executables from our example Makefiles examples/example_apple_metal/example_apple_metal +examples/example_apple_opengl2/example_apple_opengl2 examples/example_glfw_metal/example_glfw_metal examples/example_glfw_opengl2/example_glfw_opengl2 examples/example_glfw_opengl3/example_glfw_opengl3 diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 558ed9f2ade3..32e562472dd5 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -477,7 +477,7 @@ bool ImGui_ImplOSX_Init(NSView* view) [view addSubview:bd->KeyEventResponder]; ImGui_ImplOSX_AddTrackingArea(view); - platform_io.Platform_SetImeDataFn = [](ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void + platform_io.Platform_SetImeDataFn = [](ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data) -> void { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); if (data->WantVisible) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1d37496b5967..5f957e7f0f2b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -130,6 +130,7 @@ Other changes: - Backends: Vulkan: fixed validation errors in window create/resize helpers used by examples and by multi-viewports implementation, which would typically trigger errors while detaching secondary viewports. (#8600, #8176) [@ChrisTom-94] +- Examples: Apple+Metal, Apple+OpenGL: add Makefile (CLion opens them nicely). (#8637) [@pthom] - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] diff --git a/examples/example_apple_metal/Makefile b/examples/example_apple_metal/Makefile index a15fc431ca4a..9412c9b53316 100644 --- a/examples/example_apple_metal/Makefile +++ b/examples/example_apple_metal/Makefile @@ -1,25 +1,21 @@ # Makefile for example_apple_metal, for macOS only (**not iOS**) -TARGET := example_apple_metal -CXX := clang++ -CXXFLAGS := -std=c++17 -ObjC++ -fobjc-arc -Wall -Wextra \ - -I../../ \ - -I../../backends -FRAMEWORKS := -framework AppKit -framework Metal -framework MetalKit -framework QuartzCore -framework GameController -IMGUI_SRC := ../../imgui.cpp ../../imgui_draw.cpp ../../imgui_demo.cpp \ - ../../imgui_tables.cpp ../../imgui_widgets.cpp -BACKENDS := ../../backends/imgui_impl_metal.mm ../../backends/imgui_impl_osx.mm -SRC := main.mm $(IMGUI_SRC) $(BACKENDS) +CXX = clang++ +EXE = example_apple_metal +IMGUI_DIR = ../../ +SOURCES = main.mm +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_metal.mm -.PHONY: all run clean +CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +FRAMEWORKS = -framework AppKit -framework Metal -framework MetalKit -framework QuartzCore -framework GameController +all: $(EXE) -all: $(TARGET) - -$(TARGET): $(SRC) +$(EXE): $(SOURCES) $(CXX) $(CXXFLAGS) $^ $(FRAMEWORKS) -o $@ run: all - ./$(TARGET) + ./$(EXE) clean: - rm -f $(TARGET) *.o + rm -f $(EXE) *.o diff --git a/examples/example_apple_opengl2/Makefile b/examples/example_apple_opengl2/Makefile index 02b4fba5806f..4ad5fa6924a5 100644 --- a/examples/example_apple_opengl2/Makefile +++ b/examples/example_apple_opengl2/Makefile @@ -1,25 +1,21 @@ -IMGUI_DIR = ../../ +# Makefile for example_apple_metal, for macOS only (**not iOS**) CXX = clang++ -CXXFLAGS = -std=c++17 -ObjC++ -Wall -Wextra -g -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -FRAMEWORKS = -framework Cocoa -framework OpenGL -framework GameController +EXE = example_apple_opengl2 +IMGUI_DIR = ../../ +SOURCES = main.mm +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp -SOURCES = \ - main.mm \ - $(IMGUI_DIR)/backends/imgui_impl_osx.mm \ - $(IMGUI_DIR)/backends/imgui_impl_opengl2.cpp \ - $(IMGUI_DIR)/imgui.cpp \ - $(IMGUI_DIR)/imgui_draw.cpp \ - $(IMGUI_DIR)/imgui_demo.cpp \ - $(IMGUI_DIR)/imgui_tables.cpp \ - $(IMGUI_DIR)/imgui_widgets.cpp +CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +FRAMEWORKS = -framework Cocoa -framework OpenGL -framework GameController -TARGET = imgui_example_apple_opengl2 +all: $(EXE) -all: $(TARGET) +$(EXE): $(SOURCES) + $(CXX) $(CXXFLAGS) $(SOURCES) -o $(EXE) $(FRAMEWORKS) -$(TARGET): $(SOURCES) - $(CXX) $(CXXFLAGS) $(SOURCES) -o imgui_example_apple_opengl2 $(FRAMEWORKS) +run: all + ./$(EXE) clean: - rm -f $(TARGET) - rm -rf $(TARGET).dSYM + rm -f $(EXE) *.o From 9361c35176e770dd3098039a9a8cbc900e7e68e8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 May 2025 15:36:42 +0200 Subject: [PATCH 399/716] Backends: SDL2, SDL3: maximum room for sanitizer to not be zealous. --- backends/imgui_impl_sdl2.cpp | 2 +- backends/imgui_impl_sdl3.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 3d82bc348b7f..fa2714bb907b 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -136,7 +136,7 @@ struct ImGui_ImplSDL2_Data SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; - char BackendPlatformName[40]; + char BackendPlatformName[48]; // Mouse handling Uint32 MouseWindowID; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 41511140c46f..58cc11c442b3 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -102,7 +102,7 @@ struct ImGui_ImplSDL3_Data SDL_Renderer* Renderer; Uint64 Time; char* ClipboardTextData; - char BackendPlatformName[40]; + char BackendPlatformName[48]; // IME handling SDL_Window* ImeWindow; From 6d939fcedc1f15313a3be782040b260c5fc29b4d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 May 2025 17:35:29 +0200 Subject: [PATCH 400/716] (Breaking) TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. (#1079, #8639) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 3 ++- imgui.h | 9 +++++---- imgui_demo.cpp | 6 +++--- imgui_internal.h | 2 +- imgui_widgets.cpp | 10 +++++----- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5f957e7f0f2b..628ccfce40b3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,6 +41,8 @@ HOW TO UPDATE? Breaking changes: +- TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent + for clarity. Kept inline redirection enum (will obsolete). (#1079, #8639) - Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() diff --git a/imgui.cpp b/imgui.cpp index cb36ac536c5c..9a39394caece 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,6 +431,7 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/05/15 (1.92.0) - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). - 2025/03/05 (1.91.9) - BeginMenu(): Internals: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238) - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); @@ -12801,7 +12802,7 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result) NavUpdateAnyRequestFlag(); } -// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere +// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsToParent void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, const ImGuiTreeNodeStackData* tree_node_data) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 633f9f6dc7d0..10198bb31a1e 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19195 +#define IMGUI_VERSION_NUM 19196 #define IMGUI_HAS_TABLE /* @@ -1211,7 +1211,7 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_SpanAllColumns = 1 << 14, // Frame will span all columns of its container table (label will still fit in current column) ImGuiTreeNodeFlags_LabelSpanAllColumns = 1 << 15, // Label will span all columns of its container table //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 16, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible - ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 17, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop) + ImGuiTreeNodeFlags_NavLeftJumpsToParent = 1 << 17, // Nav: left arrow moves back to parent. This is processed in TreePop() when there's an unfullfilled Left nav request remaining. ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog, // [EXPERIMENTAL] Draw lines connecting TreeNode hierarchy. Discuss in GitHub issue #2920. @@ -1221,8 +1221,9 @@ enum ImGuiTreeNodeFlags_ ImGuiTreeNodeFlags_DrawLinesToNodes = 1 << 20, // Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. Slower (for large trees). #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 - ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth,// Renamed in 1.90.7 + ImGuiTreeNodeFlags_NavLeftJumpsBackHere = ImGuiTreeNodeFlags_NavLeftJumpsToParent, // Renamed in 1.92.0 + ImGuiTreeNodeFlags_SpanTextWidth = ImGuiTreeNodeFlags_SpanLabelWidth, // Renamed in 1.90.7 + ImGuiTreeNodeFlags_AllowItemOverlap = ImGuiTreeNodeFlags_AllowOverlap, // Renamed in 1.89.7 #endif }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 091a5256932d..69018315c023 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2990,7 +2990,7 @@ static void DemoWindowWidgetsSelectionAndMultiSelect(ImGuiDemoWindowData* demo_d static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection) { ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; - tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent + tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Enable pressing left to jump to parent if (node->Childs.Size == 0) tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf; if (selection->Contains((ImGuiID)node->UID)) @@ -4012,7 +4012,7 @@ static void DemoWindowWidgetsTreeNodes() ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only."); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)"); - ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere); + ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsToParent", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsToParent); HelpMarker("Default option for DrawLinesXXX is stored in style.TreeLinesFlags"); ImGui::CheckboxFlags("ImGuiTreeNodeFlags_DrawLinesNone", &base_flags, ImGuiTreeNodeFlags_DrawLinesNone); @@ -9366,7 +9366,7 @@ struct ExampleAppPropertyEditor ImGui::PushID(node->UID); ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None; tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;// Standard opening mode as we are likely to want to add selection afterwards - tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support + tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Left arrow support tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines if (node == VisibleNode) diff --git a/imgui_internal.h b/imgui_internal.h index 996eb82a29dc..fb23c6cfba5b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1289,7 +1289,7 @@ struct ImGuiLastItemData }; // Store data emitted by TreeNode() for usage by TreePop() -// - To implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere: store the minimum amount of data +// - To implement ImGuiTreeNodeFlags_NavLeftJumpsToParent: store the minimum amount of data // which we can't infer in TreePop(), to perform the equivalent of NavApplyItemToResult(). // Only stored when the node is a potential candidate for landing on a Left arrow jump. struct ImGuiTreeNodeStackData diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1204a45990dd..f0108d12b763 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6681,17 +6681,17 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; g.LastItemData.DisplayRect = frame_bb; - // If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled: + // If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsToParent enabled: // Store data for the current depth to allow returning to this node from any child item. // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop(). - // It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle. + // It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsToParent by default or move it to ImGuiStyle. bool store_tree_node_stack_data = false; if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) flags |= g.Style.TreeLinesFlags; const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { - if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !g.NavIdIsAlive) + if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsToParent) && !g.NavIdIsAlive) if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) store_tree_node_stack_data = true; if (draw_tree_lines) @@ -6994,8 +6994,8 @@ void ImGui::TreePop() const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; IM_ASSERT(data->ID == window->IDStack.back()); - // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) - if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) + // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsToParent is enabled) + if (data->TreeFlags & ImGuiTreeNodeFlags_NavLeftJumpsToParent) if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, data); From d93d918eca6eaa361fd058218bea1498fca4e160 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 May 2025 17:38:45 +0200 Subject: [PATCH 401/716] (Breaking) Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4. (#3092) Amend e83fb46. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 1 + imgui.h | 6 +++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 628ccfce40b3..1bdce0ce5077 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,10 @@ Breaking changes: - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). (#1079, #8639) +- Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted + in 1.89.4 (March 2023). (#3092) + - PushAllowKeyboardFocus(bool tab_stop) --> PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); + - PopAllowKeyboardFocus() --> PopItemFlag(). - Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() diff --git a/imgui.cpp b/imgui.cpp index 9a39394caece..7f4c18c4c646 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -432,6 +432,7 @@ CODE You can read releases logs https://github.com/ocornut/imgui/releases for more details. - 2025/05/15 (1.92.0) - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). + - 2025/05/15 (1.92.0) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4. Use PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop)/PopItemFlag() instead. (#3092) - 2025/03/05 (1.91.9) - BeginMenu(): Internals: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238) - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); diff --git a/imgui.h b/imgui.h index 10198bb31a1e..688f9c5e986e 100644 --- a/imgui.h +++ b/imgui.h @@ -3668,11 +3668,11 @@ namespace ImGui IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); // OBSOLETED in 1.89.7 (from June 2023) IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item. - // OBSOLETED in 1.89.4 (from March 2023) - static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } - static inline void PopAllowKeyboardFocus() { PopItemFlag(); } // Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE) + //-- OBSOLETED in 1.89.4 (from March 2023) + //static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); } + //static inline void PopAllowKeyboardFocus() { PopItemFlag(); } //-- OBSOLETED in 1.89 (from August 2022) //IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). Refer to code in 1.91 if you want to grab a copy of this version. //-- OBSOLETED in 1.88 (from May 2022) From cdb5cbe6f8786ced227624a71bc8a677618e5327 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 May 2025 17:44:10 +0200 Subject: [PATCH 402/716] (Breaking) Commented out ImGuiListClipper::ForceDisplayRangeByIndices() which was obsoleted in 1.89.6. Amend ecb0aaa. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 1 + imgui.h | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1bdce0ce5077..384d0b26df01 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,9 @@ Breaking changes: in 1.89.4 (March 2023). (#3092) - PushAllowKeyboardFocus(bool tab_stop) --> PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); - PopAllowKeyboardFocus() --> PopItemFlag(). +- Commented out ImGuiListClipper::ForceDisplayRangeByIndices() which was obsoleted + in 1.89.6 (June 2023). + - ForceDisplayRangeByIndices() --> IncludeItemsByIndex() - Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() diff --git a/imgui.cpp b/imgui.cpp index 7f4c18c4c646..6150475b08f0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -433,6 +433,7 @@ CODE - 2025/05/15 (1.92.0) - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). - 2025/05/15 (1.92.0) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4. Use PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop)/PopItemFlag() instead. (#3092) + - 2025/05/15 (1.92.0) - Commented out ImGuiListClipper::ForceDisplayRangeByIndices() which was obsoleted in 1.89.6. Use ImGuiListClipper::IncludeItemsByIndex() instead. - 2025/03/05 (1.91.9) - BeginMenu(): Internals: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238) - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); diff --git a/imgui.h b/imgui.h index 688f9c5e986e..6794abedeb7d 100644 --- a/imgui.h +++ b/imgui.h @@ -2731,7 +2731,7 @@ struct ImGuiListClipper #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS inline void IncludeRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.9] - inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.6] + //inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.6] //inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] #endif }; From 10a0eb3e1c31b8b6b6595ce75e8d65ec984b2ff9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 May 2025 18:40:45 +0200 Subject: [PATCH 403/716] Alter windows min/max size logic to prioritize enforcing size_max bounds rather than size_min. Docking branch until now used the opposite, aka ImClamp(size_desired, size_min, ImMax(size_min, size_max));, will be standardized across branches. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 6150475b08f0..b5d6b802d9aa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6408,7 +6408,7 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont // Maximum window size is determined by the viewport size or monitor size ImVec2 size_min = CalcWindowMinSize(window); ImVec2 size_max = ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup)) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; - ImVec2 size_auto_fit = ImClamp(size_desired, size_min, size_max); + ImVec2 size_auto_fit = ImClamp(size_desired, ImMin(size_min, size_max), size_max); // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars, // we may need to compute/store three variants of size_auto_fit, for x/y/xy. From 415dddf0fac942647fc29ce3b9a02cfda89383e0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 May 2025 18:26:15 +0200 Subject: [PATCH 404/716] Tooltips: tooltips have a maximum size corresponding to host display/monitor size. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 384d0b26df01..48201acdf7a2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -93,6 +93,10 @@ Other changes: in a certain order. (#8595, #8250) - Tabs: fixes small issues with how "..." ellipsis moved depending on visibility of Close Button or Unsaved Document marker. (#8387) +- Tooltips: tooltips have a maximum size corresponding to host display/monitor size, + which mitigates edge case issues in multi-viewport scenarios where abnormally large + windows (e.g. determined programmatically) can lead to renderer backend trying to + create abnormally large framebuffers. - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index b5d6b802d9aa..6a4c37f41863 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6398,16 +6398,19 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y; ImVec2 size_pad = window->WindowPadding * 2.0f; ImVec2 size_desired = size_contents + size_pad + ImVec2(decoration_w_without_scrollbars, decoration_h_without_scrollbars); + + // Determine maximum window size + // Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction + ImVec2 size_max = ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup)) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; + if (window->Flags & ImGuiWindowFlags_Tooltip) { - // Tooltip always resize - return size_desired; + // Tooltip always resize (up to maximum size) + return ImMin(size_desired, size_max); } else { - // Maximum window size is determined by the viewport size or monitor size ImVec2 size_min = CalcWindowMinSize(window); - ImVec2 size_max = ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup)) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f; ImVec2 size_auto_fit = ImClamp(size_desired, ImMin(size_min, size_max), size_max); // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars, From 1ffa7a40ac02a9edbc04c31db574304dbc017dac Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 May 2025 17:31:58 +0200 Subject: [PATCH 405/716] TextLinkOpenURL(): added bool return value on click. (#8645, #8451, #7660) --- docs/CHANGELOG.txt | 1 + imgui.h | 2 +- imgui_widgets.cpp | 9 +++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 48201acdf7a2..4fbbeea92be3 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -97,6 +97,7 @@ Other changes: which mitigates edge case issues in multi-viewport scenarios where abnormally large windows (e.g. determined programmatically) can lead to renderer backend trying to create abnormally large framebuffers. +- TextLinkOpenURL(): added bool return value on click. (#8645, #8451, #7660) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.h b/imgui.h index 6794abedeb7d..f90e4dfc0597 100644 --- a/imgui.h +++ b/imgui.h @@ -559,7 +559,7 @@ namespace ImGui IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL); IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses IMGUI_API bool TextLink(const char* label); // hyperlink text button, return true when clicked - IMGUI_API void TextLinkOpenURL(const char* label, const char* url = NULL); // hyperlink text button, automatically open file/url when clicked + IMGUI_API bool TextLinkOpenURL(const char* label, const char* url = NULL); // hyperlink text button, automatically open file/url when clicked // Widgets: Images // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index f0108d12b763..b99e6e5c06c8 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1529,14 +1529,14 @@ bool ImGui::TextLink(const char* label) return pressed; } -void ImGui::TextLinkOpenURL(const char* label, const char* url) +bool ImGui::TextLinkOpenURL(const char* label, const char* url) { ImGuiContext& g = *GImGui; if (url == NULL) url = label; - if (TextLink(label)) - if (g.PlatformIO.Platform_OpenInShellFn != NULL) - g.PlatformIO.Platform_OpenInShellFn(&g, url); + bool pressed = TextLink(label); + if (pressed && g.PlatformIO.Platform_OpenInShellFn != NULL) + g.PlatformIO.Platform_OpenInShellFn(&g, url); SetItemTooltip(LocalizeGetMsg(ImGuiLocKey_OpenLink_s), url); // It is more reassuring for user to _always_ display URL when we same as label if (BeginPopupContextItem()) { @@ -1544,6 +1544,7 @@ void ImGui::TextLinkOpenURL(const char* label, const char* url) SetClipboardText(url); EndPopup(); } + return pressed; } //------------------------------------------------------------------------- From 143924bbf3eb5aa548711dd2e5fbaf5822772cf0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 May 2025 17:53:17 +0200 Subject: [PATCH 406/716] Image(), ImageWithBg(): added extra comments. (#8131, #8238) --- imgui.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index f90e4dfc0597..f4b692ab25b6 100644 --- a/imgui.h +++ b/imgui.h @@ -566,6 +566,7 @@ namespace ImGui // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. + // - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by the ImageWithBg() function. IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1)); IMGUI_API void ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); @@ -3649,7 +3650,7 @@ struct ImGuiPlatformImeData namespace ImGui { // OBSOLETED in 1.91.9 (from February 2025) - IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- border_col was removed in favor of ImGuiCol_ImageBorder. + IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. // OBSOLETED in 1.91.0 (from July 2024) static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } static inline void PopButtonRepeat() { PopItemFlag(); } From 5f0acadf7db1b6d469f0771284e2e3f7818443ce Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 May 2025 18:06:12 +0200 Subject: [PATCH 407/716] RenderTextEllipsis() added breaking comments. --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4fbbeea92be3..f6207965e06b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,7 +51,9 @@ Breaking changes: in 1.89.6 (June 2023). - ForceDisplayRangeByIndices() --> IncludeItemsByIndex() - Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] - - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() + - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() +- Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly + preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387) Other changes: diff --git a/imgui.cpp b/imgui.cpp index 6a4c37f41863..16632d8daeb1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -435,6 +435,7 @@ CODE - 2025/05/15 (1.92.0) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4. Use PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop)/PopItemFlag() instead. (#3092) - 2025/05/15 (1.92.0) - Commented out ImGuiListClipper::ForceDisplayRangeByIndices() which was obsoleted in 1.89.6. Use ImGuiListClipper::IncludeItemsByIndex() instead. - 2025/03/05 (1.91.9) - BeginMenu(): Internals: reworked mangling of menu windows to use "###Menu_00" etc. instead of "##Menu_00", allowing them to also store the menu name before it. This shouldn't affect code unless directly accessing menu window from their mangled name. + - 2025/04/16 (1.91.9) - Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387) - 2025/02/27 (1.91.9) - Image(): removed 'tint_col' and 'border_col' parameter from Image() function. Added ImageWithBg() replacement. (#8131, #8238) - old: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1), ImVec4 tint_col = (1,1,1,1), ImVec4 border_col = (0,0,0,0)); - new: void Image (ImTextureID tex_id, ImVec2 image_size, ImVec2 uv0 = (0,0), ImVec2 uv1 = (1,1)); @@ -3696,6 +3697,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons // Another overly complex function until we reorganize everything into a nice all-in-one helper. // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) from 'ellipsis_max_x' which may be beyond it. // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. +// (BREAKING) On 2025/04/16 we removed the 'float clip_max_x' parameters which was preceeding 'float ellipsis_max' and was the same value for 99% of users. void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) { ImGuiContext& g = *GImGui; From 407a0b972eac6166095d2b5b5b0896bad6e9687a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 18:10:42 +0100 Subject: [PATCH 408/716] (Breaking) Fonts: CalcWordWrapPositionA() -> CalcWordWrapPosition(), takes size instead of scale. This will be needed for upcoming changes. --- docs/CHANGELOG.txt | 10 ++++++++-- imgui.cpp | 4 ++++ imgui.h | 8 ++++++-- imgui_draw.cpp | 13 +++++++------ 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f6207965e06b..f45fa178cd08 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,12 @@ Breaking changes: - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). (#1079, #8639) +- Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition(): + - old: const char* CalcWordWrapPositionA(float scale, const char* text, ....); + - new: const char* CalcWordWrapPosition (float size, const char* text, ....); + The leading 'float scale' parameters was changed to 'float size'. + This was necessary as 'scale' is assuming standard font size which is a concept we aim to + eliminate in an upcoming update. Kept inline redirection function. - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4 (March 2023). (#3092) - PushAllowKeyboardFocus(bool tab_stop) --> PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); @@ -51,7 +57,7 @@ Breaking changes: in 1.89.6 (June 2023). - ForceDisplayRangeByIndices() --> IncludeItemsByIndex() - Backends: SDL3: Fixed casing typo in function name: (#8509, #8163, #7998, #7988) [@puugz] - - Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData() + - Imgui_ImplSDLGPU3_PrepareDrawData() --> ImGui_ImplSDLGPU3_PrepareDrawData() - Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387) @@ -109,7 +115,7 @@ Other changes: - Fonts: reworked text ellipsis logic to ensure a "..." is always displayed instead of a single character. (#7024) - Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) -- Fonts: fixed CalcWordWrapPositionA() fallback when width is too small to wrap: +- Fonts: fixed CalcWordWrapPosition() fallback when width is too small to wrap: would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) diff --git a/imgui.cpp b/imgui.cpp index 16632d8daeb1..30263bac6499 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -431,6 +431,10 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/05/23 (1.92.0) - Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition() + - old: const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, ....); + - new: const char* ImFont::CalcWordWrapPosition (float size, const char* text, ....); + The leading 'float scale' parameters was changed to 'float size'. This was necessary as 'scale' is assuming standard font size which is a concept we aim to eliminate in an upcoming update. Kept inline redirection function. - 2025/05/15 (1.92.0) - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). - 2025/05/15 (1.92.0) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4. Use PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop)/PopItemFlag() instead. (#3092) - 2025/05/15 (1.92.0) - Commented out ImGuiListClipper::ForceDisplayRangeByIndices() which was obsoleted in 1.89.6. Use ImGuiListClipper::IncludeItemsByIndex() instead. diff --git a/imgui.h b/imgui.h index f4b692ab25b6..8e0e09b2517f 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19196 +#define IMGUI_VERSION_NUM 19197 #define IMGUI_HAS_TABLE /* @@ -3533,10 +3533,14 @@ struct ImFont // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 - IMGUI_API const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width); + IMGUI_API const char* CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(FontSize * scale, text, text_end, wrap_width); } +#endif + // [Internal] Don't use! IMGUI_API void BuildLookupTable(); IMGUI_API void ClearOutputData(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dbc659d254b6..78b0e152effa 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3936,7 +3936,7 @@ static inline const char* CalcWordWrapNextLineStartA(const char* text, const cha // Simple word-wrapping for English, not full-featured. Please submit failing cases! // This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) -const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) +const char* ImFont::CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width) { // For references, possible wrap point marked with ^ // "aaa bbb, ccc,ddd. eee fff. ggg!" @@ -3952,6 +3952,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c float line_width = 0.0f; float word_width = 0.0f; float blank_width = 0.0f; + const float scale = size / FontSize; wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters const char* word_end = text; @@ -4055,7 +4056,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) - word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width); + word_wrap_eol = CalcWordWrapPosition(size, s, text_end, wrap_width - line_width); if (s >= word_wrap_eol) { @@ -4175,10 +4176,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im const char* line_end = (const char*)ImMemchr(s, '\n', text_end - s); if (word_wrap_enabled) { - // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA(). - // If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both. + // FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPosition(). + // If the specs for CalcWordWrapPosition() were reworked to optionally return on \n we could combine both. // However it is still better than nothing performing the fast-forward! - s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width); + s = CalcWordWrapPosition(size, s, line_end ? line_end : text_end, wrap_width); s = CalcWordWrapNextLineStartA(s, text_end); } else @@ -4223,7 +4224,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im { // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature. if (!word_wrap_eol) - word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - origin_x)); + word_wrap_eol = CalcWordWrapPosition(size, s, text_end, wrap_width - (x - origin_x)); if (s >= word_wrap_eol) { From 77f1d3b317c400c34ee02fe9a5354d0d757b55ca Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 19:32:28 +0200 Subject: [PATCH 409/716] Refactor: move SetCurrentFont(), PushFont(), PopFont() to a section. --- imgui.cpp | 121 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 68 insertions(+), 53 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 30263bac6499..2332073a2c21 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -77,6 +77,7 @@ CODE // [SECTION] RENDER HELPERS // [SECTION] INITIALIZATION, SHUTDOWN // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) +// [SECTION] FONTS // [SECTION] ID STACK // [SECTION] INPUTS // [SECTION] ERROR CHECKING, STATE RECOVERY @@ -1268,6 +1269,7 @@ static void UpdateMouseWheel(); static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); // Misc +static void UpdateFontsNewFrame(); static void UpdateSettings(); static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static void RenderWindowOuterBorders(ImGuiWindow* window); @@ -5218,10 +5220,8 @@ void ImGui::NewFrame() UpdateViewportsNewFrame(); // Setup current font and draw list shared data - g.IO.Fonts->Locked = true; SetupDrawListSharedData(); - SetCurrentFont(GetDefaultFont()); - IM_ASSERT(g.Font->IsLoaded()); + UpdateFontsNewFrame(); // Mark rendering data as invalid to prevent user who may have a handle on it to use it. for (ImGuiViewportP* viewport : g.Viewports) @@ -7872,56 +7872,6 @@ void ImGui::End() SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window); } -// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. -void ImGui::SetCurrentFont(ImFont* font) -{ - ImGuiContext& g = *GImGui; - IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? - IM_ASSERT(font->Scale > 0.0f); - g.Font = font; - g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); - g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; - g.FontScale = g.FontSize / g.Font->FontSize; - - ImFontAtlas* atlas = g.Font->ContainerAtlas; - g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; - g.DrawListSharedData.TexUvLines = atlas->TexUvLines; - g.DrawListSharedData.Font = g.Font; - g.DrawListSharedData.FontSize = g.FontSize; - g.DrawListSharedData.FontScale = g.FontScale; -} - -// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authoritative against window-local ImDrawList. -// - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls. -// - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... -// - Some code paths never really fully worked with multiple atlas textures. -// - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() -// the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem -// because we have a concrete need and a test bed for multiple atlas textures. -void ImGui::PushFont(ImFont* font) -{ - ImGuiContext& g = *GImGui; - if (font == NULL) - font = GetDefaultFont(); - g.FontStack.push_back(font); - SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); -} - -void ImGui::PopFont() -{ - ImGuiContext& g = *GImGui; - if (g.FontStack.Size <= 0) - { - IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); - return; - } - g.FontStack.pop_back(); - ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); - SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); -} - void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) { ImGuiContext& g = *GImGui; @@ -8546,6 +8496,71 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); } +//----------------------------------------------------------------------------- +// [SECTION] FONTS +//----------------------------------------------------------------------------- +// Most of the relevant font logic is in imgui_draw.cpp. +// Those are high-level support functions. +//----------------------------------------------------------------------------- + +void ImGui::UpdateFontsNewFrame() +{ + ImGuiContext& g = *GImGui; + g.IO.Fonts->Locked = true; + SetCurrentFont(GetDefaultFont()); + IM_ASSERT(g.Font->IsLoaded()); +} + +// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. +void ImGui::SetCurrentFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.Font = font; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); + g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + g.FontScale = g.FontSize / g.Font->FontSize; + + ImFontAtlas* atlas = g.Font->ContainerAtlas; + g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; + g.DrawListSharedData.TexUvLines = atlas->TexUvLines; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; + g.DrawListSharedData.FontScale = g.FontScale; +} + +// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authoritative against window-local ImDrawList. +// - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls. +// - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... +// - Some code paths never really fully worked with multiple atlas textures. +// - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() +// the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem +// because we have a concrete need and a test bed for multiple atlas textures. +void ImGui::PushFont(ImFont* font) +{ + ImGuiContext& g = *GImGui; + if (font == NULL) + font = GetDefaultFont(); + g.FontStack.push_back(font); + SetCurrentFont(font); + g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); +} + +void ImGui::PopFont() +{ + ImGuiContext& g = *GImGui; + if (g.FontStack.Size <= 0) + { + IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); + return; + } + g.FontStack.pop_back(); + ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); + SetCurrentFont(font); + g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); +} + //----------------------------------------------------------------------------- // [SECTION] ID STACK //----------------------------------------------------------------------------- From 87a6443c5bc6297f18cbbb2712db2dc28983d23f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 May 2025 20:47:50 +0200 Subject: [PATCH 410/716] Scroll: fixed contents size, scrollbar visibility and scrolling reet issue with abnormally large contents ranges. (#3609, #8215) --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 10 +++++----- imgui_internal.h | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f45fa178cd08..4b123e59aca7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -106,6 +106,8 @@ Other changes: windows (e.g. determined programmatically) can lead to renderer backend trying to create abnormally large framebuffers. - TextLinkOpenURL(): added bool return value on click. (#8645, #8451, #7660) +- Scroll: fixed contents size, scrollbar visibility and scrolling resetting issues + with abnormally large contents ranges. (#3609, #8215) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index 2332073a2c21..4e85502bec54 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6390,10 +6390,10 @@ static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_cur return; } - content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_TRUNC(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); - content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_TRUNC(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); - content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_TRUNC(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x); - content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_TRUNC(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y); + content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : ImTrunc64(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x); + content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : ImTrunc64(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y); + content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : ImTrunc64(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x); + content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : ImTrunc64(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y); } static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents) @@ -11166,7 +11166,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window) } scroll[axis] = scroll_target - center_ratio * (window->SizeFull[axis] - decoration_size[axis]); } - scroll[axis] = IM_ROUND(ImMax(scroll[axis], 0.0f)); + scroll[axis] = ImRound64(ImMax(scroll[axis], 0.0f)); if (!window->Collapsed && !window->SkipItems) scroll[axis] = ImMin(scroll[axis], window->ScrollMax[axis]); } diff --git a/imgui_internal.h b/imgui_internal.h index fb23c6cfba5b..ca250e0b7caa 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -496,6 +496,8 @@ static inline float ImTrunc(float f) static inline ImVec2 ImTrunc(const ImVec2& v) { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); } static inline float ImFloor(float f) { return (float)((f >= 0 || (float)(int)f == f) ? (int)f : (int)f - 1); } // Decent replacement for floorf() static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2(ImFloor(v.x), ImFloor(v.y)); } +static inline float ImTrunc64(float f) { return (float)(ImS64)(f); } +static inline float ImRound64(float f) { return (float)(ImS64)(f + 0.5f); } static inline int ImModPositive(int a, int b) { return (a + b) % b; } static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; } static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } From c53c9a8644e05a9e4a0573896eb79d5aeaa354c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 May 2025 21:11:23 +0200 Subject: [PATCH 411/716] Clipper: further mitigation/improvements for abnormally large contents ranges (larger than e.g. 2^31). (#3609, #8215) --- docs/CHANGELOG.txt | 1 + imgui.cpp | 11 +++++++++-- imgui.h | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4b123e59aca7..8fd49b525369 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -108,6 +108,7 @@ Other changes: - TextLinkOpenURL(): added bool return value on click. (#8645, #8451, #7660) - Scroll: fixed contents size, scrollbar visibility and scrolling resetting issues with abnormally large contents ranges. (#3609, #8215) +- Clipper: some mitigation/improvements for abnormally large contents ranges. (#3609, #8215) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) - Error Handling: added better error report and recovery for extraneous diff --git a/imgui.cpp b/imgui.cpp index 4e85502bec54..fb49662922ea 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3195,10 +3195,17 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) if (table) IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y); - clipper->ItemsHeight = (window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart); - bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); + bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision((float)clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); if (affected_by_floating_point_precision) + { + // Mitigation/hack for very large range: assume last time height constitute line height. clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries. + window->DC.CursorPos.y = (float)(clipper->StartPosY + clipper->ItemsHeight); + } + else + { + clipper->ItemsHeight = (float)(window->DC.CursorPos.y - clipper->StartPosY) / (float)(clipper->DisplayEnd - clipper->DisplayStart); + } if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode. return false; IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); diff --git a/imgui.h b/imgui.h index 8e0e09b2517f..6d062c190cf2 100644 --- a/imgui.h +++ b/imgui.h @@ -2708,7 +2708,7 @@ struct ImGuiListClipper int DisplayEnd; // End of items to display (exclusive) int ItemsCount; // [Internal] Number of items float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it - float StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed + double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows. void* TempData; // [Internal] Internal data From 19289d587a3a7a13c4ca799dbf2108c2a5bb4935 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 May 2025 21:33:09 +0200 Subject: [PATCH 412/716] Nav: fixed scroll fallback (when there are no interactive widgets to jump to) not being enabled on windows with menu or title bar. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8fd49b525369..92df7b4f65c2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -111,6 +111,8 @@ Other changes: - Clipper: some mitigation/improvements for abnormally large contents ranges. (#3609, #8215) - Nav: fixed assertion when holding gamepad FaceLeft/West button to open CTRL+Tab windowing + pressing a keyboard key. (#8525) +- Nav: fixed scroll fallback (when there are no interactive widgets to jump to) not + being enabled on windows with menu or title bar. - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) - Error Handling: added better error report and recovery when calling EndFrame() diff --git a/imgui.cpp b/imgui.cpp index fb49662922ea..36d2e976ebc1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -13598,7 +13598,7 @@ static float ImGui::NavUpdatePageUpPageDown() if (g.NavLayer != ImGuiNavLayer_Main) NavRestoreLayer(ImGuiNavLayer_Main); - if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavWindowHasScrollY) + if ((window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Main)) == 0 && window->DC.NavWindowHasScrollY) { // Fallback manual-scroll when window has no navigable item if (IsKeyPressed(ImGuiKey_PageUp, ImGuiInputFlags_Repeat, ImGuiKeyOwner_NoOwner)) From c3a3a39e92adaf64272c5c3542844852a52d0ec6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 May 2025 21:46:33 +0200 Subject: [PATCH 413/716] Nav: fixed abnormal clipping disable over large ranges, could lead to stall. (#3841, #1725) Amend 93cccd27f --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 92df7b4f65c2..1f03f7936a0b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -113,6 +113,8 @@ Other changes: CTRL+Tab windowing + pressing a keyboard key. (#8525) - Nav: fixed scroll fallback (when there are no interactive widgets to jump to) not being enabled on windows with menu or title bar. +- Nav: fixed an issue handling PageUp/PageDown on windows with abnormally large contents + range which could lead to clipper requesting very large ranges. - Error Handling: added better error report and recovery for extraneous EndPopup() call. (#1651, #8499) - Error Handling: added better error report and recovery when calling EndFrame() diff --git a/imgui.cpp b/imgui.cpp index 36d2e976ebc1..419098b8069f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3229,7 +3229,10 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper) // Add range selected to be included for navigation const bool is_nav_request = (g.NavMoveScoringItems && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav); if (is_nav_request) + { + data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringRect.Min.y, g.NavScoringRect.Max.y, 0, 0)); data->Ranges.push_back(ImGuiListClipperRange::FromPositions(g.NavScoringNoClipRect.Min.y, g.NavScoringNoClipRect.Max.y, 0, 0)); + } if (is_nav_request && (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) && g.NavTabbingDir == -1) data->Ranges.push_back(ImGuiListClipperRange::FromIndices(clipper->ItemsCount - 1, clipper->ItemsCount)); @@ -13379,7 +13382,7 @@ void ImGui::NavUpdateCreateMoveRequest() //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] } g.NavScoringRect = scoring_rect; - g.NavScoringNoClipRect.Add(scoring_rect); + //g.NavScoringNoClipRect.Add(scoring_rect); } void ImGui::NavUpdateCreateTabbingRequest() From e6913f58b90f9eaf034fab5b576ca8ef6bd80aa7 Mon Sep 17 00:00:00 2001 From: Romain Moret Date: Mon, 26 May 2025 19:02:18 +0200 Subject: [PATCH 414/716] imgui_freetype: Update lunasvg API to support v3.0+ (#8656, #6842, #6591) --- docs/CHANGELOG.txt | 1 + misc/freetype/imgui_freetype.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1f03f7936a0b..aaf219a6ec75 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -268,6 +268,7 @@ Other changes: - Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) - Debug Tools: Tweaked layout of ID Stack Tool and always display full path. (#4631) +- imgui_freetype: update lunasvg API to support v3.0+. (#8656, #6842, #6591) - Misc: Various zealous warning fixes for newer version of Clang. - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors (busy/wait/hourglass shape, with or without an arrow cursor). diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 73b9862bcfb9..39a997e67c90 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -880,8 +880,12 @@ static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state) // rows is height, pitch (or stride) equals to width * sizeof(int32) lunasvg::Bitmap bitmap((uint8_t*)slot->bitmap.buffer, slot->bitmap.width, slot->bitmap.rows, slot->bitmap.pitch); +#if LUNASVG_VERSION_MAJOR >= 3 + state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated +#else state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated +#endif state->err = FT_Err_Ok; return state->err; } @@ -904,7 +908,11 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_ return state->err; } +#if LUNASVG_VERSION_MAJOR >= 3 + lunasvg::Box box = state->svg->boundingBox(); +#else lunasvg::Box box = state->svg->box(); +#endif double scale = std::min(metrics.x_ppem / box.w, metrics.y_ppem / box.h); double xx = (double)document->transform.xx / (1 << 16); double xy = -(double)document->transform.xy / (1 << 16); @@ -913,6 +921,15 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_ double x0 = (double)document->delta.x / 64 * box.w / metrics.x_ppem; double y0 = -(double)document->delta.y / 64 * box.h / metrics.y_ppem; +#if LUNASVG_VERSION_MAJOR >= 3 + // Scale, transform and pre-translate the matrix for the rendering step + state->matrix = lunasvg::Matrix::translated(-box.x, -box.y); + state->matrix.multiply(lunasvg::Matrix(xx, xy, yx, yy, x0, y0)); + state->matrix.scale(scale, scale); + + // Apply updated transformation to the bounding box + box.transform(state->matrix); +#else // Scale and transform, we don't translate the svg yet state->matrix.identity(); state->matrix.scale(scale, scale); @@ -924,6 +941,7 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_ // Get the box again after the transformation box = state->svg->box(); +#endif // Calculate the bitmap size slot->bitmap_left = FT_Int(box.x); From 69e1fb50cacbde1c2c585ae59898e68c1818d9b7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 30 May 2025 21:59:13 +0200 Subject: [PATCH 415/716] Docs: fixed missing commit credit. (#8656) --- docs/CHANGELOG.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index aaf219a6ec75..956c041208f8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -268,7 +268,7 @@ Other changes: - Debug Tools: Added io.ConfigDebugHighlightIdConflictsShowItemPicker (defaults to true) to allow disabled Item Picker suggestion in user facing builds. (#7961, #7669) - Debug Tools: Tweaked layout of ID Stack Tool and always display full path. (#4631) -- imgui_freetype: update lunasvg API to support v3.0+. (#8656, #6842, #6591) +- imgui_freetype: update lunasvg API to support v3.0+. (#8656, #6842, #6591) [@moretromain] - Misc: Various zealous warning fixes for newer version of Clang. - Misc: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursors (busy/wait/hourglass shape, with or without an arrow cursor). From b7ab2b7523748401ed9fc7b82a40d20e3b8b36cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Jun 2025 20:41:01 +0200 Subject: [PATCH 416/716] TreeNode: fixed an issue where tree lines are not drawn on node opening frame. (#2920) --- imgui_widgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b99e6e5c06c8..cc3b5201efa6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6690,7 +6690,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if ((flags & ImGuiTreeNodeFlags_DrawLinesMask_) == 0) flags |= g.Style.TreeLinesFlags; const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); - if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) + if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsToParent) && !g.NavIdIsAlive) if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) @@ -6889,7 +6889,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l TablePopBackgroundChannel(); } - if (store_tree_node_stack_data && is_open) + if (is_open && store_tree_node_stack_data) TreeNodeStoreStackData(flags, text_pos.x - text_offset_x); // Call before TreePushOverrideID() if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) TreePushOverrideID(id); // Could use TreePush(label) but this avoid computing twice From ef503ab0c881934fb971c3e73745ba44bd355434 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Jun 2025 20:50:12 +0200 Subject: [PATCH 417/716] TreeNode: fixed out of bound access in ImGuiTreeNodeFlags_DrawLinesXXX feature. (#2920) TreeNode behavior would read TreeRecordsClippedNodesY2Mask from an older node at same lebel, and write to g.TreeNodeStack.Data[-1]. --- imgui_widgets.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index cc3b5201efa6..6b80d19d1ea1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6990,7 +6990,7 @@ void ImGui::TreePop() window->DC.TreeDepth--; ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); - if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) // Only set during request + if (window->DC.TreeHasStackDataDepthMask & tree_depth_mask) { const ImGuiTreeNodeStackData* data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; IM_ASSERT(data->ID == window->IDStack.back()); @@ -7006,6 +7006,7 @@ void ImGui::TreePop() g.TreeNodeStack.pop_back(); window->DC.TreeHasStackDataDepthMask &= ~tree_depth_mask; + window->DC.TreeRecordsClippedNodesY2Mask &= ~tree_depth_mask; } IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. From e877f78b0e9938ae6e8806ffa3c97392882c6501 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Jun 2025 20:57:21 +0200 Subject: [PATCH 418/716] TreeNode: minor amend to b7ab2b7. (#2920) --- imgui_widgets.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6b80d19d1ea1..341bf2712253 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6692,11 +6692,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l const bool draw_tree_lines = (flags & (ImGuiTreeNodeFlags_DrawLinesFull | ImGuiTreeNodeFlags_DrawLinesToNodes)) && (frame_bb.Min.y < window->ClipRect.Max.y) && (g.Style.TreeLinesSize > 0.0f); if (!(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) { + store_tree_node_stack_data = draw_tree_lines; if ((flags & ImGuiTreeNodeFlags_NavLeftJumpsToParent) && !g.NavIdIsAlive) if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) store_tree_node_stack_data = true; - if (draw_tree_lines) - store_tree_node_stack_data = true; } const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0; From 9485aeb5c8cf11277ac6f30cac477ba1050d2c07 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Jun 2025 17:30:17 +0200 Subject: [PATCH 419/716] Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). --- docs/CHANGELOG.txt | 1 + imgui.cpp | 11 +++++------ imgui_demo.cpp | 27 ++++++++++++++++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 956c041208f8..e490133ca112 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -131,6 +131,7 @@ Other changes: of WantVisible. This is set in the same structure because activating text input generally requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] +- Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). - Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594) - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad diff --git a/imgui.cpp b/imgui.cpp index 419098b8069f..df41d9713b25 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7563,12 +7563,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerClipRect.Max.y = ImFloor(window->InnerRect.Max.y - window->WindowBorderSize * 0.5f); window->InnerClipRect.ClipWithFull(host_rect); - // Default item width. Make it proportional to window size if window manually resizes - if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) - window->ItemWidthDefault = ImTrunc(window->Size.x * 0.65f); - else - window->ItemWidthDefault = ImTrunc(g.FontSize * 16.0f); - // SCROLLING // Lock down maximum scrolling @@ -7681,6 +7675,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->DC.LayoutType = ImGuiLayoutType_Vertical; window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical; + // Default item width. Make it proportional to window size if window manually resizes + if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize)) + window->ItemWidthDefault = ImTrunc(window->Size.x * 0.65f); + else + window->ItemWidthDefault = ImTrunc(g.FontSize * 16.0f); window->DC.ItemWidth = window->ItemWidthDefault; window->DC.TextWrapPos = -1.0f; // disabled window->DC.ItemWidthStack.resize(0); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 69018315c023..82e7d4801fd5 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -410,9 +410,19 @@ void ImGui::ShowDemoWindow(bool* p_open) return; } - // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details. - ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets. - //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align) + // Most framed widgets share a common width settings. Remaining width is used for the label. + // The width of the frame may be changed with PushItemWidth() or SetNextItemWidth(). + // - Positive value for absolute size, negative value for right-alignment. + // - The default value is about GetWindowWidth() * 0.65f. + // - See 'Demo->Layout->Widgets Width' for details. + // Here we change the frame width based on how much width we want to give to the label. + const float label_width_base = ImGui::GetFontSize() * 12; // Some amount of width for label, based on font size. + const float label_width_max = ImGui::GetContentRegionAvail().x * 0.40f; // ...but always leave some room for framed widgets. + const float label_width = IM_MIN(label_width_base, label_width_max); + ImGui::PushItemWidth(-label_width); // Right-align: framed items will leave 'label_width' available for the label. + //ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for framed widgets, leaving 60% width for labels. + //ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.40f); // e.g. Use 40% width for labels, leaving 60% width for framed widgets. + //ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Use XXX width for labels, leaving the rest for framed widgets. // Menu Bar DemoWindowMenuBar(&demo_data); @@ -4426,6 +4436,17 @@ static void DemoWindowLayout() } ImGui::PopItemWidth(); + ImGui::Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))"); + ImGui::PushItemWidth(-IM_MIN(ImGui::GetFontSize() * 12, ImGui::GetContentRegionAvail().x * 0.40f)); + ImGui::DragFloat("float##4a", &f); + if (show_indented_items) + { + ImGui::Indent(); + ImGui::DragFloat("float (indented)##4b", &f); + ImGui::Unindent(); + } + ImGui::PopItemWidth(); + // Demonstrate using PushItemWidth to surround three items. // Calling SetNextItemWidth() before each of them would have the same effect. ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); From 91f72bbe1c286645108cff4fa89d4031139241f8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Jun 2025 21:29:12 +0200 Subject: [PATCH 420/716] Demo: omit ImGui:: prefix from ShowStyleEditor(), ShowUserGuide() code. --- imgui_demo.cpp | 385 +++++++++++++++++++++++++------------------------ 1 file changed, 193 insertions(+), 192 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 82e7d4801fd5..14dcc32047b2 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8225,12 +8225,13 @@ static const char* GetTreeLinesFlagsName(ImGuiTreeNodeFlags flags) return ""; } +// We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. void ImGui::ShowStyleEditor(ImGuiStyle* ref) { IMGUI_DEMO_MARKER("Tools/Style Editor"); // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to // (without a reference style pointer, we will use one compared locally as a reference) - ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle& style = GetStyle(); static ImGuiStyle ref_saved_style; // Default to using internal storage as reference @@ -8241,206 +8242,206 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) if (ref == NULL) ref = &ref_saved_style; - ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f); + PushItemWidth(GetWindowWidth() * 0.50f); - if (ImGui::ShowStyleSelector("Colors##Selector")) + if (ShowStyleSelector("Colors##Selector")) ref_saved_style = style; - ImGui::ShowFontSelector("Fonts##Selector"); + ShowFontSelector("Fonts##Selector"); // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) - if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) + if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding - { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } - ImGui::SameLine(); - { bool border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } - ImGui::SameLine(); - { bool border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } + { bool border = (style.WindowBorderSize > 0.0f); if (Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } + SameLine(); + { bool border = (style.FrameBorderSize > 0.0f); if (Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } + SameLine(); + { bool border = (style.PopupBorderSize > 0.0f); if (Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } // Save/Revert button - if (ImGui::Button("Save Ref")) + if (Button("Save Ref")) *ref = ref_saved_style = style; - ImGui::SameLine(); - if (ImGui::Button("Revert Ref")) + SameLine(); + if (Button("Revert Ref")) style = *ref; - ImGui::SameLine(); + SameLine(); HelpMarker( "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " "Use \"Export\" below to save them somewhere."); - ImGui::Separator(); - - if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None)) - { - if (ImGui::BeginTabItem("Sizes")) - { - ImGui::SeparatorText("Main"); - ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); - ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); - ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); - - ImGui::SeparatorText("Borders"); - ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); - - ImGui::SeparatorText("Rounding"); - ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); - - ImGui::SeparatorText("Tabs"); - ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); - ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); - ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); - ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); - ImGui::DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f"); - ImGui::DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f"); - ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); - - ImGui::SeparatorText("Tables"); - ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); - ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); - - ImGui::SeparatorText("Trees"); - bool combo_open = ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)); - ImGui::SameLine(); + Separator(); + + if (BeginTabBar("##tabs", ImGuiTabBarFlags_None)) + { + if (BeginTabItem("Sizes")) + { + SeparatorText("Main"); + SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); + SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); + SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); + SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); + SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f"); + SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f"); + SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f"); + SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f"); + + SeparatorText("Borders"); + SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f"); + SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f"); + SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f"); + SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f"); + + SeparatorText("Rounding"); + SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); + SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); + SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f"); + SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f"); + SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f"); + + SeparatorText("Tabs"); + SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f"); + SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f"); + SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 3.0f, "%.0f"); + SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set."); + DragFloat("TabCloseButtonMinWidthSelected", &style.TabCloseButtonMinWidthSelected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthSelected < 0.0f) ? "%.0f (Always)" : "%.0f"); + DragFloat("TabCloseButtonMinWidthUnselected", &style.TabCloseButtonMinWidthUnselected, 0.1f, -1.0f, 100.0f, (style.TabCloseButtonMinWidthUnselected < 0.0f) ? "%.0f (Always)" : "%.0f"); + SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); + + SeparatorText("Tables"); + SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f"); + SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); + SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); + + SeparatorText("Trees"); + bool combo_open = BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)); + SameLine(); HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode."); if (combo_open) { const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes }; for (ImGuiTreeNodeFlags option : options) - if (ImGui::Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option)) + if (Selectable(GetTreeLinesFlagsName(option), style.TreeLinesFlags == option)) style.TreeLinesFlags = option; - ImGui::EndCombo(); + EndCombo(); } - ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f"); - ImGui::SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f"); + SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f"); + SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f"); - ImGui::SeparatorText("Windows"); - ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); + SeparatorText("Windows"); + SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); int window_menu_button_position = style.WindowMenuButtonPosition + 1; - if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) + if (Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); - ImGui::SeparatorText("Widgets"); - ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); - ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); - ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); - ImGui::SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); - ImGui::SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); - ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); - ImGui::SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, 1.0f, "%.0f"); - - ImGui::SeparatorText("Tooltips"); + SeparatorText("Widgets"); + Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); + SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); + SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); + SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); + SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content."); + SliderFloat("SeparatorTextBorderSize", &style.SeparatorTextBorderSize, 0.0f, 10.0f, "%.0f"); + SliderFloat2("SeparatorTextAlign", (float*)&style.SeparatorTextAlign, 0.0f, 1.0f, "%.2f"); + SliderFloat2("SeparatorTextPadding", (float*)&style.SeparatorTextPadding, 0.0f, 40.0f, "%.0f"); + SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f"); + SliderFloat("ImageBorderSize", &style.ImageBorderSize, 0.0f, 1.0f, "%.0f"); + + SeparatorText("Tooltips"); for (int n = 0; n < 2; n++) - if (ImGui::TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav")) + if (TreeNodeEx(n == 0 ? "HoverFlagsForTooltipMouse" : "HoverFlagsForTooltipNav")) { ImGuiHoveredFlags* p = (n == 0) ? &style.HoverFlagsForTooltipMouse : &style.HoverFlagsForTooltipNav; - ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone); - ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort); - ImGui::CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal); - ImGui::CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary); - ImGui::CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay); - ImGui::TreePop(); + CheckboxFlags("ImGuiHoveredFlags_DelayNone", p, ImGuiHoveredFlags_DelayNone); + CheckboxFlags("ImGuiHoveredFlags_DelayShort", p, ImGuiHoveredFlags_DelayShort); + CheckboxFlags("ImGuiHoveredFlags_DelayNormal", p, ImGuiHoveredFlags_DelayNormal); + CheckboxFlags("ImGuiHoveredFlags_Stationary", p, ImGuiHoveredFlags_Stationary); + CheckboxFlags("ImGuiHoveredFlags_NoSharedDelay", p, ImGuiHoveredFlags_NoSharedDelay); + TreePop(); } - ImGui::SeparatorText("Misc"); - ImGui::SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen."); - ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); + SeparatorText("Misc"); + SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen."); + SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured)."); - ImGui::EndTabItem(); + EndTabItem(); } - if (ImGui::BeginTabItem("Colors")) + if (BeginTabItem("Colors")) { static int output_dest = 0; static bool output_only_modified = true; - if (ImGui::Button("Export")) + if (Button("Export")) { if (output_dest == 0) - ImGui::LogToClipboard(); + LogToClipboard(); else - ImGui::LogToTTY(); - ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE); + LogToTTY(); + LogText("ImVec4* colors = GetStyle().Colors;" IM_NEWLINE); for (int i = 0; i < ImGuiCol_COUNT; i++) { const ImVec4& col = style.Colors[i]; - const char* name = ImGui::GetStyleColorName(i); + const char* name = GetStyleColorName(i); if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0) - ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, + LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w); } - ImGui::LogFinish(); + LogFinish(); } - ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); - ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified); + SameLine(); SetNextItemWidth(120); Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); + SameLine(); Checkbox("Only Modified Colors", &output_only_modified); static ImGuiTextFilter filter; - filter.Draw("Filter colors", ImGui::GetFontSize() * 16); + filter.Draw("Filter colors", GetFontSize() * 16); static ImGuiColorEditFlags alpha_flags = 0; - if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } ImGui::SameLine(); - if (ImGui::RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine(); - if (ImGui::RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine(); + if (RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_AlphaOpaque)) { alpha_flags = ImGuiColorEditFlags_AlphaOpaque; } SameLine(); + if (RadioButton("Alpha", alpha_flags == ImGuiColorEditFlags_None)) { alpha_flags = ImGuiColorEditFlags_None; } SameLine(); + if (RadioButton("Both", alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } SameLine(); HelpMarker( "In the color list:\n" "Left-click on color square to open color picker,\n" "Right-click to open edit options menu."); - ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); - ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); - ImGui::PushItemWidth(ImGui::GetFontSize() * -12); + SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX)); + BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar); + PushItemWidth(GetFontSize() * -12); for (int i = 0; i < ImGuiCol_COUNT; i++) { - const char* name = ImGui::GetStyleColorName(i); + const char* name = GetStyleColorName(i); if (!filter.PassFilter(name)) continue; - ImGui::PushID(i); + PushID(i); #ifndef IMGUI_DISABLE_DEBUG_TOOLS - if (ImGui::Button("?")) - ImGui::DebugFlashStyleColor((ImGuiCol)i); - ImGui::SetItemTooltip("Flash given color to identify places where it is used."); - ImGui::SameLine(); + if (Button("?")) + DebugFlashStyleColor((ImGuiCol)i); + SetItemTooltip("Flash given color to identify places where it is used."); + SameLine(); #endif - ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); + ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags); if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0) { // Tips: in a real user application, you may want to merge and use an icon font into the main font, // so instead of "Save"/"Revert" you'd use icons! // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } + SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Save")) { ref->Colors[i] = style.Colors[i]; } + SameLine(0.0f, style.ItemInnerSpacing.x); if (Button("Revert")) { style.Colors[i] = ref->Colors[i]; } } - ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); - ImGui::TextUnformatted(name); - ImGui::PopID(); + SameLine(0.0f, style.ItemInnerSpacing.x); + TextUnformatted(name); + PopID(); } - ImGui::PopItemWidth(); - ImGui::EndChild(); + PopItemWidth(); + EndChild(); - ImGui::EndTabItem(); + EndTabItem(); } - if (ImGui::BeginTabItem("Fonts")) + if (BeginTabItem("Fonts")) { - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = GetIO(); ImFontAtlas* atlas = io.Fonts; HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); - ImGui::ShowFontAtlas(atlas); + ShowFontAtlas(atlas); // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). @@ -8452,119 +8453,119 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" "Using those settings here will give you poor quality results."); static float window_scale = 1.0f; - ImGui::PushItemWidth(ImGui::GetFontSize() * 8); - if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window - ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything - ImGui::PopItemWidth(); + PushItemWidth(GetFontSize() * 8); + if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + SetWindowFontScale(window_scale); + DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + PopItemWidth(); - ImGui::EndTabItem(); + EndTabItem(); } - if (ImGui::BeginTabItem("Rendering")) + if (BeginTabItem("Rendering")) { - ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); - ImGui::SameLine(); + Checkbox("Anti-aliased lines", &style.AntiAliasedLines); + SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well."); - ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); - ImGui::SameLine(); + Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex); + SameLine(); HelpMarker("Faster lines using texture data. Require backend to render with bilinear filtering (not point/nearest filtering)."); - ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill); - ImGui::PushItemWidth(ImGui::GetFontSize() * 8); - ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); + Checkbox("Anti-aliased fill", &style.AntiAliasedFill); + PushItemWidth(GetFontSize() * 8); + DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f"); if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f; // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles. - ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); - const bool show_samples = ImGui::IsItemActive(); + DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp); + const bool show_samples = IsItemActive(); if (show_samples) - ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos()); - if (show_samples && ImGui::BeginTooltip()) + SetNextWindowPos(GetCursorScreenPos()); + if (show_samples && BeginTooltip()) { - ImGui::TextUnformatted("(R = radius, N = approx number of segments)"); - ImGui::Spacing(); - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x; + TextUnformatted("(R = radius, N = approx number of segments)"); + Spacing(); + ImDrawList* draw_list = GetWindowDrawList(); + const float min_widget_width = CalcTextSize("R: MMM\nN: MMM").x; for (int n = 0; n < 8; n++) { const float RAD_MIN = 5.0f; const float RAD_MAX = 70.0f; const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f); - ImGui::BeginGroup(); + BeginGroup(); // N is not always exact here due to how PathArcTo() function work internally - ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad)); + Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad)); const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f); const float offset_x = floorf(canvas_width * 0.5f); const float offset_y = floorf(RAD_MAX); - const ImVec2 p1 = ImGui::GetCursorScreenPos(); - draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); - ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + const ImVec2 p1 = GetCursorScreenPos(); + draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); + Dummy(ImVec2(canvas_width, RAD_MAX * 2)); /* - const ImVec2 p2 = ImGui::GetCursorScreenPos(); - draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text)); - ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2)); + const ImVec2 p2 = GetCursorScreenPos(); + draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, GetColorU32(ImGuiCol_Text)); + Dummy(ImVec2(canvas_width, RAD_MAX * 2)); */ - ImGui::EndGroup(); - ImGui::SameLine(); + EndGroup(); + SameLine(); } - ImGui::EndTooltip(); + EndTooltip(); } - ImGui::SameLine(); + SameLine(); HelpMarker("When drawing circle primitives with \"num_segments == 0\" tessellation will be calculated automatically."); - ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. - ImGui::DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); - ImGui::PopItemWidth(); + DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero. + DragFloat("Disabled Alpha", &style.DisabledAlpha, 0.005f, 0.0f, 1.0f, "%.2f"); SameLine(); HelpMarker("Additional alpha multiplier for disabled items (multiply over current value of Alpha)."); + PopItemWidth(); - ImGui::EndTabItem(); + EndTabItem(); } - ImGui::EndTabBar(); + EndTabBar(); } - - ImGui::PopItemWidth(); + PopItemWidth(); } //----------------------------------------------------------------------------- // [SECTION] User Guide / ShowUserGuide() //----------------------------------------------------------------------------- +// We omit the ImGui:: prefix in this function, as we don't expect user to be copy and pasting this code. void ImGui::ShowUserGuide() { - ImGuiIO& io = ImGui::GetIO(); - ImGui::BulletText("Double-click on title bar to collapse window."); - ImGui::BulletText( + ImGuiIO& io = GetIO(); + BulletText("Double-click on title bar to collapse window."); + BulletText( "Click and drag on lower corner to resize window\n" "(double-click to auto fit window to its contents)."); - ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); - ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); - ImGui::BulletText("CTRL+Tab to select a window."); + BulletText("CTRL+Click on a slider or drag box to input value as text."); + BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields."); + BulletText("CTRL+Tab to select a window."); if (io.FontAllowUserScaling) - ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents."); - ImGui::BulletText("While inputting text:\n"); - ImGui::Indent(); - ImGui::BulletText("CTRL+Left/Right to word jump."); - ImGui::BulletText("CTRL+A or double-click to select all."); - ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); - ImGui::BulletText("CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo."); - ImGui::BulletText("ESCAPE to revert."); - ImGui::Unindent(); - ImGui::BulletText("With keyboard navigation enabled:"); - ImGui::Indent(); - ImGui::BulletText("Arrow keys to navigate."); - ImGui::BulletText("Space to activate a widget."); - ImGui::BulletText("Return to input text into a widget."); - ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window."); - ImGui::BulletText("Alt to jump to the menu layer of a window."); - ImGui::Unindent(); + BulletText("CTRL+Mouse Wheel to zoom window contents."); + BulletText("While inputting text:\n"); + Indent(); + BulletText("CTRL+Left/Right to word jump."); + BulletText("CTRL+A or double-click to select all."); + BulletText("CTRL+X/C/V to use clipboard cut/copy/paste."); + BulletText("CTRL+Z to undo, CTRL+Y/CTRL+SHIFT+Z to redo."); + BulletText("ESCAPE to revert."); + Unindent(); + BulletText("With keyboard navigation enabled:"); + Indent(); + BulletText("Arrow keys to navigate."); + BulletText("Space to activate a widget."); + BulletText("Return to input text into a widget."); + BulletText("Escape to deactivate a widget, close popup, exit child window."); + BulletText("Alt to jump to the menu layer of a window."); + Unindent(); } //----------------------------------------------------------------------------- From c3d7ada9dfa8dc8ba80fb72d824ca70e2688a48b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Jun 2025 22:27:34 +0200 Subject: [PATCH 421/716] Demo: add indentation to simplify upcoming merges. --- imgui_demo.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 14dcc32047b2..3a6f3a501935 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8244,18 +8244,21 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) PushItemWidth(GetWindowWidth() * 0.50f); - if (ShowStyleSelector("Colors##Selector")) - ref_saved_style = style; - ShowFontSelector("Fonts##Selector"); + { + // General + if (ShowStyleSelector("Colors##Selector")) + ref_saved_style = style; + ShowFontSelector("Fonts##Selector"); - // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) - if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) - style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding - { bool border = (style.WindowBorderSize > 0.0f); if (Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } - SameLine(); - { bool border = (style.FrameBorderSize > 0.0f); if (Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } - SameLine(); - { bool border = (style.PopupBorderSize > 0.0f); if (Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } + // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) + if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) + style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding + { bool border = (style.WindowBorderSize > 0.0f); if (Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } } + SameLine(); + { bool border = (style.FrameBorderSize > 0.0f); if (Checkbox("FrameBorder", &border)) { style.FrameBorderSize = border ? 1.0f : 0.0f; } } + SameLine(); + { bool border = (style.PopupBorderSize > 0.0f); if (Checkbox("PopupBorder", &border)) { style.PopupBorderSize = border ? 1.0f : 0.0f; } } + } // Save/Revert button if (Button("Save Ref")) From 201899b611c34d35e6e38778abab91d76b0451c0 Mon Sep 17 00:00:00 2001 From: Dylam De La Torre Date: Wed, 4 Jun 2025 23:08:19 +0200 Subject: [PATCH 422/716] Backends: OpenGL3: Fixed using non-existing features on GLES 3.20 which would push a GL error. (#8664) * GL_PRIMITIVE_RESTART is not a valid enum for glEnable&co on GLES 3.20 * GL_CONTEXT_PROFILE_MASK is not a valid enum for glGetIntegerv on GLES 3.20 --- backends/imgui_impl_opengl3.cpp | 18 ++++++++++-------- docs/CHANGELOG.txt | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 7d0b53621960..8b7a2ecb5ac2 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-06-28: OpenGL: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748) @@ -325,11 +326,6 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) if (major == 0 && minor == 0) sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "." bd->GlVersion = (GLuint)(major * 100 + minor * 10); -#if defined(GL_CONTEXT_PROFILE_MASK) - if (bd->GlVersion >= 320) - glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask); - bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0; -#endif #if defined(IMGUI_IMPL_OPENGL_ES3) bd->GlProfileIsES3 = true; @@ -338,6 +334,12 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) bd->GlProfileIsES3 = true; #endif +#if defined(GL_CONTEXT_PROFILE_MASK) + if (!bd->GlProfileIsES3 && bd->GlVersion >= 320) + glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask); + bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0; +#endif + bd->UseBufferSubData = false; /* // Query vendor to enable glBufferSubData kludge @@ -439,7 +441,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid glDisable(GL_STENCIL_TEST); glEnable(GL_SCISSOR_TEST); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART - if (bd->GlVersion >= 310) + if (!bd->GlProfileIsES3 && bd->GlVersion >= 310) glDisable(GL_PRIMITIVE_RESTART); #endif #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE @@ -551,7 +553,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST); GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART - GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE; + GLboolean last_enable_primitive_restart = (!bd->GlProfileIsES3 && bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE; #endif // Setup desired GL state @@ -670,7 +672,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART - if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); } + if (!bd->GlProfileIsES3 && bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); } #endif #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e490133ca112..059daf5b5c0a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -149,6 +149,8 @@ Other changes: - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] - Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) +- Backends: OpenGL3: made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor + GL_PRIMITIVE_RESTART. (#8664) [@DyXel] - Backends: DirectX10, DirectX11, DirectX12: Honor FramebufferScale to allow for custom platform backends and experiments using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). (#8412) [@WSSDude] From b2f39318cb10eb51f37f393bd5c6bbe07dd0edcd Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 13:41:06 +0200 Subject: [PATCH 423/716] Adding .cache to ignore list. (#8674) --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6cadd63b48d1..6f6c50cb4648 100644 --- a/.gitignore +++ b/.gitignore @@ -29,8 +29,9 @@ ipch ## Getting files created in JSON/Schemas/Catalog/ from a VS2022 update JSON/ -## Commonly used CMake directories +## Commonly used CMake directories & CMake CPM cache build*/ +.cache ## Xcode & macOS artifacts project.xcworkspace From 191a728ecca454f11ff473e285804d1f7362a83d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 19:13:17 +0100 Subject: [PATCH 424/716] (Breaking) added ImTextureRef struct. Changed ImDrawCmd::TextureId to TexRef. Softly breaking. May require support from language binding generator. Rebased and reworked completely on 2025/03/19. --- imgui.cpp | 30 +++++------ imgui.h | 75 +++++++++++++++++++--------- imgui_demo.cpp | 2 +- imgui_draw.cpp | 85 +++++++++++++++++--------------- imgui_internal.h | 2 +- imgui_widgets.cpp | 22 ++++----- misc/freetype/imgui_freetype.cpp | 2 +- 7 files changed, 126 insertions(+), 92 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index df41d9713b25..bb5819a3754a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3841,12 +3841,12 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale))) continue; ImDrawList* draw_list = GetForegroundDrawList(viewport); - ImTextureID tex_id = font_atlas->TexID; - draw_list->PushTextureID(tex_id); - draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); - draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); - draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border); - draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill); + ImTextureRef tex_ref = font_atlas->TexID; + draw_list->PushTexture(tex_ref); + draw_list->AddImage(tex_ref, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_ref, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); + draw_list->AddImage(tex_ref, pos, pos + size * scale, uv[2], uv[3], col_border); + draw_list->AddImage(tex_ref, pos, pos + size * scale, uv[0], uv[1], col_fill); if (mouse_cursor == ImGuiMouseCursor_Wait || mouse_cursor == ImGuiMouseCursor_Progress) { float a_min = ImFmod((float)g.Time * 5.0f, 2.0f * IM_PI); @@ -3854,7 +3854,7 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso draw_list->PathArcTo(pos + ImVec2(14, -1) * scale, 6.0f * scale, a_min, a_max); draw_list->PathStroke(col_fill, ImDrawFlags_None, 3.0f * scale); } - draw_list->PopTextureID(); + draw_list->PopTexture(); } } @@ -4925,7 +4925,7 @@ static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t draw if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount) { draw_list->_ResetForNewFrame(); - draw_list->PushTextureID(g.IO.Fonts->TexID); + draw_list->PushTexture(g.IO.Fonts->TexID); draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount; } @@ -7580,7 +7580,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Setup draw list and outer clipping rectangle IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); - window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); + window->DrawList->PushTexture(g.Font->ContainerAtlas->TexID); PushClipRect(host_rect.Min, host_rect.Max, false); // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71) @@ -8553,7 +8553,7 @@ void ImGui::PushFont(ImFont* font) font = GetDefaultFont(); g.FontStack.push_back(font); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexID); } void ImGui::PopFont() @@ -8567,7 +8567,7 @@ void ImGui::PopFont() g.FontStack.pop_back(); ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); + g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexID); } //----------------------------------------------------------------------------- @@ -15500,11 +15500,11 @@ void ImGui::UpdateDebugToolFlashStyleColor() DebugFlashStyleColorStop(); } -static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id) +static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureRef tex_ref) { union { void* ptr; int integer; } tex_id_opaque; - memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id))); - if (sizeof(tex_id) >= sizeof(void*)) + memcpy(&tex_id_opaque, &tex_ref._TexID, ImMin(sizeof(void*), sizeof(tex_ref._TexID))); + if (sizeof(tex_ref._TexID) >= sizeof(void*)) ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr); else ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer); @@ -16245,7 +16245,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con } char texid_desc[20]; - FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd->TextureId); + FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd->TexRef); char buf[300]; ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex %s, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount / 3, texid_desc, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); diff --git a/imgui.h b/imgui.h index 6d062c190cf2..0e8f9c1aeed6 100644 --- a/imgui.h +++ b/imgui.h @@ -37,7 +37,7 @@ Index of this file: // [SECTION] Header mess // [SECTION] Forward declarations and basic types -// [SECTION] Texture identifier (ImTextureID) +// [SECTION] Texture identifiers (ImTextureID, ImTextureRef) // [SECTION] Dear ImGui end-user API functions // [SECTION] Flags & Enumerations // [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs) @@ -301,18 +301,38 @@ struct ImVec4 IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- -// [SECTION] Texture identifier (ImTextureID) +// [SECTION] Texture identifiers (ImTextureID, ImTextureRef) //----------------------------------------------------------------------------- -// ImTexture: user data for renderer backend to identify a texture [Compile-time configurable type] +// ImTextureID: user data for renderer backend to identify a texture [Compile-time configurable type] // - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. // - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. // - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators. // - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings) #ifndef ImTextureID -typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) #endif +// ImTextureRef contains: +// - a texture/atlas pointer, typically when created by Dear ImGui itself. +// - OR a raw ImTextureID value (user/backend identifier), typically when created by user code to load images. +// There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this to be useful to the end-user. +IM_MSVC_RUNTIME_CHECKS_OFF +struct ImTextureRef +{ + ImTextureRef() { memset(this, 0, sizeof(*this)); } + ImTextureRef(ImTextureID tex_id) { memset(this, 0, sizeof(*this)); _TexID = tex_id; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImTextureRef(void* tex_id) { memset(this, 0, sizeof(*this)); _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID + //inline operator intptr_t() const { return (intptr_t)_TexID; } // For legacy backends casting to ImTextureID +#endif + + // Members + ImFontAtlas* _Atlas; // Texture/Atlas pointer + ImTextureID _TexID; // _OR_ Underlying user/backend texture identifier, or zero if not yet uploaded. +}; +IM_MSVC_RUNTIME_CHECKS_RESTORE + //----------------------------------------------------------------------------- // [SECTION] Dear ImGui end-user API functions // (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) @@ -567,9 +587,9 @@ namespace ImGui // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. // - An obsolete version of Image(), before 1.91.9 (March 2025), had a 'tint_col' parameter which is now supported by the ImageWithBg() function. - IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1)); - IMGUI_API void ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); - IMGUI_API bool ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1)); + IMGUI_API void ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); + IMGUI_API bool ImageButton(const char* str_id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Widgets: Combo Box (Dropdown) // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. @@ -3004,11 +3024,11 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c // - VtxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, // this fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. // Backends made for <1.71. will typically ignore the VtxOffset fields. -// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). +// - The ClipRect/TexRef/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). struct ImDrawCmd { ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates - ImTextureID TextureId; // 4-8 // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + ImTextureRef TexRef; // 16 // User-provided texture ID. Set by user in ImFontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. unsigned int IdxOffset; // 4 // Start offset in index buffer. unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. @@ -3020,7 +3040,8 @@ struct ImDrawCmd ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) - inline ImTextureID GetTexID() const { return TextureId; } + // Since 1.92: removed ImDrawCmd::TextureId field, the getter function must be used! + inline ImTextureID GetTexID() const { return TexRef._TexID; } }; // Vertex layout @@ -3043,7 +3064,7 @@ IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT; struct ImDrawCmdHeader { ImVec4 ClipRect; - ImTextureID TextureId; + ImTextureRef TexRef; unsigned int VtxOffset; }; @@ -3128,7 +3149,7 @@ struct ImDrawList ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back(). ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) ImVector _ClipRectStack; // [Internal] - ImVector _TextureIdStack; // [Internal] + ImVector _TextureStack; // [Internal] ImVector _CallbacksDataBuf; // [Internal] float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content const char* _OwnerName; // Pointer to owner window's name for debugging @@ -3141,8 +3162,8 @@ struct ImDrawList IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const 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(); IMGUI_API void PopClipRect(); - IMGUI_API void PushTextureID(ImTextureID texture_id); - IMGUI_API void PopTextureID(); + IMGUI_API void PushTexture(ImTextureRef tex_ref); + IMGUI_API void PopTexture(); inline ImVec2 GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); } inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); } @@ -3180,12 +3201,12 @@ struct ImDrawList IMGUI_API void AddConcavePolyFilled(const ImVec2* points, int num_points, ImU32 col); // Image primitives - // - Read FAQ to understand what ImTextureID is. + // - Read FAQ to understand what ImTextureID/ImTextureRef are. // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle. // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture. - IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); - IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); - IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); + IMGUI_API void AddImage(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageQuad(ImTextureRef tex_ref, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE); + IMGUI_API void AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags = 0); // Stateful path API, add points then finish with PathFillConvex() or PathStroke() // - Important: filled shapes must always use clockwise winding order! The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing. @@ -3241,6 +3262,10 @@ struct ImDrawList inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index // Obsolete names +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //IMGUI_API void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.x + //IMGUI_API void PopTextureID() { PopTexture(); } // RENAMED in 1.92.x +#endif //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) //inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) //inline void PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments = 0) { PathEllipticalArcTo(center, ImVec2(radius_x, radius_y), rot, a_min, a_max, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) @@ -3253,9 +3278,9 @@ struct ImDrawList IMGUI_API void _PopUnusedDrawCmd(); IMGUI_API void _TryMergeDrawCmds(); IMGUI_API void _OnChangedClipRect(); - IMGUI_API void _OnChangedTextureID(); + IMGUI_API void _OnChangedTexture(); IMGUI_API void _OnChangedVtxOffset(); - IMGUI_API void _SetTextureID(ImTextureID texture_id); + IMGUI_API void _SetTexture(ImTextureRef tex_ref); IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const; IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step); IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments); @@ -3412,7 +3437,11 @@ struct ImFontAtlas IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... - void SetTexID(ImTextureID id) { TexID = id; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + void SetTexID(ImTextureID id){ TexID._Atlas = this; TexID._TexID = id; } // FIXME-NEWATLAS: Called by legacy backends. + void SetTexID(ImTextureRef id) { TexID = id; } // FIXME-NEWATLAS: Called by legacy backends. +#endif + //------------------------------------------- // Glyph Ranges @@ -3456,7 +3485,7 @@ struct ImFontAtlas // Input ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) - ImTextureID TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + ImTextureRef TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). @@ -3654,7 +3683,7 @@ struct ImGuiPlatformImeData namespace ImGui { // OBSOLETED in 1.91.9 (from February 2025) - IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. + IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. // OBSOLETED in 1.91.0 (from July 2024) static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } static inline void PopButtonRepeat() { PopItemFlag(); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 3a6f3a501935..790f3761181f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1778,7 +1778,7 @@ static void DemoWindowWidgetsImages() // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImTextureID my_tex_id = io.Fonts->TexID; + ImTextureRef my_tex_id = io.Fonts->TexID; float my_tex_w = (float)io.Fonts->TexWidth; float my_tex_h = (float)io.Fonts->TexHeight; { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 78b0e152effa..8a31b79f7151 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -423,8 +423,8 @@ void ImDrawList::_ResetForNewFrame() { // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. IM_STATIC_ASSERT(offsetof(ImDrawCmd, ClipRect) == 0); - IM_STATIC_ASSERT(offsetof(ImDrawCmd, TextureId) == sizeof(ImVec4)); - IM_STATIC_ASSERT(offsetof(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + IM_STATIC_ASSERT(offsetof(ImDrawCmd, TexRef) == sizeof(ImVec4)); + IM_STATIC_ASSERT(offsetof(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureRef)); if (_Splitter._Count > 1) _Splitter.Merge(this); @@ -437,7 +437,7 @@ void ImDrawList::_ResetForNewFrame() _VtxWritePtr = NULL; _IdxWritePtr = NULL; _ClipRectStack.resize(0); - _TextureIdStack.resize(0); + _TextureStack.resize(0); _CallbacksDataBuf.resize(0); _Path.resize(0); _Splitter.Clear(); @@ -455,7 +455,7 @@ void ImDrawList::_ClearFreeMemory() _VtxWritePtr = NULL; _IdxWritePtr = NULL; _ClipRectStack.clear(); - _TextureIdStack.clear(); + _TextureStack.clear(); _CallbacksDataBuf.clear(); _Path.clear(); _Splitter.ClearFreeMemory(); @@ -475,7 +475,7 @@ void ImDrawList::AddDrawCmd() { ImDrawCmd draw_cmd; draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() - draw_cmd.TextureId = _CmdHeader.TextureId; + draw_cmd.TexRef = _CmdHeader.TexRef; draw_cmd.VtxOffset = _CmdHeader.VtxOffset; draw_cmd.IdxOffset = IdxBuffer.Size; @@ -530,10 +530,10 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* userdata, size_t use AddDrawCmd(); // Force a new command after us (see comment below) } -// Compare ClipRect, TextureId and VtxOffset with a single memcmp() +// Compare ClipRect, TexRef and VtxOffset with a single memcmp() #define ImDrawCmd_HeaderSize (offsetof(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) -#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset -#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TexRef, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TexRef, VtxOffset #define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset) // Try to merge two last draw commands @@ -573,12 +573,16 @@ void ImDrawList::_OnChangedClipRect() curr_cmd->ClipRect = _CmdHeader.ClipRect; } -void ImDrawList::_OnChangedTextureID() +// Operators for easy compare +static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._Atlas == rhs._Atlas; } +static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._Atlas != rhs._Atlas; } + +void ImDrawList::_OnChangedTexture() { // If current command is used with different settings we need to add a new command IM_ASSERT_PARANOID(CmdBuffer.Size > 0); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) + if (curr_cmd->ElemCount != 0 && curr_cmd->TexRef != _CmdHeader.TexRef) { AddDrawCmd(); return; @@ -592,7 +596,7 @@ void ImDrawList::_OnChangedTextureID() CmdBuffer.pop_back(); return; } - curr_cmd->TextureId = _CmdHeader.TextureId; + curr_cmd->TexRef = _CmdHeader.TexRef; } void ImDrawList::_OnChangedVtxOffset() @@ -653,27 +657,27 @@ void ImDrawList::PopClipRect() _OnChangedClipRect(); } -void ImDrawList::PushTextureID(ImTextureID texture_id) +void ImDrawList::PushTexture(ImTextureRef tex_ref) { - _TextureIdStack.push_back(texture_id); - _CmdHeader.TextureId = texture_id; - _OnChangedTextureID(); + _TextureStack.push_back(tex_ref); + _CmdHeader.TexRef = tex_ref; + _OnChangedTexture(); } -void ImDrawList::PopTextureID() +void ImDrawList::PopTexture() { - _TextureIdStack.pop_back(); - _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; - _OnChangedTextureID(); + _TextureStack.pop_back(); + _CmdHeader.TexRef = (_TextureStack.Size == 0) ? ImTextureRef() : _TextureStack.Data[_TextureStack.Size - 1]; + _OnChangedTexture(); } // This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID(). -void ImDrawList::_SetTextureID(ImTextureID texture_id) +void ImDrawList::_SetTexture(ImTextureRef tex_ref) { - if (_CmdHeader.TextureId == texture_id) + if (_CmdHeader.TexRef == tex_ref) return; - _CmdHeader.TextureId = texture_id; - _OnChangedTextureID(); + _CmdHeader.TexRef = tex_ref; + _OnChangedTexture(); } // Reserve space for a number of vertices and indices. @@ -1686,7 +1690,7 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 if (font_size == 0.0f) font_size = _Data->FontSize; - IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TexRef); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. ImVec4 clip_rect = _CmdHeader.ClipRect; if (cpu_fine_clip_rect) @@ -1704,39 +1708,39 @@ void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, c AddText(_Data->Font, _Data->FontSize, pos, col, text_begin, text_end); } -void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) +void ImDrawList::AddImage(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col) { if ((col & IM_COL32_A_MASK) == 0) return; - const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + const bool push_texture_id = tex_ref != _CmdHeader.TexRef; if (push_texture_id) - PushTextureID(user_texture_id); + PushTexture(tex_ref); PrimReserve(6, 4); PrimRectUV(p_min, p_max, uv_min, uv_max, col); if (push_texture_id) - PopTextureID(); + PopTexture(); } -void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) +void ImDrawList::AddImageQuad(ImTextureRef tex_ref, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col) { if ((col & IM_COL32_A_MASK) == 0) return; - const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + const bool push_texture_id = tex_ref != _CmdHeader.TexRef; if (push_texture_id) - PushTextureID(user_texture_id); + PushTexture(tex_ref); PrimReserve(6, 4); PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col); if (push_texture_id) - PopTextureID(); + PopTexture(); } -void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) +void ImDrawList::AddImageRounded(ImTextureRef tex_ref, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawFlags flags) { if ((col & IM_COL32_A_MASK) == 0) return; @@ -1744,13 +1748,13 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_mi flags = FixRectCornerFlags(flags); if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) { - AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col); + AddImage(tex_ref, p_min, p_max, uv_min, uv_max, col); return; } - const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; + const bool push_texture_id = tex_ref != _CmdHeader.TexRef; if (push_texture_id) - PushTextureID(user_texture_id); + PushTexture(tex_ref); int vert_start_idx = VtxBuffer.Size; PathRect(p_min, p_max, rounding, flags); @@ -1759,7 +1763,7 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_mi ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true); if (push_texture_id) - PopTextureID(); + PopTexture(); } //----------------------------------------------------------------------------- @@ -2187,7 +2191,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; if (curr_cmd->ElemCount == 0) - ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) draw_list->AddDrawCmd(); @@ -2213,7 +2217,7 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) if (curr_cmd == NULL) draw_list->AddDrawCmd(); else if (curr_cmd->ElemCount == 0) - ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TexRef, VtxOffset else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) draw_list->AddDrawCmd(); } @@ -2483,6 +2487,7 @@ ImFontAtlas::ImFontAtlas() { memset(this, 0, sizeof(*this)); TexGlyphPadding = 1; + TexID._Atlas = this; PackIdMouseCursors = PackIdLines = -1; } @@ -2882,7 +2887,7 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) ImFontAtlasBuildInit(atlas); // Clear atlas - atlas->TexID = (ImTextureID)NULL; + atlas->TexID._TexID = 0; atlas->TexWidth = atlas->TexHeight = 0; atlas->TexUvScale = ImVec2(0.0f, 0.0f); atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); diff --git a/imgui_internal.h b/imgui_internal.h index ca250e0b7caa..91ac0bc83b0e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3454,7 +3454,7 @@ namespace ImGui // Widgets IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0); - IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); + IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0); IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags, float thickness = 1.0f); IMGUI_API void SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_width); IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 341bf2712253..1c22bd4c6fa0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1103,9 +1103,9 @@ bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, ImS6 return held; } -// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples +// - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. -void ImGui::ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) +void ImGui::ImageWithBg(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -1123,28 +1123,28 @@ void ImGui::ImageWithBg(ImTextureID user_texture_id, const ImVec2& image_size, c window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border), 0.0f, ImDrawFlags_None, g.Style.ImageBorderSize); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); - window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); } -void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1) +void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1) { - ImageWithBg(user_texture_id, image_size, uv0, uv1); + ImageWithBg(tex_ref, image_size, uv0, uv1); } // 1.91.9 (February 2025) removed 'tint_col' and 'border_col' parameters, made border size not depend on color value. (#8131, #8238) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -void ImGui::Image(ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) +void ImGui::Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col) { ImGuiContext& g = *GImGui; PushStyleVar(ImGuiStyleVar_ImageBorderSize, (border_col.w > 0.0f) ? ImMax(1.0f, g.Style.ImageBorderSize) : 0.0f); // Preserve legacy behavior where border is always visible when border_col's Alpha is >0.0f PushStyleColor(ImGuiCol_Border, border_col); - ImageWithBg(user_texture_id, image_size, uv0, uv1, ImVec4(0, 0, 0, 0), tint_col); + ImageWithBg(tex_ref, image_size, uv0, uv1, ImVec4(0, 0, 0, 0), tint_col); PopStyleColor(); PopStyleVar(); } #endif -bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) +bool ImGui::ImageButtonEx(ImGuiID id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -1166,21 +1166,21 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID user_texture_id, const ImVec2& RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, g.Style.FrameRounding)); if (bg_col.w > 0.0f) window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col)); - window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); + window->DrawList->AddImage(tex_ref, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col)); return pressed; } // - ImageButton() adds style.FramePadding*2.0f to provided size. This is in order to facilitate fitting an image in a button. // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. (#8165) // FIXME: Maybe that's not the best design? -bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) +bool ImGui::ImageButton(const char* str_id, ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; if (window->SkipItems) return false; - return ImageButtonEx(window->GetID(str_id), user_texture_id, image_size, uv0, uv1, bg_col, tint_col); + return ImageButtonEx(window->GetID(str_id), tex_ref, image_size, uv0, uv1, bg_col, tint_col); } #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 39a997e67c90..6521f83b99df 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -448,7 +448,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u ImFontAtlasBuildInit(atlas); // Clear atlas - atlas->TexID = 0; + atlas->TexID._TexID = 0; atlas->TexWidth = atlas->TexHeight = 0; atlas->TexUvScale = ImVec2(0.0f, 0.0f); atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); From 0f0473bf1c9d6e4cd74dde883f37f87f57165096 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 13:42:35 +0100 Subject: [PATCH 425/716] Fonts, Textures: main code for ImGuiBackendFlags_RendererHasTextures feature. # Conflicts: # imgui.h # imgui_demo.cpp --- examples/example_null/main.cpp | 7 +- imgui.cpp | 180 ++- imgui.h | 212 +++- imgui_demo.cpp | 13 +- imgui_draw.cpp | 1990 ++++++++++++++++++++---------- imgui_internal.h | 123 +- imgui_widgets.cpp | 5 +- misc/freetype/imgui_freetype.cpp | 4 +- 8 files changed, 1741 insertions(+), 793 deletions(-) diff --git a/examples/example_null/main.cpp b/examples/example_null/main.cpp index f7153cc48889..460f33caba3c 100644 --- a/examples/example_null/main.cpp +++ b/examples/example_null/main.cpp @@ -11,9 +11,10 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); // Build atlas - unsigned char* tex_pixels = nullptr; - int tex_w, tex_h; - io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_w, &tex_h); + //unsigned char* tex_pixels = nullptr; + //int tex_w, tex_h; + //io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_w, &tex_h); + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; for (int n = 0; n < 20; n++) { diff --git a/imgui.cpp b/imgui.cpp index bb5819a3754a..5acd91c0cf6d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1270,6 +1270,7 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); // Misc static void UpdateFontsNewFrame(); +static void UpdateTexturesNewFrame(); static void UpdateSettings(); static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static void RenderWindowOuterBorders(ImGuiWindow* window); @@ -3841,7 +3842,7 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale))) continue; ImDrawList* draw_list = GetForegroundDrawList(viewport); - ImTextureRef tex_ref = font_atlas->TexID; + ImTextureRef tex_ref = font_atlas->TexRef; draw_list->PushTexture(tex_ref); draw_list->AddImage(tex_ref, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow); draw_list->AddImage(tex_ref, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow); @@ -4194,6 +4195,11 @@ void ImGui::Initialize() #ifdef IMGUI_HAS_DOCK #endif + // ImDrawList/ImFontAtlas are designed to function without ImGui, and 99% of it works without an ImGui context. + // But this link allows us to facilitate/handle a few edge cases better. + g.DrawListSharedData.Context = &g; + ImFontAtlasAddDrawListSharedData(g.IO.Fonts, &g.DrawListSharedData); + g.Initialized = true; } @@ -4205,6 +4211,8 @@ void ImGui::Shutdown() IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == NULL, "Forgot to shutdown Renderer backend?"); // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) + if (g.IO.Fonts) + ImFontAtlasRemoveDrawListSharedData(g.IO.Fonts, &g.DrawListSharedData); if (g.IO.Fonts && g.FontAtlasOwnedByContext) { g.IO.Fonts->Locked = false; @@ -4339,7 +4347,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NUL SettingsOffset = -1; DrawList = &DrawListInst; DrawList->_OwnerName = Name; - DrawList->_Data = &Ctx->DrawListSharedData; + DrawList->_SetDrawListSharedData(&Ctx->DrawListSharedData); NavPreferredScoringPosRel[0] = NavPreferredScoringPosRel[1] = ImVec2(FLT_MAX, FLT_MAX); } @@ -4925,7 +4933,7 @@ static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t draw if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount) { draw_list->_ResetForNewFrame(); - draw_list->PushTexture(g.IO.Fonts->TexID); + draw_list->PushTexture(g.IO.Fonts->TexRef); draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount; } @@ -5166,6 +5174,14 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } +static void ImGui::UpdateTexturesNewFrame() +{ + // FIXME-NEWATLAS: How to reach/target all atlas? + ImGuiContext& g = *GImGui; + ImFontAtlas* atlas = g.IO.Fonts; + ImFontAtlasUpdateNewFrame(atlas); +} + // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. // FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! static void SetupDrawListSharedData() @@ -5202,6 +5218,13 @@ void ImGui::NewFrame() CallContextHooks(&g, ImGuiContextHookType_NewFramePre); + // Check that font atlas was built or backend support texture reload in which case we can build now + ImFontAtlas* atlas = g.IO.Fonts; + if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) + atlas->Build(); + else // Legacy backend + IM_ASSERT(atlas->TexIsBuilt && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"); + // Check and assert for various common IO and Configuration mistakes ErrorCheckNewFrameSanityChecks(); @@ -5209,7 +5232,6 @@ void ImGui::NewFrame() UpdateSettings(); g.Time += g.IO.DeltaTime; - g.WithinFrameScope = true; g.FrameCount += 1; g.TooltipOverrideCount = 0; g.WindowsActiveCount = 0; @@ -5229,10 +5251,15 @@ void ImGui::NewFrame() // Update viewports (after processing input queue, so io.MouseHoveredViewport is set) UpdateViewportsNewFrame(); + // Update texture list (collect destroyed textures, etc.) + UpdateTexturesNewFrame(); + // Setup current font and draw list shared data SetupDrawListSharedData(); UpdateFontsNewFrame(); + g.WithinFrameScope = true; + // Mark rendering data as invalid to prevent user who may have a handle on it to use it. for (ImGuiViewportP* viewport : g.Viewports) viewport->DrawDataP.Valid = false; @@ -5810,6 +5837,11 @@ void ImGui::Render() g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; } +#ifndef IMGUI_DISABLE_DEBUG_TOOLS + if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) + ImFontAtlasDebugLogTextureRequests(g.IO.Fonts); +#endif + CallContextHooks(&g, ImGuiContextHookType_RenderPost); } @@ -7580,7 +7612,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Setup draw list and outer clipping rectangle IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0); - window->DrawList->PushTexture(g.Font->ContainerAtlas->TexID); + window->DrawList->PushTexture(g.Font->ContainerAtlas->TexRef); PushClipRect(host_rect.Min, host_rect.Max, false); // Child windows can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call (since 1.71) @@ -8515,7 +8547,12 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) void ImGui::UpdateFontsNewFrame() { ImGuiContext& g = *GImGui; - g.IO.Fonts->Locked = true; + if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) + { + g.IO.Fonts->Locked = true; + for (ImFont* font : g.IO.Fonts->Fonts) + font->LockDisableLoading = true; + } SetCurrentFont(GetDefaultFont()); IM_ASSERT(g.Font->IsLoaded()); } @@ -8530,13 +8567,12 @@ void ImGui::SetCurrentFont(ImFont* font) g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; g.FontScale = g.FontSize / g.Font->FontSize; - - ImFontAtlas* atlas = g.Font->ContainerAtlas; - g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel; - g.DrawListSharedData.TexUvLines = atlas->TexUvLines; g.DrawListSharedData.Font = g.Font; g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontScale; + ImFontAtlasUpdateDrawListsSharedData(g.Font->ContainerAtlas); + if (g.CurrentWindow) + g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexRef); } // Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authoritative against window-local ImDrawList. @@ -8546,6 +8582,7 @@ void ImGui::SetCurrentFont(ImFont* font) // - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() // the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem // because we have a concrete need and a test bed for multiple atlas textures. +// FIXME-NEWATLAS: perhaps we can now leverage ImFontAtlasUpdateDrawListsTextures() ? void ImGui::PushFont(ImFont* font) { ImGuiContext& g = *GImGui; @@ -8553,7 +8590,6 @@ void ImGui::PushFont(ImFont* font) font = GetDefaultFont(); g.FontStack.push_back(font); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexID); } void ImGui::PopFont() @@ -8567,7 +8603,6 @@ void ImGui::PopFont() g.FontStack.pop_back(); ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); SetCurrentFont(font); - g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexID); } //----------------------------------------------------------------------------- @@ -10278,7 +10313,6 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?"); IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!"); - IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"); IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!"); IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations @@ -15460,10 +15494,12 @@ void ImGui::DebugTextEncoding(const char* str) Text("0x%02X", (int)(unsigned char)p[byte_index]); } TableNextColumn(); - if (GetFont()->FindGlyphNoFallback((ImWchar)c)) - TextUnformatted(p, p + c_utf8_len); - else - TextUnformatted((c == IM_UNICODE_CODEPOINT_INVALID) ? "[invalid]" : "[missing]"); + TextUnformatted(p, p + c_utf8_len); + if (GetFont()->FindGlyphNoFallback((ImWchar)c) == NULL) + { + SameLine(); + TextUnformatted("[missing]"); + } TableNextColumn(); Text("U+%04X", (int)c); p += c_utf8_len; @@ -15500,17 +15536,25 @@ void ImGui::UpdateDebugToolFlashStyleColor() DebugFlashStyleColorStop(); } -static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureRef tex_ref) +static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, ImTextureID tex_id) { union { void* ptr; int integer; } tex_id_opaque; - memcpy(&tex_id_opaque, &tex_ref._TexID, ImMin(sizeof(void*), sizeof(tex_ref._TexID))); - if (sizeof(tex_ref._TexID) >= sizeof(void*)) + memcpy(&tex_id_opaque, &tex_id, ImMin(sizeof(void*), sizeof(tex_id))); + if (sizeof(tex_id) >= sizeof(void*)) ImFormatString(buf, buf_size, "0x%p", tex_id_opaque.ptr); else ImFormatString(buf, buf_size, "0x%04X", tex_id_opaque.integer); return buf; } +static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, const ImDrawCmd* cmd) +{ + char* buf_end = buf + buf_size; + if (cmd->TexRef._TexData != NULL) + buf += ImFormatString(buf, buf_end - buf, "#%03d: ", cmd->TexRef._TexData->UniqueID); + return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), cmd->GetTexID()); +} + // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. static void MetricsHelpMarker(const char* desc) { @@ -15524,6 +15568,10 @@ static void MetricsHelpMarker(const char* desc) } } +#ifdef IMGUI_ENABLE_FREETYPE +namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetBackendIOForFreeType(); } +#endif + // [DEBUG] List fonts in a font atlas and display its texture void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { @@ -15538,6 +15586,36 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; Checkbox("Show font preview", &cfg->ShowFontPreview); + // Font loaders + if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL")) + { + const ImFontLoader* loader_current = atlas->FontLoader; + BeginDisabled(!atlas->DrawListSharedData || !atlas->DrawListSharedData->RendererHasTextures); +#ifdef IMGUI_ENABLE_STB_TRUETYPE + const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype(); + if (RadioButton("stb_truetype", loader_current == loader_stbtruetype)) + ImFontAtlasBuildSetupFontLoader(atlas, loader_stbtruetype); +#else + BeginDisabled(); + RadioButton("stb_truetype", false); + SetItemTooltip("Requires IMGUI_ENABLE_STB_TRUETYPE"); + EndDisabled(); +#endif + SameLine(); +#ifdef IMGUI_ENABLE_FREETYPE + const ImFontLoader* loader_freetype = ImGuiFreeType::GetBackendIOForFreeType(); + if (RadioButton("FreeType", loader_current == loader_freetype)) + ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); +#else + BeginDisabled(); + RadioButton("FreeType", false); + SetItemTooltip("Requires IMGUI_ENABLE_FREETYPE + imgui_freetype.cpp."); + EndDisabled(); +#endif + EndDisabled(); + TreePop(); + } + // Font list for (ImFont* font : atlas->Fonts) { @@ -15545,11 +15623,32 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) DebugNodeFont(font); PopID(); } - if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight)) + + // Texture list + for (ImTextureData* tex : atlas->TexList) + { + PushID(tex); + DebugNodeTexture(tex); + PopID(); + } +} + +void ImGui::DebugNodeTexture(ImTextureData* tex) +{ + ImGuiContext& g = *GImGui; + if (TreeNode(tex, "Texture #%03d (%dx%d pixels)", tex->UniqueID, tex->Width, tex->Height)) { PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); - ImageWithBg(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImTextureRef tex_id; + tex_id._TexData = tex; // Don't use tex->TexID directly so first frame works. + ImageWithBg(tex_id, ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); PopStyleVar(); + + char texid_desc[20]; + Text("Format = %d", tex->Format); + Text("TexID = %s", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID)); + Text("BackendUserData = %p", tex->BackendUserData); + Text("UseColors = %d", tex->UseColors); TreePop(); } } @@ -15793,6 +15892,14 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } + // Details for Fonts + ImFontAtlas* atlas = g.IO.Fonts; + if (TreeNode("Fonts", "Fonts (%d), Textures (%d)", atlas->Fonts.Size, atlas->TexList.Size)) + { + ShowFontAtlas(atlas); + TreePop(); + } + // Details for Popups if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) { @@ -15829,14 +15936,6 @@ void ImGui::ShowMetricsWindow(bool* p_open) TreePop(); } - // Details for Fonts - ImFontAtlas* atlas = g.IO.Fonts; - if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size)) - { - ShowFontAtlas(atlas); - TreePop(); - } - // Details for InputText if (TreeNode("InputText")) { @@ -16245,7 +16344,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con } char texid_desc[20]; - FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd->TexRef); + FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd); char buf[300]; ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex %s, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount / 3, texid_desc, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w); @@ -16379,7 +16478,7 @@ void ImGui::DebugNodeFont(ImFont* font) for (int config_i = 0; config_i < font->SourcesCount; config_i++) if (font->Sources) { - const ImFontConfig* src = &font->Sources[config_i]; + ImFontConfig* src = &font->Sources[config_i]; int oversample_h, oversample_v; ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", @@ -16390,6 +16489,10 @@ void ImGui::DebugNodeFont(ImFont* font) { if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) { + if (SmallButton("Load all")) + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++) + font->FindGlyph((ImWchar)base); + ImDrawList* draw_list = GetWindowDrawList(); const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); const float cell_size = font->FontSize * 1; @@ -16407,7 +16510,7 @@ void ImGui::DebugNodeFont(ImFont* font) int count = 0; for (unsigned int n = 0; n < 256; n++) - if (font->FindGlyphNoFallback((ImWchar)(base + n))) + if (font->IsGlyphLoaded((ImWchar)(base + n))) count++; if (count <= 0) continue; @@ -16422,7 +16525,7 @@ void ImGui::DebugNodeFont(ImFont* font) // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n)); + const ImFontGlyph* glyph = font->IsGlyphLoaded((ImWchar)(base + n)) ? font->FindGlyph((ImWchar)(base + n)) : NULL; draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); if (!glyph) continue; @@ -16443,7 +16546,7 @@ void ImGui::DebugNodeFont(ImFont* font) Unindent(); } -void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph) +void ImGui::DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph) { Text("Codepoint: U+%04X", glyph->Codepoint); Separator(); @@ -16451,6 +16554,11 @@ void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph) Text("AdvanceX: %.1f", glyph->AdvanceX); Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1); Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); + if (glyph->PackId >= 0) + { + ImFontAtlasRect* r = ImFontAtlasPackGetRect(font->ContainerAtlas, glyph->PackId); + Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y);; + } } // [DEBUG] Display contents of ImGuiStorage @@ -16727,7 +16835,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open) ShowDebugLogFlag("Clipper", ImGuiDebugLogFlags_EventClipper); ShowDebugLogFlag("Focus", ImGuiDebugLogFlags_EventFocus); ShowDebugLogFlag("IO", ImGuiDebugLogFlags_EventIO); - //ShowDebugLogFlag("Font", ImGuiDebugLogFlags_EventFont); + ShowDebugLogFlag("Font", ImGuiDebugLogFlags_EventFont); ShowDebugLogFlag("Nav", ImGuiDebugLogFlags_EventNav); ShowDebugLogFlag("Popup", ImGuiDebugLogFlags_EventPopup); ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection); diff --git a/imgui.h b/imgui.h index 0e8f9c1aeed6..0420b4358ed8 100644 --- a/imgui.h +++ b/imgui.h @@ -31,6 +31,7 @@ #define IMGUI_VERSION "1.92.0 WIP" #define IMGUI_VERSION_NUM 19197 #define IMGUI_HAS_TABLE +#define IMGUI_HAS_TEXTURES // 1.92+ WIP branch with ImGuiBackendFlags_RendererHasTextures /* @@ -48,6 +49,7 @@ Index of this file: // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage) // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) +// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) // [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData) @@ -169,10 +171,13 @@ struct ImDrawListSplitter; // Helper to split a draw list into differen struct ImDrawVert; // A single vertex (pos + uv + col = 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 -struct ImFontBuilderIO; // Opaque interface to a font builder (stb_truetype or FreeType). +struct ImFontAtlasBuilder; // Opaque storage for building a ImFontAtlas struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImFontLoader; // Opaque interface to a font loading backend (stb_truetype, FreeType etc.). +struct ImTextureData; // Specs and pixel storage for a texture used by Dear ImGui. +struct ImTextureRect; // Coordinates of a rectangle within a texture. struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using) // Forward declarations: ImGui layer @@ -328,8 +333,8 @@ struct ImTextureRef #endif // Members - ImFontAtlas* _Atlas; // Texture/Atlas pointer - ImTextureID _TexID; // _OR_ Underlying user/backend texture identifier, or zero if not yet uploaded. + ImTextureData* _TexData; // Texture, generally owned by a ImFontAtlas + ImTextureID _TexID; // _OR_ Underlying texture identifier for backend, if already uploaded (otherwise pulled from _TexData) }; IM_MSVC_RUNTIME_CHECKS_RESTORE @@ -1638,6 +1643,7 @@ enum ImGuiBackendFlags_ ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. + ImGuiBackendFlags_RendererHasTextures = 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables incremental texture updates and texture reloads. }; // Enumeration for PushStyleColor() / PopStyleColor() @@ -2794,6 +2800,14 @@ static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return IM_MSVC_RUNTIME_CHECKS_RESTORE #endif +// Helpers: ImTexture ==/!= operators provided as convenience (not strictly necessary) +static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } +static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } +//#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // For legacy backends +//static inline bool operator==(ImTextureID lhs, const ImTextureRef& rhs) { return lhs == rhs._TexID && rhs._TexData == NULL; } +//static inline bool operator==(const ImTextureRef& lhs, ImTextureID rhs) { return lhs._TexID == rhs && lhs._TexData == NULL; } +//#endif + // Helpers macros to generate 32-bit encoded colors // - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. // - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. @@ -3041,7 +3055,8 @@ struct ImDrawCmd // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) // Since 1.92: removed ImDrawCmd::TextureId field, the getter function must be used! - inline ImTextureID GetTexID() const { return TexRef._TexID; } + // If for some reason you non C++ tech stack makes it difficult to call it, we may decide to separate the fields in ImDrawCmd. + inline ImTextureID GetTexID() const; }; // Vertex layout @@ -3273,6 +3288,7 @@ struct ImDrawList //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021) // [Internal helpers] + IMGUI_API void _SetDrawListSharedData(ImDrawListSharedData* data); IMGUI_API void _ResetForNewFrame(); IMGUI_API void _ClearFreeMemory(); IMGUI_API void _PopUnusedDrawCmd(); @@ -3309,6 +3325,73 @@ struct ImDrawData IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. }; +//----------------------------------------------------------------------------- +// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureDataUpdate, ImTextureData +//----------------------------------------------------------------------------- + +// We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. +enum ImTextureFormat +{ + ImTextureFormat_RGBA32, // 4 components per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 + ImTextureFormat_Alpha8, // 1 component per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight +}; + +// Status of a texture +enum ImTextureStatus +{ + ImTextureStatus_OK, + ImTextureStatus_Destroyed, // Backend destroyed the texture. + ImTextureStatus_WantCreate, // Requesting backend to create the texture. Set status OK when done. + ImTextureStatus_WantUpdates, // Requesting backend to update specific blocks of pixels (write to texture portions which have never been used before). Set status OK when done. + ImTextureStatus_WantDestroy, // Requesting backend to destroy the texture. Set status to Destroyed when done. +}; + +// Coordinates of a rectangle within a texture. +// When a texture is in ImTextureStatus_WantUpdates state, we provide a list of individual rectangles to copy to GPU texture. +// You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box. +struct ImTextureRect +{ + unsigned short x, y; // Upper-left coordinates of rectangle to update + unsigned short w, h; // Size of rectangle to update (in pixels) +}; + +// Specs and pixel storage for a texture used by Dear ImGui. +// The renderer backend will generally create a GPU-side version of this. +// Why does we store two identifiers: TexID and BackendUserData? +// - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. +// - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. +struct IMGUI_API ImTextureData +{ + ImTextureStatus Status; // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy + ImTextureFormat Format; // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 + int Width; // Texture width + int Height; // Texture height + int BytesPerPixel; // 4 or 1 + int UniqueID; // Sequential index to facilitate identifying a texture when debugging/printing. Only unique per atlas. + unsigned char* Pixels; // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. + ImTextureID TexID; // Identifier stored in ImDrawCmd::GetTexID() and passed to backend RenderDrawData loop. + void* BackendUserData; // Convenience storage for backend. Some backends may have enough with TexID. + ImTextureRect UpdateRect; // Bounding box encompassing all individual updates. + ImVector Updates; // Array of individual updates. + int UnusedFrames; // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. + + // [Internal] + bool UseColors; // [Internal] Tell whether our texture data is known to use colors (rather than just white + alpha). + bool WantDestroyNextFrame; // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. + + // Functions + ImTextureData() { memset(this, 0, sizeof(*this)); } + ~ImTextureData() { DestroyPixels(); } + void Create(ImTextureFormat format, int w, int h); + void DestroyPixels(); + unsigned char* GetPixels() { IM_ASSERT(Pixels != NULL); return Pixels; } + unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } + int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } + int GetPitch() const { return Width * BytesPerPixel; } + ImTextureRef GetTexRef() const { ImTextureRef tex_ref; tex_ref._TexData = (ImTextureData*)(void*)this; tex_ref._TexID = TexID; return tex_ref; } + ImTextureID GetTexID() const { return TexID; } +}; + //----------------------------------------------------------------------------- // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont) //----------------------------------------------------------------------------- @@ -3338,7 +3421,8 @@ struct ImFontConfig // [Internal] char Name[40]; // Name (strictly to ease debugging) - ImFont* DstFont; + ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) + void* FontLoaderData; // Font loader opaque storage (per font config) IMGUI_API ImFontConfig(); }; @@ -3353,6 +3437,9 @@ struct ImFontGlyph float AdvanceX; // Horizontal distance to advance layout with float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates + int PackId; // [Internal] ImFontAtlasRectId value (FIXME: Cold data, could be moved elsewhere?) + + ImFontGlyph() { memset(this, 0, sizeof(*this)); PackId = -1; } }; // Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges(). @@ -3400,12 +3487,14 @@ enum ImFontAtlasFlags_ // - One or more fonts. // - Custom graphics data needed to render the shapes needed by Dear ImGui. // - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). -// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api. -// - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you. -// - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. -// - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples) +// - If you don't call any AddFont*** functions, the default font embedded in the code will be loaded for you. +// It is the rendering backend responsibility to upload texture into your graphics API: +// - ImGui_ImplXXXX_RenderDrawData() functions generally iterate atlas->TexList[] to create/update/destroy each ImTextureData instance. +// - Backend then set ImTextureData's TexID and BackendUserData. +// - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. +// Legacy path: +// - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. -// This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. // Common pitfalls: // - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the // atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data. @@ -3423,25 +3512,30 @@ struct ImFontAtlas IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + + // FIXME-NEWATLAS: Clarify meaning/purpose IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. IMGUI_API void ClearFonts(); // Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. IMGUI_API void Clear(); // Clear all input and output. + IMGUI_API void ClearCache(); // Clear cached glyphs + // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). // The pitch is always = Width * BytesPerPixels (1 or 4) // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. - IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel - IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - bool IsBuilt() const { return Fonts.Size > 0 && TexReady; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... + IMGUI_API void BuildGrowTexture(); + IMGUI_API void BuildCompactTexture(); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - void SetTexID(ImTextureID id){ TexID._Atlas = this; TexID._TexID = id; } // FIXME-NEWATLAS: Called by legacy backends. - void SetTexID(ImTextureRef id) { TexID = id; } // FIXME-NEWATLAS: Called by legacy backends. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + void SetTexID(ImTextureID id) { TexRef._TexData = NULL; TexRef._TexID = id; } // Called by legacy backends. + void SetTexID(ImTextureRef id) { TexRef = id; } // Called by legacy backends. #endif - + bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... //------------------------------------------- // Glyph Ranges @@ -3466,10 +3560,15 @@ struct ImFontAtlas //------------------------------------------- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. - // - After calling Build(), you can query the rectangle position and render your pixels. - // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. - // - You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), - // so you can render e.g. custom colorful icons and use them as regular glyphs. + // You can request your rectangles to be mapped as font glyph (given a font + Unicode point), + // so you can render e.g. custom colorful icons and use them as regular glyphs. + // - If your backend supports ImGuiBackendFlags_RendererHasTextures (since 1.92.X): + // - Packing is done immediately. Returns >= on success. Return <0 on error. + // - You can render your pixels into the texture right after calling the AddCustomRectXXX functions. + // - Texture may be resized, so you cannot cache UV coordinates. // FIXME-NEWATLAS-V1: How to handle that smoothly? + // - If your backend does NOT supports ImGuiBackendFlags_RendererHasTextures (older than 1.92.X): + // - After calling Build(), you can query the rectangle position and render your pixels. + // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); @@ -3485,34 +3584,38 @@ struct ImFontAtlas // Input ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) - ImTextureRef TexID; // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. + ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. + ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8). int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). + // Output + ImTextureData* TexData; // Current texture + ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). + // [Internal] - // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you. bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. - bool TexReady; // Set when texture was built matching current font input - bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format. - unsigned char* TexPixelsAlpha8; // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight - unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 - int TexWidth; // Texture width calculated during Build(). - int TexHeight; // Texture height calculated during Build(). - ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight) + bool TexIsBuilt; // Set when texture was built matching current font input + bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. + ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight) ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVector Sources; // Source/configuration data ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines + int TexNextUniqueID; // Next value to be stored in TexData->UniqueID + ImDrawListSharedData* DrawListSharedData; // In principle this could become an array (e.g. multiple contexts using same atlas) // [Internal] Font builder - const ImFontBuilderIO* FontBuilderIO; // Opaque interface to a font builder (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). - unsigned int FontBuilderFlags; // Shared flags (for all fonts) for custom font builder. THIS IS BUILD IMPLEMENTATION DEPENDENT. Per-font override is also available in ImFontConfig. - - // [Internal] Packing data - int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors - int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines + ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public + const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! + const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name + void* FontLoaderData; // Font backend opaque storage + unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. + int _PackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size. + int _PackedRects; // Number of packed rectangles. + float _PackNodesFactor = 1.0f; // [Obsolete] //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ @@ -3525,13 +3628,13 @@ struct ImFont { // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize) ImVector IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). - float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX + float FallbackAdvanceX; // 4 // out // FindGlyph(FallbackChar)->AdvanceX float FontSize; // 4 // in // Height of characters/line, set during loading (don't change after loading) // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // All glyphs. - ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + int FallbackGlyphIndex; // 4 // out // Index of FontFallbackChar // [Internal] Members: Cold ~32/40 bytes // Conceptually Sources[] is the list of font sources merged to create this font. @@ -3543,18 +3646,21 @@ struct ImFont ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float EllipsisWidth; // 4 // out // Total ellipsis Width float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 - float Scale; // 4 // in // Base font scale (1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() + float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) - bool DirtyLookupTables; // 1 // out // ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + bool LockDisableLoading; + ImFontConfig* LockSingleSrcConfig; // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API ImFontGlyph* FindGlyph(ImWchar c); - IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); - float GetCharAdvance(ImWchar c) { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; } + IMGUI_API ImFontGlyph* FindGlyph(ImWchar c); // Return fallback glyph if requested glyph doesn't exists. + IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist + IMGUI_API float GetCharAdvance(ImWchar c); + IMGUI_API bool IsGlyphLoaded(ImWchar c); + IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } const char* GetDebugName() const { return Sources ? Sources->Name : ""; } @@ -3571,14 +3677,24 @@ struct ImFont #endif // [Internal] Don't use! - IMGUI_API void BuildLookupTable(); IMGUI_API void ClearOutputData(); - IMGUI_API void GrowIndex(int new_size); - IMGUI_API void AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x); - IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , bool overwrite_dst = true); // Makes 'from_codepoint' character points to 'to_codepoint' character. Currently needs to be called AFTER fonts have been built. + IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); + IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c); + IMGUI_API void BuildRegisterGlyph(ImFontConfig* src, const ImFontGlyph* glyph); + IMGUI_API void BuildGrowIndex(int new_size); + IMGUI_API void BuildClearGlyphs(); }; +// FIXME-NEWATLAS: Added indirection to avoid patching ImDrawCmd after texture updates. +inline ImTextureID ImDrawCmd::GetTexID() const +{ + ImTextureID tex_id = TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID; + if (TexRef._TexData != NULL) + IM_ASSERT(tex_id && "ImDrawCmd is referring to Atlas texture that wasn't uploaded to graphics system."); + return tex_id; +} + //----------------------------------------------------------------------------- // [SECTION] Viewports //----------------------------------------------------------------------------- @@ -3657,6 +3773,10 @@ struct ImGuiPlatformIO // Input - Interface with Renderer Backend //------------------------------------------------------------------ + // Optional: Maximum texture size supported by renderer (used to adjust how we size textures). 0 if not known. + int Renderer_TextureMaxWidth; + int Renderer_TextureMaxHeight; + // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. void* Renderer_RenderState; }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 790f3761181f..5d5075e81b34 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -576,6 +576,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors); ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", &io.BackendFlags, ImGuiBackendFlags_HasSetMousePos); ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset); + ImGui::CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); ImGui::EndDisabled(); ImGui::TreePop(); @@ -1778,9 +1779,9 @@ static void DemoWindowWidgetsImages() // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples - ImTextureRef my_tex_id = io.Fonts->TexID; - float my_tex_w = (float)io.Fonts->TexWidth; - float my_tex_h = (float)io.Fonts->TexHeight; + ImTextureRef my_tex_id = io.Fonts->TexRef; + float my_tex_w = (float)io.Fonts->TexData->Width; + float my_tex_h = (float)io.Fonts->TexData->Height; { ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); ImVec2 pos = ImGui::GetCursorScreenPos(); @@ -8041,7 +8042,7 @@ void ImGui::ShowAboutWindow(bool* p_open) if (copy_to_clipboard) { ImGui::LogToClipboard(); - ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub + ImGui::LogText("```cpp\n"); // Back quotes will make text appears without formatting when pasting on GitHub } ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); @@ -8137,8 +8138,10 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors"); if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos"); if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset"); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) ImGui::Text(" RendererHasTextures"); ImGui::Separator(); - ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight); + ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height); + ImGui::Text("io.Fonts->FontLoaderName: \"%s\"", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL"); ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); ImGui::Separator(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8a31b79f7151..b1cf15ff4389 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -13,7 +13,8 @@ Index of this file: // [SECTION] ImDrawData // [SECTION] Helpers ShadeVertsXXX functions // [SECTION] ImFontConfig -// [SECTION] ImFontAtlas +// [SECTION] ImFontAtlas, ImFontAtlasBuilder +// [SECTION] ImFontAtlas: backend for stb_truetype // [SECTION] ImFontAtlas: glyph ranges helpers // [SECTION] ImFontGlyphRangesBuilder // [SECTION] ImFont @@ -389,6 +390,12 @@ ImDrawListSharedData::ImDrawListSharedData() ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); } ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); + RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. +} + +ImDrawListSharedData::~ImDrawListSharedData() +{ + IM_ASSERT(DrawLists.Size == 0); } void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) @@ -409,12 +416,22 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) ImDrawList::ImDrawList(ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); - _Data = shared_data; + _SetDrawListSharedData(shared_data); } ImDrawList::~ImDrawList() { _ClearFreeMemory(); + _SetDrawListSharedData(NULL); +} + +void ImDrawList::_SetDrawListSharedData(ImDrawListSharedData* data) +{ + if (_Data != NULL) + _Data->DrawLists.find_erase_unsorted(this); + _Data = data; + if (_Data != NULL) + _Data->DrawLists.push_back(this); } // Initialize before use in a new frame. We always have a command ready in the buffer. @@ -573,10 +590,6 @@ void ImDrawList::_OnChangedClipRect() curr_cmd->ClipRect = _CmdHeader.ClipRect; } -// Operators for easy compare -static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._Atlas == rhs._Atlas; } -static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._Atlas != rhs._Atlas; } - void ImDrawList::_OnChangedTexture() { // If current command is used with different settings we need to add a new command @@ -1690,8 +1703,6 @@ void ImDrawList::AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 if (font_size == 0.0f) font_size = _Data->FontSize; - IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TexRef); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. - ImVec4 clip_rect = _CmdHeader.ClipRect; if (cpu_fine_clip_rect) { @@ -2396,39 +2407,113 @@ ImFontConfig::ImFontConfig() } //----------------------------------------------------------------------------- -// [SECTION] ImFontAtlas +// [SECTION] ImTextureData +//----------------------------------------------------------------------------- +// - ImTextureData::Create() +// - ImTextureData::DestroyPixels() +//----------------------------------------------------------------------------- + +static int GetTextureFormatBytesPerPixel(ImTextureFormat format) +{ + switch (format) + { + case ImTextureFormat_Alpha8: return 1; + case ImTextureFormat_RGBA32: return 4; + } + IM_ASSERT(0); + return 0; +} + +void ImTextureData::Create(ImTextureFormat format, int w, int h) +{ + DestroyPixels(); + Format = format; + Width = w; + Height = h; + BytesPerPixel = GetTextureFormatBytesPerPixel(format); + UseColors = false; + Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel); + IM_ASSERT(Pixels != NULL); + memset(Pixels, 0, Width * Height * BytesPerPixel); +} + +void ImTextureData::DestroyPixels() +{ + if (Pixels) + IM_FREE(Pixels); + Pixels = NULL; + UseColors = false; +} + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas, ImFontAtlasBuilder //----------------------------------------------------------------------------- // - Default texture data encoded in ASCII +// - ImFontAtlasBuilder // - ImFontAtlas::ClearInputData() // - ImFontAtlas::ClearTexData() // - ImFontAtlas::ClearFonts() // - ImFontAtlas::Clear() -// - ImFontAtlas::GetTexDataAsAlpha8() -// - ImFontAtlas::GetTexDataAsRGBA32() +// - ImFontAtlas::ClearCache() +// - ImFontAtlas::BuildGrowTexture() +// - ImFontAtlas::BuildCompactTexture() +// - ImFontAtlasUpdateTextures() +//----------------------------------------------------------------------------- +// - ImFontAtlasTextureBlockConvertAndPostProcess() +// - ImFontAtlasTextureBlockConvert() +// - ImFontAtlasTextureBlockPostProcessMultiply() +// - ImFontAtlasTextureBlockCopy() +// - ImFontAtlasTextureBlockQueueUpload() +//----------------------------------------------------------------------------- +// - ImFontAtlas::GetTexDataAsAlpha8() [legacy] +// - ImFontAtlas::GetTexDataAsRGBA32() [legacy] +// - ImFontAtlas::Build() +//----------------------------------------------------------------------------- // - ImFontAtlas::AddFont() // - ImFontAtlas::AddFontDefault() // - ImFontAtlas::AddFontFromFileTTF() // - ImFontAtlas::AddFontFromMemoryTTF() // - ImFontAtlas::AddFontFromMemoryCompressedTTF() // - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF() +//----------------------------------------------------------------------------- // - ImFontAtlas::AddCustomRectRegular() // - ImFontAtlas::AddCustomRectFontGlyph() // - ImFontAtlas::CalcCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() -// - ImFontAtlas::Build() -// - ImFontAtlasBuildMultiplyCalcLookupTable() -// - ImFontAtlasBuildMultiplyRectAlpha8() -// - ImFontAtlasBuildWithStbTruetype() -// - ImFontAtlasGetBuilderForStbTruetype() -// - ImFontAtlasUpdateSourcesPointers() -// - ImFontAtlasBuildSetupFont() -// - ImFontAtlasBuildPackCustomRects() -// - ImFontAtlasBuildRender8bppRectFromString() -// - ImFontAtlasBuildRender32bppRectFromString() -// - ImFontAtlasBuildRenderDefaultTexData() -// - ImFontAtlasBuildRenderLinesTexData() +//----------------------------------------------------------------------------- +// - ImFontAtlasBuildSetupFontLoader() +// - ImFontAtlasBuildPreloadAllGlyphRanges() +// - ImFontAtlasBuildUpdatePointers() +// - ImFontAtlasBuildRenderBitmapFromString() +// - ImFontAtlasBuildUpdateBasicTexData() +// - ImFontAtlasBuildUpdateLinesTexData() +// - ImFontAtlasBuildAddFont() +// - ImFontAtlasBuildSetupFontSpecialGlyphs() +// - ImFontAtlasBuildReloadFont() +//----------------------------------------------------------------------------- +// - ImFontAtlasAddDrawListSharedData() +// - ImFontAtlasRemoveDrawListSharedData() +// - ImFontAtlasUpdateDrawListsTextures() +// - ImFontAtlasUpdateDrawListsSharedData() +//----------------------------------------------------------------------------- +// - ImFontAtlasBuildSetTexture() +// - ImFontAtlasBuildAddTexture() +// - ImFontAtlasBuildRepackTexture() +// - ImFontAtlasBuildGrowTexture() +// - ImFontAtlasBuildCompactTexture() // - ImFontAtlasBuildInit() -// - ImFontAtlasBuildFinish() +// - ImFontAtlasBuildDestroy() +//----------------------------------------------------------------------------- +// - ImFontAtlasPackInit() +// - ImFontAtlasPackAddRect() +// - ImFontAtlasPackGetRect() +//----------------------------------------------------------------------------- +// - ImFont::BuildLoadGlyph() +// - ImFont::BuildClearGlyphs() +//----------------------------------------------------------------------------- +// - ImFontAtlasDebugLogTextureRequests() +//----------------------------------------------------------------------------- +// - ImFontAtlasGetFontLoaderForStbTruetype() //----------------------------------------------------------------------------- // A work of art lies ahead! (. = white layer, X = black layer, others are blank) @@ -2483,23 +2568,29 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed }; +#define IM_FONTGLYPH_INDEX_UNUSED ((ImU16)-1) // 0xFFFF +#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE + ImFontAtlas::ImFontAtlas() { memset(this, 0, sizeof(*this)); + TexDesiredFormat = ImTextureFormat_RGBA32; TexGlyphPadding = 1; - TexID._Atlas = this; - PackIdMouseCursors = PackIdLines = -1; + TexRef._TexData = NULL;// this; + TexNextUniqueID = 1; + _PackNodesFactor = 1.0f; + Builder = NULL; } ImFontAtlas::~ImFontAtlas() { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); Clear(); } -void ImFontAtlas::ClearInputData() +void ImFontAtlas::ClearInputData() { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); for (ImFontConfig& font_cfg : Sources) if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas) { @@ -2516,77 +2607,281 @@ void ImFontAtlas::ClearInputData() } Sources.clear(); CustomRects.clear(); - PackIdMouseCursors = PackIdLines = -1; // Important: we leave TexReady untouched } -void ImFontAtlas::ClearTexData() +void ImFontAtlas::ClearTexData() { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); - if (TexPixelsAlpha8) - IM_FREE(TexPixelsAlpha8); - if (TexPixelsRGBA32) - IM_FREE(TexPixelsRGBA32); - TexPixelsAlpha8 = NULL; - TexPixelsRGBA32 = NULL; - TexPixelsUseColors = false; - // Important: we leave TexReady untouched + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); + TexList.clear(); + IM_DELETE(TexData); + TexData = NULL; + // TexData.Destroy(); + //IM_ASSERT(0); + // Important: we leave TexReady untouched } -void ImFontAtlas::ClearFonts() +void ImFontAtlas::ClearFonts() { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + // FIXME-NEWATLAS: Illegal to remove currently bound font. + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); ClearInputData(); Fonts.clear_delete(); - TexReady = false; + TexIsBuilt = false; + DrawListSharedData->Font = NULL; + DrawListSharedData->FontScale = DrawListSharedData->FontSize = 0.0f; } -void ImFontAtlas::Clear() +void ImFontAtlas::Clear() { + //IM_DELETE(Builder); // FIXME-NEW-ATLAS: ClearXXX functions + const ImFontLoader* font_loader = FontLoader; + ImFontAtlasBuildSetupFontLoader(this, NULL); ClearInputData(); ClearTexData(); ClearFonts(); + ImFontAtlasBuildSetupFontLoader(this, font_loader); +} + +void ImFontAtlas::ClearCache() +{ + int tex_w = (TexData && TexData->Status != ImTextureStatus_WantDestroy) ? TexData->Width : 0; + int tex_h = (TexData && TexData->Status != ImTextureStatus_WantDestroy) ? TexData->Height : 0; + ImFontAtlasBuildDestroy(this); + if (tex_w != 0 && tex_h != 0) + ImFontAtlasBuildAddTexture(this, tex_w, tex_h); + ImFontAtlasBuildInit(this); +} + +void ImFontAtlas::BuildGrowTexture() +{ + ImFontAtlasBuildGrowTexture(this, TexData->Width, TexData->Height); +} + +void ImFontAtlas::BuildCompactTexture() +{ + ImFontAtlasBuildCompactTexture(this); +} + +static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas) +{ + // [LEGACY] Copy back the ImGuiBackendFlags_RendererHasTextures flag from ImGui context. + // - This is the 1% exceptional case where that dependency if useful, to bypass an issue where otherwise at the + // time of an early call to Build(), it would be impossible for us to tell if the backend supports texture update. + // - Without this hack, we would have quite a pitfall as many legacy codebases have an early call to Build(). + // Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare. + if (atlas->DrawListSharedData) + if (ImGuiContext* imgui_ctx = atlas->DrawListSharedData->Context) + atlas->DrawListSharedData->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; +} + +// Called by NewFrame() +void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) +{ + if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) + { + ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); + IM_ASSERT_USER_ERROR(atlas->DrawListSharedData->RendererHasTextures == false, + "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); + } + + for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) + { + ImTextureData* tex = atlas->TexList[tex_n]; + bool remove_from_list = false; + tex->Updates.resize(0); + tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0; + tex->UpdateRect.w = tex->UpdateRect.h = 0; + + if (tex->Status == ImTextureStatus_Destroyed) + { + IM_ASSERT(tex->TexID == 0 && tex->BackendUserData == NULL); + if (tex->WantDestroyNextFrame) + remove_from_list = true; // Destroy was scheduled by us + else + tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend (e.g. freed resources mid-run) + } + else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy) + { + // Request destroy. Keep bool as it allows us to keep track of things. + IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); + tex->Status = ImTextureStatus_WantDestroy; + tex->DestroyPixels(); + } + + // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering. + // We allow the texture staying in _WantDestroy state and increment a counter which the backend can use to take its decision. + if (tex->Status == ImTextureStatus_WantDestroy) + tex->UnusedFrames++; + + // If a texture has never reached the backend, they don't need to know about it. + if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == 0 && tex->BackendUserData == NULL) + remove_from_list = true; + + // Remove + if (remove_from_list) + { + IM_DELETE(tex); + atlas->TexList.erase(atlas->TexList.begin() + tex_n); + tex_n--; + } + } } -void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +// Source buffer may be written to (used for in-place mods). +// Post-process hooks may eventually be added here. +void ImFontAtlasTextureBlockConvertAndPostProcess(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) { - // Build atlas on demand - if (TexPixelsAlpha8 == NULL) - Build(); + IM_UNUSED(atlas); + IM_UNUSED(font); + IM_UNUSED(glyph); + + // Multiply operator (legacy) + if (src->RasterizerMultiply != 1.0f) + ImFontAtlasTextureBlockPostProcessMultiply(atlas, font, src, glyph, src_pixels, src_fmt, w, h, src_pitch, src->RasterizerMultiply); + + ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, dst, dst_fmt, dst_pitch, w, h); +} - *out_pixels = TexPixelsAlpha8; - if (out_width) *out_width = TexWidth; - if (out_height) *out_height = TexHeight; - if (out_bytes_per_pixel) *out_bytes_per_pixel = 1; +void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) +{ + IM_ASSERT(src_pixels != NULL && dst_pixels != NULL); + if (src_fmt == dst_fmt) + { + int line_sz = w * GetTextureFormatBytesPerPixel(src_fmt); + for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch) + memcpy(dst_pixels, src_pixels, line_sz); + } + else if (src_fmt == ImTextureFormat_Alpha8 && dst_fmt == ImTextureFormat_RGBA32) + { + for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch) + { + const ImU8* src_p = (const ImU8*)src_pixels; + ImU32* dst_p = (ImU32*)(void*)dst_pixels; + for (int nx = w; nx > 0; nx--) + *dst_p++ = IM_COL32(255, 255, 255, (unsigned int)(*src_p++)); + } + } + else if (src_fmt == ImTextureFormat_RGBA32 && dst_fmt == ImTextureFormat_Alpha8) + { + for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch) + { + const ImU32* src_p = (const ImU32*)(void*)src_pixels; + ImU8* dst_p = (ImU8*)dst_pixels; + for (int nx = w; nx > 0; nx--) + *dst_p++ = ((*src_p++) >> IM_COL32_A_SHIFT) & 0xFF; + } + } + else + { + IM_ASSERT(0); + } } -void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* pixels, ImTextureFormat format, int w, int h, int pitch, float in_multiply_factor) { - // Convert to RGBA32 format on demand - // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp - if (!TexPixelsRGBA32) + IM_UNUSED(atlas); + IM_UNUSED(font); + IM_UNUSED(src); + IM_UNUSED(glyph); + IM_ASSERT(in_multiply_factor >= 0.0f); + IM_ASSERT_PARANOID(w <= pitch); + if (format == ImTextureFormat_Alpha8) { - unsigned char* pixels = NULL; - GetTexDataAsAlpha8(&pixels, NULL, NULL); - if (pixels) + for (int ny = h; ny > 0; ny--, pixels += pitch) { - TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4); - const unsigned char* src = pixels; - unsigned int* dst = TexPixelsRGBA32; - for (int n = TexWidth * TexHeight; n > 0; n--) - *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++)); + ImU8* p = (ImU8*)pixels; + for (int nx = w; nx > 0; nx--, p++) + { + unsigned int v = ImMin((unsigned int)(*p * in_multiply_factor), (unsigned int)255); + *p = (unsigned char)v; + } + } + } + else if (format == ImTextureFormat_RGBA32) + { + for (int ny = h; ny > 0; ny--, pixels += pitch) + { + ImU32* p = (ImU32*)(void*)pixels; + for (int nx = w; nx > 0; nx--, p++) + { + unsigned int a = ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * in_multiply_factor), (unsigned int)255); + *p = IM_COL32((*p >> IM_COL32_R_SHIFT) & 0xFF, (*p >> IM_COL32_G_SHIFT) & 0xFF, (*p >> IM_COL32_B_SHIFT) & 0xFF, a); + } } } + else + { + IM_ASSERT(0); + } +} + +// Convert block from one texture to another +void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h) +{ + IM_ASSERT(src_tex != dst_tex); + IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL); + IM_ASSERT(src_tex->Format == dst_tex->Format); + IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width); + IM_ASSERT(src_y >= 0 && src_y + h <= src_tex->Height); + IM_ASSERT(dst_x >= 0 && dst_x + w <= dst_tex->Width); + IM_ASSERT(dst_y >= 0 && dst_y + h <= dst_tex->Height); + for (int y = 0; y < h; y++) + memcpy(dst_tex->GetPixelsAt(dst_x, dst_y + y), src_tex->GetPixelsAt(src_x, src_y + y), w * dst_tex->BytesPerPixel); +} + +// Queue texture block update for renderer backend +void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h) +{ + // Queue texture update (no need to queue if status is _WantCreate) + IM_ASSERT(atlas); + if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates) + { + IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000); + ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h }; + tex->Status = ImTextureStatus_WantUpdates; + tex->Updates.push_back(req); + int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w); + int new_y1 = ImMax(tex->UpdateRect.h == 0 ? 0 : tex->UpdateRect.y + tex->UpdateRect.h, req.y + req.h); + IM_ASSERT(new_x1 < 0x8000); + IM_ASSERT(new_y1 < 0x8000); + tex->UpdateRect.x = ImMin(tex->UpdateRect.x, req.x); + tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y); + tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x); + tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y); + } +} + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static void GetTexDataAsFormat(ImFontAtlas* atlas, ImTextureFormat format, unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + ImTextureData* tex = atlas->TexData; + if (!atlas->TexIsBuilt || tex == NULL || tex->Pixels == NULL || atlas->TexDesiredFormat != format) + { + atlas->TexDesiredFormat = format; + atlas->Build(); + tex = atlas->TexData; + } + if (out_pixels) { *out_pixels = (unsigned char*)tex->Pixels; }; + if (out_width) { *out_width = tex->Width; }; + if (out_height) { *out_height = tex->Height; }; + if (out_bytes_per_pixel) { *out_bytes_per_pixel = tex->BytesPerPixel; } +} + +void ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + GetTexDataAsFormat(this, ImTextureFormat_Alpha8, out_pixels, out_width, out_height, out_bytes_per_pixel); +} - *out_pixels = (unsigned char*)TexPixelsRGBA32; - if (out_width) *out_width = TexWidth; - if (out_height) *out_height = TexHeight; - if (out_bytes_per_pixel) *out_bytes_per_pixel = 4; +void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel) +{ + GetTexDataAsFormat(this, ImTextureFormat_RGBA32, out_pixels, out_width, out_height, out_bytes_per_pixel); } +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); @@ -2614,12 +2909,15 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // - We may support it better later and remove this rounding. new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels); - // Pointers to Sources data are otherwise dangling - ImFontAtlasUpdateSourcesPointers(this); + // Pointers to Sources are otherwise dangling + ImFontAtlasBuildUpdatePointers(this); + + if (Builder != NULL) + ImFontAtlasBuildAddFont(this, &new_font_cfg); // Invalidate texture - TexReady = false; - ClearTexData(); + //TexReady = false; + //ClearTexData(); return new_font_cfg.DstFont; } @@ -2672,7 +2970,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); size_t data_size = 0; void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); if (!data) @@ -2694,7 +2992,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, // NB: Transfer ownership of 'ttf_data' to ImFontAtlas, unless font_cfg_template->FontDataOwnedByAtlas == false. Owned TTF buffer will be deleted after Build(). ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges) { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); IM_ASSERT(font_cfg.FontData == NULL); IM_ASSERT(font_data_size > 100 && "Incorrect value for font_data_size!"); // Heuristic to prevent accidentally passing a wrong value to font_data_size. @@ -2728,6 +3026,25 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed return font; } +// FIXME-NEWATLAS-V1: Feature is broken for now. +/* + // Register custom rectangle glyphs + for (int i = 0; i < atlas->CustomRects.Size; i++) + { + const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; + if (r->Font == NULL || r->GlyphID == 0) + continue; + + // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, PixelSnapH + IM_ASSERT(r->Font->ContainerAtlas == atlas); + ImVec2 uv0, uv1; + atlas->CalcCustomRectUV(r, &uv0, &uv1); + r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); + if (r->GlyphColored) + r->Font->Glyphs.back().Colored = 1; + } +*/ + int ImFontAtlas::AddCustomRectRegular(int width, int height) { IM_ASSERT(width > 0 && width <= 0xFFFF); @@ -2761,7 +3078,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const { - IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates + IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); @@ -2774,9 +3091,8 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) return false; - IM_ASSERT(atlas->PackIdMouseCursors != -1); - ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); - ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors); + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->x, (float)r->y); ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; *out_size = size; *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2]; @@ -2788,407 +3104,104 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } -bool ImFontAtlas::Build() +bool ImFontAtlas::Build() { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); // Default font is none are specified if (Sources.Size == 0) AddFontDefault(); // Select builder - // - Note that we do not reassign to atlas->FontBuilderIO, since it is likely to point to static data which + // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are - // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBuilderIO somewhere - // and point to it instead of pointing directly to return value of the GetBuilderXXX functions. - const ImFontBuilderIO* builder_io = FontBuilderIO; - if (builder_io == NULL) + // using a hot-reloading scheme that messes up static data, store your own instance of ImFontLoader somewhere + // and point to it instead of pointing directly to return value of the GetBackendIOXXX functions. + if (FontLoader == NULL) { #ifdef IMGUI_ENABLE_FREETYPE - builder_io = ImGuiFreeType::GetBuilderForFreeType(); + ImFontAtlasBuildSetupFontLoader(this, ImGuiFreeType::GetBackendIOForFreeType()); #elif defined(IMGUI_ENABLE_STB_TRUETYPE) - builder_io = ImFontAtlasGetBuilderForStbTruetype(); + ImFontAtlasBuildSetupFontLoader(this, ImFontAtlasGetFontLoaderForStbTruetype()); #else IM_ASSERT(0); // Invalid Build function #endif } - // Build - return builder_io->FontBuilder_Build(this); -} + // Create initial texture size + ImFontAtlasBuildAddTexture(this, 512, 128); + ImFontAtlasBuildInit(this); -void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor) -{ - for (unsigned int i = 0; i < 256; i++) - { - unsigned int value = (unsigned int)(i * in_brighten_factor); - out_table[i] = value > 255 ? 255 : (value & 0xFF); - } -} + // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs + ImFontAtlasBuildUpdateRendererHasTexturesFromContext(this); + if (DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures + ImFontAtlasBuildPreloadAllGlyphRanges(this); + TexIsBuilt = true; -void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride) -{ - IM_ASSERT_PARANOID(w <= stride); - unsigned char* data = pixels + x + y * stride; - for (int j = h; j > 0; j--, data += stride - w) - for (int i = w; i > 0; i--, data++) - *data = table[*data]; + return true; } -void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v) +void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v) { // Automatically disable horizontal oversampling over size 36 *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (src->SizePixels * src->RasterizerDensity > 36.0f || src->PixelSnapH) ? 1 : 2; *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1; } -#ifdef IMGUI_ENABLE_STB_TRUETYPE -// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont) -// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.) -struct ImFontBuildSrcData -{ - stbtt_fontinfo FontInfo; - stbtt_pack_range PackRange; // Hold the list of codepoints to pack (essentially points to Codepoints.Data) - stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. - stbtt_packedchar* PackedChars; // Output glyphs - const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) - int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] - int GlyphsHighest; // Highest requested codepoint - int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) - ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) - ImVector GlyphsList; // Glyph codepoints list (flattened version of GlyphsSet) -}; - -// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) -struct ImFontBuildDstData -{ - int SrcCount; // Number of source fonts targeting this destination font. - int GlyphsHighest; - int GlyphsCount; - ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. -}; - -static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector* out) -{ - IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int)); - const ImU32* it_begin = in->Storage.begin(); - const ImU32* it_end = in->Storage.end(); - for (const ImU32* it = it_begin; it < it_end; it++) - if (ImU32 entries_32 = *it) - for (ImU32 bit_n = 0; bit_n < 32; bit_n++) - if (entries_32 & ((ImU32)1 << bit_n)) - out->push_back((int)(((it - it_begin) << 5) + bit_n)); -} - -static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) +void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader) { - IM_ASSERT(atlas->Sources.Size > 0); - - ImFontAtlasBuildInit(atlas); - - // Clear atlas - atlas->TexID._TexID = 0; - atlas->TexWidth = atlas->TexHeight = 0; - atlas->TexUvScale = ImVec2(0.0f, 0.0f); - atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); - atlas->ClearTexData(); - - // Temporary storage for building - ImVector src_tmp_array; - ImVector dst_tmp_array; - src_tmp_array.resize(atlas->Sources.Size); - dst_tmp_array.resize(atlas->Fonts.Size); - memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); - memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); - - // 1. Initialize font loading structure, check font data validity - for (int src_i = 0; src_i < atlas->Sources.Size; src_i++) - { - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - ImFontConfig& src = atlas->Sources[src_i]; - IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas)); - - // Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) - src_tmp.DstIndex = -1; - for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) - if (src.DstFont == atlas->Fonts[output_i]) - src_tmp.DstIndex = output_i; - if (src_tmp.DstIndex == -1) - { - IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array? - return false; - } - // Initialize helper structure for font loading and verify that the TTF/OTF data is correct - const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src.FontData, src.FontNo); - IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); - if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)src.FontData, font_offset)) - { - IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); - return false; - } - - // Measure highest codepoints - ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault(); - for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) - { - // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, - // or to forget to zero-terminate the glyph range array. - IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); - src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); - } - dst_tmp.SrcCount++; - dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); - } - - // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. - int total_glyphs_count = 0; - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); - if (dst_tmp.GlyphsSet.Storage.empty()) - dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); - - for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) - for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) - { - if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) - continue; - if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? - continue; - - // Add to avail set/counters - src_tmp.GlyphsCount++; - dst_tmp.GlyphsCount++; - src_tmp.GlyphsSet.SetBit(codepoint); - dst_tmp.GlyphsSet.SetBit(codepoint); - total_glyphs_count++; - } - } - - // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); - UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList); - src_tmp.GlyphsSet.Clear(); - IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); - } - for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) - dst_tmp_array[dst_i].GlyphsSet.Clear(); - dst_tmp_array.clear(); - - // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) - // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) - ImVector buf_rects; - ImVector buf_packedchars; - buf_rects.resize(total_glyphs_count); - buf_packedchars.resize(total_glyphs_count); - memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); - memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes()); - - // 4. Gather glyphs sizes so we can pack them in our virtual canvas. - int total_surface = 0; - int buf_rects_out_n = 0; - int buf_packedchars_out_n = 0; - const int pack_padding = atlas->TexGlyphPadding; - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; - - src_tmp.Rects = &buf_rects[buf_rects_out_n]; - src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n]; - buf_rects_out_n += src_tmp.GlyphsCount; - buf_packedchars_out_n += src_tmp.GlyphsCount; - - // Automatic selection of oversampling parameters - ImFontConfig& src = atlas->Sources[src_i]; - int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(&src, &oversample_h, &oversample_v); - - // Convert our ranges in the format stb_truetype wants - src_tmp.PackRange.font_size = src.SizePixels * src.RasterizerDensity; - src_tmp.PackRange.first_unicode_codepoint_in_range = 0; - src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data; - src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size; - src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars; - src_tmp.PackRange.h_oversample = (unsigned char)oversample_h; - src_tmp.PackRange.v_oversample = (unsigned char)oversample_v; - - // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects) - const float scale = (src.SizePixels > 0.0f) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels * src.RasterizerDensity) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -src.SizePixels * src.RasterizerDensity); - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) - { - int x0, y0, x1, y1; - const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]); - IM_ASSERT(glyph_index_in_font != 0); - stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * oversample_h, scale * oversample_v, 0, 0, &x0, &y0, &x1, &y1); - src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + pack_padding + oversample_h - 1); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + pack_padding + oversample_v - 1); - total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; - } - } - for (int i = 0; i < atlas->CustomRects.Size; i++) - total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding); - - // We need a width for the skyline algorithm, any width! - // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. - // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. - const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; - atlas->TexHeight = 0; - if (atlas->TexDesiredWidth > 0) - atlas->TexWidth = atlas->TexDesiredWidth; - else - atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512; - - // 5. Start packing - // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). - const int TEX_HEIGHT_MAX = 1024 * 32; - stbtt_pack_context spc = {}; - stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, 0, NULL); - spc.padding = atlas->TexGlyphPadding; // Because we mixup stbtt_PackXXX and stbrp_PackXXX there's a bit of a hack here, not passing the value to stbtt_PackBegin() allows us to still pack a TexWidth-1 wide item. (#8107) - ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info); - - // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; - - stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount); - - // Extend texture height and mark missing glyphs as non-packed so we won't render them. - // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) - if (src_tmp.Rects[glyph_i].was_packed) - atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); - } - - // 7. Allocate texture - atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); - atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); - memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); - spc.pixels = atlas->TexPixelsAlpha8; - spc.height = atlas->TexHeight; - - // 8. Render/rasterize font characters into the texture - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontConfig& src = atlas->Sources[src_i]; - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; - - stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects); - - // Apply multiply operator - if (src.RasterizerMultiply != 1.0f) - { - unsigned char multiply_table[256]; - ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply); - stbrp_rect* r = &src_tmp.Rects[0]; - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++) - if (r->was_packed) - ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1); - } - src_tmp.Rects = NULL; - } - - // End packing - stbtt_PackEnd(&spc); - buf_rects.clear(); + if (atlas->FontLoader == font_loader) + return; + IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); - // 9. Setup ImFont and glyphs for runtime - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) + ImFontAtlasBuildDestroy(atlas); + if (atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { - // When merging fonts with MergeMode=true: - // - We can have multiple input fonts writing into a same destination font. - // - dst_font->Sources is != from src which is our source configuration. - ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; - ImFontConfig& src = atlas->Sources[src_i]; - ImFont* dst_font = src.DstFont; - - const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, src.SizePixels); - int unscaled_ascent, unscaled_descent, unscaled_line_gap; - stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); - - const float ascent = ImCeil(unscaled_ascent * font_scale); - const float descent = ImFloor(unscaled_descent * font_scale); - ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent); - const float font_off_x = src.GlyphOffset.x; - const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent); - - const float inv_rasterization_scale = 1.0f / src.RasterizerDensity; - - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) - { - // Register glyph - const int codepoint = src_tmp.GlyphsList[glyph_i]; - const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i]; - stbtt_aligned_quad q; - float unused_x = 0.0f, unused_y = 0.0f; - stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0); - float x0 = q.x0 * inv_rasterization_scale + font_off_x; - float y0 = q.y0 * inv_rasterization_scale + font_off_y; - float x1 = q.x1 * inv_rasterization_scale + font_off_x; - float y1 = q.y1 * inv_rasterization_scale + font_off_y; - dst_font->AddGlyph(&src, (ImWchar)codepoint, x0, y0, x1, y1, q.s0, q.t0, q.s1, q.t1, pc.xadvance * inv_rasterization_scale); - } + atlas->FontLoader->LoaderShutdown(atlas); + IM_ASSERT(atlas->FontLoaderData == NULL); } - - // Cleanup - src_tmp_array.clear_destruct(); - - ImFontAtlasBuildFinish(atlas); - return true; + atlas->FontLoader = font_loader; + atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL"; + if (atlas->FontLoader && atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); + if (atlas->Builder && font_loader != NULL) + atlas->ClearCache(); } -const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype() +// Preload all glyph ranges for legacy backends. +// This may lead to multiple texture creation which might be a little slower than before. +void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) { - static ImFontBuilderIO io; - io.FontBuilder_Build = ImFontAtlasBuildWithStbTruetype; - return &io; + atlas->Builder->PreloadedAllGlyphsRanges = true; + for (int src_n = 0; src_n < atlas->Sources.Size; src_n++) + { + ImFontConfig* src = &atlas->Sources[src_n]; + const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); + IM_ASSERT(ranges != NULL); + for (; ranges[0]; ranges += 2) + for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 + src->DstFont->FindGlyphNoFallback((ImWchar)c); + } } -#endif // IMGUI_ENABLE_STB_TRUETYPE - -void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas) +void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) { - for (ImFontConfig& src : atlas->Sources) + for (int src_n = 0; src_n < atlas->Sources.Size; src_n++) { - ImFont* font = src.DstFont; - if (!src.MergeMode) + ImFontConfig* src = &atlas->Sources[src_n]; + ImFont* font = src->DstFont; + if (!src->MergeMode) { - font->Sources = &src; + font->Sources = src; font->SourcesCount = 0; } font->SourcesCount++; } } -void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent) -{ - if (!font_config->MergeMode) - { - font->ClearOutputData(); - font->FontSize = font_config->SizePixels; - IM_ASSERT(font->Sources == font_config); - font->ContainerAtlas = atlas; - font->Ascent = ascent; - font->Descent = descent; - } -} - void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) { + ImTextureData* tex = atlas->TexData; stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; IM_ASSERT(pack_context != NULL); @@ -3213,175 +3226,828 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa { user_rects[i].X = (unsigned short)pack_rects[i].x; user_rects[i].Y = (unsigned short)pack_rects[i].y; - IM_ASSERT(pack_rects[i].w == user_rects[i].Width + pack_padding && pack_rects[i].h == user_rects[i].Height + pack_padding); - atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h); + IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); + tex->Height = ImMax(tex->Height, pack_rects[i].y + pack_rects[i].h); } } -void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value) +// Render a white-colored bitmap encoded in a string +void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char) { - IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); - IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); - unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth); - for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) - for (int off_x = 0; off_x < w; off_x++) - out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; -} + ImTextureData* tex = atlas->TexData; + IM_ASSERT(x >= 0 && x + w <= tex->Width); + IM_ASSERT(y >= 0 && y + h <= tex->Height); -void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value) -{ - IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); - IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); - unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth); - for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) - for (int off_x = 0; off_x < w; off_x++) - out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS; + switch (tex->Format) + { + case ImTextureFormat_Alpha8: + { + ImU8* out_p = tex->GetPixelsAt(x, y); + for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_p[off_x] = (in_str[off_x] == in_marker_char) ? 0xFF : 0x00; + break; + } + case ImTextureFormat_RGBA32: + { + ImU32* out_p = (ImU32*)(void*)tex->GetPixelsAt(x, y); + for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_p[off_x] = (in_str[off_x] == in_marker_char) ? IM_COL32_WHITE : IM_COL32_BLACK_TRANS; + break; + } + } } -static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) +static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_draw) { - ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); - IM_ASSERT(r->IsPacked()); + ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); - const int w = atlas->TexWidth; - if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) - { - // White pixels only - IM_ASSERT(r->Width == 2 && r->Height == 2); - const int offset = (int)r->X + (int)r->Y * w; - if (atlas->TexPixelsAlpha8 != NULL) - { - atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; - } - else - { - atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; - } - } - else + // Pack and store identifier so we can refresh UV coordinates on texture resize. + // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing. + ImFontAtlasBuilder* builder = atlas->Builder; + + if (add_and_draw) + builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); + + // Draw to texture + if (add_and_draw) { - // White pixels and mouse cursor - IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); - const int x_for_white = r->X; - const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - if (atlas->TexPixelsAlpha8 != NULL) + if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) { - ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); - ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + // 2x2 white pixels + ImFontAtlasBuildRenderBitmapFromString(atlas, r->x, r->y, 2, 2, "XX" "XX", 'X'); } else { - ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); - ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + // 2x2 white pixels + mouse cursors + const int x_for_white = r->x; + const int x_for_black = r->x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r->y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.'); + ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r->y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); } } - atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); + atlas->TexUvWhitePixel = ImVec2((r->x + 0.5f) * atlas->TexUvScale.x, (r->y + 0.5f) * atlas->TexUvScale.y); } -static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) +static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_draw) { if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) return; + ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + + // Pack and store identifier so we can refresh UV coordinates on texture resize. + ImFontAtlasBuilder* builder = atlas->Builder; + if (add_and_draw) + builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); + + // Register texture region for thick lines + // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them - ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines); - IM_ASSERT(r->IsPacked()); + ImTextureData* tex = atlas->TexData; for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle int y = n; int line_width = n; - int pad_left = (r->Width - line_width) / 2; - int pad_right = r->Width - (pad_left + line_width); + int pad_left = (r->w - line_width) / 2; + int pad_right = r->w - (pad_left + line_width); // Write each slice - IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels - if (atlas->TexPixelsAlpha8 != NULL) + IM_ASSERT(pad_left + line_width + pad_right == r->w && y < r->h); // Make sure we're inside the texture bounds before we start writing pixels + if (add_and_draw) { - unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; - for (int i = 0; i < pad_left; i++) - *(write_ptr + i) = 0x00; - - for (int i = 0; i < line_width; i++) - *(write_ptr + pad_left + i) = 0xFF; + switch (tex->Format) + { + case ImTextureFormat_Alpha8: + { + ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r->x, r->y + y); + for (int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; - for (int i = 0; i < pad_right; i++) - *(write_ptr + pad_left + line_width + i) = 0x00; - } - else - { - unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; - for (int i = 0; i < pad_left; i++) - *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + for (int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; - for (int i = 0; i < line_width; i++) - *(write_ptr + pad_left + i) = IM_COL32_WHITE; + for (int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + break; + } + case ImTextureFormat_RGBA32: + { + ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r->x, r->y + y); + for (int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + + for (int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; - for (int i = 0; i < pad_right; i++) - *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); + for (int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); + break; + } + } } // Calculate UVs for this line - ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; - ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale; + ImVec2 uv0 = ImVec2((float)(r->x + pad_left - 1), (float)(r->y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r->x + pad_left + line_width + 1), (float)(r->y + y + 1)) * atlas->TexUvScale; float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); } } -// Note: this is called / shared by both the stb_truetype and the FreeType builder -void ImFontAtlasBuildInit(ImFontAtlas* atlas) +//----------------------------------------------------------------------------------------------------------------------------- + +static const ImFontGlyph* LoadFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) { - // Register texture region for mouse cursors or standard white pixels - if (atlas->PackIdMouseCursors < 0) + for (int n = 0; n < candidate_chars_count; n++) + if (candidate_chars[n] != 0) + if (const ImFontGlyph* glyph = font->FindGlyphNoFallback(candidate_chars[n])) + return glyph; + return NULL; +} + +bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) +{ + ImFont* font = src->DstFont; + if (src->MergeMode == false) { - if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors)) - atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); - else - atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2); + font->ClearOutputData(); + font->FontSize = src->SizePixels; + font->ContainerAtlas = atlas; + IM_ASSERT(font->Sources == src); } - // Register texture region for thick lines - // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row - if (atlas->PackIdLines < 0) + const ImFontLoader* font_loader = atlas->FontLoader; + if (!font_loader->FontSrcInit(atlas, src)) + return false; // FIXME-NEWATLAS: error handling + + ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); + return true; +} + +// Load/identify special glyphs +// (note that this is called again for fonts with MergeMode) +void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src) +{ + ImFont* font = src->DstFont; + IM_UNUSED(atlas); + + // While manipulating glyphs during init we want to restrict all searches for one source font. + font->LockSingleSrcConfig = src; + + // Setup Fallback character + // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? + const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; + if (font->FallbackGlyphIndex == -1) + if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, fallback_chars, IM_ARRAYSIZE(fallback_chars))) + { + font->FallbackChar = (ImWchar)glyph->Codepoint; + font->FallbackGlyphIndex = font->Glyphs.index_from_ptr(glyph); // Storing index avoid need to update pointer on growth. + font->FallbackAdvanceX = glyph->AdvanceX; + } + + // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews) + ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)font->FindGlyph((ImWchar)' '); + if (space_glyph != NULL) + space_glyph->Visible = false; + + // Setup Tab character. + // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) + if (font->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL) { - if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines)) - atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + ImFontGlyph tab_glyph; + tab_glyph.Codepoint = '\t'; + tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE; + font->BuildRegisterGlyph(font->Sources, &tab_glyph); } + + // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). + // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. + // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. + const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; + if (font->EllipsisChar == 0) + if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars))) + { + font->EllipsisChar = (ImWchar)glyph->Codepoint; + font->EllipsisCharCount = 1; + font->EllipsisWidth = font->EllipsisCharStep = glyph->X1; + } + if (font->EllipsisChar == 0) + { + // FIXME-NEWATLAS-V2: We can now rasterize this into a regular character and register it! + const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; + if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) + { + font->EllipsisChar = (ImWchar)dot_glyph->Codepoint; + font->EllipsisCharCount = 3; + font->EllipsisCharStep = (float)(int)(dot_glyph->X1 - dot_glyph->X0) + 1.0f; + font->EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + font->EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. + } + } + + font->LockSingleSrcConfig = NULL; } -// This is called/shared by both the stb_truetype and the FreeType builder. -void ImFontAtlasBuildFinish(ImFontAtlas* atlas) +// Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* +void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) { - // Render into our custom data blocks - IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); - ImFontAtlasBuildRenderDefaultTexData(atlas); - ImFontAtlasBuildRenderLinesTexData(atlas); + IM_ASSERT(atlas->DrawListSharedData == NULL && data->FontAtlas == NULL); + atlas->DrawListSharedData = data; + data->FontAtlas = atlas; +} - // Register custom rectangle glyphs - for (int i = 0; i < atlas->CustomRects.Size; i++) +void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) +{ + IM_ASSERT(atlas->DrawListSharedData == data && data->FontAtlas == atlas); + atlas->DrawListSharedData = data; + data->FontAtlas = NULL; +} + +// Update texture identifier in all active draw lists +void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex) +{ + ImDrawListSharedData* shared_data = atlas->DrawListSharedData; + for (ImDrawList* draw_list : shared_data->DrawLists) { - const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; - if (r->Font == NULL || r->GlyphID == 0) - continue; + // Replace in command-buffer + // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[], + // other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow) + if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex) + draw_list->_SetTexture(new_tex); + + // Replace in stack + for (ImTextureRef& stacked_tex : draw_list->_TextureStack) + if (stacked_tex == old_tex) + stacked_tex = new_tex; + } +} - // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, PixelSnapH - IM_ASSERT(r->Font->ContainerAtlas == atlas); - ImVec2 uv0, uv1; - atlas->CalcCustomRectUV(r, &uv0, &uv1); - r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); - if (r->GlyphColored) - r->Font->Glyphs.back().Colored = 1; +// Update texture coordinates in all draw list shared context +void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) +{ + ImDrawListSharedData* shared_data = atlas->DrawListSharedData; + shared_data->FontAtlas = atlas; + shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; + shared_data->TexUvLines = atlas->TexUvLines; +} + +// Set current texture. This is mostly called from AddTexture() + to handle a failed resize. +static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex) +{ + ImTextureRef old_tex_ref = atlas->TexRef; + atlas->TexData = tex; + atlas->TexUvScale = ImVec2(1.0f / tex->Width, 1.0f / tex->Height); + atlas->TexRef._TexData = tex; + //atlas->TexID._TexID = tex->TexID; // <-- We intentionally don't do that and leave it 0, to allow late upload. + ImTextureRef new_tex_ref = atlas->TexRef; + ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, new_tex_ref); +} + +// Create a new texture, discard previous one +ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h) +{ + ImTextureData* old_tex = atlas->TexData; + ImTextureData* new_tex; + + // FIXME: Cannot reuse texture because old UV may have been used already (unless we remap UV). + /*if (old_tex != NULL && old_tex->Status == ImTextureStatus_WantCreate) + { + // Reuse texture not yet used by backend. + IM_ASSERT(old_tex->TexID == 0 && old_tex->BackendUserData == NULL); + old_tex->DestroyPixels(); + old_tex->Updates.clear(); + new_tex = old_tex; + old_tex = NULL; } + else*/ + { + // Add new + new_tex = IM_NEW(ImTextureData)(); + new_tex->UniqueID = atlas->TexNextUniqueID++; + atlas->TexList.push_back(new_tex); + } + if (old_tex != NULL) + { + // Queue old as to destroy next frame + old_tex->WantDestroyNextFrame = true; + IM_ASSERT(old_tex->Status == ImTextureStatus_OK || old_tex->Status == ImTextureStatus_WantCreate || old_tex->Status == ImTextureStatus_WantUpdates); + } + + new_tex->Create(atlas->TexDesiredFormat, w, h); + new_tex->Status = ImTextureStatus_WantCreate; + + ImFontAtlasBuildSetTexture(atlas, new_tex); + + return new_tex; +} + +void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) +{ + ImGuiContext& g = *GImGui; + IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() + + ImFontAtlasBuilder* builder = atlas->Builder; + builder->LockDisableResize = true; + + ImTextureData* old_tex = atlas->TexData; + ImTextureData* new_tex = ImFontAtlasBuildAddTexture(atlas, w, h); + new_tex->UseColors = old_tex->UseColors; + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height); + + // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. + +#if 1 + // Repack + copy pixels + // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic. + ImFontAtlasPackInit(atlas); + ImVector old_rects; + old_rects.swap(builder->Rects); + for (ImFontAtlasRect& old_r : old_rects) + { + ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h); + if (new_r_id == -1) + { + // Undo, grow texture and try repacking again. + // FIXME-NEWATLAS-TESTS: This is a very rarely exercised path! It needs to be automatically tested properly. + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize failed. Will grow.\n", new_tex->UniqueID); + new_tex->WantDestroyNextFrame = true; + old_rects.swap(builder->Rects); + ImFontAtlasBuildSetTexture(atlas, old_tex); + ImFontAtlasBuildGrowTexture(atlas, w, h); + return; + } + ImFontAtlasRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id); + ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h); + } + IM_ASSERT(old_rects.Size == builder->Rects.Size); - // Build all fonts lookup tables + // Patch glyphs UV for (ImFont* font : atlas->Fonts) - if (font->DirtyLookupTables) - font->BuildLookupTable(); + for (ImFontGlyph& glyph : font->Glyphs) + if (glyph.PackId != -1) + { + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); + glyph.U0 = (r->x) * atlas->TexUvScale.x; + glyph.V0 = (r->y) * atlas->TexUvScale.y; + glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; + glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + } + + // Update other cached UV + ImFontAtlasBuildUpdateLinesTexData(atlas, false); + ImFontAtlasBuildUpdateBasicTexData(atlas, false); + +#else + // Copy previous pixels + ImFontAtlasTextureCopyBlock(atlas, old_tex, 0, 0, new_tex, 0, 0, ImMin(old_tex->Width, new_tex->Width), ImMin(old_tex->Height, new_tex->Height)); + + // Scale UV coordinates + // FIXME-NEWATLAS: Probably lossy? + ImVec2 uv_scale((float)old_tex->Width / new_tex->Width, (float)old_tex->Height / new_tex->Height); + for (ImFont* font : atlas->Fonts) + for (ImFontGlyph& glyph : font->Glyphs) + { + glyph.U0 *= uv_scale.x; + glyph.U1 *= uv_scale.x; + glyph.V0 *= uv_scale.y; + glyph.V1 *= uv_scale.y; + } + ImVec4 uv_scale4(uv_scale.x, uv_scale.y, uv_scale.x, uv_scale.y); + atlas->TexUvWhitePixel *= uv_scale; + for (ImVec4& uv : atlas->TexUvLines) + uv = uv * uv_scale4; +#endif - atlas->TexReady = true; + builder->LockDisableResize = false; + ImFontAtlasUpdateDrawListsSharedData(atlas); } +void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_h) +{ + ImFontAtlasBuilder* builder = atlas->Builder; + if (old_tex_w == -1) + old_tex_w = atlas->TexData->Width; + if (old_tex_h == -1) + old_tex_h = atlas->TexData->Height; + + // FIXME-NEWATLAS-V1: Handle atlas->TexDesiredWidth from user? + // FIXME-NEWATLAS-V1: What to do when reaching limits exposed by backend? + // FIXME-NEWATLAS-V1: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? + IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); + + // Grow texture so it follows roughly a square. + int new_tex_w = (old_tex_h < old_tex_w) ? old_tex_w : old_tex_w * 2; + int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h; + + // Handle minimum size first (for pathologically large packed rects) + new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + builder->PackPadding)); + new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + builder->PackPadding)); + + ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); +} + +// You should not need to call this manually! +// If you think you do, let us know and we can advise about policies auto-compact. +void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) +{ + ImFontAtlasBuilder* builder = atlas->Builder; + + ImTextureData* old_tex = atlas->TexData; + int old_tex_w = old_tex->Width; + int old_tex_h = old_tex->Height; + + // FIXME-NEWATLAS: Expose atlas->TexMinWidth etc. + const int min_w = ImMax(builder->MaxRectSize.x, 512); + const int min_h = builder->MaxRectSize.y; + const int surface_sqrt = (int)sqrtf((float)atlas->_PackedSurface); + + int new_tex_w; + int new_tex_h; + if (min_w >= min_h) + { + new_tex_w = ImMax(min_w, ImUpperPowerOfTwo(surface_sqrt)); + new_tex_h = ImMax(min_h, (int)(atlas->_PackedSurface / new_tex_w)); + if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0) + new_tex_h = ImUpperPowerOfTwo(new_tex_h); + } + else + { + new_tex_h = ImMax(min_h, ImUpperPowerOfTwo(surface_sqrt)); + if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0) + new_tex_h = ImUpperPowerOfTwo(new_tex_h); + new_tex_w = ImMax(min_w, (int)(atlas->_PackedSurface / new_tex_h)); + } + + if (new_tex_w == old_tex_w && new_tex_h == old_tex_h) + return; + + ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); +} + +// Start packing over current empty texture +void ImFontAtlasBuildInit(ImFontAtlas* atlas) +{ + ImFontAtlasBuilder* builder = atlas->Builder; + + const bool builder_is_new = (builder == NULL); + if (builder_is_new) + { + builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); + builder->PackPadding = 1; + } + + ImFontAtlasPackInit(atlas); + + // Add required texture data + ImFontAtlasBuildUpdateLinesTexData(atlas, true); + ImFontAtlasBuildUpdateBasicTexData(atlas, true); + + // Register fonts + if (builder_is_new) + { + ImFontAtlasBuildUpdatePointers(atlas); + for (ImFontConfig& cfg : atlas->Sources) + ImFontAtlasBuildAddFont(atlas, &cfg); + } + + // Update UV coordinates etc. stored in bound ImDrawListSharedData instance + ImFontAtlasUpdateDrawListsSharedData(atlas); + + //atlas->TexIsBuilt = true; +} + +// Destroy builder and all cached glyphs. Do not destroy actual fonts. +void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) +{ + for (ImFont* font : atlas->Fonts) + font->BuildClearGlyphs(); + if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL) + for (ImFontConfig& font_cfg : atlas->Sources) + atlas->FontLoader->FontSrcDestroy(atlas, &font_cfg); + + IM_DELETE(atlas->Builder); + atlas->Builder = NULL; +} + +void ImFontAtlasPackInit(ImFontAtlas* atlas) +{ + ImTextureData* tex = atlas->TexData; + ImFontAtlasBuilder* builder = atlas->Builder; + + // FIXME-NEWATLAS-V2: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 + // FIXME-NEWATLAS-V2: Experiment with number of nodes. 2024-11-05: Seems to be quite fine to reduce this. + int pack_node_count = tex->Width - builder->PackPadding; + //pack_node_count *= atlas->_PackNodesFactor; + builder->PackNodes.resize(pack_node_count); + IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); + stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width - builder->PackPadding, tex->Height - builder->PackPadding, builder->PackNodes.Data, builder->PackNodes.Size); + atlas->_PackedSurface = atlas->_PackedRects = 0; + builder->MaxRectSize = ImVec2i(0, 0); + builder->MaxRectBounds = ImVec2i(0, 0); +} + +// Important: Calling this may recreate a new texture and therefore change atlas->TexData +ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) +{ + IM_ASSERT(w > 0 && w <= 0xFFFF); + IM_ASSERT(h > 0 && h <= 0xFFFF); + + ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + builder->MaxRectSize.x = ImMax(builder->MaxRectSize.x, w); + builder->MaxRectSize.y = ImMax(builder->MaxRectSize.y, h); + + // Pack + ImFontAtlasRect r = { 0, 0, (unsigned short)w, (unsigned short)h }; + for (int attempts_remaining = 3; attempts_remaining >= 0; attempts_remaining--) + { + // Try packing + stbrp_rect pack_r = {}; + pack_r.w = r.w + builder->PackPadding; + pack_r.h = r.h + builder->PackPadding; + stbrp_pack_rects((stbrp_context*)(void*)&builder->PackContext, &pack_r, 1); + r.x = (unsigned short)(pack_r.x + builder->PackPadding); + r.y = (unsigned short)(pack_r.y + builder->PackPadding); + if (pack_r.was_packed) + break; + + // If we ran out of attempts, return fallback + if (attempts_remaining == 0 || builder->LockDisableResize) + { + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + IMGUI_DEBUG_LOG_FONT("[font] Failed packing %dx%d rectangle. Returning fallback.\n", w, h); + return -1; + } + + // Resize atlas! (this should be a rare event) + ImFontAtlasBuildGrowTexture(atlas); + } + + builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w); + builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h); + atlas->_PackedSurface += w * h; + atlas->_PackedRects++; + + builder->Rects.push_back(r); + return builder->Rects.Size - 1; +} + +ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) +{ + ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + return &builder->Rects[id]; +} + +ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) +{ + if (LockDisableLoading) + return NULL; + + //char utf8_buf[5]; + //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); + + ImFontAtlas* atlas = ContainerAtlas; + const ImFontLoader* font_loader = atlas->FontLoader; + if (!font_loader->FontAddGlyph(atlas, this, codepoint)) + { + // Mark index as not found, so we don't attempt the search twice + BuildGrowIndex(codepoint + 1); + IndexAdvanceX[codepoint] = (float)IM_FONTGLYPH_INDEX_NOT_FOUND; + IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; + return NULL; + } + + // FIXME: Add hooks for e.g. #7962 + ImFontGlyph* glyph = &Glyphs.back(); + return glyph; +} + +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) +{ + // [DEBUG] Log texture update requests + ImGuiContext& g = *GImGui; + IM_UNUSED(g); + for (ImTextureData* tex : atlas->TexList) + { + if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) + IM_ASSERT(tex->Updates.Size == 0); + if (tex->Status == ImTextureStatus_WantCreate) + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: create %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + else if (tex->Status == ImTextureStatus_WantDestroy) + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: destroy %dx%d, texid=0x%" IM_PRIX64 ", backend_data=%p\n", tex->UniqueID, tex->Width, tex->Height, tex->TexID, tex->BackendUserData); + else if (tex->Status == ImTextureStatus_WantUpdates) + { + IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update %d regions, texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, tex->Updates.Size, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); + for (const ImTextureRect& r : tex->Updates) + { + IM_ASSERT(r.x >= 0 && r.y >= 0); + IM_ASSERT(r.x + r.w < tex->Width && r.y + r.h < tex->Height); + //IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); + } + } + } +} +#endif + +//------------------------------------------------------------------------- +// [SECTION] ImFontAtlas: backend for stb_truetype +//------------------------------------------------------------------------- +// (imstb_truetype.h in included near the top of this file, when IMGUI_ENABLE_STB_TRUETYPE is set) +//------------------------------------------------------------------------- + +#ifdef IMGUI_ENABLE_STB_TRUETYPE + +// One for each ConfigData +struct ImGui_ImplStbTrueType_FontSrcData +{ + stbtt_fontinfo FontInfo; + float ScaleForRasterX; // Factor in RasterizationDensity * OversampleH + float ScaleForRasterY; // Factor in RasterizationDensity * OversampleV + float ScaleForLayout; +}; + +static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) +{ + IM_UNUSED(atlas); + + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplStbTrueType_FontSrcData); + IM_ASSERT(src->FontLoaderData == NULL); + + // Initialize helper structure for font loading and verify that the TTF/OTF data is correct + const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo); + IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); // FIXME-NEWATLAS: error handling + if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset)) + { + IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); + return false; + } + src->FontLoaderData = bd_font_data; + + // FIXME-NEWATLAS-V2: reevaluate sizing metrics + int oversample_h, oversample_v; + ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); + if (src->SizePixels > 0.0f) + { + bd_font_data->ScaleForRasterX = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels * src->RasterizerDensity) * oversample_h; + bd_font_data->ScaleForRasterY = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels * src->RasterizerDensity) * oversample_v; + bd_font_data->ScaleForLayout = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels); + } + else + { + bd_font_data->ScaleForRasterX = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels * src->RasterizerDensity) * oversample_h; + bd_font_data->ScaleForRasterY = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels * src->RasterizerDensity) * oversample_v; + bd_font_data->ScaleForLayout = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels); + } + + // FIXME-NEWATLAS-V2: make use of line gap value + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + + if (src->MergeMode == false) + { + ImFont* font = src->DstFont; + font->Ascent = ImCeil(unscaled_ascent * bd_font_data->ScaleForLayout); + font->Descent = ImFloor(unscaled_descent * bd_font_data->ScaleForLayout); + } + + return true; +} + +static void ImGui_ImplStbTrueType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) +{ + IM_UNUSED(atlas); + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + IM_DELETE(bd_font_data); + src->FontLoaderData = NULL; +} + +static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) +{ + IM_UNUSED(atlas); + + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + IM_ASSERT(bd_font_data != NULL); + + int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); + return glyph_index != 0; +} + +static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImWchar codepoint) +{ + // Search for first font which has the glyph + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = NULL; + ImFontConfig* src = NULL; + int glyph_index = 0; + int scan_count = (font->LockSingleSrcConfig != NULL) ? 1 : font->SourcesCount; + for (int src_n = 0; src_n < scan_count; src_n++, bd_font_data++) + { + src = font->LockSingleSrcConfig ? font->LockSingleSrcConfig : &font->Sources[src_n]; + bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); + if (glyph_index != 0) + break; + } + if (glyph_index == 0) + return false; // Not found + + // FIXME-NEWATLAS: Handling of atlas->TexGlyphPadding? + const float scale_for_layout = bd_font_data->ScaleForLayout; // ~ (font units to pixels) + const float scale_for_raster_x = bd_font_data->ScaleForRasterX; // ~ (font units to pixels) * RasterizationDensity * OversampleH + const float scale_for_raster_y = bd_font_data->ScaleForRasterY; // ~ (font units to pixels) * RasterizationDensity * OversampleV + + // Obtain size and advance + int x0, y0, x1, y1; + int advance, lsb; + stbtt_GetGlyphBitmapBoxSubpixel(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0, &x0, &y0, &x1, &y1); + stbtt_GetGlyphHMetrics(&bd_font_data->FontInfo, glyph_index, &advance, &lsb); + const bool is_visible = (x0 != x1 && y0 != y1); + + // Prepare glyph + ImFontGlyph glyph; + glyph.Codepoint = codepoint; + glyph.AdvanceX = advance * scale_for_layout; + + // Pack and retrieve position inside texture atlas + // (generally based on stbtt_PackFontRangesRenderIntoRects) + if (is_visible) + { + int oversample_h, oversample_v; + ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); + const int w = (x1 - x0 + oversample_h - 1); + const int h = (y1 - y0 + oversample_v - 1); + ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + font->MetricsTotalSurface += w * h; + + // Render + stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1); + ImFontAtlasBuilder* builder = atlas->Builder; + builder->TempBuffer.resize(w * h * 1); + unsigned char* bitmap_pixels = builder->TempBuffer.Data; + memset(bitmap_pixels, 0, w * h * 1); + stbtt_MakeGlyphBitmapSubpixel(&bd_font_data->FontInfo, bitmap_pixels, r->w - oversample_h + 1, r->h - oversample_v + 1, w, + scale_for_raster_x, scale_for_raster_y, 0, 0, glyph_index); + + // Oversampling + // (those functions conveniently assert if pixels are not cleared, which is another safety layer) + if (oversample_h > 1) + stbtt__h_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_h); + if (oversample_v > 1) + stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v); + + float font_off_x = src->GlyphOffset.x + stbtt__oversample_shift(oversample_h); + float font_off_y = src->GlyphOffset.y + stbtt__oversample_shift(oversample_v) + IM_ROUND(font->Ascent); + float recip_h = 1.0f / (oversample_h * src->RasterizerDensity); + float recip_v = 1.0f / (oversample_v * src->RasterizerDensity); + + // Register glyph + // r->x r->y are coordinates inside texture (in pixels) + // glyph.X0, glyph.Y0 are drawing coordinates from base text position, and accounting for oversampling. + glyph.X0 = x0 * recip_h + font_off_x; + glyph.Y0 = y0 * recip_v + font_off_y; + glyph.X1 = (x0 + (int)r->w) * recip_h + font_off_x; + glyph.Y1 = (y0 + (int)r->h) * recip_v + font_off_y; + glyph.U0 = (r->x) * atlas->TexUvScale.x; + glyph.V0 = (r->y) * atlas->TexUvScale.y; + glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; + glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + glyph.Visible = true; + glyph.PackId = pack_id; + font->BuildRegisterGlyph(src, &glyph); + + // Copy to texture, post-process and queue update for backend + ImTextureData* tex = atlas->TexData; + IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); + ImFontAtlasTextureBlockConvertAndPostProcess(atlas, font, src, &font->Glyphs.back(), + bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); + } + else + { + font->BuildRegisterGlyph(src, &glyph); + } + + return true; +} + +const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() +{ + static ImFontLoader loader; + loader.Name = "stb_truetype"; + loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit; + loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy; + loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph; + loader.FontAddGlyph = ImGui_ImplStbTrueType_FontAddGlyph; + return &loader; +} + +#endif // IMGUI_ENABLE_STB_TRUETYPE + //------------------------------------------------------------------------- // [SECTION] ImFontAtlas: glyph ranges helpers //------------------------------------------------------------------------- @@ -3710,113 +4376,30 @@ ImFont::~ImFont() ClearOutputData(); } -void ImFont::ClearOutputData() +void ImFont::ClearOutputData() { FontSize = 0.0f; FallbackAdvanceX = 0.0f; Glyphs.clear(); IndexAdvanceX.clear(); IndexLookup.clear(); - FallbackGlyph = NULL; + FallbackGlyphIndex = -1; ContainerAtlas = NULL; - DirtyLookupTables = true; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); } -static ImWchar FindFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) +void ImFont::BuildClearGlyphs() { - for (int n = 0; n < candidate_chars_count; n++) - if (font->FindGlyphNoFallback(candidate_chars[n]) != NULL) - return candidate_chars[n]; - return 0; -} - -void ImFont::BuildLookupTable() -{ - int max_codepoint = 0; - for (int i = 0; i != Glyphs.Size; i++) - max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint); - - // Build lookup table - IM_ASSERT(Glyphs.Size > 0 && "Font has not loaded glyph!"); - IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved + FallbackAdvanceX = 0.0f; + Glyphs.clear(); IndexAdvanceX.clear(); IndexLookup.clear(); - DirtyLookupTables = false; + FallbackGlyphIndex = 0; + MetricsTotalSurface = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); - GrowIndex(max_codepoint + 1); - for (int i = 0; i < Glyphs.Size; i++) - { - int codepoint = (int)Glyphs[i].Codepoint; - IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX; - IndexLookup[codepoint] = (ImU16)i; - - // Mark 4K page as used - const int page_n = codepoint / 8192; - Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); - } - - // Create a glyph to handle TAB - // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) - if (FindGlyph((ImWchar)' ')) - { - if (Glyphs.back().Codepoint != '\t') // So we can call this function multiple times (FIXME: Flaky) - Glyphs.resize(Glyphs.Size + 1); - ImFontGlyph& tab_glyph = Glyphs.back(); - tab_glyph = *FindGlyph((ImWchar)' '); - tab_glyph.Codepoint = '\t'; - tab_glyph.AdvanceX *= IM_TABSIZE; - IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX; - IndexLookup[(int)tab_glyph.Codepoint] = (ImU16)(Glyphs.Size - 1); - } - - // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons) - if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)' ')) - glyph->Visible = false; - if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)'\t')) - glyph->Visible = false; - - // Setup Fallback character - const ImWchar fallback_chars[] = { (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; - FallbackGlyph = FindGlyphNoFallback(FallbackChar); - if (FallbackGlyph == NULL) - { - FallbackChar = FindFirstExistingGlyph(this, fallback_chars, IM_ARRAYSIZE(fallback_chars)); - FallbackGlyph = FindGlyphNoFallback(FallbackChar); - if (FallbackGlyph == NULL) - { - FallbackGlyph = &Glyphs.back(); - FallbackChar = (ImWchar)FallbackGlyph->Codepoint; - } - } - FallbackAdvanceX = FallbackGlyph->AdvanceX; - for (int i = 0; i < max_codepoint + 1; i++) - if (IndexAdvanceX[i] < 0.0f) - IndexAdvanceX[i] = FallbackAdvanceX; - - // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). - // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. - // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. - const ImWchar ellipsis_chars[] = { Sources->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; - const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; - if (EllipsisChar == 0) - EllipsisChar = FindFirstExistingGlyph(this, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars)); - const ImWchar dot_char = FindFirstExistingGlyph(this, dots_chars, IM_ARRAYSIZE(dots_chars)); - if (EllipsisChar != 0) - { - EllipsisCharCount = 1; - EllipsisWidth = EllipsisCharStep = FindGlyph(EllipsisChar)->X1; - } - else if (dot_char != 0) - { - const ImFontGlyph* dot_glyph = FindGlyph(dot_char); - EllipsisChar = dot_char; - EllipsisCharCount = 3; - EllipsisCharStep = (float)(int)(dot_glyph->X1 - dot_glyph->X0) + 1.0f; - EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. - } + // Don't clear BuilderData } // API is designed this way to avoid exposing the 8K page size @@ -3832,7 +4415,7 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) return true; } -void ImFont::GrowIndex(int new_size) +void ImFont::BuildGrowIndex(int new_size) { IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); if (new_size <= IndexLookup.Size) @@ -3844,50 +4427,43 @@ void ImFont::GrowIndex(int new_size) // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). // 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. -void ImFont::AddGlyph(const ImFontConfig* src, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x) +void ImFont::BuildRegisterGlyph(ImFontConfig* src, const ImFontGlyph* in_glyph) { + int glyph_idx = Glyphs.Size; + Glyphs.push_back(*in_glyph); + ImFontGlyph& glyph = Glyphs[glyph_idx]; + IM_ASSERT(Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. + if (src != NULL) { // Clamp & recenter if needed - const float advance_x_original = advance_x; - advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX, src->GlyphMaxAdvanceX); - if (advance_x != advance_x_original) + float advance_x = ImClamp(glyph.AdvanceX, src->GlyphMinAdvanceX, src->GlyphMaxAdvanceX); + if (advance_x != glyph.AdvanceX) { - float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f; - x0 += char_off_x; - x1 += char_off_x; + float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph.AdvanceX) * 0.5f) : (advance_x - glyph.AdvanceX) * 0.5f; + glyph.X0 += char_off_x; + glyph.X1 += char_off_x; } // Snap to pixel if (src->PixelSnapH) advance_x = IM_ROUND(advance_x); - // Bake extra spacing - advance_x += src->GlyphExtraAdvanceX; + // Bake spacing + glyph.AdvanceX = advance_x + src->GlyphExtraAdvanceX; } + if (glyph.Colored) + ContainerAtlas->TexPixelsUseColors = ContainerAtlas->TexData->UseColors = true; - int glyph_idx = Glyphs.Size; - Glyphs.resize(Glyphs.Size + 1); - ImFontGlyph& glyph = Glyphs[glyph_idx]; - glyph.Codepoint = (unsigned int)codepoint; - glyph.Visible = (x0 != x1) && (y0 != y1); - glyph.Colored = false; - glyph.X0 = x0; - glyph.Y0 = y0; - glyph.X1 = x1; - glyph.Y1 = y1; - glyph.U0 = u0; - glyph.V0 = v0; - glyph.U1 = u1; - glyph.V1 = v1; - glyph.AdvanceX = advance_x; - IM_ASSERT(Glyphs.Size < 0xFFFF); // IndexLookup[] hold 16-bit values and -1 is reserved. - - // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round) - // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling. - float pad = ContainerAtlas->TexGlyphPadding + 0.99f; - DirtyLookupTables = true; - MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad); + // Update lookup tables + int codepoint = glyph.Codepoint; + BuildGrowIndex(codepoint + 1); + IndexAdvanceX[codepoint] = glyph.AdvanceX; + IndexLookup[codepoint] = (ImU16)glyph_idx; + + // Mark 4K page as used + const int page_n = codepoint / 8192; + Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); } void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) @@ -3900,30 +4476,76 @@ void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool ove if (to_codepoint >= index_size && from_codepoint >= index_size) // both 'from_codepoint' and 'to_codepoint' don't exist -> no-op return; - GrowIndex(from_codepoint + 1); + BuildGrowIndex(from_codepoint + 1); IndexLookup[from_codepoint] = (to_codepoint < index_size) ? IndexLookup.Data[to_codepoint] : (ImU16)-1; IndexAdvanceX[from_codepoint] = (to_codepoint < index_size) ? IndexAdvanceX.Data[to_codepoint] : 1.0f; } -// Find glyph, return fallback if missing +// Find glyph, load if necessary, return fallback if missing ImFontGlyph* ImFont::FindGlyph(ImWchar c) { - if (c >= (size_t)IndexLookup.Size) - return FallbackGlyph; - const ImU16 i = IndexLookup.Data[c]; - if (i == (ImU16)-1) - return FallbackGlyph; - return &Glyphs.Data[i]; + if (c < (size_t)IndexLookup.Size) IM_LIKELY + { + const int i = (int)IndexLookup.Data[c]; + if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) + return &Glyphs.Data[FallbackGlyphIndex]; + if (i != IM_FONTGLYPH_INDEX_UNUSED) + return &Glyphs.Data[i]; + } + ImFontGlyph* glyph = BuildLoadGlyph(c); + return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex]; } +// Attempt to load but when missing, return NULL instead of FallbackGlyph ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) { - if (c >= (size_t)IndexLookup.Size) - return NULL; - const ImU16 i = IndexLookup.Data[c]; - if (i == (ImU16)-1) - return NULL; - return &Glyphs.Data[i]; + if (c < (size_t)IndexLookup.Size) IM_LIKELY + { + const int i = (int)IndexLookup.Data[c]; + if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) + return NULL; + if (i != IM_FONTGLYPH_INDEX_UNUSED) + return &Glyphs.Data[i]; + } + ImFontGlyph* glyph = BuildLoadGlyph(c); + return glyph; +} + +bool ImFont::IsGlyphLoaded(ImWchar c) +{ + if (c < (size_t)IndexLookup.Size) IM_LIKELY + { + const int i = (int)IndexLookup.Data[c]; + if (i == IM_FONTGLYPH_INDEX_NOT_FOUND) + return false; + if (i != IM_FONTGLYPH_INDEX_UNUSED) + return true; + } + return false; +} + +// This is not fast query +bool ImFont::IsGlyphInFont(ImWchar c) +{ + ImFontAtlas* atlas = ContainerAtlas; + for (int src_n = 0; src_n < SourcesCount; src_n++) + if (atlas->FontLoader->FontSrcContainsGlyph(atlas, &Sources[src_n], c)) + return true; + return false; +} + +float ImFont::GetCharAdvance(ImWchar c) +{ + if (c < (size_t)IndexAdvanceX.Size) + { + const float x = IndexAdvanceX.Data[c]; + if (x >= 0.0f) + return x; + if (x == (float)IM_FONTGLYPH_INDEX_NOT_FOUND) // FIXME-NEWATLAS: could bake in index + return FallbackAdvanceX; + } + const ImFontGlyph* glyph = BuildLoadGlyph(c); + return glyph ? glyph->AdvanceX : FallbackAdvanceX; } // Trim trailing space and find beginning of next line @@ -3991,7 +4613,9 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha } } - const float char_width = ImFontGetCharAdvanceX(this, c); + // FIXME-NEWATLAS-V1: Measure perf, inline etc. + //const float char_width = ImFontGetCharAdvanceX(this, c); + const float char_width = GetCharAdvance((ImWchar)c); // ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); if (ImCharIsBlankW(c)) { if (inside_word) @@ -4096,7 +4720,9 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - const float char_width = ImFontGetCharAdvanceX(this, c) * scale; + // FIXME-NEWATLAS-V1: Measure perf, inline etc. + //const float char_width = ImFontGetCharAdvanceX(this, c) * scale; + const float char_width = GetCharAdvance((ImWchar)c) /* (int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX)*/ * scale; if (line_width + char_width >= max_width) { s = prev_s; diff --git a/imgui_internal.h b/imgui_internal.h index 91ac0bc83b0e..3b650c9d5a98 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -37,6 +37,7 @@ Index of this file: // [SECTION] Tab bar, Tab item support // [SECTION] Table support // [SECTION] ImGui internal API +// [SECTION] ImFontLoader // [SECTION] ImFontAtlas internal API // [SECTION] Test Engine specific hooks (imgui_test_engine) @@ -140,6 +141,8 @@ struct ImGuiTextIndex; // Maintain a line index for a text buffer. // ImDrawList/ImFontAtlas struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances +struct ImFontAtlasRect; // Packed rectangle (same as ImTextureRect) +struct ImFontAtlasBuilder; // Internal storage for incrementally packing and building a ImFontAtlas // ImGui struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others) @@ -530,6 +533,14 @@ struct ImVec1 constexpr ImVec1(float _x) : x(_x) { } }; +// Helper: ImVec2i (2D vector, integer) +struct ImVec2i +{ + int x, y; + constexpr ImVec2i() : x(0), y(0) {} + constexpr ImVec2i(int _x, int _y) : x(_x), y(_y) {} +}; + // Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage) struct ImVec2ih { @@ -789,8 +800,9 @@ IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStorag // You may want to create your own instance of you try to ImDrawList completely without ImGui. In that case, watch out for future changes to this structure. struct IMGUI_API ImDrawListSharedData { - ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas - const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas + ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel) + const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->TexUvLines) + ImFontAtlas* FontAtlas; // Current font atlas ImFont* Font; // Current/default font (optional, for simplified AddText overload) float FontSize; // Current/default font size (optional, for simplified AddText overload) float FontScale; // Current/default font scale (== FontSize / Font->FontSize) @@ -800,13 +812,17 @@ struct IMGUI_API ImDrawListSharedData ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards) ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen() ImVector TempBuffer; // Temporary write buffer + ImVector DrawLists; // All draw lists associated to this ImDrawListSharedData + ImGuiContext* Context; // [OPTIONAL] Link to Dear ImGui context. 99% of ImDrawList/ImFontAtlas can function without an ImGui context, but this facilitate handling one legacy edge case. // Lookup tables ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) + bool RendererHasTextures; // Copy of (GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures). ImDrawListSharedData(); + ~ImDrawListSharedData(); void SetCircleTessellationMaxError(float max_error); }; @@ -2085,6 +2101,7 @@ struct ImGuiContext float FontScale; // == FontSize / Font->FontSize float CurrentDpiScale; // Current window/viewport DpiScale ImDrawListSharedData DrawListSharedData; + ImVectorTextures; double Time; int FrameCount; int FrameCountEnded; @@ -3561,6 +3578,7 @@ namespace ImGui IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); + IMGUI_API void DebugNodeTexture(ImTextureData* tex); IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); IMGUI_API void DebugNodeTable(ImGuiTable* table); @@ -3594,30 +3612,101 @@ namespace ImGui //----------------------------------------------------------------------------- -// [SECTION] ImFontAtlas internal API +// [SECTION] ImFontLoader //----------------------------------------------------------------------------- +// Hooks and storage for a given font backend. // This structure is likely to evolve as we add support for incremental atlas updates. // Conceptually this could be in ImGuiPlatformIO, but we are far from ready to make this public. -struct ImFontBuilderIO +struct ImFontLoader { - bool (*FontBuilder_Build)(ImFontAtlas* atlas); + const char* Name; + bool (*LoaderInit)(ImFontAtlas* atlas); + void (*LoaderShutdown)(ImFontAtlas* atlas); + bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); + void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); + bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); + bool (*FontAddGlyph)(ImFontAtlas* atlas, ImFont* font, ImWchar codepoint); + + ImFontLoader() { memset(this, 0, sizeof(*this)); } }; -// Helper for font builder #ifdef IMGUI_ENABLE_STB_TRUETYPE -IMGUI_API const ImFontBuilderIO* ImFontAtlasGetBuilderForStbTruetype(); +IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); +#endif + +//----------------------------------------------------------------------------- +// [SECTION] ImFontAtlas internal API +//----------------------------------------------------------------------------- + +// Packed rectangle (same as ImTextureRect) +struct ImFontAtlasRect +{ + unsigned short x, y; + unsigned short w, h; +}; +typedef int ImFontAtlasRectId; // <0 when invalid + +// Internal storage for incrementally packing and building a ImFontAtlas +struct stbrp_context_opaque { char data[80]; }; +struct stbrp_node; +struct ImFontAtlasBuilder +{ + stbrp_context_opaque PackContext; // Actually 'stbrp_context' but we don't want to define this in the header file. + ImVector PackNodes; + int PackPadding; // Generally 1 to avoid bilinear filtering issues. + ImVector Rects; + ImVector TempBuffer; // Misc scratch buffer + ImVec2i MaxRectSize; // Largest rectangle to pack (defacto used as a "minimum texture size") + ImVec2i MaxRectBounds; // Bottom-right most used pixels + bool LockDisableResize; // Disable resizing texture + bool PreloadedAllGlyphsRanges; // Set when missing ImGuiBackendFlags_RendererHasTextures features forces atlas to preload everything. + + // Custom rectangle identifiers + ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure. + ImFontAtlasRectId PackIdLinesTexData; + + ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); } +}; + +// FIXME-NEWATLAS: Cleanup +IMGUI_API void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader); +IMGUI_API void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char); + +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas); + +IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); +IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); +IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); +IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); + +IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy +IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); + +IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); +IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h); +IMGUI_API ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); + +IMGUI_API void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); +IMGUI_API void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); +IMGUI_API void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex); +IMGUI_API void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas); + +IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas); + +IMGUI_API void ImFontAtlasTextureBlockConvertAndPostProcess(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); +IMGUI_API void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); +IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* pixels, ImTextureFormat format, int w, int h, int pitch, float in_multiply_factor); +IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h); +IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); + +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +IMGUI_API void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas); #endif -IMGUI_API void ImFontAtlasUpdateSourcesPointers(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, float ascent, float descent); -IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); -IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); -IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); -IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); -IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); -IMGUI_API void ImFontAtlasBuildGetOversampleFactors(const ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); IMGUI_API bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1c22bd4c6fa0..186b639b5072 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3984,7 +3984,8 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c if (c == '\r') continue; - const float char_width = ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX) * scale; + // FIXME-NEWATLAS-V1: Measure perf, inline etc. + const float char_width = font->GetCharAdvance((ImWchar)c) * scale;// ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX)* scale; line_width += char_width; } @@ -4322,7 +4323,7 @@ void ImGui::PushPasswordFont() out_font->Ascent = in_font->Ascent; out_font->Descent = in_font->Descent; out_font->ContainerAtlas = in_font->ContainerAtlas; - out_font->FallbackGlyph = glyph; + out_font->FallbackGlyphIndex = in_font->Glyphs.index_from_ptr(glyph); // FIXME: broken out_font->FallbackAdvanceX = glyph->AdvanceX; IM_ASSERT(out_font->Glyphs.Size == 0 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0); PushFont(out_font); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 6521f83b99df..1a268365b912 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -166,7 +166,7 @@ namespace // NB: No ctor/dtor, explicitly call Init()/Shutdown() struct FreeTypeFont { - bool InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + bool InitFont(FT_Library ft_library, ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. void CloseFont(); void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); @@ -185,7 +185,7 @@ namespace float InvRasterizationDensity; }; - bool FreeTypeFont::InitFont(FT_Library ft_library, const ImFontConfig& src, unsigned int extra_font_builder_flags) + bool FreeTypeFont::InitFont(FT_Library ft_library, ImFontConfig& src, unsigned int extra_font_builder_flags) { FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src.FontData, (uint32_t)src.FontDataSize, (uint32_t)src.FontNo, &Face); if (error != 0) From 2cde9125d6286c878c5e00d4a9ff9c85e108aa8d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 17 Jan 2025 18:06:25 +0100 Subject: [PATCH 426/716] Fonts: Selecting font config source list done by shared code. --- imgui.h | 10 +++++----- imgui_draw.cpp | 24 +++++++++++++++--------- imgui_internal.h | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/imgui.h b/imgui.h index 0420b4358ed8..753fffe92e05 100644 --- a/imgui.h +++ b/imgui.h @@ -3631,19 +3631,19 @@ struct ImFont float FallbackAdvanceX; // 4 // out // FindGlyph(FallbackChar)->AdvanceX float FontSize; // 4 // in // Height of characters/line, set during loading (don't change after loading) - // [Internal] Members: Hot ~28/40 bytes (for RenderText loop) + // [Internal] Members: Hot ~28/36 bytes (for RenderText loop) ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // All glyphs. int FallbackGlyphIndex; // 4 // out // Index of FontFallbackChar - // [Internal] Members: Cold ~32/40 bytes + // [Internal] Members: Cold ~32/40/60 bytes // Conceptually Sources[] is the list of font sources merged to create this font. - ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into - ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. short EllipsisCharCount; // 1 // out // 1 or 3 ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') + ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances + ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into float EllipsisWidth; // 4 // out // Total ellipsis Width float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() @@ -3651,7 +3651,7 @@ struct ImFont int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool LockDisableLoading; - ImFontConfig* LockSingleSrcConfig; + short LockSingleSrcConfigIdx; // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b1cf15ff4389..a497663b96f8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3394,10 +3394,12 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src) { ImFont* font = src->DstFont; + const int cfg_idx_in_font = (int)(src - font->Sources); + IM_ASSERT(cfg_idx_in_font >= 0 && cfg_idx_in_font < font->SourcesCount); IM_UNUSED(atlas); // While manipulating glyphs during init we want to restrict all searches for one source font. - font->LockSingleSrcConfig = src; + font->LockSingleSrcConfigIdx = (short)cfg_idx_in_font; // Setup Fallback character // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? @@ -3448,8 +3450,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr font->EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + font->EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. } } - - font->LockSingleSrcConfig = NULL; + font->LockSingleSrcConfigIdx = -1; } // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* @@ -3809,10 +3810,15 @@ ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); - ImFontAtlas* atlas = ContainerAtlas; + + // Load from single source or all sources? + int srcs_count = (LockSingleSrcConfigIdx != -1) ? 1 : SourcesCount; + ImFontConfig* srcs = (LockSingleSrcConfigIdx != -1) ? &Sources[LockSingleSrcConfigIdx] : Sources; + + // Call backend const ImFontLoader* font_loader = atlas->FontLoader; - if (!font_loader->FontAddGlyph(atlas, this, codepoint)) + if (!font_loader->FontAddGlyph(atlas, this, srcs, srcs_count, codepoint)) { // Mark index as not found, so we don't attempt the search twice BuildGrowIndex(codepoint + 1); @@ -3937,16 +3943,15 @@ static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFon return glyph_index != 0; } -static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImWchar codepoint) +static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) { // Search for first font which has the glyph ImGui_ImplStbTrueType_FontSrcData* bd_font_data = NULL; ImFontConfig* src = NULL; int glyph_index = 0; - int scan_count = (font->LockSingleSrcConfig != NULL) ? 1 : font->SourcesCount; - for (int src_n = 0; src_n < scan_count; src_n++, bd_font_data++) + for (int src_n = 0; src_n < srcs_count; src_n++) { - src = font->LockSingleSrcConfig ? font->LockSingleSrcConfig : &font->Sources[src_n]; + src = &srcs[src_n]; bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); if (glyph_index != 0) @@ -4369,6 +4374,7 @@ ImFont::ImFont() { memset(this, 0, sizeof(*this)); Scale = 1.0f; + LockSingleSrcConfigIdx = -1; } ImFont::~ImFont() diff --git a/imgui_internal.h b/imgui_internal.h index 3b650c9d5a98..27d1ca8e1988 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3626,7 +3626,7 @@ struct ImFontLoader bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); - bool (*FontAddGlyph)(ImFontAtlas* atlas, ImFont* font, ImWchar codepoint); + bool (*FontAddGlyph)(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint); ImFontLoader() { memset(this, 0, sizeof(*this)); } }; From ee357aaddf438e93127eed68e9be6456ca5130a3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 30 Jan 2025 15:35:32 +0100 Subject: [PATCH 427/716] Textures: Add ImTextureUserID_Invalid + introducing SetTexID(). Which gives us room for potentially updating ImDrawData during render. --- imgui.h | 21 +++++++++++++++------ imgui_draw.cpp | 6 +++--- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index 753fffe92e05..e51280e44f7a 100644 --- a/imgui.h +++ b/imgui.h @@ -318,6 +318,11 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) #endif +// Define this to another value if you need value of 0 to be valid. +#ifndef ImTextureID_Invalid +#define ImTextureID_Invalid ((ImTextureID)0) +#endif + // ImTextureRef contains: // - a texture/atlas pointer, typically when created by Dear ImGui itself. // - OR a raw ImTextureID value (user/backend identifier), typically when created by user code to load images. @@ -3362,21 +3367,19 @@ struct ImTextureRect // - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. struct IMGUI_API ImTextureData { - ImTextureStatus Status; // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy + ImTextureStatus Status; // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! ImTextureFormat Format; // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 int Width; // Texture width int Height; // Texture height int BytesPerPixel; // 4 or 1 int UniqueID; // Sequential index to facilitate identifying a texture when debugging/printing. Only unique per atlas. unsigned char* Pixels; // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. - ImTextureID TexID; // Identifier stored in ImDrawCmd::GetTexID() and passed to backend RenderDrawData loop. + ImTextureID TexID; // Always use SetTexID() to modify! Identifier stored in ImDrawCmd::GetTexID() and passed to backend RenderDrawData loop. void* BackendUserData; // Convenience storage for backend. Some backends may have enough with TexID. ImTextureRect UpdateRect; // Bounding box encompassing all individual updates. ImVector Updates; // Array of individual updates. int UnusedFrames; // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. - - // [Internal] - bool UseColors; // [Internal] Tell whether our texture data is known to use colors (rather than just white + alpha). + bool UseColors; // Tell whether our texture data is known to use colors (rather than just white + alpha). bool WantDestroyNextFrame; // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. // Functions @@ -3390,6 +3393,10 @@ struct IMGUI_API ImTextureData int GetPitch() const { return Width * BytesPerPixel; } ImTextureRef GetTexRef() const { ImTextureRef tex_ref; tex_ref._TexData = (ImTextureData*)(void*)this; tex_ref._TexID = TexID; return tex_ref; } ImTextureID GetTexID() const { return TexID; } + + // Called by Renderer backend + void SetTexID(ImTextureID tex_id) { TexID = tex_id; } // Call after creating or destroying the texture. Never modify TexID directly! + void SetStatus(ImTextureStatus status) { Status = status; } // Call after honoring a request. Never modify Status directly! }; //----------------------------------------------------------------------------- @@ -3689,9 +3696,11 @@ struct ImFont // FIXME-NEWATLAS: Added indirection to avoid patching ImDrawCmd after texture updates. inline ImTextureID ImDrawCmd::GetTexID() const { + // If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92) + // must iterate and handle ImTextureData requests stored in ImDrawData::Textures[]. ImTextureID tex_id = TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID; if (TexRef._TexData != NULL) - IM_ASSERT(tex_id && "ImDrawCmd is referring to Atlas texture that wasn't uploaded to graphics system."); + IM_ASSERT(tex_id != ImTextureID_Invalid && "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!"); return tex_id; } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a497663b96f8..1e66a3b9c65e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2695,7 +2695,7 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) if (tex->Status == ImTextureStatus_Destroyed) { - IM_ASSERT(tex->TexID == 0 && tex->BackendUserData == NULL); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL); if (tex->WantDestroyNextFrame) remove_from_list = true; // Destroy was scheduled by us else @@ -2715,7 +2715,7 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) tex->UnusedFrames++; // If a texture has never reached the backend, they don't need to know about it. - if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == 0 && tex->BackendUserData == NULL) + if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) remove_from_list = true; // Remove @@ -3518,7 +3518,7 @@ ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h) /*if (old_tex != NULL && old_tex->Status == ImTextureStatus_WantCreate) { // Reuse texture not yet used by backend. - IM_ASSERT(old_tex->TexID == 0 && old_tex->BackendUserData == NULL); + IM_ASSERT(old_tex->TexID == ImTextureID_Invalid && old_tex->BackendUserData == NULL); old_tex->DestroyPixels(); old_tex->Updates.clear(); new_tex = old_tex; From a21a2e855b74d92b33172fc8b7d880a8f6e09d71 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 31 Jan 2025 19:12:58 +0100 Subject: [PATCH 428/716] Textures: Single Textures[] array allows backend to not have to care about atlases. # Conflicts: # imgui.h --- imgui.cpp | 15 +++++++++++++++ imgui.h | 15 ++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5acd91c0cf6d..dd6b939e5a14 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1271,6 +1271,7 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); // Misc static void UpdateFontsNewFrame(); static void UpdateTexturesNewFrame(); +static void UpdateTexturesEndFrame(); static void UpdateSettings(); static int UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_hovered, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect); static void RenderWindowOuterBorders(ImGuiWindow* window); @@ -5182,6 +5183,18 @@ static void ImGui::UpdateTexturesNewFrame() ImFontAtlasUpdateNewFrame(atlas); } +// Build a single texture list +// We want to avoid user reading from atlas->TexList[] in order to facilitate better support for multiple atlases. +static void ImGui::UpdateTexturesEndFrame() +{ + ImGuiContext& g = *GImGui; + ImFontAtlas* atlas = g.IO.Fonts; + g.PlatformIO.Textures.resize(0); + g.PlatformIO.Textures.reserve(atlas->TexList.Size); + for (ImTextureData* tex : atlas->TexList) + g.PlatformIO.Textures.push_back(tex); +} + // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. // FIXME-VIEWPORT: the concept of a single ClipRectFullscreen is not ideal! static void SetupDrawListSharedData() @@ -5759,6 +5772,8 @@ void ImGui::EndFrame() g.Windows.swap(g.WindowsTempSortBuffer); g.IO.MetricsActiveWindows = g.WindowsActiveCount; + UpdateTexturesEndFrame(); + // Unlock font atlas g.IO.Fonts->Locked = false; diff --git a/imgui.h b/imgui.h index e51280e44f7a..936c177fe1a1 100644 --- a/imgui.h +++ b/imgui.h @@ -3496,7 +3496,7 @@ enum ImFontAtlasFlags_ // - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas). // - If you don't call any AddFont*** functions, the default font embedded in the code will be loaded for you. // It is the rendering backend responsibility to upload texture into your graphics API: -// - ImGui_ImplXXXX_RenderDrawData() functions generally iterate atlas->TexList[] to create/update/destroy each ImTextureData instance. +// - ImGui_ImplXXXX_RenderDrawData() functions generally iterate platform_io->Textures[] to create/update/destroy each ImTextureData instance. // - Backend then set ImTextureData's TexID and BackendUserData. // - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. // Legacy path: @@ -3597,11 +3597,9 @@ struct ImFontAtlas int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). - // Output - ImTextureData* TexData; // Current texture - ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). - // [Internal] + ImTextureData* TexData; // Current texture + ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetPlatformIO().Textures[] instead! bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. bool TexIsBuilt; // Set when texture was built matching current font input bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. @@ -3788,6 +3786,13 @@ struct ImGuiPlatformIO // Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure. void* Renderer_RenderState; + + //------------------------------------------------------------------ + // Output + //------------------------------------------------------------------ + + // Textures list (the list is updated by calling ImGui::EndFrame or ImGui::Render) + ImVector Textures; // Texture list (most often Textures.Size == 1). }; // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). From 208705368efdb9da4c45b377dc9bc0c5ea8458b6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Mar 2025 16:14:11 +0100 Subject: [PATCH 429/716] Textures: Adding a RefCount to textures so backend can avoid destroying them on shutdown if atlas is shared. --- imgui.cpp | 19 ++++++++++++++----- imgui.h | 5 +++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index dd6b939e5a14..7821841d4cae 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3942,6 +3942,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Font = NULL; FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); + IO.Fonts->RefCount++; Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; @@ -4212,12 +4213,15 @@ void ImGui::Shutdown() IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == NULL, "Forgot to shutdown Renderer backend?"); // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) - if (g.IO.Fonts) - ImFontAtlasRemoveDrawListSharedData(g.IO.Fonts, &g.DrawListSharedData); - if (g.IO.Fonts && g.FontAtlasOwnedByContext) + if (ImFontAtlas* atlas = g.IO.Fonts) { - g.IO.Fonts->Locked = false; - IM_DELETE(g.IO.Fonts); + ImFontAtlasRemoveDrawListSharedData(atlas, &g.DrawListSharedData); + atlas->RefCount--; + if (g.FontAtlasOwnedByContext) + { + atlas->Locked = false; + IM_DELETE(atlas); + } } g.IO.Fonts = NULL; g.DrawListSharedData.TempBuffer.clear(); @@ -5192,7 +5196,12 @@ static void ImGui::UpdateTexturesEndFrame() g.PlatformIO.Textures.resize(0); g.PlatformIO.Textures.reserve(atlas->TexList.Size); for (ImTextureData* tex : atlas->TexList) + { + // We provide this information so backends can decide whether to destroy textures. + // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized. + tex->RefCount = (unsigned short)atlas->RefCount; g.PlatformIO.Textures.push_back(tex); + } } // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. diff --git a/imgui.h b/imgui.h index 936c177fe1a1..b9e8f93bc20f 100644 --- a/imgui.h +++ b/imgui.h @@ -3379,6 +3379,7 @@ struct IMGUI_API ImTextureData ImTextureRect UpdateRect; // Bounding box encompassing all individual updates. ImVector Updates; // Array of individual updates. int UnusedFrames; // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. + unsigned short RefCount; // Number of contexts using this texture. bool UseColors; // Tell whether our texture data is known to use colors (rather than just white + alpha). bool WantDestroyNextFrame; // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. @@ -3591,13 +3592,12 @@ struct ImFontAtlas // Input ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) - ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. - int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height. ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8). int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] + ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. ImTextureData* TexData; // Current texture ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetPlatformIO().Textures[] instead! bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. @@ -3618,6 +3618,7 @@ struct ImFontAtlas const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name void* FontLoaderData; // Font backend opaque storage unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. + int RefCount; // Number of contexts using this atlas int _PackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size. int _PackedRects; // Number of packed rectangles. float _PackNodesFactor = 1.0f; From c20e160e0f22b35fcff66393abe03254c6f00bf1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 9 May 2025 21:41:01 +0200 Subject: [PATCH 430/716] Textures: added texture list pointer in ImDrawData. # Conflicts: # imgui.h --- imgui.cpp | 1 + imgui.h | 10 ++++++---- imgui_draw.cpp | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7821841d4cae..ce2b06462e03 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5588,6 +5588,7 @@ static void InitViewportDrawData(ImGuiViewportP* viewport) draw_data->DisplaySize = viewport->Size; draw_data->FramebufferScale = io.DisplayFramebufferScale; draw_data->OwnerViewport = viewport; + draw_data->Textures = &ImGui::GetPlatformIO().Textures; } // Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. diff --git a/imgui.h b/imgui.h index b9e8f93bc20f..c95f5ac57a7b 100644 --- a/imgui.h +++ b/imgui.h @@ -366,7 +366,7 @@ namespace ImGui IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame(). IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all! IMGUI_API void Render(); // ends the Dear ImGui frame, finalize the draw data. You can then get call GetDrawData(). - IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render. + IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). Call ImGui_ImplXXXX_RenderDrawData() function in your Renderer Backend to render. // Demo, Debug, Information IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application! @@ -3313,7 +3313,7 @@ struct ImDrawList struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - int CmdListsCount; // Number of ImDrawList* to render (should always be == CmdLists.size) + int CmdListsCount; // Number of ImDrawList* to render. (== CmdLists.Size). Exists for legacy reason. int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. @@ -3321,6 +3321,7 @@ struct ImDrawData ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. ImGuiViewport* OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). + ImVector* Textures; // List of textures to update. Most of the times the list is shared by all ImDrawData, has only 1 texture and it doesn't need any update. This almost always points to ImGui::GetPlatformIO().Textures[]. May be overriden or set to NULL if you want to manually update textures. // Functions ImDrawData() { Clear(); } @@ -3599,7 +3600,7 @@ struct ImFontAtlas // [Internal] ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. ImTextureData* TexData; // Current texture - ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetPlatformIO().Textures[] instead! + ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. bool TexIsBuilt; // Set when texture was built matching current font input bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. @@ -3793,7 +3794,8 @@ struct ImGuiPlatformIO //------------------------------------------------------------------ // Textures list (the list is updated by calling ImGui::EndFrame or ImGui::Render) - ImVector Textures; // Texture list (most often Textures.Size == 1). + // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which points to this. The array is available here mostly because backends will want to destroy textures on shutdown. + ImVector Textures; // List of textures used by Dear ImGui (most often 1). }; // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1e66a3b9c65e..0bde7a11648a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2244,6 +2244,7 @@ void ImDrawData::Clear() CmdLists.resize(0); // The ImDrawList are NOT owned by ImDrawData but e.g. by ImGuiContext, so we don't clear them. DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.0f, 0.0f); OwnerViewport = NULL; + Textures = NULL; } // Important: 'out_list' is generally going to be draw_data->CmdLists, but may be another temporary list From 372fd27e714893b0c80e9fe0dc554c0caabd3933 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 18:46:02 +0100 Subject: [PATCH 431/716] Backends: DirectX11: added ImGuiBackendFlags_RendererHasTextures support. # Conflicts: # backends/imgui_impl_dx11.cpp --- backends/imgui_impl_dx11.cpp | 114 +++++++++++++++++++++++------------ backends/imgui_impl_dx11.h | 6 +- 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index f6a7f35f6ccf..14e74e9b245e 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -16,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler. // 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -51,6 +53,12 @@ #endif // DirectX11 data +struct ImGui_ImplDX11_Texture +{ + ID3D11Texture2D* pTexture; + ID3D11ShaderResourceView* pTextureView; +}; + struct ImGui_ImplDX11_Data { ID3D11Device* pd3dDevice; @@ -63,7 +71,6 @@ struct ImGui_ImplDX11_Data ID3D11Buffer* pVertexConstantBuffer; ID3D11PixelShader* pPixelShader; ID3D11SamplerState* pFontSampler; - ID3D11ShaderResourceView* pFontTextureView; ID3D11RasterizerState* pRasterizerState; ID3D11BlendState* pBlendState; ID3D11DepthStencilState* pDepthStencilState; @@ -153,6 +160,13 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); ID3D11DeviceContext* device = bd->pd3dDeviceContext; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplDX11_UpdateTexture(tex); + // Create and grow vertex/index buffers if needed if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { @@ -320,21 +334,39 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) device->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } -static void ImGui_ImplDX11_CreateFontsTexture() +static void ImGui_ImplDX11_DestroyTexture(ImTextureData* tex) { - // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + ImGui_ImplDX11_Texture* backend_tex = (ImGui_ImplDX11_Texture*)tex->BackendUserData; + if (backend_tex == nullptr) + return; + IM_ASSERT(backend_tex->pTextureView == (ID3D11ShaderResourceView*)(intptr_t)tex->TexID); + backend_tex->pTextureView->Release(); + backend_tex->pTexture->Release(); + IM_DELETE(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; +} - // Upload texture to graphics system +void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex) +{ + ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); + if (tex->Status == ImTextureStatus_WantCreate) { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + unsigned int* pixels = (unsigned int*)tex->GetPixels(); + ImGui_ImplDX11_Texture* backend_tex = IM_NEW(ImGui_ImplDX11_Texture)(); + + // Create texture D3D11_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(desc)); - desc.Width = width; - desc.Height = height; + desc.Width = (UINT)tex->Width; + desc.Height = (UINT)tex->Height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -342,14 +374,12 @@ static void ImGui_ImplDX11_CreateFontsTexture() desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; - - ID3D11Texture2D* pTexture = nullptr; D3D11_SUBRESOURCE_DATA subResource; subResource.pSysMem = pixels; subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); - IM_ASSERT(pTexture != nullptr); + bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &backend_tex->pTexture); + IM_ASSERT(backend_tex->pTexture != nullptr && "Backend failed to create texture!"); // Create texture view D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; @@ -358,23 +388,29 @@ static void ImGui_ImplDX11_CreateFontsTexture() srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = desc.MipLevels; srvDesc.Texture2D.MostDetailedMip = 0; - bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView); - pTexture->Release(); - } + bd->pd3dDevice->CreateShaderResourceView(backend_tex->pTexture, &srvDesc, &backend_tex->pTextureView); + IM_ASSERT(backend_tex->pTextureView != nullptr && "Backend failed to create texture!"); - // Store our identifier - io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); -} - -static void ImGui_ImplDX11_DestroyFontsTexture() -{ - ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); - if (bd->pFontTextureView) + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)backend_tex->pTextureView); + tex->SetStatus(ImTextureStatus_OK); + tex->BackendUserData = backend_tex; + } + else if (tex->Status == ImTextureStatus_WantUpdates) { - bd->pFontTextureView->Release(); - bd->pFontTextureView = nullptr; - ImGui::GetIO().Fonts->SetTexID(0); // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + ImGui_ImplDX11_Texture* backend_tex = (ImGui_ImplDX11_Texture*)tex->BackendUserData; + IM_ASSERT(backend_tex->pTextureView == (ID3D11ShaderResourceView*)(intptr_t)tex->TexID); + for (ImTextureRect& r : tex->Updates) + { + D3D11_BOX box = { (UINT)r.x, (UINT)r.y, (UINT)0, (UINT)(r.x + r.w), (UINT)(r.y + r .h), (UINT)1 }; + bd->pd3dDeviceContext->UpdateSubresource(backend_tex->pTexture, 0, &box, tex->GetPixelsAt(r.x, r.y), (UINT)tex->GetPitch(), 0); + } + tex->SetStatus(ImTextureStatus_OK); } + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + ImGui_ImplDX11_DestroyTexture(tex); } bool ImGui_ImplDX11_CreateDeviceObjects() @@ -382,8 +418,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects() ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); if (!bd->pd3dDevice) return false; - if (bd->pFontSampler) - ImGui_ImplDX11_InvalidateDeviceObjects(); + ImGui_ImplDX11_InvalidateDeviceObjects(); // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) // If you would like to use this DX11 sample code but remove this dependency you can: @@ -542,8 +577,6 @@ bool ImGui_ImplDX11_CreateDeviceObjects() bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); } - ImGui_ImplDX11_CreateFontsTexture(); - return true; } @@ -553,7 +586,10 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (!bd->pd3dDevice) return; - ImGui_ImplDX11_DestroyFontsTexture(); + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplDX11_DestroyTexture(tex); if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } @@ -578,6 +614,10 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx11"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; @@ -612,7 +652,7 @@ void ImGui_ImplDX11_Shutdown() if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); } io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -621,7 +661,7 @@ void ImGui_ImplDX11_NewFrame() ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX11_Init()?"); - if (!bd->pFontSampler) + if (!bd->pVertexShader) ImGui_ImplDX11_CreateDeviceObjects(); } diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 772c1b920c05..c120bf093b30 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -33,6 +34,9 @@ IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex); + // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX11_RenderDrawData() call. // (Please open an issue if you feel you need access to more data) From 75efba7ec76729d34692187f97b7218c46d51a21 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 18:47:21 +0100 Subject: [PATCH 432/716] Backends: DirectX9: added ImGuiBackendFlags_RendererHasTextures support # Conflicts: # backends/imgui_impl_dx9.cpp --- backends/imgui_impl_dx9.cpp | 104 ++++++++++++++++++++++++++---------- backends/imgui_impl_dx9.h | 6 ++- 2 files changed, 81 insertions(+), 29 deletions(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 2cc8681a6d06..2617988e7ca7 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -16,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. @@ -50,7 +52,6 @@ struct ImGui_ImplDX9_Data LPDIRECT3DDEVICE9 pd3dDevice; LPDIRECT3DVERTEXBUFFER9 pVB; LPDIRECT3DINDEXBUFFER9 pIB; - LPDIRECT3DTEXTURE9 FontTexture; int VertexBufferSize; int IndexBufferSize; bool HasRgbaSupport; @@ -163,6 +164,13 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); LPDIRECT3DDEVICE9 device = bd->pd3dDevice; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplDX9_UpdateTexture(tex); + // Create and grow buffers if needed if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { @@ -322,6 +330,10 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx9"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096; bd->pd3dDevice = device; bd->pd3dDevice->AddRef(); @@ -340,12 +352,12 @@ void ImGui_ImplDX9_Shutdown() if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) -static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h) +static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h) { #ifndef IMGUI_USE_BGRA_PACKED_COLOR ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); @@ -366,28 +378,61 @@ static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, ImU32* src, int } } -static bool ImGui_ImplDX9_CreateFontsTexture() +void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex) { - // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); - unsigned char* pixels; - int width, height, bytes_per_pixel; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); - // Upload texture to graphics system - bd->FontTexture = nullptr; - if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) - return false; - D3DLOCKED_RECT tex_locked_rect; - if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) - return false; - ImGui_ImplDX9_CopyTextureRegion(io.Fonts->TexPixelsUseColors, (ImU32*)pixels, width * bytes_per_pixel, (ImU32*)tex_locked_rect.pBits, (int)tex_locked_rect.Pitch, width, height); - bd->FontTexture->UnlockRect(0); + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + LPDIRECT3DTEXTURE9 dx_tex = nullptr; + HRESULT hr = bd->pd3dDevice->CreateTexture(tex->Width, tex->Height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &dx_tex, nullptr); + if (hr < 0) + { + IM_ASSERT(hr >= 0 && "Backend failed to create texture!"); + return; + } - // Store our identifier - io.Fonts->SetTexID((ImTextureID)bd->FontTexture); - return true; + D3DLOCKED_RECT locked_rect; + if (dx_tex->LockRect(0, &locked_rect, nullptr, 0) == D3D_OK) + { + ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixels(), tex->Width * 4, (ImU32*)locked_rect.pBits, (ImU32)locked_rect.Pitch, tex->Width, tex->Height); + dx_tex->UnlockRect(0); + } + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)dx_tex); + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantUpdates) + { + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)(intptr_t)tex->TexID; + RECT update_rect = { (LONG)tex->UpdateRect.x, (LONG)tex->UpdateRect.y, (LONG)(tex->UpdateRect.x + tex->UpdateRect.w), (LONG)(tex->UpdateRect.y + tex->UpdateRect.h) }; + D3DLOCKED_RECT locked_rect; + if (backend_tex->LockRect(0, &locked_rect, &update_rect, 0) == D3D_OK) + for (ImTextureRect& r : tex->Updates) + ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixelsAt(r.x, r.y), tex->Width * 4, + (ImU32*)locked_rect.pBits + (r.x - update_rect.left) + (r.y - update_rect.top) * (locked_rect.Pitch / 4), (int)locked_rect.Pitch, r.w, r.h); + backend_tex->UnlockRect(0); + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy) + { + LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID; + if (backend_tex == nullptr) + return; + IM_ASSERT(tex->TexID == (ImTextureID)(intptr_t)backend_tex); + backend_tex->Release(); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + } } bool ImGui_ImplDX9_CreateDeviceObjects() @@ -395,8 +440,6 @@ bool ImGui_ImplDX9_CreateDeviceObjects() ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); if (!bd || !bd->pd3dDevice) return false; - if (!ImGui_ImplDX9_CreateFontsTexture()) - return false; return true; } @@ -405,18 +448,23 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); if (!bd || !bd->pd3dDevice) return; + + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + { + tex->SetStatus(ImTextureStatus_WantDestroy); + ImGui_ImplDX9_UpdateTexture(tex); + } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } - if (bd->FontTexture) { bd->FontTexture->Release(); bd->FontTexture = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. } void ImGui_ImplDX9_NewFrame() { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX9_Init()?"); - - if (!bd->FontTexture) - ImGui_ImplDX9_CreateDeviceObjects(); + IM_UNUSED(bd); } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index b693054d9b6b..600f0a750af8 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -30,4 +31,7 @@ IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex); + #endif // #ifndef IMGUI_DISABLE From 2d2b1bc1cc17f86c7a2253fcce4ceef41c238d96 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 13:05:27 +0100 Subject: [PATCH 433/716] Backends: DirectX10: added ImGuiBackendFlags_RendererHasTextures support. # Conflicts: # backends/imgui_impl_dx10.cpp # backends/imgui_impl_dx10.h --- backends/imgui_impl_dx10.cpp | 112 ++++++++++++++++++++++++----------- backends/imgui_impl_dx10.h | 6 +- 2 files changed, 81 insertions(+), 37 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index dd06e0e7fdea..4dc5f884ebb6 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -15,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-10-07: DirectX10: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -49,6 +51,12 @@ #endif // DirectX10 data +struct ImGui_ImplDX10_Texture +{ + ID3D10Texture2D* pTexture; + ID3D10ShaderResourceView* pTextureView; +}; + struct ImGui_ImplDX10_Data { ID3D10Device* pd3dDevice; @@ -60,7 +68,6 @@ struct ImGui_ImplDX10_Data ID3D10Buffer* pVertexConstantBuffer; ID3D10PixelShader* pPixelShader; ID3D10SamplerState* pFontSampler; - ID3D10ShaderResourceView* pFontTextureView; ID3D10RasterizerState* pRasterizerState; ID3D10BlendState* pBlendState; ID3D10DepthStencilState* pDepthStencilState; @@ -147,6 +154,13 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); ID3D10Device* device = bd->pd3dDevice; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplDX10_UpdateTexture(tex); + // Create and grow vertex/index buffers if needed if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) { @@ -304,21 +318,39 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) device->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); } -static void ImGui_ImplDX10_CreateFontsTexture() +static void ImGui_ImplDX10_DestroyTexture(ImTextureData* tex) { - // Build texture atlas - ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + ImGui_ImplDX10_Texture* backend_tex = (ImGui_ImplDX10_Texture*)tex->BackendUserData; + if (backend_tex == nullptr) + return; + IM_ASSERT(backend_tex->pTextureView == (ID3D10ShaderResourceView*)(intptr_t)tex->TexID); + backend_tex->pTexture->Release(); + backend_tex->pTextureView->Release(); + IM_DELETE(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; +} - // Upload texture to graphics system +void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex) +{ + ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); + if (tex->Status == ImTextureStatus_WantCreate) { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + unsigned int* pixels = (unsigned int*)tex->GetPixels(); + ImGui_ImplDX10_Texture* backend_tex = IM_NEW(ImGui_ImplDX10_Texture)(); + + // Create texture D3D10_TEXTURE2D_DESC desc; ZeroMemory(&desc, sizeof(desc)); - desc.Width = width; - desc.Height = height; + desc.Width = (UINT)tex->Width; + desc.Height = (UINT)tex->Height; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -327,13 +359,12 @@ static void ImGui_ImplDX10_CreateFontsTexture() desc.BindFlags = D3D10_BIND_SHADER_RESOURCE; desc.CPUAccessFlags = 0; - ID3D10Texture2D* pTexture = nullptr; D3D10_SUBRESOURCE_DATA subResource; subResource.pSysMem = pixels; subResource.SysMemPitch = desc.Width * 4; subResource.SysMemSlicePitch = 0; - bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); - IM_ASSERT(pTexture != nullptr); + bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &backend_tex->pTexture); + IM_ASSERT(backend_tex->pTexture != nullptr && "Backend failed to create texture!"); // Create texture view D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; @@ -342,23 +373,29 @@ static void ImGui_ImplDX10_CreateFontsTexture() srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; srv_desc.Texture2D.MipLevels = desc.MipLevels; srv_desc.Texture2D.MostDetailedMip = 0; - bd->pd3dDevice->CreateShaderResourceView(pTexture, &srv_desc, &bd->pFontTextureView); - pTexture->Release(); - } + bd->pd3dDevice->CreateShaderResourceView(backend_tex->pTexture, &srv_desc, &backend_tex->pTextureView); + IM_ASSERT(backend_tex->pTextureView != nullptr && "Backend failed to create texture!"); - // Store our identifier - io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); -} - -static void ImGui_ImplDX10_DestroyFontsTexture() -{ - ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); - if (bd->pFontTextureView) + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)backend_tex->pTextureView); + tex->SetStatus(ImTextureStatus_OK); + tex->BackendUserData = backend_tex; + } + else if (tex->Status == ImTextureStatus_WantUpdates) { - bd->pFontTextureView->Release(); - bd->pFontTextureView = nullptr; - ImGui::GetIO().Fonts->SetTexID(0); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well. + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + ImGui_ImplDX10_Texture* backend_tex = (ImGui_ImplDX10_Texture*)tex->BackendUserData; + IM_ASSERT(backend_tex->pTextureView == (ID3D10ShaderResourceView*)(intptr_t)tex->TexID); + for (ImTextureRect& r : tex->Updates) + { + D3D10_BOX box = { (UINT)r.x, (UINT)r.y, (UINT)0, (UINT)(r.x + r.w), (UINT)(r.y + r.h), (UINT)1 }; + bd->pd3dDevice->UpdateSubresource(backend_tex->pTexture, 0, &box, tex->GetPixelsAt(r.x, r.y), (UINT)tex->GetPitch(), 0); + } + tex->SetStatus(ImTextureStatus_OK); } + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + ImGui_ImplDX10_DestroyTexture(tex); } bool ImGui_ImplDX10_CreateDeviceObjects() @@ -366,8 +403,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects() ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); if (!bd->pd3dDevice) return false; - if (bd->pFontSampler) - ImGui_ImplDX10_InvalidateDeviceObjects(); + ImGui_ImplDX10_InvalidateDeviceObjects(); // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) // If you would like to use this DX10 sample code but remove this dependency you can: @@ -526,8 +562,6 @@ bool ImGui_ImplDX10_CreateDeviceObjects() bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); } - ImGui_ImplDX10_CreateFontsTexture(); - return true; } @@ -537,8 +571,10 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() if (!bd->pd3dDevice) return; - ImGui_ImplDX10_DestroyFontsTexture(); - + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplDX10_DestroyTexture(tex); if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } @@ -562,6 +598,10 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx10"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; // Get factory from device IDXGIDevice* pDXGIDevice = nullptr; @@ -592,7 +632,7 @@ void ImGui_ImplDX10_Shutdown() if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index d9f29987d7ee..38ecbdfe369d 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -31,6 +32,9 @@ IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex); + // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX10_RenderDrawData() call. // (Please open an issue if you feel you need access to more data) From eefe5d5aac1a9040020855c3bb918fe469cf4a38 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 18:46:09 +0100 Subject: [PATCH 434/716] Backends: DirectX12: added ImGuiBackendFlags_RendererHasTextures support. # Conflicts: # backends/imgui_impl_dx12.cpp --- backends/imgui_impl_dx12.cpp | 229 ++++++++++++++++++++++++----------- backends/imgui_impl_dx12.h | 6 +- 2 files changed, 163 insertions(+), 72 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index a373e8eec4cf..ea7e3b8813bc 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. @@ -19,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: DirectX12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-02-24: DirectX12: Fixed an issue where ImGui_ImplDX12_Init() signature change from 2024-11-15 combined with change from 2025-01-15 made legacy ImGui_ImplDX12_Init() crash. (#8429) // 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own. @@ -184,6 +186,13 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplDX12_UpdateTexture(tex); + // FIXME: We are assuming that this only gets called once per frame! ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); bd->frameIndex = bd->frameIndex + 1; @@ -316,18 +325,39 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL platform_io.Renderer_RenderState = nullptr; } -static void ImGui_ImplDX12_CreateFontsTexture() +static void ImGui_ImplDX12_DestroyTexture(ImTextureData* tex) +{ + ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData; + if (backend_tex == nullptr) + return; + IM_ASSERT(backend_tex->hFontSrvGpuDescHandle.ptr == (UINT64)tex->TexID); + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, backend_tex->hFontSrvCpuDescHandle, backend_tex->hFontSrvGpuDescHandle); + SafeRelease(backend_tex->pTextureResource); + backend_tex->hFontSrvCpuDescHandle.ptr = 0; + backend_tex->hFontSrvGpuDescHandle.ptr = 0; + IM_DELETE(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; +} + +void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex) { - // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + bool need_barrier_before_copy = true; // Do we need a resource barrier before we copy new data in? - // Upload texture to graphics system - ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; + if (tex->Status == ImTextureStatus_WantCreate) { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + ImGui_ImplDX12_Texture* backend_tex = IM_NEW(ImGui_ImplDX12_Texture)(); + bd->InitInfo.SrvDescriptorAllocFn(&bd->InitInfo, &backend_tex->hFontSrvCpuDescHandle, &backend_tex->hFontSrvGpuDescHandle); // Allocate a desctriptor handle + D3D12_HEAP_PROPERTIES props = {}; props.Type = D3D12_HEAP_TYPE_DEFAULT; props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; @@ -337,8 +367,8 @@ static void ImGui_ImplDX12_CreateFontsTexture() ZeroMemory(&desc, sizeof(desc)); desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; desc.Alignment = 0; - desc.Width = width; - desc.Height = height; + desc.Width = tex->Width; + desc.Height = tex->Height; desc.DepthOrArraySize = 1; desc.MipLevels = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -351,8 +381,47 @@ static void ImGui_ImplDX12_CreateFontsTexture() bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture)); - UINT upload_pitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); - UINT upload_size = height * upload_pitch; + // Create SRV + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; + ZeroMemory(&srvDesc, sizeof(srvDesc)); + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = desc.MipLevels; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, backend_tex->hFontSrvCpuDescHandle); + SafeRelease(backend_tex->pTextureResource); + backend_tex->pTextureResource = pTexture; + + // Store identifiers + tex->SetTexID((ImTextureID)backend_tex->hFontSrvGpuDescHandle.ptr); + tex->BackendUserData = backend_tex; + need_barrier_before_copy = false; // Because this is a newly-created texture it will be in D3D12_RESOURCE_STATE_COMMON and thus we don't need a barrier + // We don't set tex->Status to ImTextureStatus_OK to let the code fallthrough below. + } + + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) + { + ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData; + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // We could use the smaller rect on _WantCreate but using the full rect allows us to clear the texture. + // FIXME-OPT: Uploading single box even when using ImTextureStatus_WantUpdates. Could use tex->Updates[] + // - Copy all blocks contiguously in upload buffer. + // - Barrier before copy, submit all CopyTextureRegion(), barrier after copy. + const int upload_x = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.x; + const int upload_y = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.y; + const int upload_w = (tex->Status == ImTextureStatus_WantCreate) ? tex->Width : tex->UpdateRect.w; + const int upload_h = (tex->Status == ImTextureStatus_WantCreate) ? tex->Height : tex->UpdateRect.h; + + // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions. + UINT upload_pitch_src = upload_w * tex->BytesPerPixel; + UINT upload_pitch_dst = (upload_pitch_src + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); + UINT upload_size = upload_pitch_dst * upload_h; + + D3D12_RESOURCE_DESC desc; + ZeroMemory(&desc, sizeof(desc)); desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; desc.Alignment = 0; desc.Width = upload_size; @@ -365,64 +434,83 @@ static void ImGui_ImplDX12_CreateFontsTexture() desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; desc.Flags = D3D12_RESOURCE_FLAG_NONE; + D3D12_HEAP_PROPERTIES props; + memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); props.Type = D3D12_HEAP_TYPE_UPLOAD; props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + // FIXME-OPT: Can upload buffer be reused? ID3D12Resource* uploadBuffer = nullptr; HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer)); IM_ASSERT(SUCCEEDED(hr)); + // Create temporary command list and execute immediately + ID3D12Fence* fence = nullptr; + hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); + IM_ASSERT(SUCCEEDED(hr)); + + HANDLE event = ::CreateEvent(0, 0, 0, 0); + IM_ASSERT(event != nullptr); + + // FIXME-OPT: Create once and reuse? + ID3D12CommandAllocator* cmdAlloc = nullptr; + hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); + IM_ASSERT(SUCCEEDED(hr)); + + // FIXME-OPT: Can be use the one from user? (pass ID3D12GraphicsCommandList* to ImGui_ImplDX12_UpdateTextures) + ID3D12GraphicsCommandList* cmdList = nullptr; + hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList)); + IM_ASSERT(SUCCEEDED(hr)); + + // Copy to upload buffer void* mapped = nullptr; D3D12_RANGE range = { 0, upload_size }; hr = uploadBuffer->Map(0, &range, &mapped); IM_ASSERT(SUCCEEDED(hr)); - for (int y = 0; y < height; y++) - memcpy((void*) ((uintptr_t) mapped + y * upload_pitch), pixels + y * width * 4, width * 4); + for (int y = 0; y < upload_h; y++) + memcpy((void*)((uintptr_t)mapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src); uploadBuffer->Unmap(0, &range); + if (need_barrier_before_copy) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = backend_tex->pTextureResource; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; + cmdList->ResourceBarrier(1, &barrier); + } + D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; { srcLocation.pResource = uploadBuffer; srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srcLocation.PlacedFootprint.Footprint.Width = width; - srcLocation.PlacedFootprint.Footprint.Height = height; + srcLocation.PlacedFootprint.Footprint.Width = upload_w; + srcLocation.PlacedFootprint.Footprint.Height = upload_h; srcLocation.PlacedFootprint.Footprint.Depth = 1; - srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch; - - dstLocation.pResource = pTexture; + srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch_dst; + dstLocation.pResource = backend_tex->pTextureResource; dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstLocation.SubresourceIndex = 0; } + cmdList->CopyTextureRegion(&dstLocation, upload_x, upload_y, 0, &srcLocation, nullptr); - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = pTexture; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - - ID3D12Fence* fence = nullptr; - hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); - IM_ASSERT(SUCCEEDED(hr)); - - HANDLE event = ::CreateEvent(0, 0, 0, 0); - IM_ASSERT(event != nullptr); - - ID3D12CommandAllocator* cmdAlloc = nullptr; - hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); - IM_ASSERT(SUCCEEDED(hr)); - - ID3D12GraphicsCommandList* cmdList = nullptr; - hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList)); - IM_ASSERT(SUCCEEDED(hr)); - - cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, nullptr); - cmdList->ResourceBarrier(1, &barrier); + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = backend_tex->pTextureResource; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + cmdList->ResourceBarrier(1, &barrier); + } hr = cmdList->Close(); IM_ASSERT(SUCCEEDED(hr)); @@ -432,6 +520,10 @@ static void ImGui_ImplDX12_CreateFontsTexture() hr = cmdQueue->Signal(fence, 1); IM_ASSERT(SUCCEEDED(hr)); + // FIXME-OPT: Suboptimal? + // - To remove this may need to create NumFramesInFlight x ImGui_ImplDX12_FrameContext in backend data (mimick docking version) + // - Store per-frame in flight: upload buffer? + // - Where do cmdList and cmdAlloc fit? fence->SetEventOnCompletion(1, event); ::WaitForSingleObject(event, INFINITE); @@ -440,22 +532,11 @@ static void ImGui_ImplDX12_CreateFontsTexture() ::CloseHandle(event); fence->Release(); uploadBuffer->Release(); - - // Create texture view - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; - ZeroMemory(&srvDesc, sizeof(srvDesc)); - srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MipLevels = desc.MipLevels; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, font_tex->hFontSrvCpuDescHandle); - SafeRelease(font_tex->pTextureResource); - font_tex->pTextureResource = pTexture; + tex->SetStatus(ImTextureStatus_OK); } - // Store our identifier - io.Fonts->SetTexID((ImTextureID)font_tex->hFontSrvGpuDescHandle.ptr); + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames >= (int)bd->numFramesInFlight) + ImGui_ImplDX12_DestroyTexture(tex); } bool ImGui_ImplDX12_CreateDeviceObjects() @@ -687,8 +768,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects() if (result_pipeline_state != S_OK) return false; - ImGui_ImplDX12_CreateFontsTexture(); - return true; } @@ -704,12 +783,10 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() SafeRelease(bd->pRootSignature); SafeRelease(bd->pPipelineState); - // Free SRV descriptor used by texture - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplDX12_Texture* font_tex = &bd->FontTexture; - bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, font_tex->hFontSrvCpuDescHandle, font_tex->hFontSrvGpuDescHandle); - SafeRelease(font_tex->pTextureResource); - io.Fonts->SetTexID(0); // We copied bd->hFontSrvGpuDescHandle to io.Fonts->TexID so let's clear that as well. + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplDX12_DestroyTexture(tex); for (UINT i = 0; i < bd->numFramesInFlight; i++) { @@ -741,6 +818,16 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx12"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplDX12_InitPlatformInterface(); + + // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport, + // Since this is created and managed by the application, we will only use the ->Resources[] fields. + ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); +>>>>>>> dda12fbd9a (Backends: DirectX12: added ImGuiBackendFlags_RendererHasTextures support.) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (init_info->SrvDescriptorAllocFn == nullptr) @@ -763,10 +850,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) }; } #endif - - // Allocate 1 SRV descriptor for the font texture IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr); - init_info->SrvDescriptorAllocFn(&bd->InitInfo, &bd->FontTexture.hFontSrvCpuDescHandle, &bd->FontTexture.hFontSrvGpuDescHandle); // Create buffers with a default size (they will later be grown as needed) bd->frameIndex = UINT_MAX; @@ -806,6 +890,9 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO bool ret = ImGui_ImplDX12_Init(&init_info); ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); bd->commandQueueOwned = true; + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; // Using legacy ImGui_ImplDX12_Init() call with 1 SRV descriptor we cannot support multiple textures. + return ret; } #endif @@ -822,7 +909,7 @@ void ImGui_ImplDX12_Shutdown() io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index a79de7b13565..4ff510455563 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. Win32) // Implemented features: -// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification. @@ -63,6 +64,9 @@ IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex); + // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX12_RenderDrawData() call. // (Please open an issue if you feel you need access to more data) From dbb91a574f35e24697754f6344455fd43b97d46d Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 18:47:14 +0100 Subject: [PATCH 435/716] Backends: OpenGL3: added ImGuiBackendFlags_RendererHasTextures support. + Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). --- backends/imgui_impl_opengl3.cpp | 135 ++++++++++++++++++--------- backends/imgui_impl_opengl3.h | 8 +- backends/imgui_impl_opengl3_loader.h | 8 +- 3 files changed, 103 insertions(+), 48 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 8b7a2ecb5ac2..3f6c087567b1 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -4,8 +4,9 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // About WebGL/ES: // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. @@ -22,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -231,7 +233,7 @@ struct ImGui_ImplOpenGL3_Data bool GlProfileIsES3; bool GlProfileIsCompat; GLint GlProfileMask; - GLuint FontTexture; + GLint MaxTextureSize; GLuint ShaderHandle; GLint AttribLocationTex; // Uniforms location GLint AttribLocationProjMtx; @@ -244,6 +246,7 @@ struct ImGui_ImplOpenGL3_Data bool HasPolygonMode; bool HasClipOrigin; bool UseBufferSubData; + ImVector TempBuffer; ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -326,6 +329,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) if (major == 0 && minor == 0) sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "." bd->GlVersion = (GLuint)(major * 100 + minor * 10); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &bd->MaxTextureSize); #if defined(IMGUI_IMPL_OPENGL_ES3) bd->GlProfileIsES3 = true; @@ -359,6 +363,10 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) if (bd->GlVersion >= 320) io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. #endif + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. + + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize; // Store GLSL version string so we can refer to it later in case we recreate shaders. // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure. @@ -411,7 +419,7 @@ void ImGui_ImplOpenGL3_Shutdown() ImGui_ImplOpenGL3_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -424,8 +432,6 @@ void ImGui_ImplOpenGL3_NewFrame() if (!bd->ShaderHandle) ImGui_ImplOpenGL3_CreateDeviceObjects(); - if (!bd->FontTexture) - ImGui_ImplOpenGL3_CreateFontsTexture(); } static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) @@ -517,6 +523,13 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplOpenGL3_UpdateTexture(tex); + // Backup GL state GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); glActiveTexture(GL_TEXTURE0); @@ -685,50 +698,82 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) (void)bd; // Not all compilation paths use this } -bool ImGui_ImplOpenGL3_CreateFontsTexture() +static void ImGui_ImplOpenGL3_DestroyTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; + glDeleteTextures(1, &gl_tex_id); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); +} - // Build texture atlas - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - GLint last_texture; - GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); - GL_CALL(glGenTextures(1, &bd->FontTexture)); - GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); - GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); +void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) +{ + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == 0 && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + const void* pixels = tex->GetPixels(); + GLuint gl_texture_id = 0; + + // Upload texture to graphics system + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + GLint last_texture; + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + GL_CALL(glGenTextures(1, &gl_texture_id)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_texture_id)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); #ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); #endif - GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); - - // Store identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); - // Restore state - GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); - - return true; -} + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)gl_texture_id); + tex->SetStatus(ImTextureStatus_OK); -void ImGui_ImplOpenGL3_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); - if (bd->FontTexture) + // Restore state + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); + } + else if (tex->Status == ImTextureStatus_WantUpdates) { - glDeleteTextures(1, &bd->FontTexture); - io.Fonts->SetTexID(0); - bd->FontTexture = 0; + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + GLint last_texture; + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + + GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; + GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); +#if 0// GL_UNPACK_ROW_LENGTH // Not on WebGL/ES + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); + for (ImTextureRect& r : tex->Updates) + GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y))); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); +#else + // GL ES doesn't have GL_UNPACK_ROW_LENGTH, so we need to (A) copy to a contiguous buffer or (B) upload line by line. + ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); + for (ImTextureRect& r : tex->Updates) + { + const int src_pitch = r.w * tex->BytesPerPixel; + bd->TempBuffer.resize(r.h * src_pitch); + char* out_p = bd->TempBuffer.Data; + for (int y = 0; y < r.h; y++, out_p += src_pitch) + memcpy(out_p, tex->GetPixelsAt(r.x, r.y + y), src_pitch); + IM_ASSERT(out_p == bd->TempBuffer.end()); + GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, bd->TempBuffer.Data)); + } +#endif + tex->SetStatus(ImTextureStatus_OK); + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); // Restore state } + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + ImGui_ImplOpenGL3_DestroyTexture(tex); } // If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. @@ -951,8 +996,6 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() glGenBuffers(1, &bd->VboHandle); glGenBuffers(1, &bd->ElementsHandle); - ImGui_ImplOpenGL3_CreateFontsTexture(); - // Restore modified GL state glBindTexture(GL_TEXTURE_2D, last_texture); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); @@ -972,7 +1015,11 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects() if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; } if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; } if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; } - ImGui_ImplOpenGL3_DestroyFontsTexture(); + + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplOpenGL3_DestroyTexture(tex); } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index 5de51cfddaf9..b72b5c887d63 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -4,8 +4,9 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!] +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // About WebGL/ES: // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES. @@ -36,11 +37,12 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); // (Optional) Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); + // Configuration flags to add in your imconfig file: //#define IMGUI_IMPL_OPENGL_ES2 // Enable ES 2 (Auto-detected on Emscripten) //#define IMGUI_IMPL_OPENGL_ES3 // Enable ES 3 (Auto-detected on iOS/Android) diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index d6ffa5a2d427..4ca0536031aa 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -167,6 +167,7 @@ typedef khronos_uint8_t GLubyte; #define GL_SCISSOR_TEST 0x0C11 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_TEXTURE_2D 0x0DE1 #define GL_UNSIGNED_BYTE 0x1401 #define GL_UNSIGNED_SHORT 0x1403 @@ -224,11 +225,13 @@ typedef khronos_float_t GLclampf; typedef double GLclampd; #define GL_TEXTURE_BINDING_2D 0x8069 typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); typedef void (APIENTRYP PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); typedef void (APIENTRYP PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); typedef void (APIENTRYP PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void *indices); +GLAPI void APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI void APIENTRY glBindTexture (GLenum target, GLuint texture); GLAPI void APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures); GLAPI void APIENTRY glGenTextures (GLsizei n, GLuint *textures); @@ -478,7 +481,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc); /* gl3w internal state */ union ImGL3WProcs { - GL3WglProc ptr[59]; + GL3WglProc ptr[60]; struct { PFNGLACTIVETEXTUREPROC ActiveTexture; PFNGLATTACHSHADERPROC AttachShader; @@ -534,6 +537,7 @@ union ImGL3WProcs { PFNGLSHADERSOURCEPROC ShaderSource; PFNGLTEXIMAGE2DPROC TexImage2D; PFNGLTEXPARAMETERIPROC TexParameteri; + PFNGLTEXSUBIMAGE2DPROC TexSubImage2D; PFNGLUNIFORM1IPROC Uniform1i; PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv; PFNGLUSEPROGRAMPROC UseProgram; @@ -599,6 +603,7 @@ GL3W_API extern union ImGL3WProcs imgl3wProcs; #define glShaderSource imgl3wProcs.gl.ShaderSource #define glTexImage2D imgl3wProcs.gl.TexImage2D #define glTexParameteri imgl3wProcs.gl.TexParameteri +#define glTexSubImage2D imgl3wProcs.gl.TexSubImage2D #define glUniform1i imgl3wProcs.gl.Uniform1i #define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv #define glUseProgram imgl3wProcs.gl.UseProgram @@ -894,6 +899,7 @@ static const char *proc_names[] = { "glShaderSource", "glTexImage2D", "glTexParameteri", + "glTexSubImage2D", "glUniform1i", "glUniformMatrix4fv", "glUseProgram", From 0430c55b84edc8097be1064ad8aafb842c3774ae Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Dec 2024 14:05:55 +0100 Subject: [PATCH 436/716] Backends: OpenGL2: added ImGuiBackendFlags_RendererHasTextures support. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). --- backends/imgui_impl_opengl2.cpp | 121 +++++++++++++++++++------------- backends/imgui_impl_opengl2.h | 8 ++- 2 files changed, 78 insertions(+), 51 deletions(-) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 2a255be4c7f7..5e9df17153d3 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -2,7 +2,8 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). @@ -24,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. @@ -81,8 +83,6 @@ // OpenGL data struct ImGui_ImplOpenGL2_Data { - GLuint FontTexture; - ImGui_ImplOpenGL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -104,6 +104,7 @@ bool ImGui_ImplOpenGL2_Init() ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)(); io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_opengl2"; + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. return true; } @@ -117,6 +118,7 @@ void ImGui_ImplOpenGL2_Shutdown() ImGui_ImplOpenGL2_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -124,11 +126,7 @@ void ImGui_ImplOpenGL2_NewFrame() { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL2_Init()?"); - - if (!bd->FontTexture) - ImGui_ImplOpenGL2_CreateDeviceObjects(); - if (!bd->FontTexture) - ImGui_ImplOpenGL2_CreateFontsTexture(); + IM_UNUSED(bd); } static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) @@ -186,6 +184,13 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) if (fb_width == 0 || fb_height == 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplOpenGL2_UpdateTexture(tex); + // Backup GL state GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); @@ -259,57 +264,77 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, last_tex_env_mode); } -bool ImGui_ImplOpenGL2_CreateFontsTexture() -{ - // Build texture atlas - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - GLint last_texture; - glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); - glGenTextures(1, &bd->FontTexture); - glBindTexture(GL_TEXTURE_2D, bd->FontTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); - - // Restore state - glBindTexture(GL_TEXTURE_2D, last_texture); - - return true; -} - -void ImGui_ImplOpenGL2_DestroyFontsTexture() +void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); - if (bd->FontTexture) + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == 0 && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + const void* pixels = tex->GetPixels(); + GLuint gl_texture_id = 0; + + // Upload texture to graphics system + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + GLint last_texture; + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + GL_CALL(glGenTextures(1, &gl_texture_id)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_texture_id)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)); + GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)gl_texture_id); + tex->SetStatus(ImTextureStatus_OK); + + // Restore state + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); + } + else if (tex->Status == ImTextureStatus_WantUpdates) + { + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + GLint last_texture; + GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + + GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; + GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); + for (ImTextureRect& r : tex->Updates) + GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y))); + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture)); // Restore state + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy) { - glDeleteTextures(1, &bd->FontTexture); - io.Fonts->SetTexID(0); - bd->FontTexture = 0; + GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; + glDeleteTextures(1, &gl_tex_id); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); } } bool ImGui_ImplOpenGL2_CreateDeviceObjects() { - return ImGui_ImplOpenGL2_CreateFontsTexture(); + return true; } void ImGui_ImplOpenGL2_DestroyDeviceObjects() { - ImGui_ImplOpenGL2_DestroyFontsTexture(); + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + { + tex->SetStatus(ImTextureStatus_WantDestroy); + ImGui_ImplOpenGL2_UpdateTexture(tex); + } } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index 5832a176599f..014a03aca619 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -2,7 +2,8 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). @@ -33,9 +34,10 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL2_NewFrame(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data); // Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplOpenGL2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_DestroyDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex); + #endif // #ifndef IMGUI_DISABLE From abe294bfd0bfff325bbaa000f2d688085f1d4696 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 27 Nov 2024 18:47:28 +0100 Subject: [PATCH 437/716] Backends: Vulkan: added ImGuiBackendFlags_RendererHasTextures support. # Conflicts: # backends/imgui_impl_vulkan.cpp --- backends/imgui_impl_vulkan.cpp | 437 ++++++++++++++++++--------------- backends/imgui_impl_vulkan.h | 13 +- 2 files changed, 242 insertions(+), 208 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 10648c3a41f5..74c7d791b9f4 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. +// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. @@ -26,7 +27,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-05-07- Vulkan: Fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) +// 2025-06-11: Vulkan: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_DestroyFontsTexture(). +// 2025-05-07: Vulkan: Fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) // 2025-05-07: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) // 2025-04-07: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's pColorAttachmentFormats buffer when set, in order to reduce common user-error of specifying a pointer to data that gets out of scope. (#8282) // 2025-02-14: *BREAKING CHANGE*: Added uint32_t api_version to ImGui_ImplVulkan_LoadFunctions(). @@ -251,7 +253,6 @@ struct ImGui_ImplVulkan_Data VkDescriptorPool DescriptorPool; // Texture management - ImGui_ImplVulkan_Texture FontTexture; VkSampler TexSampler; VkCommandPool TexCommandPool; VkCommandBuffer TexCommandBuffer; @@ -502,6 +503,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm if (fb_width <= 0 || fb_height <= 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplVulkan_UpdateTexture(tex); + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; if (pipeline == VK_NULL_HANDLE) @@ -638,220 +646,222 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm vkCmdSetScissor(command_buffer, 0, 1, &scissor); } -bool ImGui_ImplVulkan_CreateFontsTexture() +static void ImGui_ImplVulkan_DestroyTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplVulkan_Texture* backend_tex = (ImGui_ImplVulkan_Texture*)tex->BackendUserData; + if (backend_tex == nullptr) + return; + IM_ASSERT(backend_tex->DescriptorSet == (VkDescriptorSet)tex->TexID); ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - VkResult err; - - // Destroy existing texture (if any) - if (bd->FontTexture.DescriptorSet) - { - vkQueueWaitIdle(v->Queue); - ImGui_ImplVulkan_DestroyFontsTexture(); - } - - // Create command pool/buffer - if (bd->TexCommandPool == VK_NULL_HANDLE) - { - VkCommandPoolCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = 0; - info.queueFamilyIndex = v->QueueFamily; - vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->TexCommandPool); - } - if (bd->TexCommandBuffer == VK_NULL_HANDLE) - { - VkCommandBufferAllocateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - info.commandPool = bd->TexCommandPool; - info.commandBufferCount = 1; - err = vkAllocateCommandBuffers(v->Device, &info, &bd->TexCommandBuffer); - check_vk_result(err); - } - - // Start command buffer - { - err = vkResetCommandPool(v->Device, bd->TexCommandPool, 0); - check_vk_result(err); - VkCommandBufferBeginInfo begin_info = {}; - begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - err = vkBeginCommandBuffer(bd->TexCommandBuffer, &begin_info); - check_vk_result(err); - } + ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); + vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); + vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); + vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); + IM_DELETE(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; +} - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - size_t upload_size = width * height * 4 * sizeof(char); +void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) +{ + if (tex->Status == ImTextureStatus_OK) + return; + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + VkResult err; - // Create the Image: - ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; + if (tex->Status == ImTextureStatus_WantCreate) { - VkImageCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - info.imageType = VK_IMAGE_TYPE_2D; - info.format = VK_FORMAT_R8G8B8A8_UNORM; - info.extent.width = width; - info.extent.height = height; - info.extent.depth = 1; - info.mipLevels = 1; - info.arrayLayers = 1; - info.samples = VK_SAMPLE_COUNT_1_BIT; - info.tiling = VK_IMAGE_TILING_OPTIMAL; - info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - err = vkCreateImage(v->Device, &info, v->Allocator, &backend_tex->Image); - check_vk_result(err); - VkMemoryRequirements req; - vkGetImageMemoryRequirements(v->Device, backend_tex->Image, &req); - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); - alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &backend_tex->Memory); - check_vk_result(err); - err = vkBindImageMemory(v->Device, backend_tex->Image, backend_tex->Memory, 0); - check_vk_result(err); - } + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + ImGui_ImplVulkan_Texture* backend_tex = IM_NEW(ImGui_ImplVulkan_Texture)(); - // Create the Image View: - { - VkImageViewCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - info.image = backend_tex->Image; - info.viewType = VK_IMAGE_VIEW_TYPE_2D; - info.format = VK_FORMAT_R8G8B8A8_UNORM; - info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - info.subresourceRange.levelCount = 1; - info.subresourceRange.layerCount = 1; - err = vkCreateImageView(v->Device, &info, v->Allocator, &backend_tex->ImageView); - check_vk_result(err); - } + // Create the Image: + { + VkImageCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + info.imageType = VK_IMAGE_TYPE_2D; + info.format = VK_FORMAT_R8G8B8A8_UNORM; + info.extent.width = tex->Width; + info.extent.height = tex->Height; + info.extent.depth = 1; + info.mipLevels = 1; + info.arrayLayers = 1; + info.samples = VK_SAMPLE_COUNT_1_BIT; + info.tiling = VK_IMAGE_TILING_OPTIMAL; + info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + err = vkCreateImage(v->Device, &info, v->Allocator, &backend_tex->Image); + check_vk_result(err); + VkMemoryRequirements req; + vkGetImageMemoryRequirements(v->Device, backend_tex->Image, &req); + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); + alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); + err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &backend_tex->Memory); + check_vk_result(err); + err = vkBindImageMemory(v->Device, backend_tex->Image, backend_tex->Memory, 0); + check_vk_result(err); + } - // Create the Descriptor Set: - backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSampler, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + // Create the Image View: + { + VkImageViewCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + info.image = backend_tex->Image; + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + info.format = VK_FORMAT_R8G8B8A8_UNORM; + info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + info.subresourceRange.levelCount = 1; + info.subresourceRange.layerCount = 1; + err = vkCreateImageView(v->Device, &info, v->Allocator, &backend_tex->ImageView); + check_vk_result(err); + } - // Create the Upload Buffer: - VkDeviceMemory upload_buffer_memory; - VkBuffer upload_buffer; - { - VkBufferCreateInfo buffer_info = {}; - buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = upload_size; - buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &upload_buffer); - check_vk_result(err); - VkMemoryRequirements req; - vkGetBufferMemoryRequirements(v->Device, upload_buffer, &req); - bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; - VkMemoryAllocateInfo alloc_info = {}; - alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); - alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); - err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &upload_buffer_memory); - check_vk_result(err); - err = vkBindBufferMemory(v->Device, upload_buffer, upload_buffer_memory, 0); - check_vk_result(err); - } + // Create the Descriptor Set + backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSampler, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - // Upload to Buffer: - { - char* map = nullptr; - err = vkMapMemory(v->Device, upload_buffer_memory, 0, upload_size, 0, (void**)(&map)); - check_vk_result(err); - memcpy(map, pixels, upload_size); - VkMappedMemoryRange range[1] = {}; - range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range[0].memory = upload_buffer_memory; - range[0].size = upload_size; - err = vkFlushMappedMemoryRanges(v->Device, 1, range); - check_vk_result(err); - vkUnmapMemory(v->Device, upload_buffer_memory); + // Store identifiers + tex->SetTexID((ImTextureID)backend_tex->DescriptorSet); + tex->BackendUserData = backend_tex; } - // Copy to Image: + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) { - VkImageMemoryBarrier copy_barrier[1] = {}; - copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - copy_barrier[0].image = backend_tex->Image; - copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copy_barrier[0].subresourceRange.levelCount = 1; - copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.width = width; - region.imageExtent.height = height; - region.imageExtent.depth = 1; - vkCmdCopyBufferToImage(bd->TexCommandBuffer, upload_buffer, backend_tex->Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - VkImageMemoryBarrier use_barrier[1] = {}; - use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - use_barrier[0].image = backend_tex->Image; - use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - use_barrier[0].subresourceRange.levelCount = 1; - use_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); - } - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)backend_tex->DescriptorSet); - - // End command buffer - VkSubmitInfo end_info = {}; - end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - end_info.commandBufferCount = 1; - end_info.pCommandBuffers = &bd->TexCommandBuffer; - err = vkEndCommandBuffer(bd->TexCommandBuffer); - check_vk_result(err); - err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); - check_vk_result(err); + ImGui_ImplVulkan_Texture* backend_tex = (ImGui_ImplVulkan_Texture*)tex->BackendUserData; + + // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions. + // We could use the smaller rect on _WantCreate but using the full rect allows us to clear the texture. + const int upload_x = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.x; + const int upload_y = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.y; + const int upload_w = (tex->Status == ImTextureStatus_WantCreate) ? tex->Width : tex->UpdateRect.w; + const int upload_h = (tex->Status == ImTextureStatus_WantCreate) ? tex->Height : tex->UpdateRect.h; + + // Create the Upload Buffer: + VkDeviceMemory upload_buffer_memory; + + VkBuffer upload_buffer; + VkDeviceSize upload_pitch = upload_w * tex->BytesPerPixel; + VkDeviceSize upload_size = upload_h * upload_pitch; + { + VkBufferCreateInfo buffer_info = {}; + buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buffer_info.size = upload_size; + buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &upload_buffer); + check_vk_result(err); + VkMemoryRequirements req; + vkGetBufferMemoryRequirements(v->Device, upload_buffer, &req); + bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; + VkMemoryAllocateInfo alloc_info = {}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); + alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); + err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &upload_buffer_memory); + check_vk_result(err); + err = vkBindBufferMemory(v->Device, upload_buffer, upload_buffer_memory, 0); + check_vk_result(err); + } - err = vkQueueWaitIdle(v->Queue); - check_vk_result(err); + // Upload to Buffer: + { + char* map = nullptr; + err = vkMapMemory(v->Device, upload_buffer_memory, 0, upload_size, 0, (void**)(&map)); + check_vk_result(err); + for (int y = 0; y < upload_h; y++) + memcpy(map + upload_pitch * y, tex->GetPixelsAt(upload_x, upload_y + y), (size_t)upload_pitch); + VkMappedMemoryRange range[1] = {}; + range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range[0].memory = upload_buffer_memory; + range[0].size = upload_size; + err = vkFlushMappedMemoryRanges(v->Device, 1, range); + check_vk_result(err); + vkUnmapMemory(v->Device, upload_buffer_memory); + } - vkDestroyBuffer(v->Device, upload_buffer, v->Allocator); - vkFreeMemory(v->Device, upload_buffer_memory, v->Allocator); + // Start command buffer + { + err = vkResetCommandPool(v->Device, bd->TexCommandPool, 0); + check_vk_result(err); + VkCommandBufferBeginInfo begin_info = {}; + begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + begin_info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + err = vkBeginCommandBuffer(bd->TexCommandBuffer, &begin_info); + check_vk_result(err); + } - return true; -} + // Copy to Image: + { + VkImageMemoryBarrier copy_barrier[1] = {}; + copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + copy_barrier[0].image = backend_tex->Image; + copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copy_barrier[0].subresourceRange.levelCount = 1; + copy_barrier[0].subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.width = upload_w; + region.imageExtent.height = upload_h; + region.imageExtent.depth = 1; + region.imageOffset.x = upload_x; + region.imageOffset.y = upload_y; + vkCmdCopyBufferToImage(bd->TexCommandBuffer, upload_buffer, backend_tex->Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + VkImageMemoryBarrier use_barrier[1] = {}; + use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + use_barrier[0].image = backend_tex->Image; + use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + use_barrier[0].subresourceRange.levelCount = 1; + use_barrier[0].subresourceRange.layerCount = 1; + vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, use_barrier); + } -// You probably never need to call this, as it is called by ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_Shutdown(). -void ImGui_ImplVulkan_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + // End command buffer + { + VkSubmitInfo end_info = {}; + end_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + end_info.commandBufferCount = 1; + end_info.pCommandBuffers = &bd->TexCommandBuffer; + err = vkEndCommandBuffer(bd->TexCommandBuffer); + check_vk_result(err); + err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); + check_vk_result(err); + } - ImGui_ImplVulkan_Texture* backend_tex = &bd->FontTexture; + err = vkQueueWaitIdle(v->Queue); // FIXME-OPT: Suboptimal! + check_vk_result(err); + vkDestroyBuffer(v->Device, upload_buffer, v->Allocator); + vkFreeMemory(v->Device, upload_buffer_memory, v->Allocator); - if (backend_tex->DescriptorSet) - { - ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); - backend_tex->DescriptorSet = VK_NULL_HANDLE; - io.Fonts->SetTexID(0); + tex->SetStatus(ImTextureStatus_OK); } - if (backend_tex->ImageView) { vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); backend_tex->ImageView = VK_NULL_HANDLE; } - if (backend_tex->Image) { vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); backend_tex->Image = VK_NULL_HANDLE; } - if (backend_tex->Memory) { vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); backend_tex->Memory = VK_NULL_HANDLE; } + + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames >= (int)bd->VulkanInitInfo.ImageCount) + ImGui_ImplVulkan_DestroyTexture(tex); } static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAllocationCallbacks* allocator) @@ -1066,6 +1076,26 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass); + // Create command pool/buffer for texture upload + if (!bd->TexCommandPool) + { + VkCommandPoolCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + info.flags = 0; + info.queueFamilyIndex = v->QueueFamily; + err = vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->TexCommandPool); + check_vk_result(err); + } + if (!bd->TexCommandBuffer) + { + VkCommandBufferAllocateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + info.commandPool = bd->TexCommandPool; + info.commandBufferCount = 1; + err = vkAllocateCommandBuffers(v->Device, &info, &bd->TexCommandBuffer); + check_vk_result(err); + } + return true; } @@ -1074,7 +1104,11 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator); - ImGui_ImplVulkan_DestroyFontsTexture(); + + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplVulkan_DestroyTexture(tex); if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; } if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; } @@ -1175,6 +1209,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_vulkan"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. IM_ASSERT(info->Instance != VK_NULL_HANDLE); IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE); @@ -1219,7 +1254,7 @@ void ImGui_ImplVulkan_Shutdown() io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -1227,9 +1262,7 @@ void ImGui_ImplVulkan_NewFrame() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplVulkan_Init()?"); - - if (!bd->FontTexture.DescriptorSet) - ImGui_ImplVulkan_CreateFontsTexture(); + IM_UNUSED(bd); } void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index c3f40e138ae9..4baa9833501a 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..) // Implemented features: -// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions. +// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification. @@ -61,9 +62,8 @@ #define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #endif -// Current version of the backend use 1 descriptor for the font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). -// It is expected that as early as Q1 2025 the backend will use a few more descriptors. Use this value + number of desired calls to ImGui_ImplVulkan_AddTexture(). -#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (1) // Minimum per atlas +// Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). +#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (8) // Minimum per atlas // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] @@ -112,10 +112,11 @@ IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); -IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontsTexture(); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex); + // Register a texture (VkDescriptorSet == ImTextureID) // FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem // Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions. From 9fa65cd190017e7a5a838a719a1b9fe05664f4a6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 15:52:52 +0100 Subject: [PATCH 438/716] Backends: SDL_Renderer2: added ImGuiBackendFlags_RendererHasTextures support. --- backends/imgui_impl_sdlrenderer2.cpp | 102 ++++++++++++++++----------- backends/imgui_impl_sdlrenderer2.h | 10 +-- 2 files changed, 67 insertions(+), 45 deletions(-) diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index bfaeb9138161..dbdeb5c114c8 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -10,8 +10,9 @@ // and it might be difficult to step out of those boundaries. // Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -23,6 +24,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer2_CreateFontsTexture() and ImGui_ImplSDLRenderer2_DestroyFontsTexture(). // 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. // 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. @@ -54,7 +56,7 @@ struct ImGui_ImplSDLRenderer2_Data { SDL_Renderer* Renderer; // Main viewport's renderer - SDL_Texture* FontTexture; + ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -78,6 +80,7 @@ bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_sdlrenderer2"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. bd->Renderer = renderer; @@ -94,7 +97,7 @@ void ImGui_ImplSDLRenderer2_Shutdown() io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -110,9 +113,7 @@ void ImGui_ImplSDLRenderer2_NewFrame() { ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer2_Init()?"); - - if (!bd->FontTexture) - ImGui_ImplSDLRenderer2_CreateDeviceObjects(); + IM_UNUSED(bd); } void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) @@ -133,6 +134,13 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (fb_width == 0 || fb_height == 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplSDLRenderer2_UpdateTexture(tex); + // Backup SDL_Renderer state that will be modified to restore it afterwards struct BackupSDLRendererState { @@ -218,55 +226,67 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr); } -// Called by Init/NewFrame/Shutdown -bool ImGui_ImplSDLRenderer2_CreateFontsTexture() +void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); - // Build texture atlas - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); - if (bd->FontTexture == nullptr) + if (tex->Status == ImTextureStatus_WantCreate) { - SDL_Log("error creating texture"); - return false; + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // Create texture + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height); + IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!"); + SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch()); + SDL_SetTextureBlendMode(sdl_texture, SDL_BLENDMODE_BLEND); + SDL_SetTextureScaleMode(sdl_texture, SDL_ScaleModeLinear); + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)sdl_texture); + tex->SetStatus(ImTextureStatus_OK); } - SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width); - SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND); - SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear); - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); - - return true; -} - -void ImGui_ImplSDLRenderer2_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); - if (bd->FontTexture) + else if (tex->Status == ImTextureStatus_WantUpdates) { - io.Fonts->SetTexID(0); - SDL_DestroyTexture(bd->FontTexture); - bd->FontTexture = nullptr; + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID; + for (ImTextureRect& r : tex->Updates) + { + SDL_Rect sdl_r = { r.x, r.y, r.w, r.h }; + SDL_UpdateTexture(sdl_texture, &sdl_r, tex->GetPixelsAt(r.x, r.y), tex->GetPitch()); + } + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy) + { + SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID; + if (sdl_texture == nullptr) + return; + SDL_DestroyTexture(sdl_texture); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); } } -bool ImGui_ImplSDLRenderer2_CreateDeviceObjects() +void ImGui_ImplSDLRenderer2_CreateDeviceObjects() { - return ImGui_ImplSDLRenderer2_CreateFontsTexture(); } void ImGui_ImplSDLRenderer2_DestroyDeviceObjects() { - ImGui_ImplSDLRenderer2_DestroyFontsTexture(); + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + { + tex->SetStatus(ImTextureStatus_WantDestroy); + ImGui_ImplSDLRenderer2_UpdateTexture(tex); + } } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index a0337d314753..cf127c1f7917 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -10,8 +10,9 @@ // and it might be difficult to step out of those boundaries. // Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -35,11 +36,12 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer); // Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyFontsTexture(); -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex); + // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer2_RenderDrawData() call. // (Please open an issue if you feel you need access to more data) From e538883a20bd5896f33f1ee2717b171a593347d3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 15:57:32 +0100 Subject: [PATCH 439/716] Backends: SDL_Renderer3: added ImGuiBackendFlags_RendererHasTextures support. --- backends/imgui_impl_sdlrenderer3.cpp | 101 ++++++++++++++++----------- backends/imgui_impl_sdlrenderer3.h | 10 +-- 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 42fefa0cd8f3..ef6f0441c8c0 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -10,8 +10,9 @@ // and it might be difficult to step out of those boundaries. // Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -23,6 +24,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer3_CreateFontsTexture() and ImGui_ImplSDLRenderer3_DestroyFontsTexture(). // 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. // 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer3_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. // 2024-07-01: Update for SDL3 api changes: SDL_RenderGeometryRaw() uint32 version was removed (SDL#9009). @@ -51,7 +53,6 @@ struct ImGui_ImplSDLRenderer3_Data { SDL_Renderer* Renderer; // Main viewport's renderer - SDL_Texture* FontTexture; ImVector ColorBuffer; ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); } @@ -77,6 +78,7 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_sdlrenderer3"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. bd->Renderer = renderer; @@ -93,7 +95,7 @@ void ImGui_ImplSDLRenderer3_Shutdown() io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -109,9 +111,7 @@ void ImGui_ImplSDLRenderer3_NewFrame() { ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer3_Init()?"); - - if (!bd->FontTexture) - ImGui_ImplSDLRenderer3_CreateDeviceObjects(); + IM_UNUSED(bd); } // https://github.com/libsdl-org/SDL/issues/9009 @@ -152,6 +152,13 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* if (fb_width == 0 || fb_height == 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplSDLRenderer3_UpdateTexture(tex); + // Backup SDL_Renderer state that will be modified to restore it afterwards struct BackupSDLRendererState { @@ -235,55 +242,67 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr); } -// Called by Init/NewFrame/Shutdown -bool ImGui_ImplSDLRenderer3_CreateFontsTexture() +void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); - // Build texture atlas - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. - - // Upload texture to graphics system - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); - if (bd->FontTexture == nullptr) + if (tex->Status == ImTextureStatus_WantCreate) { - SDL_Log("error creating texture"); - return false; + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == 0 && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // Create texture + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height); + IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!"); + SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch()); + SDL_SetTextureBlendMode(sdl_texture, SDL_BLENDMODE_BLEND); + SDL_SetTextureScaleMode(sdl_texture, SDL_SCALEMODE_LINEAR); + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)sdl_texture); + tex->SetStatus(ImTextureStatus_OK); } - SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width); - SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND); - SDL_SetTextureScaleMode(bd->FontTexture, SDL_SCALEMODE_LINEAR); - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); - - return true; -} - -void ImGui_ImplSDLRenderer3_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); - if (bd->FontTexture) + else if (tex->Status == ImTextureStatus_WantUpdates) { - io.Fonts->SetTexID(0); - SDL_DestroyTexture(bd->FontTexture); - bd->FontTexture = nullptr; + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID; + for (ImTextureRect& r : tex->Updates) + { + SDL_Rect sdl_r = { r.x, r.y, r.w, r.h }; + SDL_UpdateTexture(sdl_texture, &sdl_r, tex->GetPixelsAt(r.x, r.y), tex->GetPitch()); + } + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy) + { + SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID; + if (sdl_texture == nullptr) + return; + SDL_DestroyTexture(sdl_texture); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); } } -bool ImGui_ImplSDLRenderer3_CreateDeviceObjects() +void ImGui_ImplSDLRenderer3_CreateDeviceObjects() { - return ImGui_ImplSDLRenderer3_CreateFontsTexture(); } void ImGui_ImplSDLRenderer3_DestroyDeviceObjects() { - ImGui_ImplSDLRenderer3_DestroyFontsTexture(); + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + { + tex->SetStatus(ImTextureStatus_WantDestroy); + ImGui_ImplSDLRenderer3_UpdateTexture(tex); + } } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 3473bcc77e00..170560fdc038 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -10,8 +10,9 @@ // and it might be difficult to step out of those boundaries. // Implemented features: -// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -35,11 +36,12 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_NewFrame(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer); // Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyFontsTexture(); -IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateDeviceObjects(); +IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex); + // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer3_RenderDrawData() call. // (Please open an issue if you feel you need access to more data) From 16fe666e364785c0a9b534ea18aa5fa62ab06a36 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 12:32:56 +0100 Subject: [PATCH 440/716] Backends: SDLGPU3: added ImGuiBackendFlags_RendererHasTextures support. # Conflicts: # backends/imgui_impl_sdlgpu3.cpp # backends/imgui_impl_sdlgpu3.h --- backends/imgui_impl_sdlgpu3.cpp | 205 +++++++++++++++++++------------- backends/imgui_impl_sdlgpu3.h | 9 +- 2 files changed, 129 insertions(+), 85 deletions(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 4bcc5bdfc4c0..92515602b108 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -3,7 +3,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -21,6 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture(). // 2025-04-28: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2025-03-30: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. // 2025-03-21: Fixed typo in function name Imgui_ImplSDLGPU3_PrepareDrawData() -> ImGui_ImplSDLGPU3_PrepareDrawData(). @@ -33,6 +35,11 @@ #include "imgui_impl_sdlgpu3_shaders.h" // SDL_GPU Data +struct ImGui_ImplSDLGPU3_Texture +{ + SDL_GPUTexture* Texture = nullptr; + SDL_GPUTextureSamplerBinding TextureSamplerBinding = { nullptr, nullptr }; +}; // Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplSDLGPU3_RenderDrawData() struct ImGui_ImplSDLGPU3_FrameData @@ -50,14 +57,12 @@ struct ImGui_ImplSDLGPU3_Data ImGui_ImplSDLGPU3_InitInfo InitInfo; // Graphics pipeline & shaders - SDL_GPUShader* VertexShader = nullptr; - SDL_GPUShader* FragmentShader = nullptr; - SDL_GPUGraphicsPipeline* Pipeline = nullptr; - - // Font data - SDL_GPUSampler* FontSampler = nullptr; - SDL_GPUTexture* FontTexture = nullptr; - SDL_GPUTextureSamplerBinding FontBinding = { nullptr, nullptr }; + SDL_GPUShader* VertexShader = nullptr; + SDL_GPUShader* FragmentShader = nullptr; + SDL_GPUGraphicsPipeline* Pipeline = nullptr; + SDL_GPUSampler* TexSampler = nullptr; + SDL_GPUTransferBuffer* TexTransferBuffer = nullptr; + uint32_t TexTransferBufferSize = 0; // Frame data for main window ImGui_ImplSDLGPU3_FrameData MainWindowFrameData; @@ -154,6 +159,13 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplSDLGPU3_UpdateTexture(tex); + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData; @@ -281,91 +293,117 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe SDL_SetGPUScissor(render_pass, &scissor_rect); } -void ImGui_ImplSDLGPU3_CreateFontsTexture() +static void ImGui_ImplSDLGPU3_DestroyTexture(ImTextureData* tex) +{ + ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); + ImGui_ImplSDLGPU3_Texture* backend_tex = (ImGui_ImplSDLGPU3_Texture*)tex->BackendUserData; + if (backend_tex == nullptr) + return; + SDL_GPUTextureSamplerBinding* binding = (SDL_GPUTextureSamplerBinding*)(intptr_t)tex->BackendUserData; + IM_ASSERT(backend_tex->Texture == binding->texture); + SDL_ReleaseGPUTexture(bd->InitInfo.Device, backend_tex->Texture); + IM_DELETE(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; +} + +void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - // Destroy existing texture (if any) - if (bd->FontTexture) + if (tex->Status == ImTextureStatus_WantCreate) { - SDL_WaitForGPUIdle(v->Device); - ImGui_ImplSDLGPU3_DestroyFontsTexture(); - } - - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - uint32_t upload_size = width * height * 4 * sizeof(char); + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + ImGui_ImplSDLGPU3_Texture* backend_tex = IM_NEW(ImGui_ImplSDLGPU3_Texture)(); - // Create the Image: - { + // Create texture SDL_GPUTextureCreateInfo texture_info = {}; - texture_info.type = SDL_GPU_TEXTURETYPE_2D; + texture_info.type = SDL_GPU_TEXTURETYPE_2D; texture_info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; texture_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; - texture_info.width = width; - texture_info.height = height; + texture_info.width = tex->Width; + texture_info.height = tex->Height; texture_info.layer_count_or_depth = 1; texture_info.num_levels = 1; texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1; - bd->FontTexture = SDL_CreateGPUTexture(v->Device, &texture_info); - IM_ASSERT(bd->FontTexture && "Failed to create font texture, call SDL_GetError() for more info"); - } + backend_tex->Texture = SDL_CreateGPUTexture(v->Device, &texture_info); + backend_tex->TextureSamplerBinding.texture = backend_tex->Texture; + backend_tex->TextureSamplerBinding.sampler = bd->TexSampler; + IM_ASSERT(backend_tex->Texture && "Failed to create font texture, call SDL_GetError() for more info"); - // Assign the texture to the TextureSamplerBinding - bd->FontBinding.texture = bd->FontTexture; + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)&backend_tex->TextureSamplerBinding); + tex->BackendUserData = backend_tex; + } - // Create all the upload structures and upload: + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) { - SDL_GPUTransferBufferCreateInfo transferbuffer_info = {}; - transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - transferbuffer_info.size = upload_size; - - SDL_GPUTransferBuffer* transferbuffer = SDL_CreateGPUTransferBuffer(v->Device, &transferbuffer_info); - IM_ASSERT(transferbuffer != nullptr && "Failed to create font transfer buffer, call SDL_GetError() for more information"); + ImGui_ImplSDLGPU3_Texture* backend_tex = (ImGui_ImplSDLGPU3_Texture*)tex->BackendUserData; + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions. + // We could use the smaller rect on _WantCreate but using the full rect allows us to clear the texture. + const int upload_x = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.x; + const int upload_y = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.y; + const int upload_w = (tex->Status == ImTextureStatus_WantCreate) ? tex->Width : tex->UpdateRect.w; + const int upload_h = (tex->Status == ImTextureStatus_WantCreate) ? tex->Height : tex->UpdateRect.h; + uint32_t upload_pitch = upload_w * tex->BytesPerPixel; + uint32_t upload_size = upload_w * upload_h * tex->BytesPerPixel; + + // Create transfer buffer + if (bd->TexTransferBufferSize < upload_size) + { + SDL_ReleaseGPUTransferBuffer(v->Device, bd->TexTransferBuffer); + SDL_GPUTransferBufferCreateInfo transferbuffer_info = {}; + transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + transferbuffer_info.size = upload_size + 1024; + bd->TexTransferBufferSize = upload_size + 1024; + bd->TexTransferBuffer = SDL_CreateGPUTransferBuffer(v->Device, &transferbuffer_info); + IM_ASSERT(bd->TexTransferBuffer != nullptr && "Failed to create font transfer buffer, call SDL_GetError() for more information"); + } - void* texture_ptr = SDL_MapGPUTransferBuffer(v->Device, transferbuffer, false); - memcpy(texture_ptr, pixels, upload_size); - SDL_UnmapGPUTransferBuffer(v->Device, transferbuffer); + // Copy to transfer buffer + { + void* texture_ptr = SDL_MapGPUTransferBuffer(v->Device, bd->TexTransferBuffer, false); + for (int y = 0; y < upload_h; y++) + memcpy((void*)((uintptr_t)texture_ptr + y * upload_pitch), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch); + SDL_UnmapGPUTransferBuffer(v->Device, bd->TexTransferBuffer); + } SDL_GPUTextureTransferInfo transfer_info = {}; transfer_info.offset = 0; - transfer_info.transfer_buffer = transferbuffer; + transfer_info.transfer_buffer = bd->TexTransferBuffer; SDL_GPUTextureRegion texture_region = {}; - texture_region.texture = bd->FontTexture; - texture_region.w = width; - texture_region.h = height; + texture_region.texture = backend_tex->Texture; + texture_region.x = (Uint32)upload_x; + texture_region.y = (Uint32)upload_y; + texture_region.w = (Uint32)upload_w; + texture_region.h = (Uint32)upload_h; texture_region.d = 1; - SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(v->Device); - SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); - SDL_UploadToGPUTexture(copy_pass, &transfer_info, &texture_region, false); - SDL_EndGPUCopyPass(copy_pass); - SDL_SubmitGPUCommandBuffer(cmd); - SDL_ReleaseGPUTransferBuffer(v->Device, transferbuffer); - } - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)&bd->FontBinding); -} + // Upload + { + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(v->Device); + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUTexture(copy_pass, &transfer_info, &texture_region, false); + SDL_EndGPUCopyPass(copy_pass); + SDL_SubmitGPUCommandBuffer(cmd); + } -// You probably never need to call this, as it is called by ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_Shutdown(). -void ImGui_ImplSDLGPU3_DestroyFontsTexture() -{ - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - if (bd->FontTexture) - { - SDL_ReleaseGPUTexture(v->Device, bd->FontTexture); - bd->FontBinding.texture = nullptr; - bd->FontTexture = nullptr; + tex->SetStatus(ImTextureStatus_OK); } - io.Fonts->SetTexID(0); + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + ImGui_ImplSDLGPU3_DestroyTexture(tex); } static void ImGui_ImplSDLGPU3_CreateShaders() @@ -517,7 +555,9 @@ void ImGui_ImplSDLGPU3_CreateDeviceObjects() ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; - if (!bd->FontSampler) + ImGui_ImplSDLGPU3_DestroyDeviceObjects(); + + if (bd->TexSampler == nullptr) { // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling. SDL_GPUSamplerCreateInfo sampler_info = {}; @@ -534,13 +574,11 @@ void ImGui_ImplSDLGPU3_CreateDeviceObjects() sampler_info.max_anisotropy = 1.0f; sampler_info.enable_compare = false; - bd->FontSampler = SDL_CreateGPUSampler(v->Device, &sampler_info); - bd->FontBinding.sampler = bd->FontSampler; - IM_ASSERT(bd->FontSampler != nullptr && "Failed to create font sampler, call SDL_GetError() for more information"); + bd->TexSampler = SDL_CreateGPUSampler(v->Device, &sampler_info); + IM_ASSERT(bd->TexSampler != nullptr && "Failed to create font sampler, call SDL_GetError() for more information"); } ImGui_ImplSDLGPU3_CreateGraphicsPipeline(); - ImGui_ImplSDLGPU3_CreateFontsTexture(); } void ImGui_ImplSDLGPU3_DestroyFrameData() @@ -564,12 +602,16 @@ void ImGui_ImplSDLGPU3_DestroyDeviceObjects() ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo; ImGui_ImplSDLGPU3_DestroyFrameData(); - ImGui_ImplSDLGPU3_DestroyFontsTexture(); - if (bd->VertexShader) { SDL_ReleaseGPUShader(v->Device, bd->VertexShader); bd->VertexShader = nullptr;} - if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->Device, bd->FragmentShader); bd->FragmentShader = nullptr;} - if (bd->FontSampler) { SDL_ReleaseGPUSampler(v->Device, bd->FontSampler); bd->FontSampler = nullptr;} - if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr;} + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplSDLGPU3_DestroyTexture(tex); + if (bd->TexTransferBuffer) { SDL_ReleaseGPUTransferBuffer(v->Device, bd->TexTransferBuffer); bd->TexTransferBuffer = nullptr; } + if (bd->VertexShader) { SDL_ReleaseGPUShader(v->Device, bd->VertexShader); bd->VertexShader = nullptr; } + if (bd->FragmentShader) { SDL_ReleaseGPUShader(v->Device, bd->FragmentShader); bd->FragmentShader = nullptr; } + if (bd->TexSampler) { SDL_ReleaseGPUSampler(v->Device, bd->TexSampler); bd->TexSampler = nullptr; } + if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr; } } bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) @@ -583,6 +625,7 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_sdlgpu3"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. IM_ASSERT(info->Device != nullptr); IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID); @@ -601,7 +644,7 @@ void ImGui_ImplSDLGPU3_Shutdown() ImGui_ImplSDLGPU3_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -610,10 +653,8 @@ void ImGui_ImplSDLGPU3_NewFrame() ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLGPU3_Init()?"); - if (!bd->FontSampler) + if (!bd->TexSampler) ImGui_ImplSDLGPU3_CreateDeviceObjects(); - if (!bd->FontTexture) - ImGui_ImplSDLGPU3_CreateFontsTexture(); } #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index c6d5a8e5d0f3..380855b297fc 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -3,7 +3,8 @@ // Implemented features: // [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. -// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. +// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ @@ -41,9 +42,11 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_NewFrame(); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline = nullptr); +// Use if you want to reset your rendering device without losing Dear ImGui state. IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyDeviceObjects(); -IMGUI_IMPL_API void ImGui_ImplSDLGPU3_CreateFontsTexture(); -IMGUI_IMPL_API void ImGui_ImplSDLGPU3_DestroyFontsTexture(); + +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex); #endif // #ifndef IMGUI_DISABLE From ee8941e0de53fb745e7508e71ec5a00ddf2ec3de Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 10:38:11 +0100 Subject: [PATCH 441/716] Backends: Allegro5: added ImGuiBackendFlags_RendererHasTextures support. --- backends/imgui_impl_allegro5.cpp | 135 +++++++++++++++++++------------ backends/imgui_impl_allegro5.h | 6 +- 2 files changed, 90 insertions(+), 51 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 9db3e51981b4..b5f8ca00a718 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -2,7 +2,8 @@ // (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.) // Implemented features: -// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Clipboard support (from Allegro 5.1.12). // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. @@ -20,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture(). // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: @@ -137,6 +139,13 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplAllegro5_UpdateTexture(tex); + // Backup Allegro state that will be modified ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); ALLEGRO_TRANSFORM last_transform = *al_get_current_transform(); @@ -232,43 +241,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) bool ImGui_ImplAllegro5_CreateDeviceObjects() { - // Build texture atlas ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - - // Create texture - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - int flags = al_get_new_bitmap_flags(); - int fmt = al_get_new_bitmap_format(); - al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); - al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE); - ALLEGRO_BITMAP* img = al_create_bitmap(width, height); - al_set_new_bitmap_flags(flags); - al_set_new_bitmap_format(fmt); - if (!img) - return false; - - ALLEGRO_LOCKED_REGION* locked_img = al_lock_bitmap(img, al_get_bitmap_format(img), ALLEGRO_LOCK_WRITEONLY); - if (!locked_img) - { - al_destroy_bitmap(img); - return false; - } - memcpy(locked_img->data, pixels, sizeof(int) * width * height); - al_unlock_bitmap(img); - - // Convert software texture to hardware texture. - ALLEGRO_BITMAP* cloned_img = al_clone_bitmap(img); - al_destroy_bitmap(img); - if (!cloned_img) - return false; - - // Store our identifier - io.Fonts->SetTexID((ImTextureID)(intptr_t)cloned_img); - bd->Texture = cloned_img; // Create an invisible mouse cursor // Because al_hide_mouse_cursor() seems to mess up with the actual inputs.. @@ -279,16 +252,81 @@ bool ImGui_ImplAllegro5_CreateDeviceObjects() return true; } -void ImGui_ImplAllegro5_InvalidateDeviceObjects() +void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex) { - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); - if (bd->Texture) + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // Create texture + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + const int new_bitmap_flags = al_get_new_bitmap_flags(); + int new_bitmap_format = al_get_new_bitmap_format(); + al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); + al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE); + ALLEGRO_BITMAP* cpu_bitmap = al_create_bitmap(tex->Width, tex->Height); + al_set_new_bitmap_flags(new_bitmap_flags); + al_set_new_bitmap_format(new_bitmap_format); + IM_ASSERT(cpu_bitmap != nullptr && "Backend failed to create texture!"); + + // Upload pixels + ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap(cpu_bitmap, al_get_bitmap_format(cpu_bitmap), ALLEGRO_LOCK_WRITEONLY); + IM_ASSERT(locked_region != nullptr && "Backend failed to create texture!"); + memcpy(locked_region->data, tex->GetPixels(), tex->GetSizeInBytes()); + al_unlock_bitmap(cpu_bitmap); + + // Convert software texture to hardware texture. + ALLEGRO_BITMAP* gpu_bitmap = al_clone_bitmap(cpu_bitmap); + al_destroy_bitmap(cpu_bitmap); + IM_ASSERT(gpu_bitmap != nullptr && "Backend failed to create texture!"); + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)gpu_bitmap); + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantUpdates) { - io.Fonts->SetTexID(0); - al_destroy_bitmap(bd->Texture); - bd->Texture = nullptr; + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + ImTextureRect r_bb = tex->UpdateRect; // Bounding box encompassing all individual updates + ALLEGRO_BITMAP* gpu_bitmap = (ALLEGRO_BITMAP*)(intptr_t)tex->TexID; + ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap_region(gpu_bitmap, r_bb.x, r_bb.y, r_bb.w, r_bb.h, al_get_bitmap_format(gpu_bitmap), ALLEGRO_LOCK_WRITEONLY); + IM_ASSERT(locked_region && "Backend failed to update texture!"); + for (ImTextureRect& r : tex->Updates) + for (int y = 0; y < r.h; y++) + memcpy((unsigned char*)locked_region->data + locked_region->pitch * (r.y - r_bb.y + y) + (r.x - r_bb.x) * tex->BytesPerPixel, // dst + tex->GetPixelsAt(r.x, r.y + y), r.w * tex->BytesPerPixel); // src, block pitch + al_unlock_bitmap(gpu_bitmap); + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy) + { + ALLEGRO_BITMAP* backend_tex = (ALLEGRO_BITMAP*)(intptr_t)tex->TexID; + if (backend_tex) + al_destroy_bitmap(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); } +} + +void ImGui_ImplAllegro5_InvalidateDeviceObjects() +{ + ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); + + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + { + tex->SetStatus(ImTextureStatus_WantDestroy); + ImGui_ImplAllegro5_UpdateTexture(tex); + } + + // Destroy mouse cursor if (bd->MouseCursorInvisible) { al_destroy_mouse_cursor(bd->MouseCursorInvisible); @@ -439,6 +477,7 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display) io.BackendPlatformUserData = (void*)bd; io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5"; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. bd->Display = display; bd->LastCursor = ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE; @@ -478,7 +517,7 @@ void ImGui_ImplAllegro5_Shutdown() io.BackendPlatformName = io.BackendRendererName = nullptr; io.BackendPlatformUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_HasMouseCursors; + io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } @@ -608,12 +647,8 @@ void ImGui_ImplAllegro5_NewFrame() ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplAllegro5_Init()?"); - if (!bd->Texture) - ImGui_ImplAllegro5_CreateDeviceObjects(); - - ImGuiIO& io = ImGui::GetIO(); - // Setup display size (every frame to accommodate for window resizing) + ImGuiIO& io = ImGui::GetIO(); int w, h; w = al_get_display_width(bd->Display); h = al_get_display_height(bd->Display); diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 356ec7d0a9f4..421bbf1294af 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -2,7 +2,8 @@ // (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.) // Implemented features: -// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Clipboard support (from Allegro 5.1.12). // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. @@ -36,4 +37,7 @@ IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event); IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex); + #endif // #ifndef IMGUI_DISABLE From 26c017d5ea73a7b52271c26438c9dd15b2b46c81 Mon Sep 17 00:00:00 2001 From: thedmd Date: Tue, 17 Dec 2024 00:42:57 +0100 Subject: [PATCH 442/716] Backends: Metal: added ImGuiBackendFlags_RendererHasTextures support. # Conflicts: # backends/imgui_impl_metal.h # backends/imgui_impl_metal.mm --- backends/imgui_impl_metal.h | 13 ++- backends/imgui_impl_metal.mm | 173 +++++++++++++++++++++++------------ 2 files changed, 122 insertions(+), 64 deletions(-) diff --git a/backends/imgui_impl_metal.h b/backends/imgui_impl_metal.h index d46998269cea..2a9a26a02756 100644 --- a/backends/imgui_impl_metal.h +++ b/backends/imgui_impl_metal.h @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. OSX) // Implemented features: -// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -35,11 +36,12 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id commandEncoder); // Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id device); -IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); + #endif //----------------------------------------------------------------------------- @@ -62,11 +64,12 @@ IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, MTL::RenderCommandEncoder* commandEncoder); // Called by Init/NewFrame/Shutdown -IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device); -IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture(); IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device); IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex); + #endif #endif diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 1cd2308d144d..b1decb2bbb46 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -2,8 +2,9 @@ // This needs to be used along with a Platform Backend (e.g. OSX) // Implemented features: -// [X] Renderer: User texture binding. Use 'MTLTexture' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -15,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture(). // 2025-02-03: Metal: Crash fix. (#8367) // 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). // 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. @@ -59,6 +61,11 @@ @interface FramebufferDescriptor : NSObject - (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor; @end +@interface MetalTexture : NSObject +@property (nonatomic, strong) id metalTexture; +- (instancetype)initWithTexture:(id)metalTexture; +@end + // A singleton that stores long-lived objects that are needed by the Metal // renderer backend. Stores the render pipeline state cache and the default // font texture, and manages the reusable buffer cache. @@ -67,7 +74,6 @@ @interface MetalContext : NSObject @property (nonatomic, strong) id depthStencilState; @property (nonatomic, strong) FramebufferDescriptor* framebufferDescriptor; // framebuffer descriptor for current frame; transient @property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors -@property (nonatomic, strong, nullable) id fontTexture; @property (nonatomic, strong) NSMutableArray* bufferCache; @property (nonatomic, assign) double lastBufferCachePurge; - (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device; @@ -110,11 +116,6 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, } -bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device) -{ - return ImGui_ImplMetal_CreateFontsTexture((__bridge id)(device)); -} - bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device) { return ImGui_ImplMetal_CreateDeviceObjects((__bridge id)(device)); @@ -134,6 +135,7 @@ bool ImGui_ImplMetal_Init(id device) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_metal"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. bd->SharedMetalContext = [[MetalContext alloc] init]; bd->SharedMetalContext.device = device; @@ -152,7 +154,7 @@ void ImGui_ImplMetal_Shutdown() ImGuiIO& io = ImGui::GetIO(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); } void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) @@ -168,7 +170,7 @@ void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device); } -static void ImGui_ImplMetal_SetupRenderState(ImDrawData* drawData, id commandBuffer, +static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id commandBuffer, id commandEncoder, id renderPipelineState, MetalBuffer* vertexBuffer, size_t vertexBufferOffset) { @@ -184,17 +186,17 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* drawData, idDisplaySize.x * drawData->FramebufferScale.x), - .height = (double)(drawData->DisplaySize.y * drawData->FramebufferScale.y), + .width = (double)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x), + .height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y), .znear = 0.0, .zfar = 1.0 }; [commandEncoder setViewport:viewport]; - float L = drawData->DisplayPos.x; - float R = drawData->DisplayPos.x + drawData->DisplaySize.x; - float T = drawData->DisplayPos.y; - float B = drawData->DisplayPos.y + drawData->DisplaySize.y; + float L = draw_data->DisplayPos.x; + float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; + float T = draw_data->DisplayPos.y; + float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; float N = (float)viewport.znear; float F = (float)viewport.zfar; const float ortho_projection[4][4] = @@ -213,17 +215,24 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* drawData, id commandBuffer, id commandEncoder) +void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id commandBuffer, id commandEncoder) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); MetalContext* ctx = bd->SharedMetalContext; // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) - int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x); - int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0 || drawData->CmdListsCount == 0) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplMetal_UpdateTexture(tex); + // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame // The hit rate for this cache should be very near 100%. id renderPipelineState = ctx.renderPipelineStateCache[ctx.framebufferDescriptor]; @@ -236,23 +245,23 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState; } - size_t vertexBufferLength = (size_t)drawData->TotalVtxCount * sizeof(ImDrawVert); - size_t indexBufferLength = (size_t)drawData->TotalIdxCount * sizeof(ImDrawIdx); + size_t vertexBufferLength = (size_t)draw_data->TotalVtxCount * sizeof(ImDrawVert); + size_t indexBufferLength = (size_t)draw_data->TotalIdxCount * sizeof(ImDrawIdx); MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device]; MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device]; - ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0); + ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0); // Will project scissor/clipping rectangles into framebuffer space - ImVec2 clip_off = drawData->DisplayPos; // (0,0) unless using multi-viewports - ImVec2 clip_scale = drawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists size_t vertexBufferOffset = 0; size_t indexBufferOffset = 0; - for (int n = 0; n < drawData->CmdListsCount; n++) + for (int n = 0; n < draw_data->CmdListsCount; n++) { - const ImDrawList* draw_list = drawData->CmdLists[n]; + const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); @@ -265,7 +274,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - ImGui_ImplMetal_SetupRenderState(drawData, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset); + ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset); else pcmd->UserCallback(draw_list, pcmd); } @@ -325,42 +334,71 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData, id c }]; } -bool ImGui_ImplMetal_CreateFontsTexture(id device) +static void ImGui_ImplMetal_DestroyTexture(ImTextureData* tex) { - ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - - // We are retrieving and uploading the font atlas as a 4-channels RGBA texture here. - // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth. - // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures. - // You can make that change in your implementation. - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm - width:(NSUInteger)width - height:(NSUInteger)height - mipmapped:NO]; - textureDescriptor.usage = MTLTextureUsageShaderRead; -#if TARGET_OS_OSX || TARGET_OS_MACCATALYST - textureDescriptor.storageMode = MTLStorageModeManaged; -#else - textureDescriptor.storageMode = MTLStorageModeShared; -#endif - id texture = [device newTextureWithDescriptor:textureDescriptor]; - [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)width, (NSUInteger)height) mipmapLevel:0 withBytes:pixels bytesPerRow:(NSUInteger)width * 4]; - bd->SharedMetalContext.fontTexture = texture; - io.Fonts->SetTexID((ImTextureID)(intptr_t)(__bridge void*)bd->SharedMetalContext.fontTexture); // ImTextureID == ImU64 + MetalTexture* backend_tex = (__bridge_transfer MetalTexture*)(tex->BackendUserData); + if (backend_tex == nullptr) + return; + IM_ASSERT(backend_tex.metalTexture == (__bridge id)(void*)(intptr_t)tex->TexID); + backend_tex.metalTexture = nil; - return (bd->SharedMetalContext.fontTexture != nil); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; } -void ImGui_ImplMetal_DestroyFontsTexture() +void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - bd->SharedMetalContext.fontTexture = nil; - io.Fonts->SetTexID(0); + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // We are retrieving and uploading the font atlas as a 4-channels RGBA texture here. + // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth. + // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures. + // You can make that change in your implementation. + MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm + width:(NSUInteger)tex->Width + height:(NSUInteger)tex->Height + mipmapped:NO]; + textureDescriptor.usage = MTLTextureUsageShaderRead; + #if TARGET_OS_OSX || TARGET_OS_MACCATALYST + textureDescriptor.storageMode = MTLStorageModeManaged; + #else + textureDescriptor.storageMode = MTLStorageModeShared; + #endif + id texture = [bd->SharedMetalContext.device newTextureWithDescriptor:textureDescriptor]; + [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)tex->Width, (NSUInteger)tex->Height) mipmapLevel:0 withBytes:tex->Pixels bytesPerRow:(NSUInteger)tex->Width * 4]; + MetalTexture* backend_tex = [[MetalTexture alloc] initWithTexture:texture]; + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)texture); + tex->SetStatus(ImTextureStatus_OK); + tex->BackendUserData = (__bridge_retained void*)(backend_tex); + } + else if (tex->Status == ImTextureStatus_WantUpdates) + { + // Update selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. + MetalTexture* backend_tex = (__bridge MetalTexture*)(tex->BackendUserData); + for (ImTextureRect& r : tex->Updates) + { + [backend_tex.metalTexture replaceRegion:MTLRegionMake2D((NSUInteger)r.x, (NSUInteger)r.y, (NSUInteger)r.w, (NSUInteger)r.h) + mipmapLevel:0 + withBytes:tex->GetPixelsAt(r.x, r.y) + bytesPerRow:(NSUInteger)tex->Width * 4]; + } + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + { + ImGui_ImplMetal_DestroyTexture(tex); + } } bool ImGui_ImplMetal_CreateDeviceObjects(id device) @@ -373,14 +411,19 @@ bool ImGui_ImplMetal_CreateDeviceObjects(id device) #ifdef IMGUI_IMPL_METAL_CPP [depthStencilDescriptor release]; #endif - ImGui_ImplMetal_CreateFontsTexture(device); + return true; } void ImGui_ImplMetal_DestroyDeviceObjects() { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); - ImGui_ImplMetal_DestroyFontsTexture(); + + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplMetal_DestroyTexture(tex); + [bd->SharedMetalContext.renderPipelineStateCache removeAllObjects]; } @@ -446,6 +489,18 @@ - (BOOL)isEqual:(id)object @end +#pragma mark - MetalTexture implementation + +@implementation MetalTexture +- (instancetype)initWithTexture:(id)metalTexture +{ + if ((self = [super init])) + self.metalTexture = metalTexture; + return self; +} + +@end + #pragma mark - MetalContext implementation @implementation MetalContext From 08e1e7681e79da420ae6a433c99f1a890817c031 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 Nov 2024 15:26:52 +0100 Subject: [PATCH 443/716] imgui_freetype: Added Freetype implementation for new architecture. --- misc/freetype/imgui_freetype.cpp | 291 ++++++++++++++++++++++++------- misc/freetype/imgui_freetype.h | 8 +- 2 files changed, 228 insertions(+), 71 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 1a268365b912..1125364bfa51 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -2,10 +2,12 @@ // (code) // Get the latest version at https://github.com/ocornut/imgui/tree/master/misc/freetype -// Original code by @vuhdo (Aleksei Skriabin). Improvements by @mikesart. Maintained since 2019 by @ocornut. +// Original code by @vuhdo (Aleksei Skriabin) in 2017, with improvements by @mikesart. +// Maintained since 2019 by @ocornut. // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025/XX/XX: refactored for the new ImFontLoader architecture, and ImGuiBackendFlags_RendererHasTextures support. // 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. // 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG'. (#6591) @@ -151,10 +153,19 @@ namespace bool IsColored; // The glyph is colored }; + // Stored in ImFontAtlas::FontLoaderData + struct ImGui_ImplFreeType_Data + { + FT_Library Library; + FT_MemoryRec_ MemoryManager; + + ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } + }; + // Font parameters and metrics. - struct FontInfo + struct ImGui_ImplFreeType_FontInfo { - uint32_t PixelHeight; // Size this font was generated with. + float PixelHeight; // Size this font was generated with. float Ascender; // The pixel extents above the baseline in pixels (typically positive). float Descender; // The extents below the baseline in pixels (typically negative). float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. @@ -162,40 +173,39 @@ namespace float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font. }; - // FreeType glyph rasterizer. - // NB: No ctor/dtor, explicitly call Init()/Shutdown() - struct FreeTypeFont + // Stored in ImFontConfig::FontLoaderData + struct ImGui_ImplFreeType_FontSrcData { - bool InitFont(FT_Library ft_library, ImFontConfig& src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. - void CloseFont(); - void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size - const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); - const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); - void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr); - FreeTypeFont() { memset((void*)this, 0, sizeof(*this)); } - ~FreeTypeFont() { CloseFont(); } - - // [Internals] - FontInfo Info; // Font descriptor of the current font. - FT_Face Face; - unsigned int UserFlags; // = ImFontConfig::RasterizerFlags - FT_Int32 LoadFlags; - FT_Render_Mode RenderMode; - float RasterizationDensity; - float InvRasterizationDensity; + bool InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + void CloseFont(); + void SetPixelHeight(float pixel_height); // Change font pixel size. + const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); + const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); + void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr); + ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); } + ~ImGui_ImplFreeType_FontSrcData() { CloseFont(); } + + // Members + ImGui_ImplFreeType_FontInfo Info; // Font descriptor of the current font. + FT_Face FtFace; + unsigned int UserFlags; // = ImFontConfig::RasterizerFlags + FT_Int32 LoadFlags; + FT_Render_Mode RenderMode; + float RasterizationDensity; + float InvRasterizationDensity; }; - bool FreeTypeFont::InitFont(FT_Library ft_library, ImFontConfig& src, unsigned int extra_font_builder_flags) + bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_font_builder_flags) { - FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src.FontData, (uint32_t)src.FontDataSize, (uint32_t)src.FontNo, &Face); + FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (uint32_t)src->FontDataSize, (uint32_t)src->FontNo, &FtFace); if (error != 0) return false; - error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE); + error = FT_Select_Charmap(FtFace, FT_ENCODING_UNICODE); if (error != 0) return false; // Convert to FreeType flags (NB: Bold and Oblique are processed separately) - UserFlags = src.FontBuilderFlags | extra_font_builder_flags; + UserFlags = src->FontBuilderFlags | extra_font_builder_flags; LoadFlags = 0; if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) @@ -222,40 +232,42 @@ namespace if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) LoadFlags |= FT_LOAD_COLOR; - RasterizationDensity = src.RasterizerDensity; + RasterizationDensity = src->RasterizerDensity; InvRasterizationDensity = 1.0f / RasterizationDensity; memset(&Info, 0, sizeof(Info)); - SetPixelHeight((uint32_t)src.SizePixels); + SetPixelHeight(src->SizePixels); return true; } - void FreeTypeFont::CloseFont() + void ImGui_ImplFreeType_FontSrcData::CloseFont() { - if (Face) + if (FtFace) { - FT_Done_Face(Face); - Face = nullptr; + FT_Done_Face(FtFace); + FtFace = nullptr; } } - void FreeTypeFont::SetPixelHeight(int pixel_height) + void ImGui_ImplFreeType_FontSrcData::SetPixelHeight(float pixel_height) { - // Vuhdo: I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' + // Vuhdo (2017): "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. - // NB: FT_Set_Pixel_Sizes() doesn't seem to get us the same result. + // FT_Set_Pixel_Sizes() doesn't seem to get us the same result." + // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) FT_Size_RequestRec req; req.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; req.height = (uint32_t)(pixel_height * 64 * RasterizationDensity); req.horiResolution = 0; req.vertResolution = 0; - FT_Request_Size(Face, &req); + FT_Request_Size(FtFace, &req); + // Note: To handle multiple sizes later, we may need to use FT_New_Size(), FT_Activate_Size() // Update font info - FT_Size_Metrics metrics = Face->size->metrics; - Info.PixelHeight = (uint32_t)(pixel_height * InvRasterizationDensity); + FT_Size_Metrics metrics = FtFace->size->metrics; + Info.PixelHeight = pixel_height * InvRasterizationDensity; Info.Ascender = (float)FT_CEIL(metrics.ascender) * InvRasterizationDensity; Info.Descender = (float)FT_CEIL(metrics.descender) * InvRasterizationDensity; Info.LineSpacing = (float)FT_CEIL(metrics.height) * InvRasterizationDensity; @@ -263,9 +275,9 @@ namespace Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * InvRasterizationDensity; } - const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint) + const FT_Glyph_Metrics* ImGui_ImplFreeType_FontSrcData::LoadGlyph(uint32_t codepoint) { - uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint); + uint32_t glyph_index = FT_Get_Char_Index(FtFace, codepoint); if (glyph_index == 0) return nullptr; @@ -274,12 +286,12 @@ namespace // - https://github.com/ocornut/imgui/issues/4567 // - https://github.com/ocornut/imgui/issues/4566 // You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version. - FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags); + FT_Error error = FT_Load_Glyph(FtFace, glyph_index, LoadFlags); if (error) return nullptr; // Need an outline for this to work - FT_GlyphSlot slot = Face->glyph; + FT_GlyphSlot slot = FtFace->glyph; #if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG) IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); #else @@ -304,25 +316,25 @@ namespace return &slot->metrics; } - const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) + const FT_Bitmap* ImGui_ImplFreeType_FontSrcData::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) { - FT_GlyphSlot slot = Face->glyph; + FT_GlyphSlot slot = FtFace->glyph; FT_Error error = FT_Render_Glyph(slot, RenderMode); if (error != 0) return nullptr; - FT_Bitmap* ft_bitmap = &Face->glyph->bitmap; + FT_Bitmap* ft_bitmap = &FtFace->glyph->bitmap; out_glyph_info->Width = (int)ft_bitmap->width; out_glyph_info->Height = (int)ft_bitmap->rows; - out_glyph_info->OffsetX = Face->glyph->bitmap_left; - out_glyph_info->OffsetY = -Face->glyph->bitmap_top; + out_glyph_info->OffsetX = FtFace->glyph->bitmap_left; + out_glyph_info->OffsetY = -FtFace->glyph->bitmap_top; out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR; out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); return ft_bitmap; } - void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) + void ImGui_ImplFreeType_FontSrcData::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) { IM_ASSERT(ft_bitmap != nullptr); const uint32_t w = ft_bitmap->width; @@ -398,6 +410,8 @@ namespace } } // namespace +#if 0 + #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION #define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) @@ -764,6 +778,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u return true; } +#endif // FreeType memory allocation callbacks static void* FreeType_Alloc(FT_Memory /*memory*/, long size) @@ -799,47 +814,189 @@ static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size return block; } -static bool ImFontAtlasBuildWithFreeType(ImFontAtlas* atlas) +bool ImGui_ImplFreeType_LoaderInit(ImFontAtlas* atlas) { + IM_ASSERT(atlas->FontLoaderData == NULL); + ImGui_ImplFreeType_Data* bd = IM_NEW(ImGui_ImplFreeType_Data)(); + // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html - FT_MemoryRec_ memory_rec = {}; - memory_rec.user = nullptr; - memory_rec.alloc = &FreeType_Alloc; - memory_rec.free = &FreeType_Free; - memory_rec.realloc = &FreeType_Realloc; + bd->MemoryManager.user = nullptr; + bd->MemoryManager.alloc = &FreeType_Alloc; + bd->MemoryManager.free = &FreeType_Free; + bd->MemoryManager.realloc = &FreeType_Realloc; // https://www.freetype.org/freetype2/docs/reference/ft2-module_management.html#FT_New_Library - FT_Library ft_library; - FT_Error error = FT_New_Library(&memory_rec, &ft_library); + FT_Error error = FT_New_Library(&bd->MemoryManager, &bd->Library); if (error != 0) + { + IM_DELETE(bd); return false; + } // If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. - FT_Add_Default_Modules(ft_library); + FT_Add_Default_Modules(bd->Library); #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG // Install svg hooks for FreeType // https://freetype.org/freetype2/docs/reference/ft2-properties.html#svg-hooks // https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html#svg_fonts SVG_RendererHooks hooks = { ImGuiLunasvgPortInit, ImGuiLunasvgPortFree, ImGuiLunasvgPortRender, ImGuiLunasvgPortPresetSlot }; - FT_Property_Set(ft_library, "ot-svg", "svg-hooks", &hooks); + FT_Property_Set(bd->Library, "ot-svg", "svg-hooks", &hooks); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG #ifdef IMGUI_ENABLE_FREETYPE_PLUTOSVG // With plutosvg, use provided hooks - FT_Property_Set(ft_library, "ot-svg", "svg-hooks", plutosvg_ft_svg_hooks()); + FT_Property_Set(bd->Library, "ot-svg", "svg-hooks", plutosvg_ft_svg_hooks()); #endif // IMGUI_ENABLE_FREETYPE_PLUTOSVG - bool ret = ImFontAtlasBuildWithFreeTypeEx(ft_library, atlas, atlas->FontBuilderFlags); - FT_Done_Library(ft_library); + // Store our data + atlas->FontLoaderData = (void*)bd; + + return true; +} - return ret; +void ImGui_ImplFreeType_LoaderShutdown(ImFontAtlas* atlas) +{ + ImGui_ImplFreeType_Data* bd = (ImGui_ImplFreeType_Data*)atlas->FontLoaderData; + IM_ASSERT(bd != NULL); + FT_Done_Library(bd->Library); + IM_DELETE(bd); + atlas->FontLoaderData = NULL; +} + +bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) +{ + ImGui_ImplFreeType_Data* bd = (ImGui_ImplFreeType_Data*)atlas->FontLoaderData; + ImGui_ImplFreeType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplFreeType_FontSrcData); + IM_ASSERT(src->FontLoaderData == NULL); + src->FontLoaderData = bd_font_data; + + if (!bd_font_data->InitFont(bd->Library, src, atlas->FontBuilderFlags)) + return false; + + if (src->MergeMode == false) + { + ImFont* font = src->DstFont; + font->Ascent = bd_font_data->Info.Ascender; + font->Descent = bd_font_data->Info.Descender; + } + return true; +} + +void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) +{ + IM_UNUSED(atlas); + ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; + IM_DELETE(bd_font_data); + src->FontLoaderData = NULL; +} + +bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) +{ + // Search for first font which has the glyph + ImGui_ImplFreeType_FontSrcData* bd_font_data = NULL; + ImFontConfig* src = NULL; + uint32_t glyph_index = 0; + for (int src_n = 0; src_n < srcs_count; src_n++) + { + src = &srcs[src_n]; + bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; + glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); + if (glyph_index != 0) + break; + } + if (glyph_index == 0) + return false; // Not found + + const FT_Glyph_Metrics* metrics = bd_font_data->LoadGlyph(codepoint); + if (metrics == NULL) + return false; + + // Render glyph into a bitmap (currently held by FreeType) + FT_Face face = bd_font_data->FtFace; + FT_GlyphSlot slot = face->glyph; + FT_Error error = FT_Render_Glyph(slot, bd_font_data->RenderMode); + if (error != 0) + return false; + + const FT_Bitmap* ft_bitmap = &slot->bitmap; + if (ft_bitmap == nullptr) + return false; + + const int w = (int)ft_bitmap->width; + const int h = (int)ft_bitmap->rows; + const bool is_visible = (w != 0 && h != 0); + + // Prepare glyph + ImFontGlyph glyph = {}; + glyph.Codepoint = codepoint; + glyph.AdvanceX = (slot->advance.x / FT_SCALEFACTOR) * bd_font_data->InvRasterizationDensity; + + // Pack and retrieve position inside texture atlas + if (is_visible) + { + ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + font->MetricsTotalSurface += w * h; + + // Render pixels to our temporary buffer + atlas->Builder->TempBuffer.resize(w * h * 4); + uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data; + bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w, nullptr);// multiply_enabled ? multiply_table : nullptr); + + float font_off_x = src->GlyphOffset.x; + float font_off_y = src->GlyphOffset.y + IM_ROUND(font->Ascent); + float recip_h = 1.0f / src->RasterizerDensity; + float recip_v = 1.0f / src->RasterizerDensity; + + // Register glyph + float glyph_off_x = (float)face->glyph->bitmap_left; + float glyph_off_y = (float)-face->glyph->bitmap_top; + glyph.X0 = glyph_off_x * recip_h + font_off_x; + glyph.Y0 = glyph_off_y * recip_v + font_off_y; + glyph.X1 = (glyph_off_x + w) * recip_h + font_off_x; + glyph.Y1 = (glyph_off_y + h) * recip_v + font_off_y; + glyph.U0 = (r->x) * atlas->TexUvScale.x; + glyph.V0 = (r->y) * atlas->TexUvScale.y; + glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; + glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + glyph.PackId = pack_id; + glyph.Visible = true; + glyph.Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); + font->BuildRegisterGlyph(src, &glyph); + + // Copy to texture, post-process and queue update for backend + ImTextureData* tex = atlas->TexData; + IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); + ImFontAtlasTextureBlockConvertAndPostProcess(atlas, font, src, &font->Glyphs.back(), + temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); + } + else + { + font->BuildRegisterGlyph(src, &glyph); + } + return true; +} + +bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) +{ + IM_UNUSED(atlas); + ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; + int glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); + return glyph_index != 0; } -const ImFontBuilderIO* ImGuiFreeType::GetBuilderForFreeType() +const ImFontLoader* ImGuiFreeType::GetFontLoader() { - static ImFontBuilderIO io; - io.FontBuilder_Build = ImFontAtlasBuildWithFreeType; - return &io; + static ImFontLoader loader; + loader.Name = "freetype"; + loader.LoaderInit = ImGui_ImplFreeType_LoaderInit; + loader.LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown; + loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit; + loader.FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy; + loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph; + loader.FontAddGlyph = ImGui_ImplFreeType_FontAddGlyph; + return &loader; } void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 9d367074e0c2..2d7b3a34fd38 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -14,7 +14,7 @@ // Forward declarations struct ImFontAtlas; -struct ImFontBuilderIO; +struct ImFontLoader; // Hinting greatly impacts visuals (and glyph sizes). // - By default, hinting is enabled and the font's native hinter is preferred over the auto-hinter. @@ -41,9 +41,9 @@ namespace ImGuiFreeType { // This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'. // If you need to dynamically select between multiple builders: - // - you can manually assign this builder with 'atlas->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()' - // - prefer deep-copying this into your own ImFontBuilderIO instance if you use hot-reloading that messes up static data. - IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType(); + // - you can manually assign this builder with 'atlas->FontLoader = ImGuiFreeType::GetFontLoader()' + // - prefer deep-copying this into your own ImFontLoader instance if you use hot-reloading that messes up static data. + IMGUI_API const ImFontLoader* GetFontLoader(); // Override allocators. By default ImGuiFreeType will use IM_ALLOC()/IM_FREE() // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired. From 1269467fa0789c927c70c4013d5ed5477b1ec49c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 Nov 2024 15:27:17 +0100 Subject: [PATCH 444/716] imgui_freetype: Removing old code. --- misc/freetype/imgui_freetype.cpp | 454 +------------------------------ 1 file changed, 14 insertions(+), 440 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 1125364bfa51..a8dfa950e655 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -142,24 +142,12 @@ namespace // | | // |------------- advanceX ----------->| - // A structure that describe a glyph. - struct GlyphInfo - { - int Width; // Glyph's width in pixels. - int Height; // Glyph's height in pixels. - FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph. - FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0. - float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0. - bool IsColored; // The glyph is colored - }; - // Stored in ImFontAtlas::FontLoaderData struct ImGui_ImplFreeType_Data { - FT_Library Library; - FT_MemoryRec_ MemoryManager; - - ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } + FT_Library Library; + FT_MemoryRec_ MemoryManager; + ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } }; // Font parameters and metrics. @@ -180,8 +168,7 @@ namespace void CloseFont(); void SetPixelHeight(float pixel_height); // Change font pixel size. const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); - const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); - void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr); + void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch); ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); } ~ImGui_ImplFreeType_FontSrcData() { CloseFont(); } @@ -316,25 +303,7 @@ namespace return &slot->metrics; } - const FT_Bitmap* ImGui_ImplFreeType_FontSrcData::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info) - { - FT_GlyphSlot slot = FtFace->glyph; - FT_Error error = FT_Render_Glyph(slot, RenderMode); - if (error != 0) - return nullptr; - - FT_Bitmap* ft_bitmap = &FtFace->glyph->bitmap; - out_glyph_info->Width = (int)ft_bitmap->width; - out_glyph_info->Height = (int)ft_bitmap->rows; - out_glyph_info->OffsetX = FtFace->glyph->bitmap_left; - out_glyph_info->OffsetY = -FtFace->glyph->bitmap_top; - out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR; - out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); - - return ft_bitmap; - } - - void ImGui_ImplFreeType_FontSrcData::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) + void ImGui_ImplFreeType_FontSrcData::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch) { IM_ASSERT(ft_bitmap != nullptr); const uint32_t w = ft_bitmap->width; @@ -346,24 +315,13 @@ namespace { case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel. { - if (multiply_table == nullptr) - { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - for (uint32_t x = 0; x < w; x++) - dst[x] = IM_COL32(255, 255, 255, src[x]); - } - else - { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - for (uint32_t x = 0; x < w; x++) - dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]); - } + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + for (uint32_t x = 0; x < w; x++) + dst[x] = IM_COL32(255, 255, 255, src[x]); break; } case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB. { - uint8_t color0 = multiply_table ? multiply_table[0] : 0; - uint8_t color1 = multiply_table ? multiply_table[255] : 255; for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) { uint8_t bits = 0; @@ -372,7 +330,7 @@ namespace { if ((x & 7) == 0) bits = *bits_ptr++; - dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0); + dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? 255 : 0); } } break; @@ -381,26 +339,12 @@ namespace { // FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good. #define DE_MULTIPLY(color, alpha) ImMin((ImU32)(255.0f * (float)color / (float)(alpha + FLT_MIN) + 0.5f), 255u) - if (multiply_table == nullptr) - { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - for (uint32_t x = 0; x < w; x++) - { - uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; - dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a); - } - } - else - { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + for (uint32_t x = 0; x < w; x++) { - for (uint32_t x = 0; x < w; x++) - { - uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; - dst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]); - } + uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; + dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a); } - } #undef DE_MULTIPLY break; } @@ -410,376 +354,6 @@ namespace } } // namespace -#if 0 - -#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds) -#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION -#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0) -#define STBRP_STATIC -#define STB_RECT_PACK_IMPLEMENTATION -#endif -#ifdef IMGUI_STB_RECT_PACK_FILENAME -#include IMGUI_STB_RECT_PACK_FILENAME -#else -#include "imstb_rectpack.h" -#endif -#endif - -struct ImFontBuildSrcGlyphFT -{ - GlyphInfo Info; - uint32_t Codepoint; - unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array - - ImFontBuildSrcGlyphFT() { memset((void*)this, 0, sizeof(*this)); } -}; - -struct ImFontBuildSrcDataFT -{ - FreeTypeFont Font; - stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position. - const ImWchar* SrcRanges; // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF) - int DstIndex; // Index into atlas->Fonts[] and dst_tmp_array[] - int GlyphsHighest; // Highest requested codepoint - int GlyphsCount; // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font) - ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB) - ImVector GlyphsList; -}; - -// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont) -struct ImFontBuildDstDataFT -{ - int SrcCount; // Number of source fonts targeting this destination font. - int GlyphsHighest; - int GlyphsCount; - ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font. -}; - -bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags) -{ - IM_ASSERT(atlas->Sources.Size > 0); - - ImFontAtlasBuildInit(atlas); - - // Clear atlas - atlas->TexID._TexID = 0; - atlas->TexWidth = atlas->TexHeight = 0; - atlas->TexUvScale = ImVec2(0.0f, 0.0f); - atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f); - atlas->ClearTexData(); - - // Temporary storage for building - bool src_load_color = false; - ImVector src_tmp_array; - ImVector dst_tmp_array; - src_tmp_array.resize(atlas->Sources.Size); - dst_tmp_array.resize(atlas->Fonts.Size); - memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes()); - memset((void*)dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes()); - - // 1. Initialize font loading structure, check font data validity - for (int src_i = 0; src_i < atlas->Sources.Size; src_i++) - { - ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - ImFontConfig& src = atlas->Sources[src_i]; - FreeTypeFont& font_face = src_tmp.Font; - IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas)); - - // Find index from src.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices) - src_tmp.DstIndex = -1; - for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++) - if (src.DstFont == atlas->Fonts[output_i]) - src_tmp.DstIndex = output_i; - IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array? - if (src_tmp.DstIndex == -1) - return false; - - // Load font - if (!font_face.InitFont(ft_library, src, extra_flags)) - return false; - - // Measure highest codepoints - src_load_color |= (src.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0; - ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault(); - for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) - { - // Check for valid range. This may also help detect *some* dangling pointers, because a common - // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent, - // or to forget to zero-terminate the glyph range array. - IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?"); - src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]); - } - dst_tmp.SrcCount++; - dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest); - } - - // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs. - int total_glyphs_count = 0; - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1); - if (dst_tmp.GlyphsSet.Storage.empty()) - dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1); - - for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) - for (int codepoint = src_range[0]; codepoint <= (int)src_range[1]; codepoint++) - { - if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) - continue; - uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..) - if (glyph_index == 0) - continue; - - // Add to avail set/counters - src_tmp.GlyphsCount++; - dst_tmp.GlyphsCount++; - src_tmp.GlyphsSet.SetBit(codepoint); - dst_tmp.GlyphsSet.SetBit(codepoint); - total_glyphs_count++; - } - } - - // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another) - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount); - - IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(ImU32)); - const ImU32* it_begin = src_tmp.GlyphsSet.Storage.begin(); - const ImU32* it_end = src_tmp.GlyphsSet.Storage.end(); - for (const ImU32* it = it_begin; it < it_end; it++) - if (ImU32 entries_32 = *it) - for (ImU32 bit_n = 0; bit_n < 32; bit_n++) - if (entries_32 & ((ImU32)1 << bit_n)) - { - ImFontBuildSrcGlyphFT src_glyph; - src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n); - //src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it.. - src_tmp.GlyphsList.push_back(src_glyph); - } - src_tmp.GlyphsSet.Clear(); - IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount); - } - for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++) - dst_tmp_array[dst_i].GlyphsSet.Clear(); - dst_tmp_array.clear(); - - // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) - // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity) - ImVector buf_rects; - buf_rects.resize(total_glyphs_count); - memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes()); - - // Allocate temporary rasterization data buffers. - // We could not find a way to retrieve accurate glyph size without rendering them. - // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform) - // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't mind the temporary allocations. - const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024; - int buf_bitmap_current_used_bytes = 0; - ImVector buf_bitmap_buffers; - buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE)); - - // 4. Gather glyphs sizes so we can pack them in our virtual canvas. - // 8. Render/rasterize font characters into the texture - int total_surface = 0; - int buf_rects_out_n = 0; - const int pack_padding = atlas->TexGlyphPadding; - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - ImFontConfig& src = atlas->Sources[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; - - src_tmp.Rects = &buf_rects[buf_rects_out_n]; - buf_rects_out_n += src_tmp.GlyphsCount; - - // Compute multiply table if requested - const bool multiply_enabled = (src.RasterizerMultiply != 1.0f); - unsigned char multiply_table[256]; - if (multiply_enabled) - ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply); - - // Gather the sizes of all rectangles we will need to pack - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++) - { - ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; - - const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint); - if (metrics == nullptr) - continue; - - // Render glyph into a bitmap (currently held by FreeType) - const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info); - if (ft_bitmap == nullptr) - continue; - - // Allocate new temporary chunk if needed - const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4; - if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE) - { - buf_bitmap_current_used_bytes = 0; - buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE)); - } - IM_ASSERT(buf_bitmap_current_used_bytes + bitmap_size_in_bytes <= BITMAP_BUFFERS_CHUNK_SIZE); // We could probably allocate custom-sized buffer instead. - - // Blit rasterized pixels to our temporary buffer and keep a pointer to it. - src_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes); - buf_bitmap_current_used_bytes += bitmap_size_in_bytes; - src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr); - - src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + pack_padding); - src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + pack_padding); - total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h; - } - } - for (int i = 0; i < atlas->CustomRects.Size; i++) - total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding); - - // We need a width for the skyline algorithm, any width! - // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height. - // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface. - const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1; - atlas->TexHeight = 0; - if (atlas->TexDesiredWidth > 0) - atlas->TexWidth = atlas->TexDesiredWidth; - else - atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512; - - // 5. Start packing - // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). - const int TEX_HEIGHT_MAX = 1024 * 32; - const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding; - ImVector pack_nodes; - pack_nodes.resize(num_nodes_for_packing_algorithm); - stbrp_context pack_context; - stbrp_init_target(&pack_context, atlas->TexWidth - atlas->TexGlyphPadding, TEX_HEIGHT_MAX - atlas->TexGlyphPadding, pack_nodes.Data, pack_nodes.Size); - ImFontAtlasBuildPackCustomRects(atlas, &pack_context); - - // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point. - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - if (src_tmp.GlyphsCount == 0) - continue; - - stbrp_pack_rects(&pack_context, src_tmp.Rects, src_tmp.GlyphsCount); - - // Extend texture height and mark missing glyphs as non-packed so we won't render them. - // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?) - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) - if (src_tmp.Rects[glyph_i].was_packed) - atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h); - } - - // 7. Allocate texture - atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); - atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - if (src_load_color) - { - size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4; - atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size); - memset(atlas->TexPixelsRGBA32, 0, tex_size); - } - else - { - size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1; - atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size); - memset(atlas->TexPixelsAlpha8, 0, tex_size); - } - - // 8. Copy rasterized font characters back into the main texture - // 9. Setup ImFont and glyphs for runtime - bool tex_use_colors = false; - for (int src_i = 0; src_i < src_tmp_array.Size; src_i++) - { - ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; - - // When merging fonts with MergeMode=true: - // - We can have multiple input fonts writing into a same destination font. - // - dst_font->Sources is != from src which is our source configuration. - ImFontConfig& src = atlas->Sources[src_i]; - ImFont* dst_font = src.DstFont; - - const float ascent = src_tmp.Font.Info.Ascender; - const float descent = src_tmp.Font.Info.Descender; - ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent); - - if (src_tmp.GlyphsCount == 0) - continue; - const float font_off_x = src.GlyphOffset.x; - const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent); - - const int padding = atlas->TexGlyphPadding; - for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++) - { - ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i]; - stbrp_rect& pack_rect = src_tmp.Rects[glyph_i]; - IM_ASSERT(pack_rect.was_packed); - if (pack_rect.w == 0 && pack_rect.h == 0) - continue; - - GlyphInfo& info = src_glyph.Info; - IM_ASSERT(info.Width + padding <= pack_rect.w); - IM_ASSERT(info.Height + padding <= pack_rect.h); - const int tx = pack_rect.x + padding; - const int ty = pack_rect.y + padding; - - // Register glyph - float x0 = info.OffsetX * src_tmp.Font.InvRasterizationDensity + font_off_x; - float y0 = info.OffsetY * src_tmp.Font.InvRasterizationDensity + font_off_y; - float x1 = x0 + info.Width * src_tmp.Font.InvRasterizationDensity; - float y1 = y0 + info.Height * src_tmp.Font.InvRasterizationDensity; - float u0 = (tx) / (float)atlas->TexWidth; - float v0 = (ty) / (float)atlas->TexHeight; - float u1 = (tx + info.Width) / (float)atlas->TexWidth; - float v1 = (ty + info.Height) / (float)atlas->TexHeight; - dst_font->AddGlyph(&src, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity); - - ImFontGlyph* dst_glyph = &dst_font->Glyphs.back(); - IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint); - if (src_glyph.Info.IsColored) - dst_glyph->Colored = tex_use_colors = true; - - // Blit from temporary buffer to final texture - size_t blit_src_stride = (size_t)src_glyph.Info.Width; - size_t blit_dst_stride = (size_t)atlas->TexWidth; - unsigned int* blit_src = src_glyph.BitmapData; - if (atlas->TexPixelsAlpha8 != nullptr) - { - unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx; - for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride) - for (int x = 0; x < info.Width; x++) - blit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF); - } - else - { - unsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx; - for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride) - for (int x = 0; x < info.Width; x++) - blit_dst[x] = blit_src[x]; - } - } - - src_tmp.Rects = nullptr; - } - atlas->TexPixelsUseColors = tex_use_colors; - - // Cleanup - for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++) - IM_FREE(buf_bitmap_buffers[buf_i]); - src_tmp_array.clear_destruct(); - - ImFontAtlasBuildFinish(atlas); - - return true; -} -#endif - // FreeType memory allocation callbacks static void* FreeType_Alloc(FT_Memory /*memory*/, long size) { @@ -941,7 +515,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon // Render pixels to our temporary buffer atlas->Builder->TempBuffer.resize(w * h * 4); uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data; - bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w, nullptr);// multiply_enabled ? multiply_table : nullptr); + bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w); float font_off_x = src->GlyphOffset.x; float font_off_y = src->GlyphOffset.y + IM_ROUND(font->Ascent); From 0f553c57bd130cbb3207ec493583030c1044bd97 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 14:28:16 +0100 Subject: [PATCH 445/716] Fonts: AddFont() actually does the work, so we can handle errors & return an accurate return value. --- imgui.h | 1 + imgui_draw.cpp | 51 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index c95f5ac57a7b..8161fb4b4f3d 100644 --- a/imgui.h +++ b/imgui.h @@ -3529,6 +3529,7 @@ struct ImFontAtlas IMGUI_API void Clear(); // Clear all input and output. IMGUI_API void ClearCache(); // Clear cached glyphs + IMGUI_API void BuildInit(); // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0bde7a11648a..3a9290296005 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2887,6 +2887,10 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); + // Lazily create builder on the first call to AddFont + if (Builder == NULL) + BuildInit(); + // Create new font if (!font_cfg->MergeMode) Fonts.push_back(IM_NEW(ImFont)); @@ -2912,9 +2916,19 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Pointers to Sources are otherwise dangling ImFontAtlasBuildUpdatePointers(this); - - if (Builder != NULL) - ImFontAtlasBuildAddFont(this, &new_font_cfg); + if (!ImFontAtlasBuildAddFont(this, &new_font_cfg)) + { + // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) + if (new_font_cfg.FontDataOwnedByAtlas) + IM_FREE(new_font_cfg.FontData); + Sources.pop_back(); + if (!font_cfg->MergeMode) + { + IM_DELETE(Fonts.back()); + Fonts.pop_back(); + } + return NULL; + } // Invalidate texture //TexReady = false; @@ -3105,14 +3119,8 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } -bool ImFontAtlas::Build() +void ImFontAtlas::BuildInit() { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - - // Default font is none are specified - if (Sources.Size == 0) - AddFontDefault(); - // Select builder // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are @@ -3132,6 +3140,18 @@ bool ImFontAtlas::Build() // Create initial texture size ImFontAtlasBuildAddTexture(this, 512, 128); ImFontAtlasBuildInit(this); +} + +bool ImFontAtlas::Build() +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); + + if (Builder == NULL) + BuildInit(); + + // Default font is none are specified + if (Sources.Size == 0) + AddFontDefault(); // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs ImFontAtlasBuildUpdateRendererHasTexturesFromContext(this); @@ -3384,7 +3404,7 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) const ImFontLoader* font_loader = atlas->FontLoader; if (!font_loader->FontSrcInit(atlas, src)) - return false; // FIXME-NEWATLAS: error handling + return false; ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); return true; @@ -3887,10 +3907,14 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* // Initialize helper structure for font loading and verify that the TTF/OTF data is correct const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo); - IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found."); // FIXME-NEWATLAS: error handling + if (font_offset < 0) + { + IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found."); + return false; + } if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset)) { - IM_ASSERT(0 && "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); + IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); return false; } src->FontLoaderData = bd_font_data; @@ -3954,6 +3978,7 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, { src = &srcs[src_n]; bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + IM_ASSERT(bd_font_data); glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); if (glyph_index != 0) break; From b670f799d5e3078477843a044e6fb99a383bbf6f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 15:16:22 +0100 Subject: [PATCH 446/716] Fonts: use TexGlyphPadding. Fixed packing issues. Removed old code. --- imgui_draw.cpp | 51 +++++++++++++----------------------------------- imgui_internal.h | 3 +-- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3a9290296005..089fc0c5d673 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3582,7 +3582,6 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. -#if 1 // Repack + copy pixels // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic. ImFontAtlasPackInit(atlas); @@ -3623,27 +3622,6 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) ImFontAtlasBuildUpdateLinesTexData(atlas, false); ImFontAtlasBuildUpdateBasicTexData(atlas, false); -#else - // Copy previous pixels - ImFontAtlasTextureCopyBlock(atlas, old_tex, 0, 0, new_tex, 0, 0, ImMin(old_tex->Width, new_tex->Width), ImMin(old_tex->Height, new_tex->Height)); - - // Scale UV coordinates - // FIXME-NEWATLAS: Probably lossy? - ImVec2 uv_scale((float)old_tex->Width / new_tex->Width, (float)old_tex->Height / new_tex->Height); - for (ImFont* font : atlas->Fonts) - for (ImFontGlyph& glyph : font->Glyphs) - { - glyph.U0 *= uv_scale.x; - glyph.U1 *= uv_scale.x; - glyph.V0 *= uv_scale.y; - glyph.V1 *= uv_scale.y; - } - ImVec4 uv_scale4(uv_scale.x, uv_scale.y, uv_scale.x, uv_scale.y); - atlas->TexUvWhitePixel *= uv_scale; - for (ImVec4& uv : atlas->TexUvLines) - uv = uv * uv_scale4; -#endif - builder->LockDisableResize = false; ImFontAtlasUpdateDrawListsSharedData(atlas); } @@ -3666,8 +3644,9 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h; // Handle minimum size first (for pathologically large packed rects) - new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + builder->PackPadding)); - new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + builder->PackPadding)); + const int pack_padding = atlas->TexGlyphPadding; + new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + pack_padding)); + new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + pack_padding)); ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); } @@ -3717,10 +3696,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) const bool builder_is_new = (builder == NULL); if (builder_is_new) - { builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); - builder->PackPadding = 1; - } ImFontAtlasPackInit(atlas); @@ -3762,11 +3738,12 @@ void ImFontAtlasPackInit(ImFontAtlas* atlas) // FIXME-NEWATLAS-V2: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 // FIXME-NEWATLAS-V2: Experiment with number of nodes. 2024-11-05: Seems to be quite fine to reduce this. - int pack_node_count = tex->Width - builder->PackPadding; + //int pack_padding = atlas->TexGlyphPadding; + int pack_node_count = tex->Width; //pack_node_count *= atlas->_PackNodesFactor; builder->PackNodes.resize(pack_node_count); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); - stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width - builder->PackPadding, tex->Height - builder->PackPadding, builder->PackNodes.Data, builder->PackNodes.Size); + stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); atlas->_PackedSurface = atlas->_PackedRects = 0; builder->MaxRectSize = ImVec2i(0, 0); builder->MaxRectBounds = ImVec2i(0, 0); @@ -3779,6 +3756,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) IM_ASSERT(h > 0 && h <= 0xFFFF); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + const int pack_padding = atlas->TexGlyphPadding; builder->MaxRectSize.x = ImMax(builder->MaxRectSize.x, w); builder->MaxRectSize.y = ImMax(builder->MaxRectSize.y, h); @@ -3788,11 +3766,11 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) { // Try packing stbrp_rect pack_r = {}; - pack_r.w = r.w + builder->PackPadding; - pack_r.h = r.h + builder->PackPadding; + pack_r.w = w + pack_padding; + pack_r.h = h + pack_padding; stbrp_pack_rects((stbrp_context*)(void*)&builder->PackContext, &pack_r, 1); - r.x = (unsigned short)(pack_r.x + builder->PackPadding); - r.y = (unsigned short)(pack_r.y + builder->PackPadding); + r.x = (unsigned short)pack_r.x; + r.y = (unsigned short)pack_r.y; if (pack_r.was_packed) break; @@ -3809,9 +3787,9 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) ImFontAtlasBuildGrowTexture(atlas); } - builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w); - builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h); - atlas->_PackedSurface += w * h; + builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding); + builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h + pack_padding); + atlas->_PackedSurface += (w + pack_padding) * (h + pack_padding); atlas->_PackedRects++; builder->Rects.push_back(r); @@ -3986,7 +3964,6 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, if (glyph_index == 0) return false; // Not found - // FIXME-NEWATLAS: Handling of atlas->TexGlyphPadding? const float scale_for_layout = bd_font_data->ScaleForLayout; // ~ (font units to pixels) const float scale_for_raster_x = bd_font_data->ScaleForRasterX; // ~ (font units to pixels) * RasterizationDensity * OversampleH const float scale_for_raster_y = bd_font_data->ScaleForRasterY; // ~ (font units to pixels) * RasterizationDensity * OversampleV diff --git a/imgui_internal.h b/imgui_internal.h index 27d1ca8e1988..4e8384beeb3b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3654,10 +3654,9 @@ struct ImFontAtlasBuilder { stbrp_context_opaque PackContext; // Actually 'stbrp_context' but we don't want to define this in the header file. ImVector PackNodes; - int PackPadding; // Generally 1 to avoid bilinear filtering issues. ImVector Rects; ImVector TempBuffer; // Misc scratch buffer - ImVec2i MaxRectSize; // Largest rectangle to pack (defacto used as a "minimum texture size") + ImVec2i MaxRectSize; // Largest rectangle to pack (de-facto used as a "minimum texture size") ImVec2i MaxRectBounds; // Bottom-right most used pixels bool LockDisableResize; // Disable resizing texture bool PreloadedAllGlyphsRanges; // Set when missing ImGuiBackendFlags_RendererHasTextures features forces atlas to preload everything. From 4f27792ffeffa2a922cc6e188a19c08506476fe7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 17:22:33 +0100 Subject: [PATCH 447/716] (Breaking) Removed atlas->TexDesiredWidth now unnecessary (github 327) --- docs/FONTS.md | 1 - imgui.h | 1 + imgui_draw.cpp | 5 ++--- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index e9fbcbe42712..514af0799300 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -60,7 +60,6 @@ Some solutions: - Reduce glyphs ranges by calculating them from source localization data. You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! - Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. -- Set `io.Fonts.TexDesiredWidth` to specify a texture width to reduce maximum texture height (see comment in `ImFontAtlas::Build()` function). Future versions of Dear ImGui should solve this problem. diff --git a/imgui.h b/imgui.h index 8161fb4b4f3d..7a57732e6cfa 100644 --- a/imgui.h +++ b/imgui.h @@ -3626,6 +3626,7 @@ struct ImFontAtlas float _PackNodesFactor = 1.0f; // [Obsolete] + //int TexDesiredWidth; // OBSOLETED in 1.91.5 (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 089fc0c5d673..a15bf0a60666 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3634,9 +3634,8 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ if (old_tex_h == -1) old_tex_h = atlas->TexData->Height; - // FIXME-NEWATLAS-V1: Handle atlas->TexDesiredWidth from user? - // FIXME-NEWATLAS-V1: What to do when reaching limits exposed by backend? - // FIXME-NEWATLAS-V1: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? + // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend? + // FIXME-NEWATLAS-V2: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); // Grow texture so it follows roughly a square. From 43cc3fc8b1a426cdf5cfa9a420c670ca3526ede6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 29 Nov 2024 17:34:52 +0100 Subject: [PATCH 448/716] Fonts: optimization bake FallbackAdvanceX into IndexAdvanceX[]. --- imgui_draw.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a15bf0a60666..c461accdeefe 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3820,7 +3820,7 @@ ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) { // Mark index as not found, so we don't attempt the search twice BuildGrowIndex(codepoint + 1); - IndexAdvanceX[codepoint] = (float)IM_FONTGLYPH_INDEX_NOT_FOUND; + IndexAdvanceX[codepoint] = FallbackAdvanceX; IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; return NULL; } @@ -4546,11 +4546,10 @@ float ImFont::GetCharAdvance(ImWchar c) { if (c < (size_t)IndexAdvanceX.Size) { + // Missing glyphs fitting inside index will have stored FallbackAdvanceX already. const float x = IndexAdvanceX.Data[c]; if (x >= 0.0f) return x; - if (x == (float)IM_FONTGLYPH_INDEX_NOT_FOUND) // FIXME-NEWATLAS: could bake in index - return FallbackAdvanceX; } const ImFontGlyph* glyph = BuildLoadGlyph(c); return glyph ? glyph->AdvanceX : FallbackAdvanceX; From ac13683c269fb0d77635c6f7328ea0d13ec757a2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Dec 2024 21:07:26 +0100 Subject: [PATCH 449/716] Fonts: ImFontAtlas accept DrawListSharedData not being set. --- imgui_draw.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c461accdeefe..ae63798f9abb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2629,8 +2629,11 @@ void ImFontAtlas::ClearFonts() ClearInputData(); Fonts.clear_delete(); TexIsBuilt = false; - DrawListSharedData->Font = NULL; - DrawListSharedData->FontScale = DrawListSharedData->FontSize = 0.0f; + if (DrawListSharedData) + { + DrawListSharedData->Font = NULL; + DrawListSharedData->FontScale = DrawListSharedData->FontSize = 0.0f; + } } void ImFontAtlas::Clear() @@ -3155,7 +3158,7 @@ bool ImFontAtlas::Build() // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs ImFontAtlasBuildUpdateRendererHasTexturesFromContext(this); - if (DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures + if (DrawListSharedData && DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures ImFontAtlasBuildPreloadAllGlyphRanges(this); TexIsBuilt = true; @@ -3493,6 +3496,8 @@ void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedDat void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex) { ImDrawListSharedData* shared_data = atlas->DrawListSharedData; + if (shared_data == NULL) + return; for (ImDrawList* draw_list : shared_data->DrawLists) { // Replace in command-buffer @@ -3512,6 +3517,8 @@ void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) { ImDrawListSharedData* shared_data = atlas->DrawListSharedData; + if (shared_data == NULL) + return; shared_data->FontAtlas = atlas; shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; shared_data->TexUvLines = atlas->TexUvLines; From 076a1ab85cd0ad18b6c07fe08100c480f0cf3cf1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Dec 2024 16:43:46 +0100 Subject: [PATCH 450/716] Fonts: Misc amends, remove _PackNodesFactor, comments. --- imgui.h | 1 - imgui_draw.cpp | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index 7a57732e6cfa..b733544ac0fc 100644 --- a/imgui.h +++ b/imgui.h @@ -3623,7 +3623,6 @@ struct ImFontAtlas int RefCount; // Number of contexts using this atlas int _PackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size. int _PackedRects; // Number of packed rectangles. - float _PackNodesFactor = 1.0f; // [Obsolete] //int TexDesiredWidth; // OBSOLETED in 1.91.5 (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ae63798f9abb..d100d7e08c28 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2579,7 +2579,6 @@ ImFontAtlas::ImFontAtlas() TexGlyphPadding = 1; TexRef._TexData = NULL;// this; TexNextUniqueID = 1; - _PackNodesFactor = 1.0f; Builder = NULL; } @@ -3742,11 +3741,8 @@ void ImFontAtlasPackInit(ImFontAtlas* atlas) ImTextureData* tex = atlas->TexData; ImFontAtlasBuilder* builder = atlas->Builder; - // FIXME-NEWATLAS-V2: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 - // FIXME-NEWATLAS-V2: Experiment with number of nodes. 2024-11-05: Seems to be quite fine to reduce this. - //int pack_padding = atlas->TexGlyphPadding; + // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it. int pack_node_count = tex->Width; - //pack_node_count *= atlas->_PackNodesFactor; builder->PackNodes.resize(pack_node_count); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); @@ -3756,6 +3752,7 @@ void ImFontAtlasPackInit(ImFontAtlas* atlas) } // Important: Calling this may recreate a new texture and therefore change atlas->TexData +// FIXME-NEWATLAS-V2: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) { IM_ASSERT(w > 0 && w <= 0xFFFF); @@ -3857,7 +3854,7 @@ void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) for (const ImTextureRect& r : tex->Updates) { IM_ASSERT(r.x >= 0 && r.y >= 0); - IM_ASSERT(r.x + r.w < tex->Width && r.y + r.h < tex->Height); + IM_ASSERT(r.x + r.w <= tex->Width && r.y + r.h <= tex->Height); // In theory should subtract PackPadding but it's currently part of atlas and mid-frame change would wreck assert. //IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); } } From a6c78019266caf640bb8ddae7db60f42677b821a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Dec 2024 19:26:45 +0100 Subject: [PATCH 451/716] Fonts: Measured and tweaked CalcTextSize() computation to minimize cost in our stress tests. --- imgui_draw.cpp | 35 ++++++++++++++++++++++++++--------- imgui_widgets.cpp | 4 +--- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d100d7e08c28..c21925de5992 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3834,6 +3834,15 @@ ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) return glyph; } +// The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b +IM_MSVC_RUNTIME_CHECKS_OFF +static float BuildLoadGlyphGetAdvanceOrFallback(ImFont* font, unsigned int codepoint) +{ + ImFontGlyph* glyph = font->BuildLoadGlyph((ImWchar)codepoint); + return glyph ? glyph->AdvanceX : font->FallbackAdvanceX; +} +IM_MSVC_RUNTIME_CHECKS_RESTORE + #ifndef IMGUI_DISABLE_DEBUG_TOOLS void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) { @@ -4546,18 +4555,23 @@ bool ImFont::IsGlyphInFont(ImWchar c) return false; } +// This is manually inlined in CalcTextSizeA() and CalcWordWrapPositionA(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback(). +IM_MSVC_RUNTIME_CHECKS_OFF float ImFont::GetCharAdvance(ImWchar c) { - if (c < (size_t)IndexAdvanceX.Size) + if ((int)c < IndexAdvanceX.Size) { // Missing glyphs fitting inside index will have stored FallbackAdvanceX already. const float x = IndexAdvanceX.Data[c]; if (x >= 0.0f) return x; } + + // Same as BuildLoadGlyphGetAdvanceOrFallback(): const ImFontGlyph* glyph = BuildLoadGlyph(c); return glyph ? glyph->AdvanceX : FallbackAdvanceX; } +IM_MSVC_RUNTIME_CHECKS_RESTORE // Trim trailing space and find beginning of next line static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) @@ -4569,8 +4583,6 @@ static inline const char* CalcWordWrapNextLineStartA(const char* text, const cha return text; } -#define ImFontGetCharAdvanceX(_FONT, _CH) ((int)(_CH) < (_FONT)->IndexAdvanceX.Size ? (_FONT)->IndexAdvanceX.Data[_CH] : (_FONT)->FallbackAdvanceX) - // Simple word-wrapping for English, not full-featured. Please submit failing cases! // This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end. // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.) @@ -4624,9 +4636,11 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha } } - // FIXME-NEWATLAS-V1: Measure perf, inline etc. - //const float char_width = ImFontGetCharAdvanceX(this, c); - const float char_width = GetCharAdvance((ImWchar)c); // ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX); + // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);' + float char_width = (c < (unsigned int)IndexAdvanceX.Size) ? IndexAdvanceX.Data[c] : -1.0f; + if (char_width < 0.0f) + char_width = BuildLoadGlyphGetAdvanceOrFallback(this, c); + if (ImCharIsBlankW(c)) { if (inside_word) @@ -4731,9 +4745,12 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons continue; } - // FIXME-NEWATLAS-V1: Measure perf, inline etc. - //const float char_width = ImFontGetCharAdvanceX(this, c) * scale; - const float char_width = GetCharAdvance((ImWchar)c) /* (int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX)*/ * scale; + // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);' + float char_width = (c < (unsigned int)IndexAdvanceX.Size) ? IndexAdvanceX.Data[c] : -1.0f; + if (char_width < 0.0f) + char_width = BuildLoadGlyphGetAdvanceOrFallback(this, c); + char_width *= scale; + if (line_width + char_width >= max_width) { s = prev_s; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 186b639b5072..47f6f7187cc9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3984,9 +3984,7 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c if (c == '\r') continue; - // FIXME-NEWATLAS-V1: Measure perf, inline etc. - const float char_width = font->GetCharAdvance((ImWchar)c) * scale;// ((int)c < font->IndexAdvanceX.Size ? font->IndexAdvanceX.Data[c] : font->FallbackAdvanceX)* scale; - line_width += char_width; + line_width += font->GetCharAdvance((ImWchar)c) * scale; } if (text_size.x < line_width) From 553b1c301df1c4ffbb9fe5c47bfa41ea86d750b6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Dec 2024 18:52:30 +0100 Subject: [PATCH 452/716] Fonts: repack without full reload, discard rectangle, fixed CustomRect api with stable id, remove public BuildInit(). --- imgui.h | 5 +- imgui_draw.cpp | 207 ++++++++++++++++++++++++++++++++++++----------- imgui_internal.h | 23 +++++- 3 files changed, 182 insertions(+), 53 deletions(-) diff --git a/imgui.h b/imgui.h index b733544ac0fc..3013eb9e074c 100644 --- a/imgui.h +++ b/imgui.h @@ -3529,7 +3529,6 @@ struct ImFontAtlas IMGUI_API void Clear(); // Clear all input and output. IMGUI_API void ClearCache(); // Clear cached glyphs - IMGUI_API void BuildInit(); // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). @@ -3583,7 +3582,7 @@ struct ImFontAtlas // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); - ImFontAtlasCustomRect* GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; } + IMGUI_API ImFontAtlasCustomRect* GetCustomRectByIndex(int index); // [Internal] IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; @@ -3608,8 +3607,8 @@ struct ImFontAtlas ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight) ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. - ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVector Sources; // Source/configuration data + //ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID ImDrawListSharedData* DrawListSharedData; // In principle this could become an array (e.g. multiple contexts using same atlas) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c21925de5992..48f99cdf1c34 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2606,7 +2606,7 @@ void ImFontAtlas::ClearInputData() font->SourcesCount = 0; } Sources.clear(); - CustomRects.clear(); + //CustomRects.clear(); // Important: we leave TexReady untouched } @@ -2646,6 +2646,7 @@ void ImFontAtlas::Clear() ImFontAtlasBuildSetupFontLoader(this, font_loader); } +// FIXME-NEWATLAS: Too widespread purpose. Clarify each call site in current WIP demo. void ImFontAtlas::ClearCache() { int tex_w = (TexData && TexData->Status != ImTextureStatus_WantDestroy) ? TexData->Width : 0; @@ -2891,7 +2892,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Lazily create builder on the first call to AddFont if (Builder == NULL) - BuildInit(); + ImFontAtlasBuildInit(this); // Create new font if (!font_cfg->MergeMode) @@ -3066,11 +3067,24 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) { IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); - ImFontAtlasCustomRect r; - r.Width = (unsigned short)width; - r.Height = (unsigned short)height; - CustomRects.push_back(r); - return CustomRects.Size - 1; // Return index + + if (DrawListSharedData && DrawListSharedData->RendererHasTextures) + { + ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); + ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); + return r_id; + } + else + { + // FIXME-NEWATLAS-V1: Unfinished + ImFontAtlasCustomRect r; + r.Width = (unsigned short)width; + r.Height = (unsigned short)height; + //CustomRects.push_back(r); + //return CustomRects.Size - 1; // Return index + return -1; + } } int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) @@ -3089,8 +3103,18 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int r.GlyphAdvanceX = advance_x; r.GlyphOffset = offset; r.Font = font; - CustomRects.push_back(r); - return CustomRects.Size - 1; // Return index + //CustomRects.push_back(r); + //return CustomRects.Size - 1; // Return index + return -1; +} + +ImFontAtlasCustomRect* ImFontAtlas::GetCustomRectByIndex(int idx) +{ + IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, X) == offsetof(ImFontAtlasRect, x)); + IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, Y) == offsetof(ImFontAtlasRect, y)); + IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, Width) == offsetof(ImFontAtlasRect, w)); + IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, Height) == offsetof(ImFontAtlasRect, h)); + return (ImFontAtlasCustomRect*)(void*)ImFontAtlasPackGetRect(this, idx); } void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const @@ -3121,35 +3145,12 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } -void ImFontAtlas::BuildInit() -{ - // Select builder - // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which - // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are - // using a hot-reloading scheme that messes up static data, store your own instance of ImFontLoader somewhere - // and point to it instead of pointing directly to return value of the GetBackendIOXXX functions. - if (FontLoader == NULL) - { -#ifdef IMGUI_ENABLE_FREETYPE - ImFontAtlasBuildSetupFontLoader(this, ImGuiFreeType::GetBackendIOForFreeType()); -#elif defined(IMGUI_ENABLE_STB_TRUETYPE) - ImFontAtlasBuildSetupFontLoader(this, ImFontAtlasGetFontLoaderForStbTruetype()); -#else - IM_ASSERT(0); // Invalid Build function -#endif - } - - // Create initial texture size - ImFontAtlasBuildAddTexture(this, 512, 128); - ImFontAtlasBuildInit(this); -} - bool ImFontAtlas::Build() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); if (Builder == NULL) - BuildInit(); + ImFontAtlasBuildInit(this); // Default font is none are specified if (Sources.Size == 0) @@ -3222,6 +3223,8 @@ void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) } } +// FIXME-NEWATLAS: Unused +#if 0 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) { ImTextureData* tex = atlas->TexData; @@ -3253,6 +3256,7 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa tex->Height = ImMax(tex->Height, pack_rects[i].y + pack_rects[i].h); } } +#endif // Render a white-colored bitmap encoded in a string void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char) @@ -3476,6 +3480,28 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr font->LockSingleSrcConfigIdx = -1; } +void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) +{ + for (ImFontGlyph& glyph : font->Glyphs) + if (glyph.PackId >= 0) + ImFontAtlasPackDiscardRect(atlas, glyph.PackId); + font->BuildClearGlyphs(); + + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; + IM_ASSERT(src->SizePixels > 0.0f); + + // Reload font in backend + if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL) + atlas->FontLoader->FontSrcDestroy(atlas, src); + if (atlas->FontLoader && atlas->FontLoader->FontSrcInit != NULL) + atlas->FontLoader->FontSrcInit(atlas, src); + + ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. + } +} + // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) { @@ -3588,29 +3614,40 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. - // Repack + copy pixels + // Repack, lose discarded rectangle, copy pixels // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic. ImFontAtlasPackInit(atlas); ImVector old_rects; + ImVector old_index = builder->RectsIndex; old_rects.swap(builder->Rects); - for (ImFontAtlasRect& old_r : old_rects) + + for (ImFontAtlasRectEntry& index_entry : builder->RectsIndex) { - ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h); + if (index_entry.Used == false) + continue; + ImFontAtlasRect& old_r = old_rects[index_entry.TargetIndex]; + if (old_r.w == 0 && old_r.h == 0) + continue; + ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, &index_entry); if (new_r_id == -1) { // Undo, grow texture and try repacking again. // FIXME-NEWATLAS-TESTS: This is a very rarely exercised path! It needs to be automatically tested properly. IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize failed. Will grow.\n", new_tex->UniqueID); new_tex->WantDestroyNextFrame = true; - old_rects.swap(builder->Rects); + builder->Rects.swap(old_rects); + builder->RectsIndex = old_index; ImFontAtlasBuildSetTexture(atlas, old_tex); - ImFontAtlasBuildGrowTexture(atlas, w, h); + ImFontAtlasBuildGrowTexture(atlas, w, h); // Recurse return; } + IM_ASSERT(new_r_id == builder->RectsIndex.index_from_ptr(&index_entry)); ImFontAtlasRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id); ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h); } - IM_ASSERT(old_rects.Size == builder->Rects.Size); + IM_ASSERT(old_rects.Size == builder->Rects.Size + builder->RectsDiscardedCount); + builder->RectsDiscardedCount = 0; + builder->RectsDiscardedSurface = 0; // Patch glyphs UV for (ImFont* font : atlas->Fonts) @@ -3645,6 +3682,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); // Grow texture so it follows roughly a square. + // FIXME-NEWATLAS-V1: Take account of RectsDiscardedSurface: may not need to grow. int new_tex_w = (old_tex_h < old_tex_w) ? old_tex_w : old_tex_w * 2; int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h; @@ -3669,14 +3707,15 @@ void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) // FIXME-NEWATLAS: Expose atlas->TexMinWidth etc. const int min_w = ImMax(builder->MaxRectSize.x, 512); const int min_h = builder->MaxRectSize.y; - const int surface_sqrt = (int)sqrtf((float)atlas->_PackedSurface); + const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack + const int surface_sqrt = (int)sqrtf((float)surface_approx); int new_tex_w; int new_tex_h; if (min_w >= min_h) { new_tex_w = ImMax(min_w, ImUpperPowerOfTwo(surface_sqrt)); - new_tex_h = ImMax(min_h, (int)(atlas->_PackedSurface / new_tex_w)); + new_tex_h = ImMax(min_h, (int)((surface_approx + new_tex_w - 1) / new_tex_w)); if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0) new_tex_h = ImUpperPowerOfTwo(new_tex_h); } @@ -3685,10 +3724,10 @@ void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) new_tex_h = ImMax(min_h, ImUpperPowerOfTwo(surface_sqrt)); if ((atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) == 0) new_tex_h = ImUpperPowerOfTwo(new_tex_h); - new_tex_w = ImMax(min_w, (int)(atlas->_PackedSurface / new_tex_h)); + new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / new_tex_h)); } - if (new_tex_w == old_tex_w && new_tex_h == old_tex_h) + if (builder->RectsDiscardedCount == 0 && new_tex_w == old_tex_w && new_tex_h == old_tex_h) return; ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); @@ -3699,6 +3738,25 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) { ImFontAtlasBuilder* builder = atlas->Builder; + // Select Backend + // - Note that we do not reassign to atlas->FontBackendIO, since it is likely to point to static data which + // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are + // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBackendIO somewhere + // and point to it instead of pointing directly to return value of the GetBackendIOXXX functions. + if (atlas->FontLoader == NULL) + { +#ifdef IMGUI_ENABLE_FREETYPE + ImFontAtlasBuildSetupFontLoader(atlas, ImGuiFreeType::GetFontLoader()); +#elif defined(IMGUI_ENABLE_STB_TRUETYPE) + ImFontAtlasBuildSetupFontLoader(atlas, ImFontAtlasGetFontLoaderForStbTruetype()); +#else + IM_ASSERT(0); // Invalid Build function +#endif + } + // Create initial texture size + if (atlas->TexData == NULL) + ImFontAtlasBuildAddTexture(atlas, 512, 128); + const bool builder_is_new = (builder == NULL); if (builder_is_new) builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); @@ -3736,7 +3794,7 @@ void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) atlas->Builder = NULL; } -void ImFontAtlasPackInit(ImFontAtlas* atlas) +void ImFontAtlasPackInit(ImFontAtlas * atlas) { ImTextureData* tex = atlas->TexData; ImFontAtlasBuilder* builder = atlas->Builder; @@ -3751,9 +3809,52 @@ void ImFontAtlasPackInit(ImFontAtlas* atlas) builder->MaxRectBounds = ImVec2i(0, 0); } +// This is essentially a free-list pattern, it may be nice to wrap it into a dedicated type. +static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int rect_idx) +{ + ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + int index_idx; + ImFontAtlasRectEntry* index_entry; + if (builder->RectsIndexFreeListStart < 0) + { + builder->RectsIndex.resize(builder->RectsIndex.Size + 1); + index_idx = builder->RectsIndex.Size - 1; + index_entry = &builder->RectsIndex[index_idx]; + } + else + { + index_idx = builder->RectsIndexFreeListStart; + index_entry = &builder->RectsIndex[index_idx]; + IM_ASSERT(index_entry->Used == false); + builder->RectsIndexFreeListStart = index_entry->TargetIndex; + } + index_entry->TargetIndex = rect_idx; + index_entry->Used = 1; + return (ImFontAtlasRectId)index_idx; +} + +// This is expected to be called in batches and followed by a repack +void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) +{ + IM_ASSERT(id >= 0); + ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; + IM_ASSERT(index_entry->Used && index_entry->TargetIndex >= 0); + + ImFontAtlasRect* rect = ImFontAtlasPackGetRect(atlas, id); + index_entry->Used = false; + index_entry->TargetIndex = builder->RectsIndexFreeListStart; + + const int pack_padding = atlas->TexGlyphPadding; + builder->RectsIndexFreeListStart = id; + builder->RectsDiscardedCount++; + builder->RectsDiscardedSurface += (rect->w + pack_padding) * (rect->h + pack_padding); + rect->w = rect->h = 0; // Clear rectangle so it won't be packed again +} + // Important: Calling this may recreate a new texture and therefore change atlas->TexData // FIXME-NEWATLAS-V2: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 -ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) +ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry) { IM_ASSERT(w > 0 && w <= 0xFFFF); IM_ASSERT(h > 0 && h <= 0xFFFF); @@ -3796,13 +3897,25 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h) atlas->_PackedRects++; builder->Rects.push_back(r); - return builder->Rects.Size - 1; + if (overwrite_entry != NULL) + { + // Write into an existing entry instead of adding one (used during repack) + IM_ASSERT(overwrite_entry->Used); + overwrite_entry->TargetIndex = builder->Rects.Size - 1; + return builder->RectsIndex.index_from_ptr(overwrite_entry); + } + else + { + return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1); + } } ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; - return &builder->Rects[id]; + ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; + IM_ASSERT(index_entry->Used); + return &builder->Rects[index_entry->TargetIndex]; } ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) diff --git a/imgui_internal.h b/imgui_internal.h index 4e8384beeb3b..67a4b50cbb47 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -142,6 +142,7 @@ struct ImGuiTextIndex; // Maintain a line index for a text buffer. struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances struct ImFontAtlasRect; // Packed rectangle (same as ImTextureRect) +struct ImFontAtlasRectEntry; // Packed rectangle lookup entry struct ImFontAtlasBuilder; // Internal storage for incrementally packing and building a ImFontAtlas // ImGui @@ -3639,7 +3640,6 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -// Packed rectangle (same as ImTextureRect) struct ImFontAtlasRect { unsigned short x, y; @@ -3647,6 +3647,17 @@ struct ImFontAtlasRect }; typedef int ImFontAtlasRectId; // <0 when invalid +// Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) +// User are returned ImFontAtlasRectId values which are meant to be persistent. +// We handle this with an indirection. While Rects[] may be in theory shuffled, compacted etc., RectsIndex[] cannot it is keyed by ImFontAtlasRectId. +// RectsIndex[] is used both as an index into Rects[] and an index into itself. This is basically a free-list. See ImFontAtlasBuildAllocRectIndexEntry() code. +// Having this also makes it easier to e.g. sort rectangles during repack. +struct ImFontAtlasRectEntry +{ + int TargetIndex : 31; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list. + unsigned int Used : 1; +}; + // Internal storage for incrementally packing and building a ImFontAtlas struct stbrp_context_opaque { char data[80]; }; struct stbrp_node; @@ -3655,7 +3666,11 @@ struct ImFontAtlasBuilder stbrp_context_opaque PackContext; // Actually 'stbrp_context' but we don't want to define this in the header file. ImVector PackNodes; ImVector Rects; + ImVector RectsIndex; // ImFontAtlasRectId -> index into Rects[] ImVector TempBuffer; // Misc scratch buffer + int RectsIndexFreeListStart;// First unused entry + int RectsDiscardedCount; + int RectsDiscardedSurface; ImVec2i MaxRectSize; // Largest rectangle to pack (de-facto used as a "minimum texture size") ImVec2i MaxRectBounds; // Bottom-right most used pixels bool LockDisableResize; // Disable resizing texture @@ -3665,7 +3680,7 @@ struct ImFontAtlasBuilder ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure. ImFontAtlasRectId PackIdLinesTexData; - ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); } + ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; } }; // FIXME-NEWATLAS: Cleanup @@ -3683,11 +3698,13 @@ IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); -IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h); +IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); +IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); From a51a26e2aa9717cc77d8a91416e31f611d4b72db Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Dec 2024 19:21:10 +0100 Subject: [PATCH 453/716] Fonts: use a structure for post-processing - easier to pass things around and iterate on. --- imgui_draw.cpp | 47 +++++++++++++------------------- imgui_internal.h | 21 ++++++++++++-- misc/freetype/imgui_freetype.cpp | 5 ++-- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 48f99cdf1c34..10e69644f71a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2460,8 +2460,8 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::BuildCompactTexture() // - ImFontAtlasUpdateTextures() //----------------------------------------------------------------------------- -// - ImFontAtlasTextureBlockConvertAndPostProcess() // - ImFontAtlasTextureBlockConvert() +// - ImFontAtlasTextureBlockPostProcess() // - ImFontAtlasTextureBlockPostProcessMultiply() // - ImFontAtlasTextureBlockCopy() // - ImFontAtlasTextureBlockQueueUpload() @@ -2734,17 +2734,11 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) // Source buffer may be written to (used for in-place mods). // Post-process hooks may eventually be added here. -void ImFontAtlasTextureBlockConvertAndPostProcess(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) +void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data) { - IM_UNUSED(atlas); - IM_UNUSED(font); - IM_UNUSED(glyph); - // Multiply operator (legacy) - if (src->RasterizerMultiply != 1.0f) - ImFontAtlasTextureBlockPostProcessMultiply(atlas, font, src, glyph, src_pixels, src_fmt, w, h, src_pitch, src->RasterizerMultiply); - - ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, dst, dst_fmt, dst_pitch, w, h); + if (data->FontSrc->RasterizerMultiply != 1.0f) + ImFontAtlasTextureBlockPostProcessMultiply(data, data->FontSrc->RasterizerMultiply); } void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) @@ -2782,34 +2776,30 @@ void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFo } } -void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* pixels, ImTextureFormat format, int w, int h, int pitch, float in_multiply_factor) +void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor) { - IM_UNUSED(atlas); - IM_UNUSED(font); - IM_UNUSED(src); - IM_UNUSED(glyph); - IM_ASSERT(in_multiply_factor >= 0.0f); - IM_ASSERT_PARANOID(w <= pitch); - if (format == ImTextureFormat_Alpha8) - { - for (int ny = h; ny > 0; ny--, pixels += pitch) + unsigned char* pixels = data->Pixels; + int pitch = data->Pitch; + if (data->Format == ImTextureFormat_Alpha8) + { + for (int ny = data->Height; ny > 0; ny--, pixels += pitch) { ImU8* p = (ImU8*)pixels; - for (int nx = w; nx > 0; nx--, p++) + for (int nx = data->Width; nx > 0; nx--, p++) { - unsigned int v = ImMin((unsigned int)(*p * in_multiply_factor), (unsigned int)255); + unsigned int v = ImMin((unsigned int)(*p * multiply_factor), (unsigned int)255); *p = (unsigned char)v; } } } - else if (format == ImTextureFormat_RGBA32) + else if (data->Format == ImTextureFormat_RGBA32) { - for (int ny = h; ny > 0; ny--, pixels += pitch) + for (int ny = data->Height; ny > 0; ny--, pixels += pitch) { ImU32* p = (ImU32*)(void*)pixels; - for (int nx = w; nx > 0; nx--, p++) + for (int nx = data->Width; nx > 0; nx--, p++) { - unsigned int a = ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * in_multiply_factor), (unsigned int)255); + unsigned int a = ImMin((unsigned int)(((*p >> IM_COL32_A_SHIFT) & 0xFF) * multiply_factor), (unsigned int)255); *p = IM_COL32((*p >> IM_COL32_R_SHIFT) & 0xFF, (*p >> IM_COL32_G_SHIFT) & 0xFF, (*p >> IM_COL32_B_SHIFT) & 0xFF, a); } } @@ -4156,8 +4146,9 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, // Copy to texture, post-process and queue update for backend ImTextureData* tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); - ImFontAtlasTextureBlockConvertAndPostProcess(atlas, font, src, &font->Glyphs.back(), - bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); + ImFontAtlasTextureBlockConvert(bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); + ImFontAtlasPostProcessData pp_data = { atlas, font, src, &font->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; + ImFontAtlasTextureBlockPostProcess(&pp_data); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } else diff --git a/imgui_internal.h b/imgui_internal.h index 67a4b50cbb47..2c97cae01e28 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -144,6 +144,7 @@ struct ImDrawListSharedData; // Data shared between all ImDrawList instan struct ImFontAtlasRect; // Packed rectangle (same as ImTextureRect) struct ImFontAtlasRectEntry; // Packed rectangle lookup entry struct ImFontAtlasBuilder; // Internal storage for incrementally packing and building a ImFontAtlas +struct ImFontAtlasPostProcessData; // Data available to potential post-process functions // ImGui struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others) @@ -3658,6 +3659,22 @@ struct ImFontAtlasRectEntry unsigned int Used : 1; }; +// Data available to potential post-process functions +struct ImFontAtlasPostProcessData +{ + ImFontAtlas* FontAtlas; + ImFont* Font; + ImFontConfig* FontSrc; + ImFontGlyph* Glyph; + + // Pixel data + unsigned char* Pixels; + ImTextureFormat Format; + int Pitch; + int Width; + int Height; +}; + // Internal storage for incrementally packing and building a ImFontAtlas struct stbrp_context_opaque { char data[80]; }; struct stbrp_node; @@ -3714,9 +3731,9 @@ IMGUI_API void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* at IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasTextureBlockConvertAndPostProcess(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); IMGUI_API void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); -IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, ImFontGlyph* glyph, unsigned char* pixels, ImTextureFormat format, int w, int h, int pitch, float in_multiply_factor); +IMGUI_API void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data); +IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor); IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h); IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index a8dfa950e655..efe8612baa31 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -541,8 +541,9 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon // Copy to texture, post-process and queue update for backend ImTextureData* tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); - ImFontAtlasTextureBlockConvertAndPostProcess(atlas, font, src, &font->Glyphs.back(), - temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); + ImFontAtlasTextureBlockConvert(temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); + ImFontAtlasPostProcessData pp_data = { atlas, font, src, &font->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; + ImFontAtlasTextureBlockPostProcess(&pp_data); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } else From ef1521b472147c372d4239cda454a8275b201361 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Dec 2024 14:40:45 +0100 Subject: [PATCH 454/716] Fonts: fix for password fields --- imgui_widgets.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 47f6f7187cc9..c632b45a4d6f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4321,9 +4321,12 @@ void ImGui::PushPasswordFont() out_font->Ascent = in_font->Ascent; out_font->Descent = in_font->Descent; out_font->ContainerAtlas = in_font->ContainerAtlas; - out_font->FallbackGlyphIndex = in_font->Glyphs.index_from_ptr(glyph); // FIXME: broken + out_font->Glyphs.resize(0); + out_font->Glyphs.push_back(*glyph); + out_font->FallbackGlyphIndex = 0; out_font->FallbackAdvanceX = glyph->AdvanceX; - IM_ASSERT(out_font->Glyphs.Size == 0 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0); + out_font->LockDisableLoading = true; + IM_ASSERT(out_font->Glyphs.Size == 1 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0); PushFont(out_font); } From 4399599de9c10f4adee0b1e484ceb3b5e9d2e399 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Dec 2024 15:21:22 +0100 Subject: [PATCH 455/716] Fonts: ClearCache(), ImFontAtlasBuildGetTextureSizeEstimate(), tweak clearing functions. --- imgui.h | 8 +++--- imgui_draw.cpp | 66 ++++++++++++++++++++++++++++++------------------ imgui_internal.h | 1 + 3 files changed, 47 insertions(+), 28 deletions(-) diff --git a/imgui.h b/imgui.h index 3013eb9e074c..3ce13eb8836e 100644 --- a/imgui.h +++ b/imgui.h @@ -3523,12 +3523,12 @@ struct ImFontAtlas IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. // FIXME-NEWATLAS: Clarify meaning/purpose - IMGUI_API void ClearInputData(); // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. - IMGUI_API void ClearFonts(); // Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). - IMGUI_API void ClearTexData(); // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. IMGUI_API void Clear(); // Clear all input and output. - IMGUI_API void ClearCache(); // Clear cached glyphs + // As we are transitioning toward a new font system, we expect to obsolete those soon: + IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. + IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). + IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 10e69644f71a..631cb22e6832 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2569,8 +2569,9 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 { ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed }; -#define IM_FONTGLYPH_INDEX_UNUSED ((ImU16)-1) // 0xFFFF -#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE +#define IM_FONTGLYPH_INDEX_UNUSED ((ImU16)-1) // 0xFFFF +#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE +#define IM_FONTATLAS_DEFAULT_TEXTURE_SIZE ImVec2i(512, 128) ImFontAtlas::ImFontAtlas() { @@ -2600,11 +2601,14 @@ void ImFontAtlas::ClearInputData() // When clearing this we lose access to the font name and other information used to build the font. for (ImFont* font : Fonts) + { if (font->Sources >= Sources.Data && font->Sources < Sources.Data + Sources.Size) { font->Sources = NULL; font->SourcesCount = 0; } + font->LockDisableLoading = true; + } Sources.clear(); //CustomRects.clear(); // Important: we leave TexReady untouched @@ -2616,15 +2620,14 @@ void ImFontAtlas::ClearTexData() TexList.clear(); IM_DELETE(TexData); TexData = NULL; - // TexData.Destroy(); - //IM_ASSERT(0); - // Important: we leave TexReady untouched + // Important: we leave TexReady untouched } void ImFontAtlas::ClearFonts() { // FIXME-NEWATLAS: Illegal to remove currently bound font. IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); + ImFontAtlasBuildDestroy(this); ClearInputData(); Fonts.clear_delete(); TexIsBuilt = false; @@ -2637,7 +2640,7 @@ void ImFontAtlas::ClearFonts() void ImFontAtlas::Clear() { - //IM_DELETE(Builder); // FIXME-NEW-ATLAS: ClearXXX functions + //IM_DELETE(Builder); // FIXME-NEW-ATLAS: Clarify ClearXXX functions const ImFontLoader* font_loader = FontLoader; ImFontAtlasBuildSetupFontLoader(this, NULL); ClearInputData(); @@ -2649,11 +2652,9 @@ void ImFontAtlas::Clear() // FIXME-NEWATLAS: Too widespread purpose. Clarify each call site in current WIP demo. void ImFontAtlas::ClearCache() { - int tex_w = (TexData && TexData->Status != ImTextureStatus_WantDestroy) ? TexData->Width : 0; - int tex_h = (TexData && TexData->Status != ImTextureStatus_WantDestroy) ? TexData->Height : 0; + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(this); ImFontAtlasBuildDestroy(this); - if (tex_w != 0 && tex_h != 0) - ImFontAtlasBuildAddTexture(this, tex_w, tex_h); + ImFontAtlasBuildAddTexture(this, new_tex_size.x, new_tex_size.y); ImFontAtlasBuildInit(this); } @@ -3139,6 +3140,13 @@ bool ImFontAtlas::Build() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); + if (TexData && TexData->Format != TexDesiredFormat) + { + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(this); + ImFontAtlasBuildDestroy(this); + ImFontAtlasBuildAddTexture(this, new_tex_size.x, new_tex_size.y); + } + if (Builder == NULL) ImFontAtlasBuildInit(this); @@ -3168,7 +3176,10 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon return; IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); + // Note that texture size estimate is likely incorrect in this situation, as Freetype backend doesn't use oversampling. + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); + if (atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { atlas->FontLoader->LoaderShutdown(atlas); @@ -3178,8 +3189,9 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL"; if (atlas->FontLoader && atlas->FontLoader->LoaderInit) atlas->FontLoader->LoaderInit(atlas); - if (atlas->Builder && font_loader != NULL) - atlas->ClearCache(); + + ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); + ImFontAtlasBuildInit(atlas); } // Preload all glyph ranges for legacy backends. @@ -3684,17 +3696,13 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); } -// You should not need to call this manually! -// If you think you do, let us know and we can advise about policies auto-compact. -void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) +// FIXME-NEWATLAS: Expose atlas->TexMinWidth etc. +ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) { - ImFontAtlasBuilder* builder = atlas->Builder; - - ImTextureData* old_tex = atlas->TexData; - int old_tex_w = old_tex->Width; - int old_tex_h = old_tex->Height; + if (atlas->Builder == NULL || atlas->TexData == NULL || atlas->TexData->Status == ImTextureStatus_WantDestroy) + return IM_FONTATLAS_DEFAULT_TEXTURE_SIZE; - // FIXME-NEWATLAS: Expose atlas->TexMinWidth etc. + ImFontAtlasBuilder* builder = atlas->Builder; const int min_w = ImMax(builder->MaxRectSize.x, 512); const int min_h = builder->MaxRectSize.y; const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack @@ -3716,11 +3724,21 @@ void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) new_tex_h = ImUpperPowerOfTwo(new_tex_h); new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / new_tex_h)); } + return ImVec2i(new_tex_w, new_tex_h); +} - if (builder->RectsDiscardedCount == 0 && new_tex_w == old_tex_w && new_tex_h == old_tex_h) +// You should not need to call this manually! +// If you think you do, let us know and we can advise about policies auto-compact. +void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) +{ + ImFontAtlasBuilder* builder = atlas->Builder; + ImTextureData* old_tex = atlas->TexData; + ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); + if (builder->RectsDiscardedCount == 0 && new_tex_size.x == old_tex_size.x && new_tex_size.y == old_tex_size.y) return; - ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); + ImFontAtlasBuildRepackTexture(atlas, new_tex_size.x, new_tex_size.y); } // Start packing over current empty texture @@ -3745,7 +3763,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) } // Create initial texture size if (atlas->TexData == NULL) - ImFontAtlasBuildAddTexture(atlas, 512, 128); + ImFontAtlasBuildAddTexture(atlas, IM_FONTATLAS_DEFAULT_TEXTURE_SIZE.x, IM_FONTATLAS_DEFAULT_TEXTURE_SIZE.y); const bool builder_is_new = (builder == NULL); if (builder_is_new) diff --git a/imgui_internal.h b/imgui_internal.h index 2c97cae01e28..53f0dbd075bd 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3712,6 +3712,7 @@ IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); +IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); From df8450d928822f8dacd9f07e0bc50dd095c8228d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Dec 2024 22:33:11 +0100 Subject: [PATCH 456/716] Fonts: marked ImFontAtlas::Build() as obsolete --- imgui.cpp | 4 ++-- imgui.h | 6 +++--- imgui_draw.cpp | 43 +++++++++++++++++++++++-------------------- imgui_internal.h | 1 + 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ce2b06462e03..249456c7ec57 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5243,9 +5243,9 @@ void ImGui::NewFrame() // Check that font atlas was built or backend support texture reload in which case we can build now ImFontAtlas* atlas = g.IO.Fonts; if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) - atlas->Build(); + ImFontAtlasBuildMain(atlas); else // Legacy backend - IM_ASSERT(atlas->TexIsBuilt && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"); + IM_ASSERT(atlas->TexIsBuilt && "Backend does not support ImGuiBackendFlags_RendererHasTexUpdates, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); // Check and assert for various common IO and Configuration mistakes ErrorCheckNewFrameSanityChecks(); diff --git a/imgui.h b/imgui.h index 3ce13eb8836e..7d04ebcd2855 100644 --- a/imgui.h +++ b/imgui.h @@ -3530,15 +3530,15 @@ struct ImFontAtlas IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void BuildGrowTexture(); + IMGUI_API void BuildCompactTexture(); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). // The pitch is always = Width * BytesPerPixels (1 or 4) // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. - IMGUI_API void BuildGrowTexture(); - IMGUI_API void BuildCompactTexture(); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel void SetTexID(ImTextureID id) { TexRef._TexData = NULL; TexRef._TexID = id; } // Called by legacy backends. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 631cb22e6832..13060843e11d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2466,9 +2466,9 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasTextureBlockCopy() // - ImFontAtlasTextureBlockQueueUpload() //----------------------------------------------------------------------------- +// - ImFontAtlas::Build() [legacy] // - ImFontAtlas::GetTexDataAsAlpha8() [legacy] // - ImFontAtlas::GetTexDataAsRGBA32() [legacy] -// - ImFontAtlas::Build() //----------------------------------------------------------------------------- // - ImFontAtlas::AddFont() // - ImFontAtlas::AddFontDefault() @@ -2872,6 +2872,12 @@ void ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, { GetTexDataAsFormat(this, ImTextureFormat_RGBA32, out_pixels, out_width, out_height, out_bytes_per_pixel); } + +bool ImFontAtlas::Build() +{ + ImFontAtlasBuildMain(this); + return true; +} #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) @@ -3136,31 +3142,28 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } -bool ImFontAtlas::Build() +void ImFontAtlasBuildMain(ImFontAtlas* atlas) { - IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - - if (TexData && TexData->Format != TexDesiredFormat) + IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); + if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat) { - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(this); - ImFontAtlasBuildDestroy(this); - ImFontAtlasBuildAddTexture(this, new_tex_size.x, new_tex_size.y); + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); + ImFontAtlasBuildDestroy(atlas); + ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); } - if (Builder == NULL) - ImFontAtlasBuildInit(this); + if (atlas->Builder == NULL) + ImFontAtlasBuildInit(atlas); // Default font is none are specified - if (Sources.Size == 0) - AddFontDefault(); - - // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs - ImFontAtlasBuildUpdateRendererHasTexturesFromContext(this); - if (DrawListSharedData && DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures - ImFontAtlasBuildPreloadAllGlyphRanges(this); - TexIsBuilt = true; - - return true; + if (atlas->Sources.Size == 0) + atlas->AddFontDefault(); + + // [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs + ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); + if (atlas->DrawListSharedData && atlas->DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures + ImFontAtlasBuildPreloadAllGlyphRanges(atlas); + atlas->TexIsBuilt = true; } void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v) diff --git a/imgui_internal.h b/imgui_internal.h index 53f0dbd075bd..48090ee90e9b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3705,6 +3705,7 @@ IMGUI_API void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, IMGUI_API void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char); +IMGUI_API void ImFontAtlasBuildMain(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas); From cec3e945f02bb2fb2e12d1bbd984971ab4f2be37 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 19 Dec 2024 16:21:07 +0100 Subject: [PATCH 457/716] Fonts: added ImFontAtlas::RemoveFont(), fixed various leaks. --- imgui.cpp | 6 ++++ imgui.h | 5 ++-- imgui_draw.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++++--- imgui_internal.h | 1 + 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 249456c7ec57..adb1e84f11e3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16484,6 +16484,12 @@ void ImGui::DebugNodeFont(ImFont* font) } if (SmallButton("Set as default")) GetIO().FontDefault = font; + if (font->ContainerAtlas->Fonts.Size > 1 && !font->ContainerAtlas->Locked) + { + SameLine(); + if (SmallButton("Remove")) + font->ContainerAtlas->RemoveFont(font); + } // Display details SetNextItemWidth(GetFontSize() * 8); diff --git a/imgui.h b/imgui.h index 7d04ebcd2855..e237e90ae357 100644 --- a/imgui.h +++ b/imgui.h @@ -3521,10 +3521,11 @@ struct ImFontAtlas IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API void RemoveFont(ImFont* font); // FIXME-NEWATLAS: Clarify meaning/purpose - IMGUI_API void Clear(); // Clear all input and output. - IMGUI_API void ClearCache(); // Clear cached glyphs + IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) + IMGUI_API void ClearCache(); // Clear cached glyphs and textures. // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 13060843e11d..faabec1d56b0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2476,6 +2476,8 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::AddFontFromMemoryTTF() // - ImFontAtlas::AddFontFromMemoryCompressedTTF() // - ImFontAtlas::AddFontFromMemoryCompressedBase85TTF() +// - ImFontAtlas::RemoveFont() +// - ImFontAtlasBuildNotifySetFont() //----------------------------------------------------------------------------- // - ImFontAtlas::AddCustomRectRegular() // - ImFontAtlas::AddCustomRectFontGlyph() @@ -2593,11 +2595,15 @@ void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); for (ImFontConfig& font_cfg : Sources) + { + if (FontLoader && FontLoader->FontSrcDestroy != NULL) + FontLoader->FontSrcDestroy(this, &font_cfg); if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas) { IM_FREE(font_cfg.FontData); font_cfg.FontData = NULL; } + } // When clearing this we lose access to the font name and other information used to build the font. for (ImFont* font : Fonts) @@ -2641,12 +2647,12 @@ void ImFontAtlas::ClearFonts() void ImFontAtlas::Clear() { //IM_DELETE(Builder); // FIXME-NEW-ATLAS: Clarify ClearXXX functions - const ImFontLoader* font_loader = FontLoader; - ImFontAtlasBuildSetupFontLoader(this, NULL); + //const ImFontLoader* font_loader = FontLoader; + //ImFontAtlasBuildSetupFontLoader(this, NULL); ClearInputData(); ClearTexData(); ClearFonts(); - ImFontAtlasBuildSetupFontLoader(this, font_loader); + //ImFontAtlasBuildSetupFontLoader(this, font_loader); } // FIXME-NEWATLAS: Too widespread purpose. Clarify each call site in current WIP demo. @@ -3041,6 +3047,59 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed return font; } +// We allow old_font == new_font which forces updating all values (e.g. sizes) +static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font) +{ + if (ImDrawListSharedData* shared_data = atlas->DrawListSharedData) + { + if (shared_data->Font == old_font) + shared_data->Font = new_font; + if (ImGuiContext* ctx = shared_data->Context) + { + if (ctx->IO.FontDefault == old_font) + ctx->IO.FontDefault = new_font; + if (ctx->Font == old_font) + { + ImGuiContext* curr_ctx = ImGui::GetCurrentContext(); + bool need_bind_ctx = ctx != curr_ctx; + if (need_bind_ctx) + ImGui::SetCurrentContext(ctx); + ImGui::SetCurrentFont(new_font); + if (need_bind_ctx) + ImGui::SetCurrentContext(curr_ctx); + } + } + } +} + +void ImFontAtlas::RemoveFont(ImFont* font) +{ + IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); + ImFontAtlasBuildDiscardFontGlyphs(this, font); + + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; + if (FontLoader && FontLoader->FontSrcDestroy != NULL) + FontLoader->FontSrcDestroy(this, src); + if (src->FontData != NULL && src->FontDataOwnedByAtlas) + IM_FREE(src->FontData); + } + + bool removed = Fonts.find_erase(font); + IM_ASSERT(removed); + + Sources.erase(font->Sources, font->Sources + font->SourcesCount); + ImFontAtlasBuildUpdatePointers(this); + + font->ContainerAtlas = NULL; + IM_DELETE(font); + + // Notify external systems + ImFont* new_current_font = Fonts.empty() ? NULL : Fonts[0]; + ImFontAtlasBuildNotifySetFont(this, font, new_current_font); +} + // FIXME-NEWATLAS-V1: Feature is broken for now. /* // Register custom rectangle glyphs @@ -3485,13 +3544,19 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr font->LockSingleSrcConfigIdx = -1; } -void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font) { for (ImFontGlyph& glyph : font->Glyphs) if (glyph.PackId >= 0) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); font->BuildClearGlyphs(); + font->FallbackChar = font->EllipsisChar = 0; +} +// Discard old glyphs and reload font. Use if changing font size. +void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) +{ + ImFontAtlasBuildDiscardFontGlyphs(atlas, font); for (int src_n = 0; src_n < font->SourcesCount; src_n++) { ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; @@ -3505,6 +3570,9 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. } + + // Notify external systems + ImFontAtlasBuildNotifySetFont(atlas, font, font); } // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* @@ -4023,11 +4091,13 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)src->FontData, src->FontNo); if (font_offset < 0) { + IM_DELETE(bd_font_data); IM_ASSERT_USER_ERROR(0, "stbtt_GetFontOffsetForIndex(): FontData is incorrect, or FontNo cannot be found."); return false; } if (!stbtt_InitFont(&bd_font_data->FontInfo, (unsigned char*)src->FontData, font_offset)) { + IM_DELETE(bd_font_data); IM_ASSERT_USER_ERROR(0, "stbtt_InitFont(): failed to parse FontData. It is correct and complete? Check FontDataSize."); return false; } diff --git a/imgui_internal.h b/imgui_internal.h index 48090ee90e9b..f340b8e5e1ef 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3717,6 +3717,7 @@ IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); From a2bc3d81c2f1866dc6abc454221adfb6b5c0ef43 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 27 Dec 2024 11:23:22 +0100 Subject: [PATCH 458/716] Fonts: Fixed support for multiple contexts. --- imgui.cpp | 7 +++-- imgui.h | 3 +- imgui_draw.cpp | 77 ++++++++++++++++++++++++------------------------ imgui_internal.h | 1 - 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index adb1e84f11e3..0cf8bce2140b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5184,7 +5184,8 @@ static void ImGui::UpdateTexturesNewFrame() // FIXME-NEWATLAS: How to reach/target all atlas? ImGuiContext& g = *GImGui; ImFontAtlas* atlas = g.IO.Fonts; - ImFontAtlasUpdateNewFrame(atlas); + if (g.FontAtlasOwnedByContext) + ImFontAtlasUpdateNewFrame(atlas); } // Build a single texture list @@ -5245,7 +5246,7 @@ void ImGui::NewFrame() if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) ImFontAtlasBuildMain(atlas); else // Legacy backend - IM_ASSERT(atlas->TexIsBuilt && "Backend does not support ImGuiBackendFlags_RendererHasTexUpdates, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); + IM_ASSERT(atlas->TexIsBuilt && "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); // Check and assert for various common IO and Configuration mistakes ErrorCheckNewFrameSanityChecks(); @@ -15615,7 +15616,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL")) { const ImFontLoader* loader_current = atlas->FontLoader; - BeginDisabled(!atlas->DrawListSharedData || !atlas->DrawListSharedData->RendererHasTextures); + BeginDisabled(!atlas->RendererHasTextures); #ifdef IMGUI_ENABLE_STB_TRUETYPE const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype(); if (RadioButton("stb_truetype", loader_current == loader_stbtruetype)) diff --git a/imgui.h b/imgui.h index e237e90ae357..2fb54a511ece 100644 --- a/imgui.h +++ b/imgui.h @@ -3603,6 +3603,7 @@ struct ImFontAtlas ImTextureData* TexData; // Current texture ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. bool TexIsBuilt; // Set when texture was built matching current font input bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight) @@ -3612,7 +3613,7 @@ struct ImFontAtlas //ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID - ImDrawListSharedData* DrawListSharedData; // In principle this could become an array (e.g. multiple contexts using same atlas) + ImVector DrawListSharedDatas; // [Internal] Font builder ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public diff --git a/imgui_draw.cpp b/imgui_draw.cpp index faabec1d56b0..b6280afb6333 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -390,7 +390,6 @@ ImDrawListSharedData::ImDrawListSharedData() ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); } ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); - RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. } ImDrawListSharedData::~ImDrawListSharedData() @@ -2580,6 +2579,7 @@ ImFontAtlas::ImFontAtlas() memset(this, 0, sizeof(*this)); TexDesiredFormat = ImTextureFormat_RGBA32; TexGlyphPadding = 1; + RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. TexRef._TexData = NULL;// this; TexNextUniqueID = 1; Builder = NULL; @@ -2637,10 +2637,10 @@ void ImFontAtlas::ClearFonts() ClearInputData(); Fonts.clear_delete(); TexIsBuilt = false; - if (DrawListSharedData) + for (ImDrawListSharedData* shared_data : DrawListSharedDatas) { - DrawListSharedData->Font = NULL; - DrawListSharedData->FontScale = DrawListSharedData->FontSize = 0.0f; + shared_data->Font = NULL; + shared_data->FontScale = shared_data->FontSize = 0.0f; } } @@ -2681,18 +2681,21 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at // time of an early call to Build(), it would be impossible for us to tell if the backend supports texture update. // - Without this hack, we would have quite a pitfall as many legacy codebases have an early call to Build(). // Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare. - if (atlas->DrawListSharedData) - if (ImGuiContext* imgui_ctx = atlas->DrawListSharedData->Context) - atlas->DrawListSharedData->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; + for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) + if (ImGuiContext* imgui_ctx = shared_data->Context) + { + atlas->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; + break; + } } -// Called by NewFrame() +// Called by NewFrame(). When multiple context own the atlas, only the first one calls this. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) { if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) { ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); - IM_ASSERT_USER_ERROR(atlas->DrawListSharedData->RendererHasTextures == false, + IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); } @@ -3050,7 +3053,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed // We allow old_font == new_font which forces updating all values (e.g. sizes) static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font) { - if (ImDrawListSharedData* shared_data = atlas->DrawListSharedData) + for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) { if (shared_data->Font == old_font) shared_data->Font = new_font; @@ -3124,7 +3127,7 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); - if (DrawListSharedData && DrawListSharedData->RendererHasTextures) + if (RendererHasTextures) { ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); @@ -3220,7 +3223,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) // [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); - if (atlas->DrawListSharedData && atlas->DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures + if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures ImFontAtlasBuildPreloadAllGlyphRanges(atlas); atlas->TexIsBuilt = true; } @@ -3578,48 +3581,46 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) { - IM_ASSERT(atlas->DrawListSharedData == NULL && data->FontAtlas == NULL); - atlas->DrawListSharedData = data; + IM_ASSERT(!atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == NULL); + atlas->DrawListSharedDatas.push_back(data); data->FontAtlas = atlas; } void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) { - IM_ASSERT(atlas->DrawListSharedData == data && data->FontAtlas == atlas); - atlas->DrawListSharedData = data; + IM_ASSERT(atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == atlas); + atlas->DrawListSharedDatas.find_erase(data); data->FontAtlas = NULL; } // Update texture identifier in all active draw lists void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex) { - ImDrawListSharedData* shared_data = atlas->DrawListSharedData; - if (shared_data == NULL) - return; - for (ImDrawList* draw_list : shared_data->DrawLists) - { - // Replace in command-buffer - // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[], - // other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow) - if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex) - draw_list->_SetTexture(new_tex); - - // Replace in stack - for (ImTextureRef& stacked_tex : draw_list->_TextureStack) - if (stacked_tex == old_tex) - stacked_tex = new_tex; - } + for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) + for (ImDrawList* draw_list : shared_data->DrawLists) + { + // Replace in command-buffer + // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[], + // other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow) + if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex) + draw_list->_SetTexture(new_tex); + + // Replace in stack + for (ImTextureRef& stacked_tex : draw_list->_TextureStack) + if (stacked_tex == old_tex) + stacked_tex = new_tex; + } } // Update texture coordinates in all draw list shared context void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) { - ImDrawListSharedData* shared_data = atlas->DrawListSharedData; - if (shared_data == NULL) - return; - shared_data->FontAtlas = atlas; - shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; - shared_data->TexUvLines = atlas->TexUvLines; + for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) + { + shared_data->FontAtlas = atlas; + shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; + shared_data->TexUvLines = atlas->TexUvLines; + } } // Set current texture. This is mostly called from AddTexture() + to handle a failed resize. diff --git a/imgui_internal.h b/imgui_internal.h index f340b8e5e1ef..830ca9c6e543 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -821,7 +821,6 @@ struct IMGUI_API ImDrawListSharedData ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. float ArcFastRadiusCutoff; // Cutoff radius after which arc drawing will fallback to slower PathArcTo() ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead) - bool RendererHasTextures; // Copy of (GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures). ImDrawListSharedData(); ~ImDrawListSharedData(); From 4ff1631b316fe849da9a649cf30a79aad752d8bb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 8 Jan 2025 19:07:40 +0100 Subject: [PATCH 459/716] Fonts: Rasterizing ellipsis character from dot as one glyph + avoid preloading if it not needed. # Conflicts: # imgui.cpp --- imgui.cpp | 5 ++- imgui.h | 7 ++-- imgui_draw.cpp | 85 +++++++++++++++++++++++++++++++++++++++--------- imgui_internal.h | 1 + 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0cf8bce2140b..7ac49382e77e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3738,7 +3738,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con const float font_size = draw_list->_Data->FontSize; const float font_scale = draw_list->_Data->FontScale; const char* text_end_ellipsis = NULL; - const float ellipsis_width = font->EllipsisWidth * font_scale; + const float ellipsis_width = font->GetCharAdvance(font->EllipsisChar) * font_scale; // We can now claim the space between pos_max.x and ellipsis_max.x const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); @@ -3754,8 +3754,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con RenderTextClippedEx(draw_list, pos_min, pos_max, text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f)); ImVec4 cpu_fine_clip_rect(pos_min.x, pos_min.y, pos_max.x, pos_max.y); ImVec2 ellipsis_pos = ImTrunc(ImVec2(pos_min.x + text_size_clipped_x, pos_min.y)); - for (int i = 0; i < font->EllipsisCharCount; i++, ellipsis_pos.x += font->EllipsisCharStep * font_scale) - font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar, &cpu_fine_clip_rect); + font->RenderChar(draw_list, font_size, ellipsis_pos, GetColorU32(ImGuiCol_Text), font->EllipsisChar, &cpu_fine_clip_rect); } else { diff --git a/imgui.h b/imgui.h index 2fb54a511ece..d5136e2a6614 100644 --- a/imgui.h +++ b/imgui.h @@ -3648,13 +3648,10 @@ struct ImFont // [Internal] Members: Cold ~32/40/60 bytes // Conceptually Sources[] is the list of font sources merged to create this font. short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. - short EllipsisCharCount; // 1 // out // 1 or 3 - ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). - ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into - float EllipsisWidth; // 4 // out // Total ellipsis Width - float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0 + ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). + ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b6280afb6333..83212712fd75 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2462,6 +2462,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasTextureBlockConvert() // - ImFontAtlasTextureBlockPostProcess() // - ImFontAtlasTextureBlockPostProcessMultiply() +// - ImFontAtlasTextureBlockFill() // - ImFontAtlasTextureBlockCopy() // - ImFontAtlasTextureBlockQueueUpload() //----------------------------------------------------------------------------- @@ -2490,6 +2491,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildUpdateBasicTexData() // - ImFontAtlasBuildUpdateLinesTexData() // - ImFontAtlasBuildAddFont() +// - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontSpecialGlyphs() // - ImFontAtlasBuildReloadFont() //----------------------------------------------------------------------------- @@ -2820,10 +2822,29 @@ void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data } } -// Convert block from one texture to another +// Fill with single color. We don't use this directly but it is convenient for anyone working on uploading custom rects. +void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col) +{ + if (dst_tex->Format == ImTextureFormat_Alpha8) + { + ImU8 col_a = (col >> IM_COL32_A_SHIFT) & 0xFF; + for (int y = 0; y < h; y++) + memset((ImU8*)dst_tex->GetPixelsAt(dst_x, dst_y + y), col_a, w); + } + else + { + for (int y = 0; y < h; y++) + { + ImU32* p = (ImU32*)(void*)dst_tex->GetPixelsAt(dst_x, dst_y + y); + for (int x = w; x > 0; x--, p++) + *p = col; + } + } +} + +// Copy block from one texture to another void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h) { - IM_ASSERT(src_tex != dst_tex); IM_ASSERT(src_tex->Pixels != NULL && dst_tex->Pixels != NULL); IM_ASSERT(src_tex->Format == dst_tex->Format); IM_ASSERT(src_x >= 0 && src_x + w <= src_tex->Width); @@ -3483,6 +3504,44 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) return true; } +// Rasterize our own ellipsis character from a dot. +// This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. +// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers. +static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* cfg, const ImFontGlyph* dot_glyph) +{ + ImFont* font = cfg->DstFont; + + ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId); + const int dot_spacing = 1; + const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; + ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h); + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + font->MetricsTotalSurface += r->w * r->h; + + ImFontGlyph glyph; + glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint. + glyph.AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. + glyph.X0 = dot_glyph->X0; + glyph.Y0 = dot_glyph->Y0; + glyph.X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing; + glyph.Y1 = dot_glyph->Y1; + glyph.U0 = (r->x) * atlas->TexUvScale.x; + glyph.V0 = (r->y) * atlas->TexUvScale.y; + glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; + glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + glyph.Visible = true; + glyph.PackId = pack_id; + font->BuildRegisterGlyph(cfg, &glyph); + font->EllipsisChar = (ImWchar)glyph.Codepoint; + + // Copy to texture, post-process and queue update for backend + // FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it. + ImTextureData* tex = atlas->TexData; + for (int n = 0; n < 3; n++) + ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h); + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); +} + // Load/identify special glyphs // (note that this is called again for fonts with MergeMode) void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src) @@ -3526,23 +3585,19 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr // FIXME: Note that 0x2026 is rarely included in our font ranges. Because of this we are more likely to use three individual dots. const ImWchar ellipsis_chars[] = { src->EllipsisChar, (ImWchar)0x2026, (ImWchar)0x0085 }; if (font->EllipsisChar == 0) - if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, ellipsis_chars, IM_ARRAYSIZE(ellipsis_chars))) - { - font->EllipsisChar = (ImWchar)glyph->Codepoint; - font->EllipsisCharCount = 1; - font->EllipsisWidth = font->EllipsisCharStep = glyph->X1; - } + for (ImWchar candidate_char : ellipsis_chars) + if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) + { + font->EllipsisChar = candidate_char; + break; + } if (font->EllipsisChar == 0) { - // FIXME-NEWATLAS-V2: We can now rasterize this into a regular character and register it! const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) - { - font->EllipsisChar = (ImWchar)dot_glyph->Codepoint; - font->EllipsisCharCount = 3; - font->EllipsisCharStep = (float)(int)(dot_glyph->X1 - dot_glyph->X0) + 1.0f; - font->EllipsisWidth = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + font->EllipsisCharStep * 3.0f - 1.0f); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. - } + ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, src, dot_glyph); + else + font->EllipsisChar = (ImWchar)' '; } font->LockSingleSrcConfigIdx = -1; } diff --git a/imgui_internal.h b/imgui_internal.h index 830ca9c6e543..bc98e83d2018 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3736,6 +3736,7 @@ IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); IMGUI_API void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data); IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor); +IMGUI_API void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h, ImU32 col); IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h); IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); From b06f3c6d1d02816b646a02fa3b30a15325d105fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 20:48:50 +0100 Subject: [PATCH 460/716] Fonts: turn public facing BuildRegisterGlyph() into ImFontAtlasBuildAddFontGlyph() thats sets up UV. --- imgui.h | 1 - imgui_draw.cpp | 55 +++++++++++++++++--------------- imgui_internal.h | 2 ++ misc/freetype/imgui_freetype.cpp | 10 ++---- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/imgui.h b/imgui.h index d5136e2a6614..c4e8818d1c21 100644 --- a/imgui.h +++ b/imgui.h @@ -3687,7 +3687,6 @@ struct ImFont IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c); - IMGUI_API void BuildRegisterGlyph(ImFontConfig* src, const ImFontGlyph* glyph); IMGUI_API void BuildGrowIndex(int new_size); IMGUI_API void BuildClearGlyphs(); }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 83212712fd75..f8797841b3ba 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3507,9 +3507,9 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) // Rasterize our own ellipsis character from a dot. // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. // FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers. -static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* cfg, const ImFontGlyph* dot_glyph) +static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* src, const ImFontGlyph* dot_glyph) { - ImFont* font = cfg->DstFont; + ImFont* font = src->DstFont; ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId); const int dot_spacing = 1; @@ -3525,13 +3525,9 @@ static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, I glyph.Y0 = dot_glyph->Y0; glyph.X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing; glyph.Y1 = dot_glyph->Y1; - glyph.U0 = (r->x) * atlas->TexUvScale.x; - glyph.V0 = (r->y) * atlas->TexUvScale.y; - glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; - glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; glyph.Visible = true; glyph.PackId = pack_id; - font->BuildRegisterGlyph(cfg, &glyph); + ImFontAtlasBuildAddFontGlyph(atlas, font, NULL, &glyph); font->EllipsisChar = (ImWchar)glyph.Codepoint; // Copy to texture, post-process and queue update for backend @@ -3577,7 +3573,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr ImFontGlyph tab_glyph; tab_glyph.Codepoint = '\t'; tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE; - font->BuildRegisterGlyph(font->Sources, &tab_glyph); + ImFontAtlasBuildAddFontGlyph(atlas, font, src, &tab_glyph); } // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). @@ -4282,13 +4278,9 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, glyph.Y0 = y0 * recip_v + font_off_y; glyph.X1 = (x0 + (int)r->w) * recip_h + font_off_x; glyph.Y1 = (y0 + (int)r->h) * recip_v + font_off_y; - glyph.U0 = (r->x) * atlas->TexUvScale.x; - glyph.V0 = (r->y) * atlas->TexUvScale.y; - glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; - glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; glyph.Visible = true; glyph.PackId = pack_id; - font->BuildRegisterGlyph(src, &glyph); + ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); // Copy to texture, post-process and queue update for backend ImTextureData* tex = atlas->TexData; @@ -4300,7 +4292,7 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, } else { - font->BuildRegisterGlyph(src, &glyph); + ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); } return true; @@ -4699,12 +4691,23 @@ void ImFont::BuildGrowIndex(int new_size) // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). // 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. -void ImFont::BuildRegisterGlyph(ImFontConfig* src, const ImFontGlyph* in_glyph) +ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph) { - int glyph_idx = Glyphs.Size; - Glyphs.push_back(*in_glyph); - ImFontGlyph& glyph = Glyphs[glyph_idx]; - IM_ASSERT(Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. + int glyph_idx = font->Glyphs.Size; + font->Glyphs.push_back(*in_glyph); + ImFontGlyph& glyph = font->Glyphs[glyph_idx]; + IM_ASSERT(font->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. + + // Set UV from packed rectangle + if (in_glyph->PackId >= 0) + { + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, in_glyph->PackId); + IM_ASSERT(in_glyph->U0 == 0.0f && in_glyph->V0 == 0.0f && in_glyph->U1 == 0.0f && in_glyph->V1 == 0.0f); + glyph.U0 = (r->x) * atlas->TexUvScale.x; + glyph.V0 = (r->y) * atlas->TexUvScale.y; + glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; + glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + } if (src != NULL) { @@ -4725,17 +4728,17 @@ void ImFont::BuildRegisterGlyph(ImFontConfig* src, const ImFontGlyph* in_glyph) glyph.AdvanceX = advance_x + src->GlyphExtraAdvanceX; } if (glyph.Colored) - ContainerAtlas->TexPixelsUseColors = ContainerAtlas->TexData->UseColors = true; + atlas->TexPixelsUseColors = atlas->TexData->UseColors = true; // Update lookup tables int codepoint = glyph.Codepoint; - BuildGrowIndex(codepoint + 1); - IndexAdvanceX[codepoint] = glyph.AdvanceX; - IndexLookup[codepoint] = (ImU16)glyph_idx; - - // Mark 4K page as used + font->BuildGrowIndex(codepoint + 1); + font->IndexAdvanceX[codepoint] = glyph.AdvanceX; + font->IndexLookup[codepoint] = (ImU16)glyph_idx; const int page_n = codepoint / 8192; - Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + font->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + + return &glyph; } void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) diff --git a/imgui_internal.h b/imgui_internal.h index bc98e83d2018..212dafbaf4c5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3721,6 +3721,8 @@ IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFon IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); +IMGUI_API ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* cfg, const ImFontGlyph* in_glyph); + IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index efe8612baa31..92238f7fdaef 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -529,14 +529,10 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon glyph.Y0 = glyph_off_y * recip_v + font_off_y; glyph.X1 = (glyph_off_x + w) * recip_h + font_off_x; glyph.Y1 = (glyph_off_y + h) * recip_v + font_off_y; - glyph.U0 = (r->x) * atlas->TexUvScale.x; - glyph.V0 = (r->y) * atlas->TexUvScale.y; - glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; - glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; - glyph.PackId = pack_id; glyph.Visible = true; glyph.Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); - font->BuildRegisterGlyph(src, &glyph); + glyph.PackId = pack_id; + ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); // Copy to texture, post-process and queue update for backend ImTextureData* tex = atlas->TexData; @@ -548,7 +544,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon } else { - font->BuildRegisterGlyph(src, &glyph); + ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); } return true; } From 14614f561b966913d595eb8904e04f66ba23ffb1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 20:57:20 +0100 Subject: [PATCH 461/716] Textures: Ensure UpdateBox is set on texture _WantCreate state too. --- imgui_draw.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f8797841b3ba..d8d46e2799a8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2435,6 +2435,8 @@ void ImTextureData::Create(ImTextureFormat format, int w, int h) Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel); IM_ASSERT(Pixels != NULL); memset(Pixels, 0, Width * Height * BytesPerPixel); + UpdateRect.x = UpdateRect.y = (unsigned short)~0; + UpdateRect.w = UpdateRect.h = 0; } void ImTextureData::DestroyPixels() @@ -2705,9 +2707,12 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) { ImTextureData* tex = atlas->TexList[tex_n]; bool remove_from_list = false; - tex->Updates.resize(0); - tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0; - tex->UpdateRect.w = tex->UpdateRect.h = 0; + if (tex->Status == ImTextureStatus_OK) + { + tex->Updates.resize(0); + tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0; + tex->UpdateRect.w = tex->UpdateRect.h = 0; + } if (tex->Status == ImTextureStatus_Destroyed) { @@ -2858,22 +2863,23 @@ void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, I // Queue texture block update for renderer backend void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h) { - // Queue texture update (no need to queue if status is _WantCreate) - IM_ASSERT(atlas); + IM_ASSERT(tex->Status != ImTextureStatus_WantDestroy && tex->Status != ImTextureStatus_Destroyed); + IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000); + IM_UNUSED(atlas); + + ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h }; + int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w); + int new_y1 = ImMax(tex->UpdateRect.h == 0 ? 0 : tex->UpdateRect.y + tex->UpdateRect.h, req.y + req.h); + tex->UpdateRect.x = ImMin(tex->UpdateRect.x, req.x); + tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y); + tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x); + tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y); + + // No need to queue if status is _WantCreate if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates) { - IM_ASSERT(x >= 0 && x <= 0xFFFF && y >= 0 && y <= 0xFFFF && w >= 0 && x + w <= 0x10000 && h >= 0 && y + h <= 0x10000); - ImTextureRect req = { (unsigned short)x, (unsigned short)y, (unsigned short)w, (unsigned short)h }; tex->Status = ImTextureStatus_WantUpdates; tex->Updates.push_back(req); - int new_x1 = ImMax(tex->UpdateRect.w == 0 ? 0 : tex->UpdateRect.x + tex->UpdateRect.w, req.x + req.w); - int new_y1 = ImMax(tex->UpdateRect.h == 0 ? 0 : tex->UpdateRect.y + tex->UpdateRect.h, req.y + req.h); - IM_ASSERT(new_x1 < 0x8000); - IM_ASSERT(new_y1 < 0x8000); - tex->UpdateRect.x = ImMin(tex->UpdateRect.x, req.x); - tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y); - tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x); - tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y); } } @@ -3403,6 +3409,7 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r->y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); } } + ImFontAtlasTextureBlockQueueUpload(atlas, atlas->TexData, r->x, r->y, r->w, r->h); atlas->TexUvWhitePixel = ImVec2((r->x + 0.5f) * atlas->TexUvScale.x, (r->y + 0.5f) * atlas->TexUvScale.y); } @@ -3472,6 +3479,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); } + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } //----------------------------------------------------------------------------------------------------------------------------- From 2137b3448b61c389d706da3deed092e32128f5c8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 9 Jan 2025 23:04:00 +0100 Subject: [PATCH 462/716] Textures: Added atlas's TexMinWidth/TexMinHeight/TexMaxWidth/TexMaxHeight. Fixed ImFontAtlasBuildGetTextureSizeEstimate(). Basic error handling on OOM. --- imgui.h | 4 ++++ imgui_draw.cpp | 39 +++++++++++++++++++++++++------- imgui_internal.h | 2 +- misc/freetype/imgui_freetype.cpp | 7 ++++++ 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index c4e8818d1c21..56366ae1e1f4 100644 --- a/imgui.h +++ b/imgui.h @@ -3596,6 +3596,10 @@ struct ImFontAtlas ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_) ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8). int TexGlyphPadding; // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false). + int TexMinWidth; // Minimum desired texture width. Must be a power of two. Default to 512. + int TexMinHeight; // Minimum desired texture height. Must be a power of two. Default to 128. + int TexMaxWidth; // Maximum desired texture width. Must be a power of two. Default to 8192. + int TexMaxHeight; // Maximum desired texture height. Must be a power of two. Default to 8192. void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // [Internal] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d8d46e2799a8..040157190ac4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2576,13 +2576,16 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3 #define IM_FONTGLYPH_INDEX_UNUSED ((ImU16)-1) // 0xFFFF #define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE -#define IM_FONTATLAS_DEFAULT_TEXTURE_SIZE ImVec2i(512, 128) ImFontAtlas::ImFontAtlas() { memset(this, 0, sizeof(*this)); TexDesiredFormat = ImTextureFormat_RGBA32; TexGlyphPadding = 1; + TexMinWidth = 512; + TexMinHeight = 128; + TexMaxWidth = 8192; + TexMaxHeight = 8192; RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. TexRef._TexData = NULL;// this; TexNextUniqueID = 1; @@ -3248,7 +3251,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) if (atlas->Sources.Size == 0) atlas->AddFontDefault(); - // [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs + // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures ImFontAtlasBuildPreloadAllGlyphRanges(atlas); @@ -3268,7 +3271,7 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon return; IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); - // Note that texture size estimate is likely incorrect in this situation, as Freetype backend doesn't use oversampling. + // Note that texture size estimate is likely incorrect in this situation, as FreeType backend doesn't use oversampling. ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); @@ -3390,6 +3393,8 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ if (add_and_draw) builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); + if (builder->PackIdMouseCursors < 0) + return; ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); // Draw to texture @@ -3424,6 +3429,8 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ ImFontAtlasBuilder* builder = atlas->Builder; if (add_and_draw) builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); + if (builder->PackIdLinesTexData < 0) + return; ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); // Register texture region for thick lines @@ -3813,6 +3820,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend? // FIXME-NEWATLAS-V2: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); + IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); // Grow texture so it follows roughly a square. // FIXME-NEWATLAS-V1: Take account of RectsDiscardedSurface: may not need to grow. @@ -3823,19 +3831,24 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ const int pack_padding = atlas->TexGlyphPadding; new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + pack_padding)); new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + pack_padding)); + new_tex_w = ImClamp(new_tex_w, atlas->TexMinWidth, atlas->TexMaxWidth); + new_tex_h = ImClamp(new_tex_h, atlas->TexMinHeight, atlas->TexMaxHeight); + if (new_tex_w == old_tex_w && new_tex_h == old_tex_h) + return; ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); } -// FIXME-NEWATLAS: Expose atlas->TexMinWidth etc. ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) { + int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth); + int min_h = ImUpperPowerOfTwo(atlas->TexMinHeight); if (atlas->Builder == NULL || atlas->TexData == NULL || atlas->TexData->Status == ImTextureStatus_WantDestroy) - return IM_FONTATLAS_DEFAULT_TEXTURE_SIZE; + return ImVec2i(min_w, min_h); ImFontAtlasBuilder* builder = atlas->Builder; - const int min_w = ImMax(builder->MaxRectSize.x, 512); - const int min_h = builder->MaxRectSize.y; + min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w); + min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h); const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack const int surface_sqrt = (int)sqrtf((float)surface_approx); @@ -3855,6 +3868,8 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) new_tex_h = ImUpperPowerOfTwo(new_tex_h); new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / new_tex_h)); } + + IM_ASSERT(ImIsPowerOfTwo(new_tex_w) && ImIsPowerOfTwo(new_tex_h)); return ImVec2i(new_tex_w, new_tex_h); } @@ -3894,7 +3909,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) } // Create initial texture size if (atlas->TexData == NULL) - ImFontAtlasBuildAddTexture(atlas, IM_FONTATLAS_DEFAULT_TEXTURE_SIZE.x, IM_FONTATLAS_DEFAULT_TEXTURE_SIZE.y); + ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); const bool builder_is_new = (builder == NULL); if (builder_is_new) @@ -4051,6 +4066,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { + IM_ASSERT(id >= 0); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; IM_ASSERT(index_entry->Used); @@ -4255,6 +4271,13 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, const int w = (x1 - x0 + oversample_h - 1); const int h = (y1 - y0 + oversample_v - 1); ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); + if (pack_id < 0) + { + // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) + IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); + return false; + } + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); font->MetricsTotalSurface += w * h; diff --git a/imgui_internal.h b/imgui_internal.h index 212dafbaf4c5..2e84a5554472 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3696,7 +3696,7 @@ struct ImFontAtlasBuilder ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure. ImFontAtlasRectId PackIdLinesTexData; - ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; } + ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; } }; // FIXME-NEWATLAS: Cleanup diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 92238f7fdaef..b388d15314e8 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -509,6 +509,13 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon if (is_visible) { ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); + if (pack_id < 0) + { + // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) + IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); + return false; + } + ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); font->MetricsTotalSurface += w * h; From 8ed4e2dde7a2832c28d2c20a6a5f97220a0e3d9f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 17:56:36 +0100 Subject: [PATCH 463/716] Fonts: Basic heuristic to repack instead of growing. Moved rects count/surface to internals. --- imgui.cpp | 4 ++-- imgui.h | 2 -- imgui_draw.cpp | 33 ++++++++++++++++++++++----------- imgui_internal.h | 3 +++ 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7ac49382e77e..e617a84d799e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15594,7 +15594,7 @@ static void MetricsHelpMarker(const char* desc) } #ifdef IMGUI_ENABLE_FREETYPE -namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetBackendIOForFreeType(); } +namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); } #endif // [DEBUG] List fonts in a font atlas and display its texture @@ -15628,7 +15628,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) #endif SameLine(); #ifdef IMGUI_ENABLE_FREETYPE - const ImFontLoader* loader_freetype = ImGuiFreeType::GetBackendIOForFreeType(); + const ImFontLoader* loader_freetype = ImGuiFreeType::GetFontLoader(); if (RadioButton("FreeType", loader_current == loader_freetype)) ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); #else diff --git a/imgui.h b/imgui.h index 56366ae1e1f4..c04d1175a8a0 100644 --- a/imgui.h +++ b/imgui.h @@ -3626,8 +3626,6 @@ struct ImFontAtlas void* FontLoaderData; // Font backend opaque storage unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. int RefCount; // Number of contexts using this atlas - int _PackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size. - int _PackedRects; // Number of packed rectangles. // [Obsolete] //int TexDesiredWidth; // OBSOLETED in 1.91.5 (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 040157190ac4..65e806c54106 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2504,6 +2504,7 @@ void ImTextureData::DestroyPixels() //----------------------------------------------------------------------------- // - ImFontAtlasBuildSetTexture() // - ImFontAtlasBuildAddTexture() +// - ImFontAtlasBuildMakeSpace() // - ImFontAtlasBuildRepackTexture() // - ImFontAtlasBuildGrowTexture() // - ImFontAtlasBuildCompactTexture() @@ -3521,7 +3522,7 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) // Rasterize our own ellipsis character from a dot. // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. -// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers. +// FIXME-NEWATLAS: This borrows too much from FontLoader's FontAddGlyph() and suggest that we should add further helpers. static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* src, const ImFontGlyph* dot_glyph) { ImFont* font = src->DstFont; @@ -3823,7 +3824,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); // Grow texture so it follows roughly a square. - // FIXME-NEWATLAS-V1: Take account of RectsDiscardedSurface: may not need to grow. + // Caller should be taking account of RectsDiscardedSurface and may not need to grow. int new_tex_w = (old_tex_h < old_tex_w) ? old_tex_w : old_tex_w * 2; int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h; @@ -3839,6 +3840,16 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); } +void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) +{ + // Currently using a heuristic for repack without growing. + ImFontAtlasBuilder* builder = atlas->Builder; + if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f) + ImFontAtlasBuildGrowTexture(atlas); + else + ImFontAtlasBuildRepackTexture(atlas, atlas->TexData->Width, atlas->TexData->Height); +} + ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) { int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth); @@ -3849,7 +3860,7 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) ImFontAtlasBuilder* builder = atlas->Builder; min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w); min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h); - const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack + const int surface_approx = builder->RectsPackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack const int surface_sqrt = (int)sqrtf((float)surface_approx); int new_tex_w; @@ -3893,10 +3904,10 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) ImFontAtlasBuilder* builder = atlas->Builder; // Select Backend - // - Note that we do not reassign to atlas->FontBackendIO, since it is likely to point to static data which + // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are - // using a hot-reloading scheme that messes up static data, store your own instance of ImFontBackendIO somewhere - // and point to it instead of pointing directly to return value of the GetBackendIOXXX functions. + // using a hot-reloading scheme that messes up static data, store your own instance of FontLoader somewhere + // and point to it instead of pointing directly to return value of the GetFontLoaderXXX functions. if (atlas->FontLoader == NULL) { #ifdef IMGUI_ENABLE_FREETYPE @@ -3958,7 +3969,7 @@ void ImFontAtlasPackInit(ImFontAtlas * atlas) builder->PackNodes.resize(pack_node_count); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); - atlas->_PackedSurface = atlas->_PackedRects = 0; + builder->RectsPackedSurface = builder->RectsPackedCount = 0; builder->MaxRectSize = ImVec2i(0, 0); builder->MaxRectBounds = ImVec2i(0, 0); } @@ -4041,14 +4052,14 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon return -1; } - // Resize atlas! (this should be a rare event) - ImFontAtlasBuildGrowTexture(atlas); + // Resize or repack atlas! (this should be a rare event) + ImFontAtlasBuildMakeSpace(atlas); } builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding); builder->MaxRectBounds.y = ImMax(builder->MaxRectBounds.y, r.y + r.h + pack_padding); - atlas->_PackedSurface += (w + pack_padding) * (h + pack_padding); - atlas->_PackedRects++; + builder->RectsPackedCount++; + builder->RectsPackedSurface += (w + pack_padding) * (h + pack_padding); builder->Rects.push_back(r); if (overwrite_entry != NULL) diff --git a/imgui_internal.h b/imgui_internal.h index 2e84a5554472..71019611ac9c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3685,6 +3685,8 @@ struct ImFontAtlasBuilder ImVector RectsIndex; // ImFontAtlasRectId -> index into Rects[] ImVector TempBuffer; // Misc scratch buffer int RectsIndexFreeListStart;// First unused entry + int RectsPackedCount; // Number of packed rectangles. + int RectsPackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size. int RectsDiscardedCount; int RectsDiscardedSurface; ImVec2i MaxRectSize; // Largest rectangle to pack (de-facto used as a "minimum texture size") @@ -3709,6 +3711,7 @@ IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas); IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); +IMGUI_API void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); From 288055180e097cf9260bae7cc15339382a02771a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 20:03:09 +0100 Subject: [PATCH 464/716] Fonts: Comments, remove ImFontAtlas facing BuildGrowTexture(), BuildCompactTexture(). Make IsBuilt() obsolete. --- imgui.cpp | 4 +- imgui.h | 9 ++--- imgui_draw.cpp | 97 +++++++++++++++++++++--------------------------- imgui_internal.h | 24 +++++------- 4 files changed, 58 insertions(+), 76 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e617a84d799e..a505d5d6cb23 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5180,7 +5180,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) static void ImGui::UpdateTexturesNewFrame() { - // FIXME-NEWATLAS: How to reach/target all atlas? + // FIXME-NEWATLAS-V2: If we aim to support multiple atlases used by same context: how to reach/target all atlases? ImGuiContext& g = *GImGui; ImFontAtlas* atlas = g.IO.Fonts; if (g.FontAtlasOwnedByContext) @@ -8607,7 +8607,7 @@ void ImGui::SetCurrentFont(ImFont* font) // - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() // the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem // because we have a concrete need and a test bed for multiple atlas textures. -// FIXME-NEWATLAS: perhaps we can now leverage ImFontAtlasUpdateDrawListsTextures() ? +// FIXME-NEWATLAS-V2: perhaps we can now leverage ImFontAtlasUpdateDrawListsTextures() ? void ImGui::PushFont(ImFont* font) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index c04d1175a8a0..19c116cab5fa 100644 --- a/imgui.h +++ b/imgui.h @@ -3336,6 +3336,7 @@ struct ImDrawData //----------------------------------------------------------------------------- // We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. +// Most standard backends only support RGBA32 but we provide a single channel option for low-resource/embedded systems. enum ImTextureFormat { ImTextureFormat_RGBA32, // 4 components per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 @@ -3523,16 +3524,14 @@ struct ImFontAtlas IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. IMGUI_API void RemoveFont(ImFont* font); - // FIXME-NEWATLAS: Clarify meaning/purpose IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) IMGUI_API void ClearCache(); // Clear cached glyphs and textures. + // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. - IMGUI_API void BuildGrowTexture(); - IMGUI_API void BuildCompactTexture(); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Build atlas, retrieve pixel data. // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). @@ -3544,8 +3543,8 @@ struct ImFontAtlas IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel void SetTexID(ImTextureID id) { TexRef._TexData = NULL; TexRef._TexID = id; } // Called by legacy backends. void SetTexID(ImTextureRef id) { TexRef = id; } // Called by legacy backends. + bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... #endif - bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... //------------------------------------------- // Glyph Ranges @@ -3693,7 +3692,7 @@ struct ImFont IMGUI_API void BuildClearGlyphs(); }; -// FIXME-NEWATLAS: Added indirection to avoid patching ImDrawCmd after texture updates. +// Added indirection to avoid patching ImDrawCmd after texture updates. inline ImTextureID ImDrawCmd::GetTexID() const { // If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 65e806c54106..3369aabe9c63 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2451,16 +2451,14 @@ void ImTextureData::DestroyPixels() // [SECTION] ImFontAtlas, ImFontAtlasBuilder //----------------------------------------------------------------------------- // - Default texture data encoded in ASCII -// - ImFontAtlasBuilder +// - ImFontAtlas() +// - ImFontAtlas::Clear() +// - ImFontAtlas::ClearCache() // - ImFontAtlas::ClearInputData() // - ImFontAtlas::ClearTexData() // - ImFontAtlas::ClearFonts() -// - ImFontAtlas::Clear() -// - ImFontAtlas::ClearCache() -// - ImFontAtlas::BuildGrowTexture() -// - ImFontAtlas::BuildCompactTexture() -// - ImFontAtlasUpdateTextures() //----------------------------------------------------------------------------- +// - ImFontAtlasUpdateNewFrame() // - ImFontAtlasTextureBlockConvert() // - ImFontAtlasTextureBlockPostProcess() // - ImFontAtlasTextureBlockPostProcessMultiply() @@ -2468,9 +2466,9 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasTextureBlockCopy() // - ImFontAtlasTextureBlockQueueUpload() //----------------------------------------------------------------------------- -// - ImFontAtlas::Build() [legacy] // - ImFontAtlas::GetTexDataAsAlpha8() [legacy] // - ImFontAtlas::GetTexDataAsRGBA32() [legacy] +// - ImFontAtlas::Build() [legacy] //----------------------------------------------------------------------------- // - ImFontAtlas::AddFont() // - ImFontAtlas::AddFontDefault() @@ -2483,6 +2481,7 @@ void ImTextureData::DestroyPixels() //----------------------------------------------------------------------------- // - ImFontAtlas::AddCustomRectRegular() // - ImFontAtlas::AddCustomRectFontGlyph() +// - ImFontAtlas::GetCustomRectByIndex() // - ImFontAtlas::CalcCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- @@ -2495,6 +2494,8 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildAddFont() // - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontSpecialGlyphs() +// - ImFontAtlasBuildDiscardFontGlyph() +// - ImFontAtlasBuildDiscardFontGlyphs() // - ImFontAtlasBuildReloadFont() //----------------------------------------------------------------------------- // - ImFontAtlasAddDrawListSharedData() @@ -2507,11 +2508,15 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildMakeSpace() // - ImFontAtlasBuildRepackTexture() // - ImFontAtlasBuildGrowTexture() +// - ImFontAtlasBuildRepackOrGrowTexture() +// - ImFontAtlasBuildGetTextureSizeEstimate() // - ImFontAtlasBuildCompactTexture() // - ImFontAtlasBuildInit() // - ImFontAtlasBuildDestroy() //----------------------------------------------------------------------------- // - ImFontAtlasPackInit() +// - ImFontAtlasPackAllocRectEntry() +// - ImFontAtlasPackDiscardRect() // - ImFontAtlasPackAddRect() // - ImFontAtlasPackGetRect() //----------------------------------------------------------------------------- @@ -2599,6 +2604,21 @@ ImFontAtlas::~ImFontAtlas() Clear(); } +void ImFontAtlas::Clear() +{ + ClearInputData(); + ClearTexData(); + ClearFonts(); +} + +void ImFontAtlas::ClearCache() +{ + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(this); + ImFontAtlasBuildDestroy(this); + ImFontAtlasBuildAddTexture(this, new_tex_size.x, new_tex_size.y); + ImFontAtlasBuildInit(this); +} + void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); @@ -2624,8 +2644,6 @@ void ImFontAtlas::ClearInputData() font->LockDisableLoading = true; } Sources.clear(); - //CustomRects.clear(); - // Important: we leave TexReady untouched } void ImFontAtlas::ClearTexData() @@ -2634,7 +2652,6 @@ void ImFontAtlas::ClearTexData() TexList.clear(); IM_DELETE(TexData); TexData = NULL; - // Important: we leave TexReady untouched } void ImFontAtlas::ClearFonts() @@ -2652,36 +2669,6 @@ void ImFontAtlas::ClearFonts() } } -void ImFontAtlas::Clear() -{ - //IM_DELETE(Builder); // FIXME-NEW-ATLAS: Clarify ClearXXX functions - //const ImFontLoader* font_loader = FontLoader; - //ImFontAtlasBuildSetupFontLoader(this, NULL); - ClearInputData(); - ClearTexData(); - ClearFonts(); - //ImFontAtlasBuildSetupFontLoader(this, font_loader); -} - -// FIXME-NEWATLAS: Too widespread purpose. Clarify each call site in current WIP demo. -void ImFontAtlas::ClearCache() -{ - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(this); - ImFontAtlasBuildDestroy(this); - ImFontAtlasBuildAddTexture(this, new_tex_size.x, new_tex_size.y); - ImFontAtlasBuildInit(this); -} - -void ImFontAtlas::BuildGrowTexture() -{ - ImFontAtlasBuildGrowTexture(this, TexData->Width, TexData->Height); -} - -void ImFontAtlas::BuildCompactTexture() -{ - ImFontAtlasBuildCompactTexture(this); -} - static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas) { // [LEGACY] Copy back the ImGuiBackendFlags_RendererHasTextures flag from ImGui context. @@ -2753,15 +2740,6 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) } } -// Source buffer may be written to (used for in-place mods). -// Post-process hooks may eventually be added here. -void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data) -{ - // Multiply operator (legacy) - if (data->FontSrc->RasterizerMultiply != 1.0f) - ImFontAtlasTextureBlockPostProcessMultiply(data, data->FontSrc->RasterizerMultiply); -} - void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h) { IM_ASSERT(src_pixels != NULL && dst_pixels != NULL); @@ -2797,6 +2775,15 @@ void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFo } } +// Source buffer may be written to (used for in-place mods). +// Post-process hooks may eventually be added here. +void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data) +{ + // Multiply operator (legacy) + if (data->FontSrc->RasterizerMultiply != 1.0f) + ImFontAtlasTextureBlockPostProcessMultiply(data, data->FontSrc->RasterizerMultiply); +} + void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor) { unsigned char* pixels = data->Pixels; @@ -3753,10 +3740,9 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) new_tex->UseColors = old_tex->UseColors; IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height); - // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. - // Repack, lose discarded rectangle, copy pixels // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic. + // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. ImFontAtlasPackInit(atlas); ImVector old_rects; ImVector old_index = builder->RectsIndex; @@ -3819,7 +3805,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ old_tex_h = atlas->TexData->Height; // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend? - // FIXME-NEWATLAS-V2: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? + // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? Could we expose e.g. tex->UsedRect. IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); @@ -4018,7 +4004,7 @@ void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) } // Important: Calling this may recreate a new texture and therefore change atlas->TexData -// FIXME-NEWATLAS-V2: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 +// FIXME-NEWFONTS: Expose other glyph padding settings for custom alteration (e.g. drop shadows). See #7962 ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry) { IM_ASSERT(w > 0 && w <= 0xFFFF); @@ -4190,9 +4176,10 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* } src->FontLoaderData = bd_font_data; - // FIXME-NEWATLAS-V2: reevaluate sizing metrics + // FIXME-NEWFONTS: reevaluate sizing metrics int oversample_h, oversample_v; ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); + if (src->SizePixels > 0.0f) { bd_font_data->ScaleForRasterX = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels * src->RasterizerDensity) * oversample_h; @@ -4206,7 +4193,7 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* bd_font_data->ScaleForLayout = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels); } - // FIXME-NEWATLAS-V2: make use of line gap value + // FIXME-NEWFONTS: make use of line gap value int unscaled_ascent, unscaled_descent, unscaled_line_gap; stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); diff --git a/imgui_internal.h b/imgui_internal.h index 71019611ac9c..2f0b5b5d746d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -141,10 +141,10 @@ struct ImGuiTextIndex; // Maintain a line index for a text buffer. // ImDrawList/ImFontAtlas struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances +struct ImFontAtlasBuilder; // Internal storage for incrementally packing and building a ImFontAtlas +struct ImFontAtlasPostProcessData; // Data available to potential texture post-processing functions struct ImFontAtlasRect; // Packed rectangle (same as ImTextureRect) struct ImFontAtlasRectEntry; // Packed rectangle lookup entry -struct ImFontAtlasBuilder; // Internal storage for incrementally packing and building a ImFontAtlas -struct ImFontAtlasPostProcessData; // Data available to potential post-process functions // ImGui struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others) @@ -3658,7 +3658,7 @@ struct ImFontAtlasRectEntry unsigned int Used : 1; }; -// Data available to potential post-process functions +// Data available to potential texture post-processing functions struct ImFontAtlasPostProcessData { ImFontAtlas* FontAtlas; @@ -3701,15 +3701,13 @@ struct ImFontAtlasBuilder ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; } }; -// FIXME-NEWATLAS: Cleanup +IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildMain(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader); IMGUI_API void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char); -IMGUI_API void ImFontAtlasBuildMain(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildDestroy(ImFontAtlas* atlas); - IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); @@ -3718,26 +3716,24 @@ IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font); -IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); +IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend! IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); -IMGUI_API ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* cfg, const ImFontGlyph* in_glyph); - IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); -IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); +IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); +IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); IMGUI_API void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); IMGUI_API void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex); IMGUI_API void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas); - IMGUI_API void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch, unsigned char* dst_pixels, ImTextureFormat dst_fmt, int dst_pitch, int w, int h); IMGUI_API void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data); IMGUI_API void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor); From 953ce90d27d361d00b4e299aa4aa62fa49cfebf4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 20:25:16 +0100 Subject: [PATCH 465/716] Fonts: ImFontAtlasBuildInit() uses the occasion to sync HasTexUpdates from imgui context, narrowing the scope where it isn't set. --- imgui_draw.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3369aabe9c63..b253b501008c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3912,6 +3912,8 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) if (builder_is_new) builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); + ImFontAtlasBuildUpdateRendererHasTexUpdatesFromContext(atlas); + ImFontAtlasPackInit(atlas); // Add required texture data From a509790a1c83f8b5727c590887c402f9fb31a2be Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 13 Jan 2025 20:33:36 +0100 Subject: [PATCH 466/716] Fonts: Added back support for AddCustomRectFontGlyph() Legacy path naturally works. --- imgui.h | 2 +- imgui_draw.cpp | 128 +++++++++++++++++------------------------------ imgui_internal.h | 1 + 3 files changed, 47 insertions(+), 84 deletions(-) diff --git a/imgui.h b/imgui.h index 19c116cab5fa..15e784b4b959 100644 --- a/imgui.h +++ b/imgui.h @@ -3581,7 +3581,7 @@ struct ImFontAtlas // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); IMGUI_API ImFontAtlasCustomRect* GetCustomRectByIndex(int index); // [Internal] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b253b501008c..af8913719915 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3121,68 +3121,51 @@ void ImFontAtlas::RemoveFont(ImFont* font) ImFontAtlasBuildNotifySetFont(this, font, new_current_font); } -// FIXME-NEWATLAS-V1: Feature is broken for now. -/* - // Register custom rectangle glyphs - for (int i = 0; i < atlas->CustomRects.Size; i++) - { - const ImFontAtlasCustomRect* r = &atlas->CustomRects[i]; - if (r->Font == NULL || r->GlyphID == 0) - continue; - - // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, PixelSnapH - IM_ASSERT(r->Font->ContainerAtlas == atlas); - ImVec2 uv0, uv1; - atlas->CalcCustomRectUV(r, &uv0, &uv1); - r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX); - if (r->GlyphColored) - r->Font->Glyphs.back().Colored = 1; - } -*/ - int ImFontAtlas::AddCustomRectRegular(int width, int height) { IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); + ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); + if (r_id < 0) + return -1; + ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) - { - ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); - ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); - return r_id; - } - else - { - // FIXME-NEWATLAS-V1: Unfinished - ImFontAtlasCustomRect r; - r.Width = (unsigned short)width; - r.Height = (unsigned short)height; - //CustomRects.push_back(r); - //return CustomRects.Size - 1; // Return index - return -1; - } + return r_id; } -int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset) +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { #ifdef IMGUI_USE_WCHAR32 - IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX); + IM_ASSERT(codepoint <= IM_UNICODE_CODEPOINT_MAX); #endif IM_ASSERT(font != NULL); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); - ImFontAtlasCustomRect r; - r.Width = (unsigned short)width; - r.Height = (unsigned short)height; - r.GlyphID = id; - r.GlyphColored = 0; // Set to 1 manually to mark glyph as colored // FIXME: No official API for that (#8133) - r.GlyphAdvanceX = advance_x; - r.GlyphOffset = offset; - r.Font = font; - //CustomRects.push_back(r); - //return CustomRects.Size - 1; // Return index - return -1; + + ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); + if (r_id < 0) + return -1; + ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); + if (RendererHasTextures) + ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); + + if (font->IsGlyphLoaded(codepoint)) + ImFontAtlasBuildDiscardFontGlyph(this, font, (ImFontGlyph*)(void*)font->FindGlyph(codepoint)); + + ImFontGlyph glyph; + glyph.Codepoint = codepoint; + glyph.AdvanceX = advance_x; + glyph.X0 = offset.x; + glyph.Y0 = offset.y; + glyph.X1 = offset.x + r->w; + glyph.Y1 = offset.y + r->h; + glyph.Visible = true; + glyph.Colored = true; // FIXME: Arbitrary + glyph.PackId = r_id; + ImFontAtlasBuildAddFontGlyph(this, font, &font->Sources[0], &glyph); + return r_id; } ImFontAtlasCustomRect* ImFontAtlas::GetCustomRectByIndex(int idx) @@ -3308,41 +3291,6 @@ void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) } } -// FIXME-NEWATLAS: Unused -#if 0 -void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque) -{ - ImTextureData* tex = atlas->TexData; - stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque; - IM_ASSERT(pack_context != NULL); - - ImVector& user_rects = atlas->CustomRects; - IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong. -#ifdef __GNUC__ - if (user_rects.Size < 1) { __builtin_unreachable(); } // Workaround for GCC bug if IM_ASSERT() is defined to conditionally throw (see #5343) -#endif - - const int pack_padding = atlas->TexGlyphPadding; - ImVector pack_rects; - pack_rects.resize(user_rects.Size); - memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes()); - for (int i = 0; i < user_rects.Size; i++) - { - pack_rects[i].w = user_rects[i].Width + pack_padding; - pack_rects[i].h = user_rects[i].Height + pack_padding; - } - stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size); - for (int i = 0; i < pack_rects.Size; i++) - if (pack_rects[i].was_packed) - { - user_rects[i].X = (unsigned short)pack_rects[i].x; - user_rects[i].Y = (unsigned short)pack_rects[i].y; - IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height); - tex->Height = ImMax(tex->Height, pack_rects[i].y + pack_rects[i].h); - } -} -#endif - // Render a white-colored bitmap encoded in a string void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char) { @@ -3601,6 +3549,20 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr font->LockSingleSrcConfigIdx = -1; } +void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph) +{ + if (glyph->PackId >= 0) + { + ImFontAtlasPackDiscardRect(atlas, glyph->PackId); + glyph->PackId = -1; + } + ImWchar c = glyph->Codepoint; + IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity + IM_ASSERT(glyph >= font->Glyphs.Data && glyph < font->Glyphs.Data + font->Glyphs.Size); + font->IndexLookup[c] = (ImWchar)IM_FONTGLYPH_INDEX_UNUSED; + font->IndexAdvanceX[c] = font->FallbackAdvanceX; +} + void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font) { for (ImFontGlyph& glyph : font->Glyphs) @@ -3912,7 +3874,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) if (builder_is_new) builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); - ImFontAtlasBuildUpdateRendererHasTexUpdatesFromContext(atlas); + ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); ImFontAtlasPackInit(atlas); diff --git a/imgui_internal.h b/imgui_internal.h index 2f0b5b5d746d..6c9c6de733b8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3718,6 +3718,7 @@ IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend! IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy From ba62becb7d0cdf18fcf2caed145b0f8bcb9b13c4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 15 Jan 2025 11:53:24 +0100 Subject: [PATCH 467/716] (Breaking) Fonts: remove ImFontAtlasCustomRect which is now the same as ImTextureRect --- imgui.h | 62 ++++++++++++++++++++++++++------------------------ imgui_draw.cpp | 21 +++++++++-------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/imgui.h b/imgui.h index 15e784b4b959..c521236bffb7 100644 --- a/imgui.h +++ b/imgui.h @@ -3468,22 +3468,6 @@ struct ImFontGlyphRangesBuilder IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges }; -// See ImFontAtlas::AddCustomRectXXX functions. -struct ImFontAtlasCustomRect -{ - unsigned short X, Y; // Output // Packed position in Atlas - - // [Internal] - unsigned short Width, Height; // Input // Desired rectangle dimension - unsigned int GlyphID : 31; // Input // For custom font glyphs only (ID < 0x110000) - unsigned int GlyphColored : 1; // Input // For custom font glyphs only: glyph is colored, removed tinting. - float GlyphAdvanceX; // Input // For custom font glyphs only: glyph xadvance - ImVec2 GlyphOffset; // Input // For custom font glyphs only: glyph display offset - ImFont* Font; // Input // For custom font glyphs only: target font - ImFontAtlasCustomRect() { X = Y = 0xFFFF; Width = Height = 0; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } - bool IsPacked() const { return X != 0xFFFF; } -}; - // Flags for ImFontAtlas build enum ImFontAtlasFlags_ { @@ -3568,24 +3552,21 @@ struct ImFontAtlas // [ALPHA] Custom Rectangles/Glyphs API //------------------------------------------- - // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. + // You can request arbitrary rectangles to be packed into the atlas, for your own purpose. // You can request your rectangles to be mapped as font glyph (given a font + Unicode point), // so you can render e.g. custom colorful icons and use them as regular glyphs. - // - If your backend supports ImGuiBackendFlags_RendererHasTextures (since 1.92.X): - // - Packing is done immediately. Returns >= on success. Return <0 on error. - // - You can render your pixels into the texture right after calling the AddCustomRectXXX functions. - // - Texture may be resized, so you cannot cache UV coordinates. // FIXME-NEWATLAS-V1: How to handle that smoothly? - // - If your backend does NOT supports ImGuiBackendFlags_RendererHasTextures (older than 1.92.X): - // - After calling Build(), you can query the rectangle position and render your pixels. - // - If you render colored output, set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. + // - Since 1.92.X, packing is done immediately in the function call. Returns >= on success, <0 on error. + // - You can render your pixels into the texture right after calling the AddCustomRectXXX functions, without waiting for the Build() call. + // - If your backend supports ImGuiBackendFlags_RendererHasTextures: + // Texture may be resized, so you cannot cache UV coordinates: always use CalcCustomRectUV(). + // - If you render colored output into your AddCustomRectRegular() rectangle: set 'atlas->TexPixelsUseColors = true' + // as this may help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); - IMGUI_API ImFontAtlasCustomRect* GetCustomRectByIndex(int index); - - // [Internal] - IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; + IMGUI_API ImTextureRect* GetCustomRectByIndex(int index); + IMGUI_API void CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; //------------------------------------------- // Members @@ -3613,7 +3594,6 @@ struct ImFontAtlas ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector Sources; // Source/configuration data - //ImVector CustomRects; // Rectangles for packing custom texture data into the atlas. ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID ImVector DrawListSharedDatas; @@ -3627,7 +3607,8 @@ struct ImFontAtlas int RefCount; // Number of contexts using this atlas // [Obsolete] - //int TexDesiredWidth; // OBSOLETED in 1.91.5 (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) + //int TexDesiredWidth; // OBSOLETED in 1.92.X (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) + //typedef ImTextureRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; @@ -3905,6 +3886,27 @@ namespace ImGui //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 } +//-- OBSOLETED in 1.91.7 (from January 2025): ImFontAtlasCustomRect becomes ImTextureRect +// - ImFontAtlasCustomRect::X --> ImTextureRect::x +// - ImFontAtlasCustomRect::Y --> ImTextureRect::y +// - ImFontAtlasCustomRect::Width --> ImTextureRect::w +// - ImFontAtlasCustomRect::Height --> ImTextureRect::h +// - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() +// We could make ImTextureRect an union to use old names, such 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. +typedef ImTextureRect ImFontAtlasCustomRect; +/*struct ImFontAtlasCustomRect +{ + unsigned short X, Y; // Output // Packed position in Atlas + unsigned short Width, Height; // Input // [Internal] Desired rectangle dimension + unsigned int GlyphID:31; // Input // [Internal] For custom font glyphs only (ID < 0x110000) + unsigned int GlyphColored:1; // Input // [Internal] For custom font glyphs only: glyph is colored, removed tinting. + float GlyphAdvanceX; // Input // [Internal] For custom font glyphs only: glyph xadvance + ImVec2 GlyphOffset; // Input // [Internal] For custom font glyphs only: glyph display offset + ImFont* Font; // Input // [Internal] For custom font glyphs only: target font + ImFontAtlasCustomRect() { X = Y = 0xFFFF; Width = Height = 0; GlyphID = 0; GlyphColored = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; } + bool IsPacked() const { return X != 0xFFFF; } +};*/ + //-- OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() //typedef ImDrawFlags ImDrawCornerFlags; //enum ImDrawCornerFlags_ diff --git a/imgui_draw.cpp b/imgui_draw.cpp index af8913719915..1f13ed0f6aae 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3135,6 +3135,8 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) return r_id; } +// FIXME: we automatically set glyph.Colored=true by default. +// If you need to alter this, you can write 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph(). int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { #ifdef IMGUI_USE_WCHAR32 @@ -3168,21 +3170,20 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid return r_id; } -ImFontAtlasCustomRect* ImFontAtlas::GetCustomRectByIndex(int idx) +ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx) { - IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, X) == offsetof(ImFontAtlasRect, x)); - IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, Y) == offsetof(ImFontAtlasRect, y)); - IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, Width) == offsetof(ImFontAtlasRect, w)); - IM_STATIC_ASSERT(offsetof(ImFontAtlasCustomRect, Height) == offsetof(ImFontAtlasRect, h)); - return (ImFontAtlasCustomRect*)(void*)ImFontAtlasPackGetRect(this, idx); + IM_STATIC_ASSERT(offsetof(ImTextureRect, x) == offsetof(ImFontAtlasRect, x)); + IM_STATIC_ASSERT(offsetof(ImTextureRect, y) == offsetof(ImFontAtlasRect, y)); + IM_STATIC_ASSERT(offsetof(ImTextureRect, w) == offsetof(ImFontAtlasRect, w)); + IM_STATIC_ASSERT(offsetof(ImTextureRect, h) == offsetof(ImFontAtlasRect, h)); + return (ImTextureRect*)(void*)ImFontAtlasPackGetRect(this, idx); } -void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +void ImFontAtlas::CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const { IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates - IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed - *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y); - *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y); + *out_uv_min = ImVec2((float)rect->x * TexUvScale.x, (float)rect->y * TexUvScale.y); + *out_uv_max = ImVec2((float)(rect->x + rect->w) * TexUvScale.x, (float)(rect->y + rect->w) * TexUvScale.y); } bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) From 2bf6552f2facc23c5aa84a610fb8c3983ae87d1d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 11:35:55 +0100 Subject: [PATCH 468/716] Fonts: Fixed/improved support for legacy backend. SetTexID() writes into our ImTextureData to keep the indirection, clear TexIsBuilt. The idea is that a legacy backend can somehow add a if (!atlas->IsBuilt()) ImGui_ImplXXXXX_CreateFontsTexture() call _after_ Render() and some features are supported. --- imgui.cpp | 16 ++++------------ imgui.h | 29 ++++++++++++++++------------- imgui_draw.cpp | 26 ++++++++++++++++++++------ 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a505d5d6cb23..f681e71b6298 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5178,13 +5178,16 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } +// FIXME-NEWATLAS-V2: If we aim to support multiple atlases used by same context: how to reach/target all atlases? static void ImGui::UpdateTexturesNewFrame() { - // FIXME-NEWATLAS-V2: If we aim to support multiple atlases used by same context: how to reach/target all atlases? ImGuiContext& g = *GImGui; ImFontAtlas* atlas = g.IO.Fonts; if (g.FontAtlasOwnedByContext) + { + atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; ImFontAtlasUpdateNewFrame(atlas); + } } // Build a single texture list @@ -5240,13 +5243,6 @@ void ImGui::NewFrame() CallContextHooks(&g, ImGuiContextHookType_NewFramePre); - // Check that font atlas was built or backend support texture reload in which case we can build now - ImFontAtlas* atlas = g.IO.Fonts; - if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) - ImFontAtlasBuildMain(atlas); - else // Legacy backend - IM_ASSERT(atlas->TexIsBuilt && "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); - // Check and assert for various common IO and Configuration mistakes ErrorCheckNewFrameSanityChecks(); @@ -8573,11 +8569,7 @@ void ImGui::UpdateFontsNewFrame() { ImGuiContext& g = *GImGui; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) - { g.IO.Fonts->Locked = true; - for (ImFont* font : g.IO.Fonts->Fonts) - font->LockDisableLoading = true; - } SetCurrentFont(GetDefaultFont()); IM_ASSERT(g.Font->IsLoaded()); } diff --git a/imgui.h b/imgui.h index c521236bffb7..73e3f7eddc77 100644 --- a/imgui.h +++ b/imgui.h @@ -3332,7 +3332,7 @@ struct ImDrawData }; //----------------------------------------------------------------------------- -// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureDataUpdate, ImTextureData +// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData //----------------------------------------------------------------------------- // We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. @@ -3517,17 +3517,20 @@ struct ImFontAtlas IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // Build atlas, retrieve pixel data. - // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). - // The pitch is always = Width * BytesPerPixels (1 or 4) - // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into - // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. - IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. - IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel - IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - void SetTexID(ImTextureID id) { TexRef._TexData = NULL; TexRef._TexID = id; } // Called by legacy backends. - void SetTexID(ImTextureRef id) { TexRef = id; } // Called by legacy backends. - bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... + // Legacy path for build atlas + retrieving pixel data. + // - User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // - The pitch is always = Width * BytesPerPixels (1 or 4) + // - Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + // - From 1.92 with backends supporting ImGuiBackendFlags_RendererHasTextures: + // - Calling Build(), GetTexDataAsAlpha8(), GetTexDataAsRGBA32() is not needed. + // - In backend: replace calls to ImFontAtlas::SetTexID() with calls to ImTextureData::SetTexID() after honoring texture creation. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + void SetTexID(ImTextureID id) { IM_ASSERT(TexRef._TexID == ImTextureID_Invalid); TexRef._TexData->TexID = id; } // Called by legacy backends. May be called before texture creation. + void SetTexID(ImTextureRef id) { IM_ASSERT(TexRef._TexID == ImTextureID_Invalid && id._TexData == NULL); TexRef._TexData->TexID = id._TexID; } // Called by legacy backends. + bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent.. #endif //------------------------------------------- @@ -3588,7 +3591,7 @@ struct ImFontAtlas ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. - bool TexIsBuilt; // Set when texture was built matching current font input + bool TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight) ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 1f13ed0f6aae..5e9d1de91fb5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2485,6 +2485,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::CalcCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- +// - ImFontAtlasBuildMain() // - ImFontAtlasBuildSetupFontLoader() // - ImFontAtlasBuildPreloadAllGlyphRanges() // - ImFontAtlasBuildUpdatePointers() @@ -2685,15 +2686,24 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at } // Called by NewFrame(). When multiple context own the atlas, only the first one calls this. +// If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) { - if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) + // Check that font atlas was built or backend support texture reload in which case we can build now + if (atlas->RendererHasTextures) + { + atlas->TexIsBuilt = true; + if (atlas->Builder == NULL) // This will only happen if fonts were not already loaded. + ImFontAtlasBuildMain(atlas); + } + else // Legacy backend { - ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); - IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, - "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); + IM_ASSERT_USER_ERROR(atlas->TexIsBuilt, "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()."); } + if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) + IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); + // Update texture status for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { ImTextureData* tex = atlas->TexList[tex_n]; @@ -2865,6 +2875,7 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y); tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x); tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y); + atlas->TexIsBuilt = false; // No need to queue if status is _WantCreate if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates) @@ -3206,6 +3217,7 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } +// When atlas->RendererHasTexUpdates == true, this is only called if no font were loaded. void ImFontAtlasBuildMain(ImFontAtlas* atlas) { IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); @@ -3589,6 +3601,7 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) atlas->FontLoader->FontSrcInit(atlas, src); ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. + atlas->TexIsBuilt = false; } // Notify external systems @@ -3684,6 +3697,7 @@ ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h) new_tex->Create(atlas->TexDesiredFormat, w, h); new_tex->Status = ImTextureStatus_WantCreate; + atlas->TexIsBuilt = false; ImFontAtlasBuildSetTexture(atlas, new_tex); @@ -4037,12 +4051,12 @@ ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) { - if (LockDisableLoading) + ImFontAtlas* atlas = ContainerAtlas; + if (LockDisableLoading || atlas->Locked) return NULL; //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); - ImFontAtlas* atlas = ContainerAtlas; // Load from single source or all sources? int srcs_count = (LockSingleSrcConfigIdx != -1) ? 1 : SourcesCount; From bd19bc50858d80113080fd22f7a8538d953e3c7c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 14:57:33 +0100 Subject: [PATCH 469/716] Fonts: Removed BuildClearGlyphs(), conflated with ClearOutputData() --- imgui.h | 1 - imgui_draw.cpp | 20 ++------------------ 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/imgui.h b/imgui.h index 73e3f7eddc77..1baa4067a8ca 100644 --- a/imgui.h +++ b/imgui.h @@ -3673,7 +3673,6 @@ struct ImFont IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c); IMGUI_API void BuildGrowIndex(int new_size); - IMGUI_API void BuildClearGlyphs(); }; // Added indirection to avoid patching ImDrawCmd after texture updates. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5e9d1de91fb5..2351b2f519b5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2522,8 +2522,6 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasPackGetRect() //----------------------------------------------------------------------------- // - ImFont::BuildLoadGlyph() -// - ImFont::BuildClearGlyphs() -//----------------------------------------------------------------------------- // - ImFontAtlasDebugLogTextureRequests() //----------------------------------------------------------------------------- // - ImFontAtlasGetFontLoaderForStbTruetype() @@ -3581,7 +3579,7 @@ void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font) for (ImFontGlyph& glyph : font->Glyphs) if (glyph.PackId >= 0) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); - font->BuildClearGlyphs(); + font->ClearOutputData(); font->FallbackChar = font->EllipsisChar = 0; } @@ -3915,7 +3913,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) { for (ImFont* font : atlas->Fonts) - font->BuildClearGlyphs(); + font->ClearOutputData(); if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL) for (ImFontConfig& font_cfg : atlas->Sources) atlas->FontLoader->FontSrcDestroy(atlas, &font_cfg); @@ -4650,30 +4648,16 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { - FontSize = 0.0f; FallbackAdvanceX = 0.0f; Glyphs.clear(); IndexAdvanceX.clear(); IndexLookup.clear(); FallbackGlyphIndex = -1; - ContainerAtlas = NULL; Ascent = Descent = 0.0f; MetricsTotalSurface = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); } -void ImFont::BuildClearGlyphs() -{ - FallbackAdvanceX = 0.0f; - Glyphs.clear(); - IndexAdvanceX.clear(); - IndexLookup.clear(); - FallbackGlyphIndex = 0; - MetricsTotalSurface = 0; - memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); - // Don't clear BuilderData -} - // API is designed this way to avoid exposing the 8K page size // e.g. use with IsGlyphRangeUnused(0, 255) bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) From 722f6013ff15957833960ebe46e1ea2eab97b5eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 16 Jan 2025 15:41:46 +0100 Subject: [PATCH 470/716] Fonts: Added a bit of user facing tooling. --- imgui.cpp | 23 +++++++++++++++++++++++ imgui_demo.cpp | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f681e71b6298..24073f715720 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15594,6 +15594,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { ImGuiContext& g = *GImGui; + SeparatorText("Fonts"); Text("Read "); SameLine(0, 0); TextLinkOpenURL("https://www.dearimgui.com/faq/"); @@ -15641,6 +15642,28 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) PopID(); } + SeparatorText("Font Atlas"); + if (Button("Clear Cache")) + atlas->ClearCache(); + SameLine(); + if (Button("Grow")) + ImFontAtlasBuildGrowTexture(atlas); + SameLine(); + if (Button("Compact")) + ImFontAtlasBuildCompactTexture(atlas); + + for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) + { + ImTextureData* tex = atlas->TexList[tex_n]; + if (tex_n > 0) + SameLine(); + Text("Tex: %dx%d", tex->Width, tex->Height); + } + const int packed_surface_sqrt = (int)sqrtf((float)atlas->Builder->RectsPackedSurface); + const int discarded_surface_sqrt = (int)sqrtf((float)atlas->Builder->RectsDiscardedSurface); + Text("Packed rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsPackedCount, atlas->Builder->RectsPackedSurface, packed_surface_sqrt, packed_surface_sqrt); + Text("incl. Discarded rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsDiscardedCount, atlas->Builder->RectsDiscardedSurface, discarded_surface_sqrt, discarded_surface_sqrt); + // Texture list for (ImTextureData* tex : atlas->TexList) { diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5d5075e81b34..55b09a2bfacb 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8446,11 +8446,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { ImGuiIO& io = GetIO(); ImFontAtlas* atlas = io.Fonts; - HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); ShowFontAtlas(atlas); // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). + SeparatorText("Legacy Scaling"); const float MIN_SCALE = 0.3f; const float MAX_SCALE = 2.0f; HelpMarker( From b203ac1e0dce0a770954ca8b1d486d2ea00ff83c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 18 Jan 2025 15:01:05 +0100 Subject: [PATCH 471/716] Fonts: Reduced reliance on ImFontConfig::DstFont. --- imgui_draw.cpp | 41 ++++++++++++++++++----------------------- imgui_internal.h | 2 +- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2351b2f519b5..18e9501c3e7e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2966,9 +2966,6 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) return NULL; } - // Invalidate texture - //TexReady = false; - //ClearTexData(); return new_font_cfg.DstFont; } @@ -3276,15 +3273,16 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) { atlas->Builder->PreloadedAllGlyphsRanges = true; - for (int src_n = 0; src_n < atlas->Sources.Size; src_n++) - { - ImFontConfig* src = &atlas->Sources[src_n]; - const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); - IM_ASSERT(ranges != NULL); - for (; ranges[0]; ranges += 2) - for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 - src->DstFont->FindGlyphNoFallback((ImWchar)c); - } + for (ImFont* font : atlas->Fonts) + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); + IM_ASSERT(ranges != NULL); + for (; ranges[0]; ranges += 2) + for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 + font->FindGlyphNoFallback((ImWchar)c); + } } void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) @@ -3462,17 +3460,15 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) if (!font_loader->FontSrcInit(atlas, src)) return false; - ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); + ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); return true; } // Rasterize our own ellipsis character from a dot. // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. // FIXME-NEWATLAS: This borrows too much from FontLoader's FontAddGlyph() and suggest that we should add further helpers. -static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFontConfig* src, const ImFontGlyph* dot_glyph) +static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph) { - ImFont* font = src->DstFont; - ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId); const int dot_spacing = 1; const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; @@ -3502,15 +3498,14 @@ static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, I // Load/identify special glyphs // (note that this is called again for fonts with MergeMode) -void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src) +void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) { - ImFont* font = src->DstFont; - const int cfg_idx_in_font = (int)(src - font->Sources); - IM_ASSERT(cfg_idx_in_font >= 0 && cfg_idx_in_font < font->SourcesCount); + const int src_idx_in_font = (int)(src - font->Sources); + IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount); IM_UNUSED(atlas); // While manipulating glyphs during init we want to restrict all searches for one source font. - font->LockSingleSrcConfigIdx = (short)cfg_idx_in_font; + font->LockSingleSrcConfigIdx = (short)src_idx_in_font; // Setup Fallback character // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? @@ -3553,7 +3548,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* sr { const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) - ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, src, dot_glyph); + ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, font, dot_glyph); else font->EllipsisChar = (ImWchar)' '; } @@ -3598,7 +3593,7 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) if (atlas->FontLoader && atlas->FontLoader->FontSrcInit != NULL) atlas->FontLoader->FontSrcInit(atlas, src); - ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. + ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. atlas->TexIsBuilt = false; } diff --git a/imgui_internal.h b/imgui_internal.h index 6c9c6de733b8..1126a91bafc7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3717,7 +3717,7 @@ IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph); -IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend! From c5653d5f34b50d9edb2d189790df3fbabdc72f82 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 20 Jan 2025 20:01:21 +0100 Subject: [PATCH 472/716] Fonts: stb_truetype loader: Reworked scale handling to suggest this is not required caching. --- imgui_draw.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 18e9501c3e7e..4edddf5fab05 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4151,19 +4151,14 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* // FIXME-NEWFONTS: reevaluate sizing metrics int oversample_h, oversample_v; ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); - + float scale; if (src->SizePixels > 0.0f) - { - bd_font_data->ScaleForRasterX = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels * src->RasterizerDensity) * oversample_h; - bd_font_data->ScaleForRasterY = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels * src->RasterizerDensity) * oversample_v; - bd_font_data->ScaleForLayout = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, src->SizePixels); - } + scale = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else - { - bd_font_data->ScaleForRasterX = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels * src->RasterizerDensity) * oversample_h; - bd_font_data->ScaleForRasterY = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels * src->RasterizerDensity) * oversample_v; - bd_font_data->ScaleForLayout = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, -src->SizePixels); - } + scale = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); + bd_font_data->ScaleForRasterX = scale * src->SizePixels * src->RasterizerDensity * oversample_h; + bd_font_data->ScaleForRasterY = scale * src->SizePixels * src->RasterizerDensity * oversample_v; + bd_font_data->ScaleForLayout = scale * src->SizePixels; // FIXME-NEWFONTS: make use of line gap value int unscaled_ascent, unscaled_descent, unscaled_line_gap; From fb69a09d6e324573371daee953232988afc24a6a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Jan 2025 12:12:07 +0100 Subject: [PATCH 473/716] Fonts: Fixed leak due to indirectly recursing ImFontAtlasPackInit(). --- imgui_draw.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4edddf5fab05..dfb7bb0d660b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3857,8 +3857,6 @@ void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) // Start packing over current empty texture void ImFontAtlasBuildInit(ImFontAtlas* atlas) { - ImFontAtlasBuilder* builder = atlas->Builder; - // Select Backend // - Note that we do not reassign to atlas->FontLoader, since it is likely to point to static data which // may mess with some hot-reloading schemes. If you need to assign to this (for dynamic selection) AND are @@ -3873,14 +3871,20 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) #else IM_ASSERT(0); // Invalid Build function #endif + return; // ImFontAtlasBuildSetupFontBackendIO() automatically call ImFontAtlasBuildInit() } + // Create initial texture size if (atlas->TexData == NULL) ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); + ImFontAtlasBuilder* builder = atlas->Builder; // Do not move above const bool builder_is_new = (builder == NULL); if (builder_is_new) + { + IM_ASSERT(atlas->Builder == NULL); builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); + } ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); From a2371ef90bad9e176e7eaa0693efc4a7329cf66c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 22 Jan 2025 20:01:26 +0100 Subject: [PATCH 474/716] Internals: added ImStableVector<> helper. --- imgui_internal.h | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/imgui_internal.h b/imgui_internal.h index 1126a91bafc7..07cd846670ee 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -133,7 +133,7 @@ Index of this file: //----------------------------------------------------------------------------- // Utilities -// (other types which are not forwarded declared are: ImBitArray<>, ImSpan<>, ImSpanAllocator<>, ImPool<>, ImChunkStream<>) +// (other types which are not forwarded declared are: ImBitArray<>, ImSpan<>, ImSpanAllocator<>, ImStableVector<>, ImPool<>, ImChunkStream<>) struct ImBitVector; // Store 1-bit per value struct ImRect; // An axis-aligned rectangle (2 points) struct ImGuiTextIndex; // Maintain a line index for a text buffer. @@ -357,6 +357,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer // - Helper: ImBitArray // - Helper: ImBitVector // - Helper: ImSpan<>, ImSpanAllocator<> +// - Helper: ImStableVector<> // - Helper: ImPool<> // - Helper: ImChunkStream<> // - Helper: ImGuiTextIndex @@ -694,6 +695,39 @@ struct ImSpanAllocator inline void GetSpan(int n, ImSpan* span) { span->set((T*)GetSpanPtrBegin(n), (T*)GetSpanPtrEnd(n)); } }; +// Helper: ImStableVector<> +// Allocating chunks of BLOCK_SIZE items. Objects pointers are never invalidated when growing, only by clear(). +// Important: does not destruct anything! +// Implemented only the minimum set of functions we need for it. +template +struct ImStableVector +{ + int Size = 0; + int Capacity = 0; + ImVector Blocks; + + // Functions + inline ~ImStableVector() { for (T* block : Blocks) IM_FREE(block); } + + inline void clear() { Size = Capacity = 0; Blocks.clear_delete(); } + inline void resize(int new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; } + inline void reserve(int new_cap) + { + new_cap = IM_MEMALIGN(new_cap, BLOCK_SIZE); + int old_count = Capacity / BLOCK_SIZE; + int new_count = new_cap / BLOCK_SIZE; + if (new_count <= old_count) + return; + Blocks.resize(new_count); + for (int n = old_count; n < new_count; n++) + Blocks[n] = (T*)IM_ALLOC(sizeof(T) * BLOCK_SIZE); + Capacity = new_cap; + } + inline T& operator[](int i) { IM_ASSERT(i >= 0 && i < Size); return Blocks[i / BLOCK_SIZE][i % BLOCK_SIZE]; } + inline const T& operator[](int i) const { IM_ASSERT(i >= 0 && i < Size); return Blocks[i / BLOCK_SIZE][i % BLOCK_SIZE]; } + inline T* push_back(const T& v) { int i = Size; IM_ASSERT(i >= 0); if (Size == Capacity) reserve(Capacity + BLOCK_SIZE); void* ptr = &Blocks[i / BLOCK_SIZE][i % BLOCK_SIZE]; memcpy(ptr, &v, sizeof(v)); Size++; return (T*)ptr; } +}; + // Helper: ImPool<> // Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer, // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. From 7aba8da5515e3003be071f5392cac3aaa663c8aa Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 24 Jan 2025 18:10:42 +0100 Subject: [PATCH 475/716] (Breaking) Fonts: CalcWordWrapPositionA() -> CalcWordWrapPosition(), takes size instead of scale as this will be needed. --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dfb7bb0d660b..c9c32e930b16 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4795,7 +4795,7 @@ bool ImFont::IsGlyphInFont(ImWchar c) return false; } -// This is manually inlined in CalcTextSizeA() and CalcWordWrapPositionA(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback(). +// This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback(). IM_MSVC_RUNTIME_CHECKS_OFF float ImFont::GetCharAdvance(ImWchar c) { From 093d01269a05d5f6fab9eee85d3e187b22364fe7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 23 Jan 2025 15:46:22 +0100 Subject: [PATCH 476/716] Fonts: Baked system, with auto-bind, v10. # Conflicts: # imgui_internal.h --- imgui.cpp | 94 +++--- imgui.h | 62 ++-- imgui_draw.cpp | 474 ++++++++++++++++++++----------- imgui_internal.h | 39 ++- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 33 ++- misc/freetype/imgui_freetype.cpp | 131 ++++++--- 7 files changed, 542 insertions(+), 293 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 24073f715720..abe3cab3e95d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3738,7 +3738,8 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con const float font_size = draw_list->_Data->FontSize; const float font_scale = draw_list->_Data->FontScale; const char* text_end_ellipsis = NULL; - const float ellipsis_width = font->GetCharAdvance(font->EllipsisChar) * font_scale; + ImFontBaked* baked = font->GetFontBaked(font_size); + const float ellipsis_width = baked->GetCharAdvance(font->EllipsisChar) * font_scale; // We can now claim the space between pos_max.x and ellipsis_max.x const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_width) - pos_min.x, 1.0f); @@ -3939,7 +3940,8 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Initialized = false; FontAtlasOwnedByContext = shared_font_atlas ? false : true; Font = NULL; - FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f; + FontBaked = NULL; + FontSize = /*FontBaseSize = */FontScale = CurrentDpiScale = 0.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); IO.Fonts->RefCount++; Time = 0.0f; @@ -4275,6 +4277,7 @@ void ImGui::Shutdown() g.MenusIdSubmittedThisFrame.clear(); g.InputTextState.ClearFreeMemory(); g.InputTextDeactivatedState.ClearFreeMemory(); + g.InputTextPasswordFont.ContainerAtlas = NULL; g.SettingsWindows.clear(); g.SettingsHandlers.clear(); @@ -4371,8 +4374,9 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking if (window) { - g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); - g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize; + // FIXME-BAKED + //g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); + //g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize; ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } } @@ -5186,7 +5190,7 @@ static void ImGui::UpdateTexturesNewFrame() if (g.FontAtlasOwnedByContext) { atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; - ImFontAtlasUpdateNewFrame(atlas); + ImFontAtlasUpdateNewFrame(atlas, g.FrameCount); } } @@ -8399,11 +8403,14 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() void ImGui::SetWindowFontScale(float scale) { IM_ASSERT(scale > 0.0f); + // FIXME-BAKED + /* ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->FontWindowScale = scale; g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize; + */ } void ImGui::PushFocusScope(ImGuiID id) @@ -8570,20 +8577,21 @@ void ImGui::UpdateFontsNewFrame() ImGuiContext& g = *GImGui; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) g.IO.Fonts->Locked = true; - SetCurrentFont(GetDefaultFont()); + SetCurrentFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels); IM_ASSERT(g.Font->IsLoaded()); } // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. -void ImGui::SetCurrentFont(ImFont* font) +void ImGui::SetCurrentFont(ImFont* font, float font_size) { ImGuiContext& g = *GImGui; IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); - g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; - g.FontScale = g.FontSize / g.Font->FontSize; + //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->Size * g.Font->Scale); + g.FontSize = font_size;// g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + g.FontBaked = g.Font->GetFontBaked(g.FontSize); + g.FontScale = g.FontSize / g.FontBaked->Size; g.DrawListSharedData.Font = g.Font; g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontScale; @@ -8606,7 +8614,7 @@ void ImGui::PushFont(ImFont* font) if (font == NULL) font = GetDefaultFont(); g.FontStack.push_back(font); - SetCurrentFont(font); + SetCurrentFont(font, g.FontSize); } void ImGui::PopFont() @@ -8619,7 +8627,14 @@ void ImGui::PopFont() } g.FontStack.pop_back(); ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); - SetCurrentFont(font); + SetCurrentFont(font, g.FontSize); // FIXME-BAKED: size in stack +} + +void ImGui::SetFontSize(float size) +{ + // FIXME-BAKED + ImGuiContext& g = *GImGui; + SetCurrentFont(g.Font, size); } //----------------------------------------------------------------------------- @@ -15512,7 +15527,7 @@ void ImGui::DebugTextEncoding(const char* str) } TableNextColumn(); TextUnformatted(p, p + c_utf8_len); - if (GetFont()->FindGlyphNoFallback((ImWchar)c) == NULL) + if (!GetFont()->IsGlyphInFont((ImWchar)c)) { SameLine(); TextUnformatted("[missing]"); @@ -16478,8 +16493,8 @@ void ImGui::DebugNodeFont(ImFont* font) { ImGuiContext& g = *GImGui; ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; - bool opened = TreeNode(font, "Font: \"%s\": %.2f px, %d glyphs, %d sources(s)", - font->Sources ? font->Sources[0].Name : "", font->FontSize, font->Glyphs.Size, font->SourcesCount); + ImFontAtlas* atlas = font->ContainerAtlas; + bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->Sources ? font->Sources[0].Name : "", font->SourcesCount); // Display preview text if (!opened) @@ -16499,11 +16514,11 @@ void ImGui::DebugNodeFont(ImFont* font) } if (SmallButton("Set as default")) GetIO().FontDefault = font; - if (font->ContainerAtlas->Fonts.Size > 1 && !font->ContainerAtlas->Locked) + if (atlas->Fonts.Size > 1 && !atlas->Locked) { SameLine(); if (SmallButton("Remove")) - font->ContainerAtlas->RemoveFont(font); + atlas->RemoveFont(font); } // Display details @@ -16515,33 +16530,43 @@ void ImGui::DebugNodeFont(ImFont* font) "You may oversample them to get some flexibility with scaling. " "You can also render at multiple sizes and select which one to use at runtime.\n\n" "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); - Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent); + char c_str[5]; Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); - const int surface_sqrt = (int)ImSqrt((float)font->MetricsTotalSurface); - Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt); - for (int config_i = 0; config_i < font->SourcesCount; config_i++) - if (font->Sources) - { - ImFontConfig* src = &font->Sources[config_i]; - int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); - BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", - config_i, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); - } + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + if (ImFontConfig* src = &font->Sources[src_n]) + BulletText("Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", + src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); // Display all glyphs of the fonts in separate pages of 256 characters + for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++) { - if (TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size)) + ImFontBaked* baked = &atlas->Builder->BakedPool[baked_n]; + if (baked->ContainerFont != font) + continue; + PushID(baked_n); + if (TreeNode("Glyphs", "Baked at %.2fpx: %d glyphs%s", baked->Size, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) { if (SmallButton("Load all")) for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++) - font->FindGlyph((ImWchar)base); + baked->FindGlyph((ImWchar)base); + + const int surface_sqrt = (int)ImSqrt((float)baked->MetricsTotalSurface); + Text("Ascent: %f, Descent: %f, Ascent-Descent: %f", baked->Ascent, baked->Descent, baked->Ascent - baked->Descent); + Text("Texture Area: about %d px ~%dx%d px", baked->MetricsTotalSurface, surface_sqrt, surface_sqrt); + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + int oversample_h, oversample_v; + ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v); + BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", + src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); + } ImDrawList* draw_list = GetWindowDrawList(); const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); - const float cell_size = font->FontSize * 1; + const float cell_size = baked->Size * 1; const float cell_spacing = GetStyle().ItemSpacing.y; for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) { @@ -16556,7 +16581,7 @@ void ImGui::DebugNodeFont(ImFont* font) int count = 0; for (unsigned int n = 0; n < 256; n++) - if (font->IsGlyphLoaded((ImWchar)(base + n))) + if (baked->IsGlyphLoaded((ImWchar)(base + n))) count++; if (count <= 0) continue; @@ -16571,7 +16596,7 @@ void ImGui::DebugNodeFont(ImFont* font) // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = font->IsGlyphLoaded((ImWchar)(base + n)) ? font->FindGlyph((ImWchar)(base + n)) : NULL; + const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL; draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); if (!glyph) continue; @@ -16587,6 +16612,7 @@ void ImGui::DebugNodeFont(ImFont* font) } TreePop(); } + PopID(); } TreePop(); Unindent(); diff --git a/imgui.h b/imgui.h index 1baa4067a8ca..85fbb47d911e 100644 --- a/imgui.h +++ b/imgui.h @@ -50,7 +50,7 @@ Index of this file: // [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage) // [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData) // [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) -// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont) +// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) // [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData) // [SECTION] Obsolete functions and types @@ -172,6 +172,7 @@ struct ImDrawVert; // A single vertex (pos + uv + col = 20 byte 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 struct ImFontAtlasBuilder; // Opaque storage for building a ImFontAtlas +struct ImFontBaked; // Baked data for a ImFont at a given size. struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data @@ -471,6 +472,8 @@ namespace ImGui // Parameters stacks (shared) IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font IMGUI_API void PopFont(); + IMGUI_API void SetFontSize(float size); + //IMGUI_API void PopFontSize(); IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); @@ -3419,10 +3422,10 @@ struct ImFontConfig int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX) - ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. + ImVec2 GlyphOffset; // 0, 0 // [FIXME-BAKED] Offset all glyphs from this font input. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font - float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs + float GlyphMinAdvanceX; // 0 // [FIXME-BAKED] Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font + float GlyphMaxAdvanceX; // FLT_MAX // [FIXME-BAKED] Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. @@ -3599,6 +3602,7 @@ struct ImFontAtlas ImVector Sources; // Source/configuration data ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID + int FontNextUniqueID; // Next value to be stored in ImFont->SourceID ImVector DrawListSharedDatas; // [Internal] Font builder @@ -3616,30 +3620,57 @@ struct ImFontAtlas //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; -// Font runtime data and rendering -// ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). -struct ImFont +// Font runtime data for a given size +// Important: pointers to ImFontBaked are only valid for the current frame. +struct ImFontBaked { // [Internal] Members: Hot ~20/24 bytes (for CalcTextSize) ImVector IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // FindGlyph(FallbackChar)->AdvanceX - float FontSize; // 4 // in // Height of characters/line, set during loading (don't change after loading) + float Size; // 4 // in // Height of characters/line, set during loading (doesn't change after loading) // [Internal] Members: Hot ~28/36 bytes (for RenderText loop) ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // All glyphs. int FallbackGlyphIndex; // 4 // out // Index of FontFallbackChar - // [Internal] Members: Cold ~32/40/60 bytes + // [Internal] Members: Cold + float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) + unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + unsigned int WantDestroy:1; // 1 // // Queued for destroy + int LastUsedFrame; // 4 // // Record of that time this was bounds + ImGuiID BakedId; // 4 // + ImFont* ContainerFont; // 4-8 // in // Parent font + void* FontBackendData; // 4-8 // // Font backend opaque storage (per baked font) + + // Functions + IMGUI_API ImFontBaked(); + IMGUI_API void ClearOutputData(); + IMGUI_API ImFontGlyph* FindGlyph(ImWchar c); // Return U+FFFD glyph if requested glyph doesn't exists. + IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist + IMGUI_API float GetCharAdvance(ImWchar c); + IMGUI_API bool IsGlyphLoaded(ImWchar c); + IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c); + IMGUI_API void BuildGrowIndex(int new_size); +}; + +// Font runtime data and rendering +// - ImFontAtlas automatically loads a default embedded font for you if you didn't load one manually. +// - Since 1.92.X a font may be rendered as any size! Therefore a font doesn't have one specific size. +// - Use 'font->GetBakedForSize(size)' to retrieve the ImFontBaked* corresponding to a given size. +// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetBakedForSize(g.FontSize). +struct ImFont +{ + // [Internal] Members: Cold ~32/40/80 bytes // Conceptually Sources[] is the list of font sources merged to create this font. + ImFontBaked* LastBaked; // Cache last bound baked. DO NOT USE. Use GetFontBaked(). + ImGuiID FontId; // Unique identifier for the font short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() - float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) - int MetricsTotalSurface;// 4 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool LockDisableLoading; short LockSingleSrcConfigIdx; @@ -3647,10 +3678,7 @@ struct ImFont // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API ImFontGlyph* FindGlyph(ImWchar c); // Return fallback glyph if requested glyph doesn't exists. - IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist - IMGUI_API float GetCharAdvance(ImWchar c); - IMGUI_API bool IsGlyphLoaded(ImWchar c); + IMGUI_API ImFontBaked* GetFontBaked(float font_size); // Get or create baked data for given size IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } const char* GetDebugName() const { return Sources ? Sources->Name : ""; } @@ -3664,15 +3692,13 @@ struct ImFont IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(FontSize * scale, text, text_end, wrap_width); } + inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(Sources[0].SizePixels * scale, text, text_end, wrap_width); } #endif // [Internal] Don't use! IMGUI_API void ClearOutputData(); IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); - IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c); - IMGUI_API void BuildGrowIndex(int new_size); }; // Added indirection to avoid patching ImDrawCmd after texture updates. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c9c32e930b16..e3986229a230 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2394,6 +2394,7 @@ void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, in // [SECTION] ImFontConfig //----------------------------------------------------------------------------- +// FIXME-NEWATLAS: Oversample specification could be more dynamic. For now, favoring automatic selection. ImFontConfig::ImFontConfig() { memset(this, 0, sizeof(*this)); @@ -2495,9 +2496,9 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildAddFont() // - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontSpecialGlyphs() -// - ImFontAtlasBuildDiscardFontGlyph() -// - ImFontAtlasBuildDiscardFontGlyphs() -// - ImFontAtlasBuildReloadFont() +// - ImFontAtlasBuildDiscardUnusedBakes() +// - ImFontAtlasBuildDiscardFontBaked() +// - ImFontAtlasBuildDiscardFontBakedGlyph() //----------------------------------------------------------------------------- // - ImFontAtlasAddDrawListSharedData() // - ImFontAtlasRemoveDrawListSharedData() @@ -2594,6 +2595,7 @@ ImFontAtlas::ImFontAtlas() RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. TexRef._TexData = NULL;// this; TexNextUniqueID = 1; + FontNextUniqueID = 1; Builder = NULL; } @@ -2685,7 +2687,8 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at // Called by NewFrame(). When multiple context own the atlas, only the first one calls this. // If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et. -void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) +// 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. +void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) { // Check that font atlas was built or backend support texture reload in which case we can build now if (atlas->RendererHasTextures) @@ -2701,6 +2704,33 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false, "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build()."); + // Clear BakedCurrent cache, this is important because it ensure the uncached path gets taken once. + // We also rely on ImFontBaked* pointers never crossing frames. + ImFontAtlasBuilder* builder = atlas->Builder; + builder->FrameCount = frame_count; + for (ImFont* font : atlas->Fonts) + font->LastBaked = NULL; + + // Garbage collect BakedPool + if (builder->BakedDiscardedCount > 0) + { + int dst_n = 0, src_n = 0; + for (; src_n < builder->BakedPool.Size; src_n++) + { + ImFontBaked* p_src = &builder->BakedPool[src_n]; + if (p_src->WantDestroy) + continue; + ImFontBaked* p_dst = &builder->BakedPool[dst_n++]; + if (p_dst == p_src) + continue; + memcpy(p_dst, p_src, sizeof(ImFontBaked)); + builder->BakedMap.SetVoidPtr(p_dst->BakedId, p_dst); + } + IM_ASSERT(dst_n + builder->BakedDiscardedCount == src_n); + builder->BakedPool.Size -= builder->BakedDiscardedCount; + builder->BakedDiscardedCount = 0; + } + // Update texture status for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { @@ -2928,15 +2958,23 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) ImFontAtlasBuildInit(this); // Create new font + ImFont* font; if (!font_cfg->MergeMode) - Fonts.push_back(IM_NEW(ImFont)); + { + font = IM_NEW(ImFont)(); + font->FontId = FontNextUniqueID++; + Fonts.push_back(font); + } else + { IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. + font = Fonts.back(); + } Sources.push_back(*font_cfg); ImFontConfig& new_font_cfg = Sources.back(); if (new_font_cfg.DstFont == NULL) - new_font_cfg.DstFont = Fonts.back(); + new_font_cfg.DstFont = font; if (!new_font_cfg.FontDataOwnedByAtlas) { new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); @@ -2960,7 +2998,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) Sources.pop_back(); if (!font_cfg->MergeMode) { - IM_DELETE(Fonts.back()); + IM_DELETE(font); Fonts.pop_back(); } return NULL; @@ -3091,7 +3129,7 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, bool need_bind_ctx = ctx != curr_ctx; if (need_bind_ctx) ImGui::SetCurrentContext(ctx); - ImGui::SetCurrentFont(new_font); + ImGui::SetCurrentFont(new_font, ctx->FontSize); if (need_bind_ctx) ImGui::SetCurrentContext(curr_ctx); } @@ -3102,7 +3140,7 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, void ImFontAtlas::RemoveFont(ImFont* font) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - ImFontAtlasBuildDiscardFontGlyphs(this, font); + font->ClearOutputData(); for (int src_n = 0; src_n < font->SourcesCount; src_n++) { @@ -3151,7 +3189,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid IM_ASSERT(font != NULL); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); - +#if 0 ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id < 0) return -1; @@ -3174,6 +3212,12 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid glyph.PackId = r_id; ImFontAtlasBuildAddFontGlyph(this, font, &font->Sources[0], &glyph); return r_id; +#endif + // FIXME-BAKED: Need a design for AddCustomRectFontGlyph() + IM_UNUSED(codepoint); + IM_UNUSED(offset); + IM_UNUSED(advance_x); + return -1; } ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx) @@ -3237,10 +3281,10 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) atlas->TexIsBuilt = true; } -void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v) +void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v) { // Automatically disable horizontal oversampling over size 36 - *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (src->SizePixels * src->RasterizerDensity > 36.0f || src->PixelSnapH) ? 1 : 2; + *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : ((size * src->RasterizerDensity > 36.0f) || src->PixelSnapH) ? 1 : 2; *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1; } @@ -3277,11 +3321,12 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) for (int src_n = 0; src_n < font->SourcesCount; src_n++) { ImFontConfig* src = &font->Sources[src_n]; + ImFontBaked* baked = font->GetFontBaked(src->SizePixels); const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); IM_ASSERT(ranges != NULL); for (; ranges[0]; ranges += 2) for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 - font->FindGlyphNoFallback((ImWchar)c); + baked->FindGlyphNoFallback((ImWchar)c); } } @@ -3436,22 +3481,23 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ //----------------------------------------------------------------------------------------------------------------------------- -static const ImFontGlyph* LoadFirstExistingGlyph(ImFont* font, const ImWchar* candidate_chars, int candidate_chars_count) +ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) { - for (int n = 0; n < candidate_chars_count; n++) - if (candidate_chars[n] != 0) - if (const ImFontGlyph* glyph = font->FindGlyphNoFallback(candidate_chars[n])) - return glyph; - return NULL; + struct { ImGuiID FontId; float BakedSize; } hashed_data; + hashed_data.FontId = font_id; + hashed_data.BakedSize = baked_size; + return ImHashData(&hashed_data, sizeof(hashed_data)); } +//----------------------------------------------------------------------------------------------------------------------------- + bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) { ImFont* font = src->DstFont; if (src->MergeMode == false) { font->ClearOutputData(); - font->FontSize = src->SizePixels; + //font->FontSize = src->SizePixels; font->ContainerAtlas = atlas; IM_ASSERT(font->Sources == src); } @@ -3466,15 +3512,15 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) // Rasterize our own ellipsis character from a dot. // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. -// FIXME-NEWATLAS: This borrows too much from FontLoader's FontAddGlyph() and suggest that we should add further helpers. -static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph) +// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers. +// FIXME-BAKED: prebaked ellipsis +/*static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph) { ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId); const int dot_spacing = 1; const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h); ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); - font->MetricsTotalSurface += r->w * r->h; ImFontGlyph glyph; glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint. @@ -3494,44 +3540,55 @@ static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, I for (int n = 0; n < 3; n++) ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); -} +}*/ -// Load/identify special glyphs -// (note that this is called again for fonts with MergeMode) -void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) +static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { - const int src_idx_in_font = (int)(src - font->Sources); - IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount); - IM_UNUSED(atlas); - - // While manipulating glyphs during init we want to restrict all searches for one source font. - font->LockSingleSrcConfigIdx = (short)src_idx_in_font; - - // Setup Fallback character // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? - const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; - if (font->FallbackGlyphIndex == -1) - if (const ImFontGlyph* glyph = LoadFirstExistingGlyph(font, fallback_chars, IM_ARRAYSIZE(fallback_chars))) + IM_ASSERT(baked->FallbackGlyphIndex == -1); + if (font->FallbackChar != 0) + if (const ImFontGlyph* glyph = baked->FindGlyphNoFallback(font->FallbackChar)) { - font->FallbackChar = (ImWchar)glyph->Codepoint; - font->FallbackGlyphIndex = font->Glyphs.index_from_ptr(glyph); // Storing index avoid need to update pointer on growth. - font->FallbackAdvanceX = glyph->AdvanceX; + baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(glyph); // Storing index avoid need to update pointer on growth. + baked->FallbackAdvanceX = glyph->AdvanceX; } // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews) - ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)font->FindGlyph((ImWchar)' '); + ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)baked->FindGlyphNoFallback((ImWchar)' '); if (space_glyph != NULL) space_glyph->Visible = false; // Setup Tab character. // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) - if (font->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL) + if (baked->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL) { ImFontGlyph tab_glyph; tab_glyph.Codepoint = '\t'; tab_glyph.AdvanceX = space_glyph->AdvanceX * IM_TABSIZE; - ImFontAtlasBuildAddFontGlyph(atlas, font, src, &tab_glyph); + ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &tab_glyph); } +} + +// Load/identify special glyphs +// (note that this is called again for fonts with MergeMode) +void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) +{ + const int src_idx_in_font = (int)(src - font->Sources); + IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount); + IM_UNUSED(atlas); + + // While manipulating glyphs during init we want to restrict all searches for one source font. + font->LockSingleSrcConfigIdx = (short)src_idx_in_font; + + // Find Fallback character. Actual glyph loaded in GetFontBaked(). + const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; + if (font->FallbackChar == 0) + for (ImWchar candidate_char : fallback_chars) + if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) // FIXME: does not respect LockSingleSrcConfigIdx() + { + font->FallbackChar = (ImWchar)candidate_char; + break; + } // Setup Ellipsis character. It is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis). // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character. @@ -3546,16 +3603,16 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im } if (font->EllipsisChar == 0) { - const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; + /*const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, font, dot_glyph); - else + else*/ font->EllipsisChar = (ImWchar)' '; } font->LockSingleSrcConfigIdx = -1; } -void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph) +void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) { if (glyph->PackId >= 0) { @@ -3564,41 +3621,45 @@ void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGl } ImWchar c = glyph->Codepoint; IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity - IM_ASSERT(glyph >= font->Glyphs.Data && glyph < font->Glyphs.Data + font->Glyphs.Size); - font->IndexLookup[c] = (ImWchar)IM_FONTGLYPH_INDEX_UNUSED; - font->IndexAdvanceX[c] = font->FallbackAdvanceX; + IM_ASSERT(glyph >= baked->Glyphs.Data && glyph < baked->Glyphs.Data + baked->Glyphs.Size); + baked->IndexLookup[c] = IM_FONTGLYPH_INDEX_UNUSED; + baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } -void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFontBaked* baked) { - for (ImFontGlyph& glyph : font->Glyphs) + ImGuiContext& g = *GImGui; + IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() + + ImFontAtlasBuilder* builder = atlas->Builder; + ImFont* font = baked->ContainerFont; + IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); + + for (ImFontGlyph& glyph : baked->Glyphs) if (glyph.PackId >= 0) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); - font->ClearOutputData(); - font->FallbackChar = font->EllipsisChar = 0; + + if (atlas->FontLoader->FontBakedDestroy) + atlas->FontLoader->FontBakedDestroy(atlas, baked); + + builder->BakedMap.SetVoidPtr(baked->BakedId, NULL); + builder->BakedDiscardedCount++; + baked->ClearOutputData(); + baked->WantDestroy = true; + font->LastBaked = NULL; } -// Discard old glyphs and reload font. Use if changing font size. -void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, ImFont* font_filter) { - ImFontAtlasBuildDiscardFontGlyphs(atlas, font); - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + ImFontAtlasBuilder* builder = atlas->Builder; + const int GC_FRAMES = 2; + for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { - ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; - IM_ASSERT(src->SizePixels > 0.0f); - - // Reload font in backend - if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL) - atlas->FontLoader->FontSrcDestroy(atlas, src); - if (atlas->FontLoader && atlas->FontLoader->FontSrcInit != NULL) - atlas->FontLoader->FontSrcInit(atlas, src); - - ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. - atlas->TexIsBuilt = false; + ImFontBaked* baked = &builder->BakedPool[baked_n]; + if (font_filter == NULL || baked->ContainerFont == font_filter) + if (baked->LastUsedFrame + GC_FRAMES < atlas->Builder->FrameCount && !baked->WantDestroy) + ImFontAtlasBuildDiscardFontBaked(atlas, baked); } - - // Notify external systems - ImFontAtlasBuildNotifySetFont(atlas, font, font); } // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* @@ -3747,8 +3808,8 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) builder->RectsDiscardedSurface = 0; // Patch glyphs UV - for (ImFont* font : atlas->Fonts) - for (ImFontGlyph& glyph : font->Glyphs) + for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs) if (glyph.PackId != -1) { ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); @@ -3798,8 +3859,11 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) { - // Currently using a heuristic for repack without growing. + // Can some baked contents be ditched? ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL); + + // Currently using a heuristic for repack without growing. if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f) ImFontAtlasBuildGrowTexture(atlas); else @@ -3845,6 +3909,8 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) { ImFontAtlasBuilder* builder = atlas->Builder; + ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL); + ImTextureData* old_tex = atlas->TexData; ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); @@ -3927,7 +3993,7 @@ void ImFontAtlasPackInit(ImFontAtlas * atlas) ImFontAtlasBuilder* builder = atlas->Builder; // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it. - int pack_node_count = tex->Width; + const int pack_node_count = tex->Width; builder->PackNodes.resize(pack_node_count); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); @@ -4046,38 +4112,40 @@ ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id return &builder->Rects[index_entry->TargetIndex]; } -ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) +ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) { - ImFontAtlas* atlas = ContainerAtlas; - if (LockDisableLoading || atlas->Locked) + ImFont* font = ContainerFont; + ImFontBaked* baked = this; + ImFontAtlas* atlas = font->ContainerAtlas; + if (font->LockDisableLoading || atlas->Locked) return NULL; //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); // Load from single source or all sources? - int srcs_count = (LockSingleSrcConfigIdx != -1) ? 1 : SourcesCount; - ImFontConfig* srcs = (LockSingleSrcConfigIdx != -1) ? &Sources[LockSingleSrcConfigIdx] : Sources; + int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount; + ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources; // Call backend const ImFontLoader* font_loader = atlas->FontLoader; - if (!font_loader->FontAddGlyph(atlas, this, srcs, srcs_count, codepoint)) + if (!font_loader->FontBakedAddGlyph(atlas, baked, srcs, srcs_count, codepoint)) { // Mark index as not found, so we don't attempt the search twice - BuildGrowIndex(codepoint + 1); - IndexAdvanceX[codepoint] = FallbackAdvanceX; - IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; + baked->BuildGrowIndex(codepoint + 1); + baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX; + baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; return NULL; } // FIXME: Add hooks for e.g. #7962 - ImFontGlyph* glyph = &Glyphs.back(); + ImFontGlyph* glyph = &baked->Glyphs.back(); return glyph; } // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b IM_MSVC_RUNTIME_CHECKS_OFF -static float BuildLoadGlyphGetAdvanceOrFallback(ImFont* font, unsigned int codepoint) +static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* font, unsigned int codepoint) { ImFontGlyph* glyph = font->BuildLoadGlyph((ImWchar)codepoint); return glyph ? glyph->AdvanceX : font->FallbackAdvanceX; @@ -4124,9 +4192,7 @@ void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) struct ImGui_ImplStbTrueType_FontSrcData { stbtt_fontinfo FontInfo; - float ScaleForRasterX; // Factor in RasterizationDensity * OversampleH - float ScaleForRasterY; // Factor in RasterizationDensity * OversampleV - float ScaleForLayout; + float ScaleFactor; }; static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) @@ -4152,28 +4218,10 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* } src->FontLoaderData = bd_font_data; - // FIXME-NEWFONTS: reevaluate sizing metrics - int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); - float scale; if (src->SizePixels > 0.0f) - scale = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); + bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else - scale = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); - bd_font_data->ScaleForRasterX = scale * src->SizePixels * src->RasterizerDensity * oversample_h; - bd_font_data->ScaleForRasterY = scale * src->SizePixels * src->RasterizerDensity * oversample_v; - bd_font_data->ScaleForLayout = scale * src->SizePixels; - - // FIXME-NEWFONTS: make use of line gap value - int unscaled_ascent, unscaled_descent, unscaled_line_gap; - stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); - - if (src->MergeMode == false) - { - ImFont* font = src->DstFont; - font->Ascent = ImCeil(unscaled_ascent * bd_font_data->ScaleForLayout); - font->Descent = ImFloor(unscaled_descent * bd_font_data->ScaleForLayout); - } + bd_font_data->ScaleFactor = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); return true; } @@ -4197,7 +4245,27 @@ static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFon return glyph_index != 0; } -static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) +static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked) +{ + IM_UNUSED(atlas); + ImFont* font = baked->ContainerFont; + + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + + // FIXME-NEWFONTS: reevaluate how to use sizing metrics + // FIXME-NEWFONTS: make use of line gap value + float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + stbtt_GetFontVMetrics(&bd_font_data->FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap); + baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); + baked->Descent = ImFloor(unscaled_descent * scale_for_layout); + } +} + +static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) { // Search for first font which has the glyph ImGui_ImplStbTrueType_FontSrcData* bd_font_data = NULL; @@ -4215,9 +4283,12 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, if (glyph_index == 0) return false; // Not found - const float scale_for_layout = bd_font_data->ScaleForLayout; // ~ (font units to pixels) - const float scale_for_raster_x = bd_font_data->ScaleForRasterX; // ~ (font units to pixels) * RasterizationDensity * OversampleH - const float scale_for_raster_y = bd_font_data->ScaleForRasterY; // ~ (font units to pixels) * RasterizationDensity * OversampleV + // Fonts unit to pixels + int oversample_h, oversample_v; + ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v); + const float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; + const float scale_for_raster_x = bd_font_data->ScaleFactor * baked->Size * src->RasterizerDensity * oversample_h; + const float scale_for_raster_y = bd_font_data->ScaleFactor * baked->Size * src->RasterizerDensity * oversample_v; // Obtain size and advance int x0, y0, x1, y1; @@ -4235,8 +4306,6 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, // (generally based on stbtt_PackFontRangesRenderIntoRects) if (is_visible) { - int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(src, &oversample_h, &oversample_v); const int w = (x1 - x0 + oversample_h - 1); const int h = (y1 - y0 + oversample_v - 1); ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); @@ -4246,9 +4315,7 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); return false; } - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); - font->MetricsTotalSurface += w * h; // Render stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1); @@ -4267,7 +4334,7 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v); float font_off_x = src->GlyphOffset.x + stbtt__oversample_shift(oversample_h); - float font_off_y = src->GlyphOffset.y + stbtt__oversample_shift(oversample_v) + IM_ROUND(font->Ascent); + float font_off_y = src->GlyphOffset.y + stbtt__oversample_shift(oversample_v) + IM_ROUND(baked->Ascent); float recip_h = 1.0f / (oversample_h * src->RasterizerDensity); float recip_v = 1.0f / (oversample_v * src->RasterizerDensity); @@ -4280,19 +4347,19 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, glyph.Y1 = (y0 + (int)r->h) * recip_v + font_off_y; glyph.Visible = true; glyph.PackId = pack_id; - ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); + ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); // Copy to texture, post-process and queue update for backend ImTextureData* tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); ImFontAtlasTextureBlockConvert(bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); - ImFontAtlasPostProcessData pp_data = { atlas, font, src, &font->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; + ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, &baked->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; ImFontAtlasTextureBlockPostProcess(&pp_data); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } else { - ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); + ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); } return true; @@ -4305,7 +4372,9 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() loader.FontSrcInit = ImGui_ImplStbTrueType_FontSrcInit; loader.FontSrcDestroy = ImGui_ImplStbTrueType_FontSrcDestroy; loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph; - loader.FontAddGlyph = ImGui_ImplStbTrueType_FontAddGlyph; + loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit; + loader.FontBakedDestroy = NULL; + loader.FontBakedAddGlyph = ImGui_ImplStbTrueType_FontBakedAddGlyph; return &loader; } @@ -4628,6 +4697,34 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector* out_ranges) // [SECTION] ImFont //----------------------------------------------------------------------------- +ImFontBaked::ImFontBaked() +{ + memset(this, 0, sizeof(*this)); + FallbackGlyphIndex = -1; +} + +void ImFontBaked::ClearOutputData() +{ + FallbackAdvanceX = 0.0f; + Glyphs.clear(); + IndexAdvanceX.clear(); + IndexLookup.clear(); + FallbackGlyphIndex = -1; + Ascent = Descent = 0.0f; + MetricsTotalSurface = 0; +} + +void ImFontBaked::BuildGrowIndex(int new_size) +{ + IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); + if (new_size <= IndexLookup.Size) + return; + //ImGuiContext& g = *GImGui; + //IMGUI_DEBUG_LOG_FONT("[font] BuildGrowIndex(%d)\n", new_size); + IndexAdvanceX.resize(new_size, -1.0f); + IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); +} + ImFont::ImFont() { memset(this, 0, sizeof(*this)); @@ -4642,14 +4739,17 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { - FallbackAdvanceX = 0.0f; - Glyphs.clear(); - IndexAdvanceX.clear(); - IndexLookup.clear(); - FallbackGlyphIndex = -1; - Ascent = Descent = 0.0f; - MetricsTotalSurface = 0; + if (ImFontAtlas* atlas = ContainerAtlas) + if (ImFontAtlasBuilder* builder = atlas->Builder) + for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + { + ImFontBaked* baked = &builder->BakedPool[baked_n]; + if (baked->ContainerFont == this) + ImFontAtlasBuildDiscardFontBaked(atlas, baked); + } + FallbackChar = EllipsisChar = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); + LastBaked = NULL; } // API is designed this way to avoid exposing the 8K page size @@ -4665,24 +4765,15 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) return true; } -void ImFont::BuildGrowIndex(int new_size) -{ - IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); - if (new_size <= IndexLookup.Size) - return; - IndexAdvanceX.resize(new_size, -1.0f); - IndexLookup.resize(new_size, (ImU16)-1); -} - // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). // 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. -ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph) +ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph) { - int glyph_idx = font->Glyphs.Size; - font->Glyphs.push_back(*in_glyph); - ImFontGlyph& glyph = font->Glyphs[glyph_idx]; - IM_ASSERT(font->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. + int glyph_idx = baked->Glyphs.Size; + baked->Glyphs.push_back(*in_glyph); + ImFontGlyph& glyph = baked->Glyphs[glyph_idx]; + IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. // Set UV from packed rectangle if (in_glyph->PackId >= 0) @@ -4693,6 +4784,7 @@ ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFo glyph.V0 = (r->y) * atlas->TexUvScale.y; glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + baked->MetricsTotalSurface += r->w * r->h; } if (src != NULL) @@ -4718,17 +4810,22 @@ ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFo // Update lookup tables int codepoint = glyph.Codepoint; - font->BuildGrowIndex(codepoint + 1); - font->IndexAdvanceX[codepoint] = glyph.AdvanceX; - font->IndexLookup[codepoint] = (ImU16)glyph_idx; + baked->BuildGrowIndex(codepoint + 1); + baked->IndexAdvanceX[codepoint] = glyph.AdvanceX; + baked->IndexLookup[codepoint] = (ImU16)glyph_idx; const int page_n = codepoint / 8192; - font->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); + baked->ContainerFont->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); return &glyph; } void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) { + // FIXME-BAKED: Implement AddRemapChar() + IM_UNUSED(from_codepoint); + IM_UNUSED(to_codepoint); + IM_UNUSED(overwrite_dst); + /* IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. unsigned int index_size = (unsigned int)IndexLookup.Size; @@ -4740,10 +4837,11 @@ void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool ove BuildGrowIndex(from_codepoint + 1); IndexLookup[from_codepoint] = (to_codepoint < index_size) ? IndexLookup.Data[to_codepoint] : (ImU16)-1; IndexAdvanceX[from_codepoint] = (to_codepoint < index_size) ? IndexAdvanceX.Data[to_codepoint] : 1.0f; + */ } // Find glyph, load if necessary, return fallback if missing -ImFontGlyph* ImFont::FindGlyph(ImWchar c) +ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c) { if (c < (size_t)IndexLookup.Size) IM_LIKELY { @@ -4758,7 +4856,7 @@ ImFontGlyph* ImFont::FindGlyph(ImWchar c) } // Attempt to load but when missing, return NULL instead of FallbackGlyph -ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) +ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c) { if (c < (size_t)IndexLookup.Size) IM_LIKELY { @@ -4768,11 +4866,10 @@ ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) if (i != IM_FONTGLYPH_INDEX_UNUSED) return &Glyphs.Data[i]; } - ImFontGlyph* glyph = BuildLoadGlyph(c); - return glyph; + return BuildLoadGlyph(c); } -bool ImFont::IsGlyphLoaded(ImWchar c) +bool ImFontBaked::IsGlyphLoaded(ImWchar c) { if (c < (size_t)IndexLookup.Size) IM_LIKELY { @@ -4797,7 +4894,7 @@ bool ImFont::IsGlyphInFont(ImWchar c) // This is manually inlined in CalcTextSizeA() and CalcWordWrapPosition(), with a non-inline call to BuildLoadGlyphGetAdvanceOrFallback(). IM_MSVC_RUNTIME_CHECKS_OFF -float ImFont::GetCharAdvance(ImWchar c) +float ImFontBaked::GetCharAdvance(ImWchar c) { if ((int)c < IndexAdvanceX.Size) { @@ -4813,6 +4910,46 @@ float ImFont::GetCharAdvance(ImWchar c) } IM_MSVC_RUNTIME_CHECKS_RESTORE +// ImFontBaked pointers are valid for the entire frame but shall never be kept between frames. +ImFontBaked* ImFont::GetFontBaked(float size) +{ + ImFontBaked* baked = LastBaked; + if (baked && baked->Size == size) + return baked; + + ImFontAtlas* atlas = ContainerAtlas; + ImFontAtlasBuilder* builder = atlas->Builder; + + ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size); + ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); + baked = *p_baked_in_map; + if (baked != NULL) + { + // FIXME-BAKED: Design for picking a nearest size? + IM_ASSERT(baked->Size == size && baked->ContainerFont == this && baked->BakedId == baked_id); + baked->LastUsedFrame = builder->FrameCount; + LastBaked = baked; + return baked; + } + + // Create new + ImGuiContext& g = *GImGui; + IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() + IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", size); + baked = builder->BakedPool.push_back(ImFontBaked()); + baked->Size = size; + baked->BakedId = baked_id; + baked->ContainerFont = this; + baked->LastUsedFrame = ContainerAtlas->Builder->FrameCount; + LastBaked = baked; + *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can. + if (atlas->FontLoader->FontBakedInit) + atlas->FontLoader->FontBakedInit(atlas, baked); + ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked); + + return baked; +} + // Trim trailing space and find beginning of next line static inline const char* CalcWordWrapNextLineStartA(const char* text, const char* text_end) { @@ -4839,10 +4976,13 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha // Cut words that cannot possibly fit within one line. // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish" + + ImFontBaked* baked = GetFontBaked(size); + const float scale = size / baked->Size; + float line_width = 0.0f; float word_width = 0.0f; float blank_width = 0.0f; - const float scale = size / FontSize; wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters const char* word_end = text; @@ -4877,9 +5017,9 @@ const char* ImFont::CalcWordWrapPosition(float size, const char* text, const cha } // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);' - float char_width = (c < (unsigned int)IndexAdvanceX.Size) ? IndexAdvanceX.Data[c] : -1.0f; + float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f; if (char_width < 0.0f) - char_width = BuildLoadGlyphGetAdvanceOrFallback(this, c); + char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c); if (ImCharIsBlankW(c)) { @@ -4935,7 +5075,8 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons text_end = text_begin + ImStrlen(text_begin); // FIXME-OPT: Need to avoid this. const float line_height = size; - const float scale = size / FontSize; + ImFontBaked* baked = GetFontBaked(size); + const float scale = size / baked->Size; ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; @@ -4986,9 +5127,9 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons } // Optimized inline version of 'float char_width = GetCharAdvance((ImWchar)c);' - float char_width = (c < (unsigned int)IndexAdvanceX.Size) ? IndexAdvanceX.Data[c] : -1.0f; + float char_width = (c < (unsigned int)baked->IndexAdvanceX.Size) ? baked->IndexAdvanceX.Data[c] : -1.0f; if (char_width < 0.0f) - char_width = BuildLoadGlyphGetAdvanceOrFallback(this, c); + char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c); char_width *= scale; if (line_width + char_width >= max_width) @@ -5015,12 +5156,13 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip) { - const ImFontGlyph* glyph = FindGlyph(c); + ImFontBaked* baked = GetFontBaked(size); + const ImFontGlyph* glyph = baked->FindGlyph(c); if (!glyph || !glyph->Visible) return; if (glyph->Colored) col |= ~IM_COL32_A_MASK; - float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; + float scale = (size >= 0.0f) ? (size / baked->Size) : 1.0f; float x = IM_TRUNC(pos.x); float y = IM_TRUNC(pos.y); @@ -5062,8 +5204,10 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im if (!text_end) text_end = text_begin + ImStrlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls. - const float scale = size / FontSize; - const float line_height = FontSize * scale; + const float line_height = size; + ImFontBaked* baked = GetFontBaked(size); + + const float scale = size / baked->Size; const float origin_x = x; const bool word_wrap_enabled = (wrap_width > 0.0f); @@ -5158,7 +5302,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im continue; } - const ImFontGlyph* glyph = FindGlyph((ImWchar)c); + const ImFontGlyph* glyph = baked->FindGlyph((ImWchar)c); if (glyph == NULL) continue; diff --git a/imgui_internal.h b/imgui_internal.h index 07cd846670ee..5075028ca4c0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2130,11 +2130,12 @@ struct ImGuiContext ImGuiIO IO; ImGuiPlatformIO PlatformIO; ImGuiStyle Style; - 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. - float FontScale; // == FontSize / Font->FontSize - float CurrentDpiScale; // Current window/viewport DpiScale + ImFont* Font; // == FontStack.back().Font + ImFontBaked* FontBaked; // == Font->GetFontBaked(FontSize) + float FontSize; // == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. + //float FontBaseSize; // == io.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. + float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; ImVectorTextures; double Time; @@ -2673,7 +2674,7 @@ struct IMGUI_API ImGuiWindow // We don't use g.FontSize because the window may be != g.CurrentWindow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; } + //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); } }; @@ -3098,7 +3099,7 @@ namespace ImGui IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags); // Fonts, drawing - IMGUI_API void SetCurrentFont(ImFont* font); + IMGUI_API void SetCurrentFont(ImFont* font, float font_size); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } IMGUI_API void PushPasswordFont(); inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. @@ -3661,7 +3662,9 @@ struct ImFontLoader bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); - bool (*FontAddGlyph)(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint); + void (*FontBakedInit)(ImFontAtlas* atlas, ImFontBaked* baked); + void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontBaked* baked); + bool (*FontBakedAddGlyph)(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint); ImFontLoader() { memset(this, 0, sizeof(*this)); } }; @@ -3698,6 +3701,7 @@ struct ImFontAtlasPostProcessData ImFontAtlas* FontAtlas; ImFont* Font; ImFontConfig* FontSrc; + ImFontBaked* FontBaked; ImFontGlyph* Glyph; // Pixel data @@ -3723,11 +3727,17 @@ struct ImFontAtlasBuilder int RectsPackedSurface; // Number of packed pixels. Used when compacting to heuristically find the ideal texture size. int RectsDiscardedCount; int RectsDiscardedSurface; + int FrameCount; // Current frame count ImVec2i MaxRectSize; // Largest rectangle to pack (de-facto used as a "minimum texture size") ImVec2i MaxRectBounds; // Bottom-right most used pixels bool LockDisableResize; // Disable resizing texture bool PreloadedAllGlyphsRanges; // Set when missing ImGuiBackendFlags_RendererHasTextures features forces atlas to preload everything. + // Cache of all ImFontBaked + ImStableVector BakedPool; + ImGuiStorage BakedMap; + int BakedDiscardedCount; + // Custom rectangle identifiers ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure. ImFontAtlasRectId PackIdLinesTexData; @@ -3750,20 +3760,23 @@ IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); -IMGUI_API ImFontGlyph* ImFontAtlasBuildAddFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontGlyph* glyph); -IMGUI_API void ImFontAtlasBuildDiscardFontGlyphs(ImFontAtlas* atlas, ImFont* font); +IMGUI_API void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, ImFont* font_filter); +IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); +IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend! IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy -IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, int* out_oversample_h, int* out_oversample_v); +IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); + +IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); +IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); IMGUI_API ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); -IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count); IMGUI_API void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); IMGUI_API void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); IMGUI_API void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e1813110dc9e..e41041ce142d 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3375,7 +3375,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ButtonBehavior(row_r, row_id, NULL, NULL); KeepAliveID(row_id); - const float ascent_scaled = g.Font->Ascent * g.FontScale; // FIXME: Standardize those scaling factors better + const float ascent_scaled = g.FontBaked->Ascent * g.FontScale; // FIXME: Standardize those scaling factors better const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f); const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component const ImVec2 align = g.Style.TableAngledHeadersTextAlign; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index c632b45a4d6f..2304aaf37b3a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1518,7 +1518,7 @@ bool ImGui::TextLink(const char* label) ColorConvertHSVtoRGB(h, s, v, line_colf.x, line_colf.y, line_colf.z); } - float line_y = bb.Max.y + ImFloor(g.Font->Descent * g.FontScale * 0.20f); + float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontScale * 0.20f); window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); @@ -3956,9 +3956,10 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end, const char** remaining, ImVec2* out_offset, bool stop_on_new_line) { ImGuiContext& g = *ctx; - ImFont* font = g.Font; + //ImFont* font = g.Font; + ImFontBaked* baked = g.FontBaked; const float line_height = g.FontSize; - const float scale = line_height / font->FontSize; + const float scale = line_height / baked->Size; ImVec2 text_size = ImVec2(0, 0); float line_width = 0.0f; @@ -3984,7 +3985,7 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c if (c == '\r') continue; - line_width += font->GetCharAdvance((ImWchar)c) * scale; + line_width += baked->GetCharAdvance((ImWchar)c) * scale; } if (text_size.x < line_width) @@ -4011,7 +4012,7 @@ namespace ImStb { static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->TextLen; } static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance((ImWchar)c) * g.FontScale; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.FontBaked->GetCharAdvance((ImWchar)c) * g.FontScale; } static char STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { @@ -4314,19 +4315,21 @@ void ImGui::PushPasswordFont() { ImGuiContext& g = *GImGui; ImFont* in_font = g.Font; + ImFontBaked* in_baked = g.FontBaked; + ImFontGlyph glyph = *in_baked->FindGlyph('*'); + glyph.PackId = -1; ImFont* out_font = &g.InputTextPasswordFont; - ImFontGlyph* glyph = in_font->FindGlyph('*'); - out_font->FontSize = in_font->FontSize; out_font->Scale = in_font->Scale; - out_font->Ascent = in_font->Ascent; - out_font->Descent = in_font->Descent; out_font->ContainerAtlas = in_font->ContainerAtlas; - out_font->Glyphs.resize(0); - out_font->Glyphs.push_back(*glyph); - out_font->FallbackGlyphIndex = 0; - out_font->FallbackAdvanceX = glyph->AdvanceX; out_font->LockDisableLoading = true; - IM_ASSERT(out_font->Glyphs.Size == 1 && out_font->IndexAdvanceX.Size == 0 && out_font->IndexLookup.Size == 0); + ImFontBaked* out_baked = out_font->GetFontBaked(in_baked->Size); + IM_ASSERT(out_baked->Glyphs.Size <= 1 && out_baked->IndexAdvanceX.Size == 0 && out_baked->IndexLookup.Size == 0); + out_baked->Ascent = in_baked->Ascent; + out_baked->Descent = in_baked->Descent; + out_baked->Glyphs.resize(0); + out_baked->Glyphs.push_back(glyph); + out_baked->FallbackGlyphIndex = 0; + out_baked->FallbackAdvanceX = glyph.AdvanceX; PushFont(out_font); } @@ -5354,7 +5357,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ else { ImVec2 rect_size = InputTextCalcTextSize(&g, p, text_selected_end, &p, NULL, true); - if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines + if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn)); rect.ClipWith(clip_rect); if (rect.Overlaps(clip_rect)) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index b388d15314e8..022ec2b2c8b0 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -46,6 +46,7 @@ #include FT_FREETYPE_H // #include FT_MODULE_H // #include FT_GLYPH_H // +#include FT_SIZES_H // #include FT_SYNTHESIS_H // // Handle LunaSVG and PlutoSVG @@ -150,15 +151,19 @@ namespace ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } }; - // Font parameters and metrics. - struct ImGui_ImplFreeType_FontInfo + // Stored in ImFontBaked::FontBackendData: pointer to SourcesCount instances of this. + struct ImGui_ImplFreeType_FontSrcBakedData { - float PixelHeight; // Size this font was generated with. + FT_Size FtSize; // This represent a FT_Face with a given size. + + // Metrics float Ascender; // The pixel extents above the baseline in pixels (typically positive). float Descender; // The extents below the baseline in pixels (typically negative). float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. float LineGap; // The spacing in pixels between one row's descent and the next row's ascent. float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font. + + ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } }; // Stored in ImFontConfig::FontLoaderData @@ -166,20 +171,19 @@ namespace { bool InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. void CloseFont(); - void SetPixelHeight(float pixel_height); // Change font pixel size. const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch); ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); } ~ImGui_ImplFreeType_FontSrcData() { CloseFont(); } // Members - ImGui_ImplFreeType_FontInfo Info; // Font descriptor of the current font. FT_Face FtFace; unsigned int UserFlags; // = ImFontConfig::RasterizerFlags FT_Int32 LoadFlags; FT_Render_Mode RenderMode; float RasterizationDensity; float InvRasterizationDensity; + ImFontBaked* BakedLastActivated; }; bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_font_builder_flags) @@ -222,9 +226,6 @@ namespace RasterizationDensity = src->RasterizerDensity; InvRasterizationDensity = 1.0f / RasterizationDensity; - memset(&Info, 0, sizeof(Info)); - SetPixelHeight(src->SizePixels); - return true; } @@ -237,31 +238,6 @@ namespace } } - void ImGui_ImplFreeType_FontSrcData::SetPixelHeight(float pixel_height) - { - // Vuhdo (2017): "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' - // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. - // FT_Set_Pixel_Sizes() doesn't seem to get us the same result." - // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) - FT_Size_RequestRec req; - req.type = (UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; - req.width = 0; - req.height = (uint32_t)(pixel_height * 64 * RasterizationDensity); - req.horiResolution = 0; - req.vertResolution = 0; - FT_Request_Size(FtFace, &req); - // Note: To handle multiple sizes later, we may need to use FT_New_Size(), FT_Activate_Size() - - // Update font info - FT_Size_Metrics metrics = FtFace->size->metrics; - Info.PixelHeight = pixel_height * InvRasterizationDensity; - Info.Ascender = (float)FT_CEIL(metrics.ascender) * InvRasterizationDensity; - Info.Descender = (float)FT_CEIL(metrics.descender) * InvRasterizationDensity; - Info.LineSpacing = (float)FT_CEIL(metrics.height) * InvRasterizationDensity; - Info.LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * InvRasterizationDensity; - Info.MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * InvRasterizationDensity; - } - const FT_Glyph_Metrics* ImGui_ImplFreeType_FontSrcData::LoadGlyph(uint32_t codepoint) { uint32_t glyph_index = FT_Get_Char_Index(FtFace, codepoint); @@ -447,12 +423,6 @@ bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) if (!bd_font_data->InitFont(bd->Library, src, atlas->FontBuilderFlags)) return false; - if (src->MergeMode == false) - { - ImFont* font = src->DstFont; - font->Ascent = bd_font_data->Info.Ascender; - font->Descent = bd_font_data->Info.Descender; - } return true; } @@ -464,7 +434,65 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) src->FontLoaderData = NULL; } -bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) +void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked) +{ + IM_UNUSED(atlas); + ImFont* font = baked->ContainerFont; + const float size = baked->Size; + + IM_ASSERT(baked->FontBackendData == NULL); + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_datas = (ImGui_ImplFreeType_FontSrcBakedData*)IM_ALLOC(sizeof(ImGui_ImplFreeType_FontSrcBakedData) * font->SourcesCount); + baked->FontBackendData = bd_baked_datas; + + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontBackendData; + bd_font_data->BakedLastActivated = baked; + + // We need one FT_Size per source, so create one ImGui_ImplFreeType_FontBakedData for each source. + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = &bd_baked_datas[src_n]; + FT_New_Size(bd_font_data->FtFace, &bd_baked_data->FtSize); + FT_Activate_Size(bd_baked_data->FtSize); + + // Vuhdo 2017: "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' + // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. + // FT_Set_Pixel_Sizes() doesn't seem to get us the same result." + // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) + FT_Size_RequestRec req; + req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; + req.width = 0; + req.height = (uint32_t)(size * 64 * bd_font_data->RasterizationDensity); + req.horiResolution = 0; + req.vertResolution = 0; + FT_Request_Size(bd_font_data->FtFace, &req); + + // Read metrics + FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; + bd_baked_data->Ascender = (float)FT_CEIL(metrics.ascender) * bd_font_data->InvRasterizationDensity; + bd_baked_data->Descender = (float)FT_CEIL(metrics.descender) * bd_font_data->InvRasterizationDensity; + bd_baked_data->LineSpacing = (float)FT_CEIL(metrics.height) * bd_font_data->InvRasterizationDensity; + bd_baked_data->LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * bd_font_data->InvRasterizationDensity; + bd_baked_data->MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * bd_font_data->InvRasterizationDensity; + + // Output + baked->Ascent = bd_baked_data->Ascender; + baked->Descent = bd_baked_data->Descender; + } +} + +void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontBaked* baked) +{ + IM_UNUSED(atlas); + ImFont* font = baked->ContainerFont; + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_datas = (ImGui_ImplFreeType_FontSrcBakedData*)baked->FontBackendData; + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + FT_Done_Size(bd_baked_datas[src_n].FtSize); + IM_FREE(bd_baked_datas); + baked->FontBackendData = NULL; +} + +bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) { // Search for first font which has the glyph ImGui_ImplFreeType_FontSrcData* bd_font_data = NULL; @@ -481,6 +509,15 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon if (glyph_index == 0) return false; // Not found + if (bd_font_data->BakedLastActivated != baked) + { + // Activate current size + int src_n = (int)(font_cfg - srcs); + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = &((ImGui_ImplFreeType_FontSrcBakedData*)baked->FontBackendData)[src_n]; + FT_Activate_Size(bd_baked_data->FtSize); + bd_font_data->BakedLastActivated = baked; + } + const FT_Glyph_Metrics* metrics = bd_font_data->LoadGlyph(codepoint); if (metrics == NULL) return false; @@ -515,9 +552,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); return false; } - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); - font->MetricsTotalSurface += w * h; // Render pixels to our temporary buffer atlas->Builder->TempBuffer.resize(w * h * 4); @@ -525,7 +560,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w); float font_off_x = src->GlyphOffset.x; - float font_off_y = src->GlyphOffset.y + IM_ROUND(font->Ascent); + float font_off_y = src->GlyphOffset.y + IM_ROUND(baked->Ascent); float recip_h = 1.0f / src->RasterizerDensity; float recip_v = 1.0f / src->RasterizerDensity; @@ -539,19 +574,19 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon glyph.Visible = true; glyph.Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); glyph.PackId = pack_id; - ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); + ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); // Copy to texture, post-process and queue update for backend ImTextureData* tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); ImFontAtlasTextureBlockConvert(temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); - ImFontAtlasPostProcessData pp_data = { atlas, font, src, &font->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; + ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, &baked->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; ImFontAtlasTextureBlockPostProcess(&pp_data); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } else { - ImFontAtlasBuildAddFontGlyph(atlas, font, src, &glyph); + ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); } return true; } @@ -573,7 +608,9 @@ const ImFontLoader* ImGuiFreeType::GetFontLoader() loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit; loader.FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy; loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph; - loader.FontAddGlyph = ImGui_ImplFreeType_FontAddGlyph; + loader.FontBakedInit = ImGui_ImplFreeType_FontBakedInit; + loader.FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy; + loader.FontBakedAddGlyph = ImGui_ImplFreeType_FontBakedAddGlyph; return &loader; } From 80404fae3048eb27ae04d06388475ad4b7475deb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 30 Jan 2025 16:32:25 +0100 Subject: [PATCH 477/716] Fonts: clarify ClearTexData() as not supported with dynamic atlases. --- imgui.cpp | 6 ++++-- imgui.h | 4 ++-- imgui_draw.cpp | 42 ++++++++++++++++++++++++------------------ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index abe3cab3e95d..0b14338574b2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5785,7 +5785,8 @@ void ImGui::EndFrame() UpdateTexturesEndFrame(); // Unlock font atlas - g.IO.Fonts->Locked = false; + ImFontAtlas* atlas = g.IO.Fonts; + atlas->Locked = false; // Clear Input data for next frame g.IO.MousePosPrev = g.IO.MousePos; @@ -8575,8 +8576,9 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) void ImGui::UpdateFontsNewFrame() { ImGuiContext& g = *GImGui; + ImFontAtlas* atlas = g.IO.Fonts; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) - g.IO.Fonts->Locked = true; + atlas->Locked = true; SetCurrentFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels); IM_ASSERT(g.Font->IsLoaded()); } diff --git a/imgui.h b/imgui.h index 85fbb47d911e..717c9f0e478a 100644 --- a/imgui.h +++ b/imgui.h @@ -3517,7 +3517,7 @@ struct ImFontAtlas // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. IMGUI_API void ClearFonts(); // [OBSOLETE] Clear input+output font data (same as ClearInputData() + glyphs storage, UV coordinates). - IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. + IMGUI_API void ClearTexData(); // [OBSOLETE] Clear CPU-side copy of the texture data. Saves RAM once the texture has been copied to graphics memory. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy path for build atlas + retrieving pixel data. @@ -3592,7 +3592,7 @@ struct ImFontAtlas ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. ImTextureData* TexData; // Current texture ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! - bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert. + bool Locked; // Marked as locked during ImGui::NewFrame()..EndFrame() scope if TexUpdates are not supported. Any attempt to modify the atlas will assert. bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. bool TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e3986229a230..7c7a7916afe7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2607,9 +2607,11 @@ ImFontAtlas::~ImFontAtlas() void ImFontAtlas::Clear() { - ClearInputData(); - ClearTexData(); ClearFonts(); + bool backup_renderer_has_textures = RendererHasTextures; + RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. + ClearTexData(); + RendererHasTextures = backup_renderer_has_textures; } void ImFontAtlas::ClearCache() @@ -2647,12 +2649,14 @@ void ImFontAtlas::ClearInputData() Sources.clear(); } +// Clear CPU-side copy of the texture data. void ImFontAtlas::ClearTexData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - TexList.clear(); - IM_DELETE(TexData); - TexData = NULL; + IM_ASSERT(RendererHasTextures == false && "Not supported for dynamic atlases, but you may call Clear()."); + for (ImTextureData* tex : TexList) + tex->DestroyPixels(); + //Locked = true; // Hoped to be able to lock this down but some reload patterns may not be happy with it. } void ImFontAtlas::ClearFonts() @@ -2686,7 +2690,7 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at } // Called by NewFrame(). When multiple context own the atlas, only the first one calls this. -// If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et. +// If you are calling this yourself, ensure atlas->RendererHasTextures is set. // 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) { @@ -3256,7 +3260,7 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } -// When atlas->RendererHasTexUpdates == true, this is only called if no font were loaded. +// When atlas->RendererHasTextures = true, this is only called if no font were loaded. void ImFontAtlasBuildMain(ImFontAtlas* atlas) { IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); @@ -3481,16 +3485,6 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ //----------------------------------------------------------------------------------------------------------------------------- -ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) -{ - struct { ImGuiID FontId; float BakedSize; } hashed_data; - hashed_data.FontId = font_id; - hashed_data.BakedSize = baked_size; - return ImHashData(&hashed_data, sizeof(hashed_data)); -} - -//----------------------------------------------------------------------------------------------------------------------------- - bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) { ImFont* font = src->DstFont; @@ -4910,6 +4904,14 @@ float ImFontBaked::GetCharAdvance(ImWchar c) } IM_MSVC_RUNTIME_CHECKS_RESTORE +ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) +{ + struct { ImGuiID FontId; float BakedSize; } hashed_data; + hashed_data.FontId = font_id; + hashed_data.BakedSize = baked_size; + return ImHashData(&hashed_data, sizeof(hashed_data)); +} + // ImFontBaked pointers are valid for the entire frame but shall never be kept between frames. ImFontBaked* ImFont::GetFontBaked(float size) { @@ -4920,18 +4922,22 @@ ImFontBaked* ImFont::GetFontBaked(float size) ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; + // FIXME-BAKED: Design for picking a nearest size? ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size); ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); baked = *p_baked_in_map; if (baked != NULL) { - // FIXME-BAKED: Design for picking a nearest size? IM_ASSERT(baked->Size == size && baked->ContainerFont == this && baked->BakedId == baked_id); baked->LastUsedFrame = builder->FrameCount; LastBaked = baked; return baked; } + // FIXME-BAKED: If atlas is locked, find closest match + if (atlas->Locked) + IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! + // Create new ImGuiContext& g = *GImGui; IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() From daaf0e4ef30678540f3ad862008de218e8fbb0f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 27 Jan 2025 20:24:05 +0100 Subject: [PATCH 478/716] Fonts: Added PushFontSize(), PopFontSize() api. Added font_size param to PushFont() as well. Fonts: Fixed PopFont() recovery. (To squash into "Added PushFontSize(), PopFontSize() api." --- imgui.cpp | 84 ++++++++++++++++++++++++++++++------------------ imgui.h | 14 ++++---- imgui_draw.cpp | 11 ++++--- imgui_internal.h | 8 ++++- 4 files changed, 75 insertions(+), 42 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0b14338574b2..fb26c967b637 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1270,6 +1270,7 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt); // Misc static void UpdateFontsNewFrame(); +static void UpdateFontsEndFrame(); static void UpdateTexturesNewFrame(); static void UpdateTexturesEndFrame(); static void UpdateSettings(); @@ -5762,6 +5763,7 @@ void ImGui::EndFrame() // End frame g.WithinFrameScope = false; g.FrameCountEnded = g.FrameCount; + UpdateFontsEndFrame(); // Initiate moving window + handle left-click and right-click focus UpdateMouseMovingWindowEndFrame(); @@ -8579,64 +8581,84 @@ void ImGui::UpdateFontsNewFrame() ImFontAtlas* atlas = g.IO.Fonts; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) atlas->Locked = true; - SetCurrentFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels); + PushFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels); IM_ASSERT(g.Font->IsLoaded()); } -// Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only. -void ImGui::SetCurrentFont(ImFont* font, float font_size) +void ImGui::UpdateFontsEndFrame() { - ImGuiContext& g = *GImGui; - IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? - IM_ASSERT(font->Scale > 0.0f); - g.Font = font; - //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->Size * g.Font->Scale); - g.FontSize = font_size;// g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; - g.FontBaked = g.Font->GetFontBaked(g.FontSize); - g.FontScale = g.FontSize / g.FontBaked->Size; - g.DrawListSharedData.Font = g.Font; - g.DrawListSharedData.FontSize = g.FontSize; - g.DrawListSharedData.FontScale = g.FontScale; - ImFontAtlasUpdateDrawListsSharedData(g.Font->ContainerAtlas); - if (g.CurrentWindow) - g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexRef); -} - -// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authoritative against window-local ImDrawList. -// - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls. + PopFont(); +} + +// Use ImDrawList::_SetTexture(), making our shared g.FontStack[] authoritative against window-local ImDrawList. +// - Whereas ImDrawList::PushTexture()/PopTexture() is not to be used across Begin() calls. // - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... // - Some code paths never really fully worked with multiple atlas textures. -// - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID() +// - The right-ish solution may be to remove _SetTexture() and make AddText/RenderText lazily call PushTexture()/PopTexture() // the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem // because we have a concrete need and a test bed for multiple atlas textures. // FIXME-NEWATLAS-V2: perhaps we can now leverage ImFontAtlasUpdateDrawListsTextures() ? -void ImGui::PushFont(ImFont* font) +void ImGui::SetCurrentFont(ImFont* font, float font_size) +{ + ImGuiContext& g = *GImGui; + g.Font = font; + //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->FontSize * g.Font->Scale); + g.FontSize = font_size;// g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + if (font != NULL) + { + IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? + IM_ASSERT(font->Scale > 0.0f); + g.FontBaked = g.Font->GetFontBaked(g.FontSize); + g.FontScale = g.FontSize / g.FontBaked->Size; + g.DrawListSharedData.Font = g.Font; + g.DrawListSharedData.FontSize = g.FontSize; + g.DrawListSharedData.FontScale = g.FontScale; + ImFontAtlasUpdateDrawListsSharedData(g.Font->ContainerAtlas); + if (g.CurrentWindow != NULL) + g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexRef); + } + else + { + g.FontBaked = NULL; + g.FontScale = 0.0f; + } +} + +void ImGui::PushFont(ImFont* font, float font_size) { ImGuiContext& g = *GImGui; if (font == NULL) font = GetDefaultFont(); - g.FontStack.push_back(font); - SetCurrentFont(font, g.FontSize); + if (font_size < 0.0f) + font_size = g.FontSize; + g.FontStack.push_back({ font, font_size }); + SetCurrentFont(font, font_size); } void ImGui::PopFont() { ImGuiContext& g = *GImGui; - if (g.FontStack.Size <= 0) + if (g.FontStack.Size <= 1 && g.WithinFrameScope) { IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); return; } g.FontStack.pop_back(); - ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back(); - SetCurrentFont(font, g.FontSize); // FIXME-BAKED: size in stack + if (ImFontStackData* font_stack_data = (g.FontStack.Size > 0) ? &g.FontStack.back() : NULL) + SetCurrentFont(font_stack_data->Font, font_stack_data->FontSize); + else + SetCurrentFont(NULL, 0.0f); } -void ImGui::SetFontSize(float size) +void ImGui::PushFontSize(float font_size) { - // FIXME-BAKED ImGuiContext& g = *GImGui; - SetCurrentFont(g.Font, size); + PushFont(g.Font, font_size); +} + +void ImGui::PopFontSize() +{ + PopFont(); } //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 717c9f0e478a..d60deceb9fee 100644 --- a/imgui.h +++ b/imgui.h @@ -469,11 +469,13 @@ namespace ImGui IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. - // Parameters stacks (shared) - IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font + // Parameters stacks (font) + IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. IMGUI_API void PopFont(); - IMGUI_API void SetFontSize(float size); - //IMGUI_API void PopFontSize(); + IMGUI_API void PushFontSize(float size); + IMGUI_API void PopFontSize(); + + // Parameters stacks (shared) IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col); IMGUI_API void PopStyleColor(int count = 1); @@ -3657,8 +3659,8 @@ struct ImFontBaked // Font runtime data and rendering // - ImFontAtlas automatically loads a default embedded font for you if you didn't load one manually. // - Since 1.92.X a font may be rendered as any size! Therefore a font doesn't have one specific size. -// - Use 'font->GetBakedForSize(size)' to retrieve the ImFontBaked* corresponding to a given size. -// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetBakedForSize(g.FontSize). +// - Use 'font->GetFontBaked(size)' to retrieve the ImFontBaked* corresponding to a given size. +// - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetFontBaked(g.FontSize). struct ImFont { // [Internal] Members: Cold ~32/40/80 bytes diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7c7a7916afe7..362697609df7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -434,7 +434,7 @@ void ImDrawList::_SetDrawListSharedData(ImDrawListSharedData* data) } // Initialize before use in a new frame. We always have a command ready in the buffer. -// In the majority of cases, you would want to call PushClipRect() and PushTextureID() after this. +// In the majority of cases, you would want to call PushClipRect() and PushTexture() after this. void ImDrawList::_ResetForNewFrame() { // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. @@ -683,7 +683,7 @@ void ImDrawList::PopTexture() _OnChangedTexture(); } -// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID(). +// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTexture()/PopTexture(). void ImDrawList::_SetTexture(ImTextureRef tex_ref) { if (_CmdHeader.TexRef == tex_ref) @@ -3042,7 +3042,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f * 1.0f; if (font_cfg.Name[0] == '\0') - ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf"); font_cfg.EllipsisChar = (ImWchar)0x0085; font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units @@ -3074,7 +3074,7 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, // Store a short copy of filename into into the font name for convenience const char* p; for (p = filename + ImStrlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {} - ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels); + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s", p); } return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges); } @@ -3137,6 +3137,9 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, if (need_bind_ctx) ImGui::SetCurrentContext(curr_ctx); } + for (ImFontStackData& font_stack_data : ctx->FontStack) + if (font_stack_data.Font == old_font) + font_stack_data.Font = new_font; } } } diff --git a/imgui_internal.h b/imgui_internal.h index 5075028ca4c0..f0812d71f6ba 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -869,6 +869,12 @@ struct ImDrawDataBuilder ImDrawDataBuilder() { memset(this, 0, sizeof(*this)); } }; +struct ImFontStackData +{ + ImFont* Font; + float FontSize; +}; + //----------------------------------------------------------------------------- // [SECTION] Style support //----------------------------------------------------------------------------- @@ -2237,7 +2243,7 @@ struct ImGuiContext ImGuiCol DebugFlashStyleColorIdx; // (Keep close to ColorStack to share cache line) ImVector ColorStack; // Stack for PushStyleColor()/PopStyleColor() - inherited by Begin() ImVector StyleVarStack; // Stack for PushStyleVar()/PopStyleVar() - inherited by Begin() - ImVector FontStack; // Stack for PushFont()/PopFont() - inherited by Begin() + ImVector FontStack; // Stack for PushFont()/PopFont() - inherited by Begin() ImVector FocusScopeStack; // Stack for PushFocusScope()/PopFocusScope() - inherited by BeginChild(), pushed into by Begin() ImVector ItemFlagsStack; // Stack for PushItemFlag()/PopItemFlag() - inherited by Begin() ImVector GroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() From be151977ca24c503cc7176d2a1eaf9aa4207ac6f Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 Jan 2025 14:31:13 +0100 Subject: [PATCH 479/716] Fonts: Texture resizing favor growing height, halve pack nodes. --- imgui_draw.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 362697609df7..ff861d8d1913 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3838,9 +3838,10 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); // Grow texture so it follows roughly a square. - // Caller should be taking account of RectsDiscardedSurface and may not need to grow. - int new_tex_w = (old_tex_h < old_tex_w) ? old_tex_w : old_tex_w * 2; - int new_tex_h = (old_tex_h < old_tex_w) ? old_tex_h * 2 : old_tex_h; + // - Grow height before width, as width imply more packing nodes. + // - Caller should be taking account of RectsDiscardedSurface and may not need to grow. + int new_tex_w = (old_tex_h <= old_tex_w) ? old_tex_w : old_tex_w * 2; + int new_tex_h = (old_tex_h <= old_tex_w) ? old_tex_h * 2 : old_tex_h; // Handle minimum size first (for pathologically large packed rects) const int pack_padding = atlas->TexGlyphPadding; @@ -3990,7 +3991,7 @@ void ImFontAtlasPackInit(ImFontAtlas * atlas) ImFontAtlasBuilder* builder = atlas->Builder; // In theory we could decide to reduce the number of nodes, e.g. halve them, and waste a little texture space, but it doesn't seem worth it. - const int pack_node_count = tex->Width; + const int pack_node_count = tex->Width / 2; builder->PackNodes.resize(pack_node_count); IM_STATIC_ASSERT(sizeof(stbrp_context) <= sizeof(stbrp_context_opaque)); stbrp_init_target((stbrp_context*)(void*)&builder->PackContext, tex->Width, tex->Height, builder->PackNodes.Data, builder->PackNodes.Size); From 3ce753c489307835eee04a448db18264fe02fa4c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 28 Jan 2025 14:36:06 +0100 Subject: [PATCH 480/716] Fonts: Debug dump to disk, debug log. --- imgui_draw.cpp | 29 ++++++++++++++++++----------- imgui_internal.h | 2 +- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ff861d8d1913..ef7ff15499cd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3625,9 +3625,6 @@ void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImF void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFontBaked* baked) { - ImGuiContext& g = *GImGui; - IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() - ImFontAtlasBuilder* builder = atlas->Builder; ImFont* font = baked->ContainerFont; IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); @@ -3755,11 +3752,20 @@ ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h) return new_tex; } -void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) +#if 0 +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "../stb/stb_image_write.h" +static void ImFontAtlasDebugWriteTexToDisk(ImTextureData* tex, const char* description) { ImGuiContext& g = *GImGui; - IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() + char buf[128]; + ImFormatString(buf, IM_ARRAYSIZE(buf), "[%05d] Texture #%03d - %s.png", g.FrameCount, tex->UniqueID, description); + stbi_write_png(buf, tex->Width, tex->Height, tex->BytesPerPixel, tex->Pixels, tex->GetPitch()); // tex->BytesPerPixel is technically not component, but ok for the formats we support. +} +#endif +void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) +{ ImFontAtlasBuilder* builder = atlas->Builder; builder->LockDisableResize = true; @@ -3767,6 +3773,10 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) ImTextureData* new_tex = ImFontAtlasBuildAddTexture(atlas, w, h); new_tex->UseColors = old_tex->UseColors; IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height); + //for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + // IMGUI_DEBUG_LOG_FONT("[font] - Baked %.2fpx, %d glyphs, want_destroy=%d\n", builder->BakedPool[baked_n].FontSize, builder->BakedPool[baked_n].Glyphs.Size, builder->BakedPool[baked_n].WantDestroy); + //IMGUI_DEBUG_LOG_FONT("[font] - Old packed rects: %d, area %d px\n", builder->RectsPackedCount, builder->RectsPackedSurface); + //ImFontAtlasDebugWriteTexToDisk(old_tex, "Before Pack"); // Repack, lose discarded rectangle, copy pixels // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic. @@ -3822,10 +3832,12 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) builder->LockDisableResize = false; ImFontAtlasUpdateDrawListsSharedData(atlas); + //ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack"); } void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_h) { + //ImFontAtlasDebugWriteTexToDisk(atlas->TexData, "Before Grow"); ImFontAtlasBuilder* builder = atlas->Builder; if (old_tex_w == -1) old_tex_w = atlas->TexData->Width; @@ -3858,6 +3870,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) { // Can some baked contents be ditched? + //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n"); ImFontAtlasBuilder* builder = atlas->Builder; ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL); @@ -4072,8 +4085,6 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon // If we ran out of attempts, return fallback if (attempts_remaining == 0 || builder->LockDisableResize) { - ImGuiContext& g = *GImGui; - IM_UNUSED(g); IMGUI_DEBUG_LOG_FONT("[font] Failed packing %dx%d rectangle. Returning fallback.\n", w, h); return -1; } @@ -4717,8 +4728,6 @@ void ImFontBaked::BuildGrowIndex(int new_size) IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); if (new_size <= IndexLookup.Size) return; - //ImGuiContext& g = *GImGui; - //IMGUI_DEBUG_LOG_FONT("[font] BuildGrowIndex(%d)\n", new_size); IndexAdvanceX.resize(new_size, -1.0f); IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); } @@ -4943,8 +4952,6 @@ ImFontBaked* ImFont::GetFontBaked(float size) IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! // Create new - ImGuiContext& g = *GImGui; - IM_UNUSED(g); // for IMGUI_DEBUG_LOG_FONT() IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", size); baked = builder->BakedPool.push_back(ImFontBaked()); baked->Size = size; diff --git a/imgui_internal.h b/imgui_internal.h index f0812d71f6ba..3216f2181908 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -247,7 +247,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) -#define IMGUI_DEBUG_LOG_FONT(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext& g2 = *GImGui; if (g2.DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Static Asserts From 57d345ff80415edbefb0024bdcb7997621292b9b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 30 Jan 2025 17:49:52 +0100 Subject: [PATCH 481/716] Textures: Comments around ImTextureID type. --- imgui.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index d60deceb9fee..935f2b3b767c 100644 --- a/imgui.h +++ b/imgui.h @@ -311,12 +311,17 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE //----------------------------------------------------------------------------- // ImTextureID: user data for renderer backend to identify a texture [Compile-time configurable type] -// - To use something else than an opaque void* pointer: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. -// - This can be whatever to you want it to be! read the FAQ about ImTextureID for details. -// - You can make this a structure with various constructors if you need. You will have to implement ==/!= operators. -// - (note: before v1.91.4 (2024/10/08) the default type for ImTextureID was void*. Use intermediary intptr_t cast and read FAQ if you have casting warnings) +// Overview: +// - Backend and user/app code provides ImTextureID values that gets stored inside draw commands (ImDrawCmd) during the ImGui frame. +// - Backend uses ImDrawCmd::GetTexID() to retrieve the ImTextureID value during rendering. Then, they can bind the textures of each draw command. +// Configuring the type: +// - To use something else than a 64-bit value: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - This can be whatever to you want it to be! read the FAQ entry about textures for details. +// - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various constructors if you like. You will need to implement ==/!= operators. +// History: +// - In v1.91.4 (2024/10/08): the default type for ImTextureID was changed from 'void*' to 'ImU64'. This allowed backends requirig 64-bit worth of data to build on 32-bit architectures. Use intermediary intptr_t cast and read FAQ if you have casting warnings. #ifndef ImTextureID -typedef ImU64 ImTextureID; // Default: store a pointer or an integer fitting in a pointer (most renderer backends are ok with that) +typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. #endif // Define this to another value if you need value of 0 to be valid. From df694c89b00ee69f4a18203630a6a1500e92b665 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 17:16:34 +0100 Subject: [PATCH 482/716] Fonts: Baked system, v11. --- imgui_draw.cpp | 38 +++++++++++++++++++++----------------- imgui_internal.h | 4 ++-- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ef7ff15499cd..b537132fb3a4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2497,8 +2497,9 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontSpecialGlyphs() // - ImFontAtlasBuildDiscardUnusedBakes() -// - ImFontAtlasBuildDiscardFontBaked() // - ImFontAtlasBuildDiscardFontBakedGlyph() +// - ImFontAtlasBuildDiscardFontBaked() +// - ImFontAtlasBuildDiscardFont() //----------------------------------------------------------------------------- // - ImFontAtlasAddDrawListSharedData() // - ImFontAtlasRemoveDrawListSharedData() @@ -3623,10 +3624,9 @@ void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImF baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } -void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFontBaked* baked) +void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { ImFontAtlasBuilder* builder = atlas->Builder; - ImFont* font = baked->ContainerFont; IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); for (ImFontGlyph& glyph : baked->Glyphs) @@ -3643,16 +3643,25 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFontBaked* baked) font->LastBaked = NULL; } -void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, ImFont* font_filter) +void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font) +{ + if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor + for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + { + ImFontBaked* baked = &builder->BakedPool[baked_n]; + if (baked->ContainerFont == font && !baked->WantDestroy) + ImFontAtlasBuildDiscardFontBaked(atlas, font, baked); + } +} + +void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, int gc_frames) { ImFontAtlasBuilder* builder = atlas->Builder; - const int GC_FRAMES = 2; for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { ImFontBaked* baked = &builder->BakedPool[baked_n]; - if (font_filter == NULL || baked->ContainerFont == font_filter) - if (baked->LastUsedFrame + GC_FRAMES < atlas->Builder->FrameCount && !baked->WantDestroy) - ImFontAtlasBuildDiscardFontBaked(atlas, baked); + if (baked->LastUsedFrame + gc_frames < atlas->Builder->FrameCount && !baked->WantDestroy) + ImFontAtlasBuildDiscardFontBaked(atlas, baked->ContainerFont, baked); } } @@ -3872,7 +3881,7 @@ void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) // Can some baked contents be ditched? //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n"); ImFontAtlasBuilder* builder = atlas->Builder; - ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL); + ImFontAtlasBuildDiscardUnusedBakes(atlas, 2); // Currently using a heuristic for repack without growing. if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f) @@ -3920,7 +3929,7 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) { ImFontAtlasBuilder* builder = atlas->Builder; - ImFontAtlasBuildDiscardUnusedBakes(atlas, NULL); + ImFontAtlasBuildDiscardUnusedBakes(atlas, 1); ImTextureData* old_tex = atlas->TexData; ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); @@ -4747,13 +4756,7 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { if (ImFontAtlas* atlas = ContainerAtlas) - if (ImFontAtlasBuilder* builder = atlas->Builder) - for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) - { - ImFontBaked* baked = &builder->BakedPool[baked_n]; - if (baked->ContainerFont == this) - ImFontAtlasBuildDiscardFontBaked(atlas, baked); - } + ImFontAtlasBuildDiscardFont(atlas, this); FallbackChar = EllipsisChar = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); LastBaked = NULL; @@ -4936,6 +4939,7 @@ ImFontBaked* ImFont::GetFontBaked(float size) ImFontAtlasBuilder* builder = atlas->Builder; // FIXME-BAKED: Design for picking a nearest size? + // FIXME-BAKED: Altering font density won't work right away. ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size); ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); baked = *p_baked_in_map; diff --git a/imgui_internal.h b/imgui_internal.h index 3216f2181908..a54e3a35067b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3767,10 +3767,10 @@ IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, ImFont* font_filter); +IMGUI_API void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, int gc_frames); +IMGUI_API void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); -IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font); // <--- Your future new best friend! IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); From 99f6b305c1e7d6b08c70f18971b8865af2a1b725 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 17:46:59 +0100 Subject: [PATCH 483/716] Fonts: Baked system, v12: support GlyphOffset / GlyphMinAdvanceX / GlyphMaxAdvanceX by scaling from ref value. Overwriting cfg->PixelSnapH = true; in imgui_freetype is weird. --- imgui.cpp | 2 +- imgui.h | 9 +++++---- imgui_draw.cpp | 14 +++++++++++--- misc/freetype/imgui_freetype.cpp | 12 ++++++++++-- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fb26c967b637..a7cc6a81a591 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8602,7 +8602,7 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size) { ImGuiContext& g = *GImGui; g.Font = font; - //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->FontSize * g.Font->Scale); + //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->Size * g.Font->Scale); g.FontSize = font_size;// g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; if (font != NULL) { diff --git a/imgui.h b/imgui.h index 935f2b3b767c..24706e062651 100644 --- a/imgui.h +++ b/imgui.h @@ -3424,15 +3424,16 @@ struct ImFontConfig bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. + bool PixelSnapV; // true // Align Scaled GlyphOffset.y to pixel boundaries. int FontNo; // 0 // Index of font within TTF/OTF file int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED IN 1.91.9: use GlyphExtraAdvanceX) - ImVec2 GlyphOffset; // 0, 0 // [FIXME-BAKED] Offset all glyphs from this font input. + //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. + ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - float GlyphMinAdvanceX; // 0 // [FIXME-BAKED] Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font - float GlyphMaxAdvanceX; // FLT_MAX // [FIXME-BAKED] Maximum AdvanceX for glyphs + float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. + float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b537132fb3a4..921241185e58 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4351,8 +4351,15 @@ static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBa if (oversample_v > 1) stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v); - float font_off_x = src->GlyphOffset.x + stbtt__oversample_shift(oversample_h); - float font_off_y = src->GlyphOffset.y + stbtt__oversample_shift(oversample_v) + IM_ROUND(baked->Ascent); + const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; + float font_off_x = (src->GlyphOffset.x * offsets_scale); + float font_off_y = (src->GlyphOffset.y * offsets_scale); + if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. + font_off_x = IM_ROUND(font_off_x); + if (src->PixelSnapV) + font_off_y = IM_ROUND(font_off_y); + font_off_x += stbtt__oversample_shift(oversample_h); + font_off_y += stbtt__oversample_shift(oversample_v) + IM_ROUND(baked->Ascent); float recip_h = 1.0f / (oversample_h * src->RasterizerDensity); float recip_v = 1.0f / (oversample_v * src->RasterizerDensity); @@ -4800,7 +4807,8 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked if (src != NULL) { // Clamp & recenter if needed - float advance_x = ImClamp(glyph.AdvanceX, src->GlyphMinAdvanceX, src->GlyphMaxAdvanceX); + const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; + float advance_x = ImClamp(glyph.AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); if (advance_x != glyph.AdvanceX) { float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph.AdvanceX) * 0.5f) : (advance_x - glyph.AdvanceX) * 0.5f; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 022ec2b2c8b0..326132b419f1 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -204,6 +204,9 @@ namespace if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting) LoadFlags |= FT_LOAD_NO_HINTING; + else + src->PixelSnapH = true; // FIXME: A bit weird to do this this way. + if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint) LoadFlags |= FT_LOAD_NO_AUTOHINT; if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint) @@ -559,8 +562,13 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data; bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w); - float font_off_x = src->GlyphOffset.x; - float font_off_y = src->GlyphOffset.y + IM_ROUND(baked->Ascent); + const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; + float font_off_x = (src->GlyphOffset.x * offsets_scale); + float font_off_y = (src->GlyphOffset.y * offsets_scale) + baked->Ascent; + if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. + font_off_x = IM_ROUND(font_off_x); + if (src->PixelSnapV) + font_off_y = IM_ROUND(font_off_y); float recip_h = 1.0f / src->RasterizerDensity; float recip_v = 1.0f / src->RasterizerDensity; From 842c313db2d2b25673383cd0830b367fc51104af Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 19:47:41 +0100 Subject: [PATCH 484/716] Fonts: Reordered ImFont fields. --- imgui.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 24706e062651..e9b31d36723b 100644 --- a/imgui.h +++ b/imgui.h @@ -3669,13 +3669,15 @@ struct ImFontBaked // - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetFontBaked(g.FontSize). struct ImFont { - // [Internal] Members: Cold ~32/40/80 bytes + // [Internal] Members: Hot ~8-16 bytes + ImFontBaked* LastBaked; // 4-8 // Cache last bound baked. DO NOT USE. Use GetFontBaked(). + ImFontAtlas* ContainerAtlas; // 4-8 // What we has been loaded into + + // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. - ImFontBaked* LastBaked; // Cache last bound baked. DO NOT USE. Use GetFontBaked(). ImGuiID FontId; // Unique identifier for the font short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances - ImFontAtlas* ContainerAtlas; // 4-8 // out // What we has been loaded into ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() From 658059022629077455c5dad7028c667944ddeec8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 19:15:26 +0100 Subject: [PATCH 485/716] Fonts: Allow PushFont/NewFrame/PopFont idioms to function. --- imgui.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index a7cc6a81a591..dd4dbf15a5b1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8581,7 +8581,13 @@ void ImGui::UpdateFontsNewFrame() ImFontAtlas* atlas = g.IO.Fonts; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) atlas->Locked = true; - PushFont(GetDefaultFont(), GetDefaultFont()->Sources[0].SizePixels); + + // We do this really unusual thing of calling *push_front()*, the reason behind that we want to support the PushFont()/NewFrame()/PopFont() idiom. + ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->Sources[0].SizePixels }; + g.FontStack.push_front(font_stack_data); + if (g.FontStack.Size == 1) + ImGui::SetCurrentFont(font_stack_data.Font, font_stack_data.FontSize); + IM_ASSERT(g.Font->IsLoaded()); } From 82b81fce685e303db2355a04e1c257eb2eb0d914 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Feb 2025 19:36:11 +0100 Subject: [PATCH 486/716] Fonts: PushFontSize() with -1 uses sources[0]'s size for now (backward compat design) --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index dd4dbf15a5b1..f416223cd10c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8636,7 +8636,7 @@ void ImGui::PushFont(ImFont* font, float font_size) if (font == NULL) font = GetDefaultFont(); if (font_size < 0.0f) - font_size = g.FontSize; + font_size = font->Sources[0].SizePixels; // g.FontSize; g.FontStack.push_back({ font, font_size }); SetCurrentFont(font, font_size); } From 066b24d7416be6b1ad640adb0c3c0e66c39193a9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 4 Feb 2025 20:02:10 +0100 Subject: [PATCH 487/716] Fonts: Fixed _OnChangedTextureID() asserting when calling on e.g. finalized drawlists. --- imgui_draw.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 921241185e58..0f3cf4dc8e3a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -599,7 +599,10 @@ void ImDrawList::_OnChangedTexture() AddDrawCmd(); return; } - IM_ASSERT(curr_cmd->UserCallback == NULL); + + // Unlike other _OnChangedXXX functions this may be called by ImFontAtlasUpdateDrawListsTextures() in more locations so we need to handle this case. + if (curr_cmd->UserCallback != NULL) + return; // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; From 96786a183bf78c12e49ece064af316604c4b5fb2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Feb 2025 14:04:05 +0100 Subject: [PATCH 488/716] Fonts: Create a fallback glyph if none is available (fix crash on fonts with no fallback) --- imgui_draw.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0f3cf4dc8e3a..89ceda78f081 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3545,20 +3545,27 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { - // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? - IM_ASSERT(baked->FallbackGlyphIndex == -1); - if (font->FallbackChar != 0) - if (const ImFontGlyph* glyph = baked->FindGlyphNoFallback(font->FallbackChar)) - { - baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(glyph); // Storing index avoid need to update pointer on growth. - baked->FallbackAdvanceX = glyph->AdvanceX; - } - // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews) ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)baked->FindGlyphNoFallback((ImWchar)' '); if (space_glyph != NULL) space_glyph->Visible = false; + // Load fallback in order to obtain its index + // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? + IM_ASSERT(baked->FallbackGlyphIndex == -1); + ImFontGlyph* fallback_glyph = NULL; + if (font->FallbackChar != 0) + fallback_glyph = baked->FindGlyphNoFallback(font->FallbackChar); + if (fallback_glyph == NULL) + { + ImFontGlyph glyph; + glyph.Codepoint = 0; + glyph.AdvanceX = space_glyph ? space_glyph->AdvanceX : IM_ROUND(baked->Size * 0.40f); + fallback_glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &glyph); + } + baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code + baked->FallbackAdvanceX = fallback_glyph->AdvanceX; + // Setup Tab character. // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) if (baked->FindGlyphNoFallback('\t') == NULL && space_glyph != NULL) From 815553c4b462c4284bd1690fe25e62d1a926ed96 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Feb 2025 14:41:59 +0100 Subject: [PATCH 489/716] Fonts: ImFontConfig: added GlyphExcludeRanges[]. --- imgui.h | 1 + imgui_draw.cpp | 23 ++++++++++++++++++++++- imgui_internal.h | 1 + misc/freetype/imgui_freetype.cpp | 2 ++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index e9b31d36723b..e0bea0f5156d 100644 --- a/imgui.h +++ b/imgui.h @@ -3432,6 +3432,7 @@ struct ImFontConfig //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). + const ImWchar* GlyphExcludeRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 89ceda78f081..11f78e8c5309 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2990,6 +2990,15 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); } + // Sanity check + if (font_cfg->GlyphExcludeRanges != NULL) + { + int size = 0; + for (const ImWchar* p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) {} + IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!"); + IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!"); + } + // Round font size // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes. @@ -4149,7 +4158,7 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) return NULL; //char utf8_buf[5]; - //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); + //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); // Load from single source or all sources? int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount; @@ -4293,6 +4302,16 @@ static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* } } +// Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries) +bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint) +{ + if (const ImWchar* exclude_list = src->GlyphExcludeRanges) + for (; exclude_list[0] != 0; exclude_list += 2) + if (codepoint >= exclude_list[0] && codepoint <= exclude_list[1]) + return false; + return true; +} + static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) { // Search for first font which has the glyph @@ -4302,6 +4321,8 @@ static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBa for (int src_n = 0; src_n < srcs_count; src_n++) { src = &srcs[src_n]; + if (src->GlyphExcludeRanges && !ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) + continue; bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; IM_ASSERT(bd_font_data); glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); diff --git a/imgui_internal.h b/imgui_internal.h index a54e3a35067b..7e7a2c6978d2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3773,6 +3773,7 @@ IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); +IMGUI_API bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 326132b419f1..e71534c52e68 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -504,6 +504,8 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked for (int src_n = 0; src_n < srcs_count; src_n++) { src = &srcs[src_n]; + if (src->GlyphExcludeRanges && !ImFontAtlasBuildFilterCodepointForSource(src, codepoint)) + continue; bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); if (glyph_index != 0) From eb79e3ab3d7a329f33a96f3ed1e3f85024b94418 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Feb 2025 17:51:46 +0100 Subject: [PATCH 490/716] Fonts: Restore a functional AddCustomRectFontGlyph(). --- imgui.h | 17 +++++++++-------- imgui_draw.cpp | 31 ++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/imgui.h b/imgui.h index e0bea0f5156d..d62f56fa8016 100644 --- a/imgui.h +++ b/imgui.h @@ -3521,7 +3521,7 @@ struct ImFontAtlas IMGUI_API void RemoveFont(ImFont* font); IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) - IMGUI_API void ClearCache(); // Clear cached glyphs and textures. + IMGUI_API void ClearCache(); // Clear cached glyphs and textures. Invalidates all AddCustomRectXXX return values. // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. @@ -3571,7 +3571,7 @@ struct ImFontAtlas // You can request your rectangles to be mapped as font glyph (given a font + Unicode point), // so you can render e.g. custom colorful icons and use them as regular glyphs. // - Since 1.92.X, packing is done immediately in the function call. Returns >= on success, <0 on error. - // - You can render your pixels into the texture right after calling the AddCustomRectXXX functions, without waiting for the Build() call. + // - You can render your pixels into the texture right after calling the AddCustomRectXXX() functions. // - If your backend supports ImGuiBackendFlags_RendererHasTextures: // Texture may be resized, so you cannot cache UV coordinates: always use CalcCustomRectUV(). // - If you render colored output into your AddCustomRectRegular() rectangle: set 'atlas->TexPixelsUseColors = true' @@ -3579,7 +3579,10 @@ struct ImFontAtlas // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); +#endif IMGUI_API ImTextureRect* GetCustomRectByIndex(int index); IMGUI_API void CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; @@ -3925,13 +3928,11 @@ namespace ImGui //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 } -//-- OBSOLETED in 1.91.7 (from January 2025): ImFontAtlasCustomRect becomes ImTextureRect -// - ImFontAtlasCustomRect::X --> ImTextureRect::x -// - ImFontAtlasCustomRect::Y --> ImTextureRect::y -// - ImFontAtlasCustomRect::Width --> ImTextureRect::w -// - ImFontAtlasCustomRect::Height --> ImTextureRect::h +//-- OBSOLETED in 1.92.x: ImFontAtlasCustomRect becomes ImTextureRect +// - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y +// - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h // - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() -// We could make ImTextureRect an union to use old names, such 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. +// We could make ImTextureRect an union to use old names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. typedef ImTextureRect ImFontAtlasCustomRect; /*struct ImFontAtlasCustomRect { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 11f78e8c5309..2a0a300a76bb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3199,9 +3199,21 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) return r_id; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// This API does not make sense anymore with scalable fonts. +// - Prefer adding a font source (ImFontConfig) using a custom/procedural loader. +// - You may use ImFontFlags_LockBakedSizes to limit an existing font to known baked sizes: +// ImFont* myfont = io.Fonts->AddFontFromFileTTF(....); +// myfont->GetFontBaked(16.0f); +// myfont->Flags |= ImFontFlags_LockBakedSizes; +int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) +{ + float font_size = font->Sources[0].SizePixels; + return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset); +} // FIXME: we automatically set glyph.Colored=true by default. // If you need to alter this, you can write 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph(). -int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) +int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { #ifdef IMGUI_USE_WCHAR32 IM_ASSERT(codepoint <= IM_UNICODE_CODEPOINT_MAX); @@ -3209,7 +3221,9 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid IM_ASSERT(font != NULL); IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); -#if 0 + + ImFontBaked* baked = font->GetFontBaked(font_size); + ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id < 0) return -1; @@ -3217,8 +3231,8 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid if (RendererHasTextures) ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); - if (font->IsGlyphLoaded(codepoint)) - ImFontAtlasBuildDiscardFontGlyph(this, font, (ImFontGlyph*)(void*)font->FindGlyph(codepoint)); + if (baked->IsGlyphLoaded(codepoint)) + ImFontAtlasBuildDiscardFontBakedGlyph(this, font, baked, (ImFontGlyph*)(void*)baked->FindGlyph(codepoint)); ImFontGlyph glyph; glyph.Codepoint = codepoint; @@ -3230,15 +3244,10 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int wid glyph.Visible = true; glyph.Colored = true; // FIXME: Arbitrary glyph.PackId = r_id; - ImFontAtlasBuildAddFontGlyph(this, font, &font->Sources[0], &glyph); + ImFontAtlasBakedAddFontGlyph(this, baked, &font->Sources[0], &glyph); return r_id; -#endif - // FIXME-BAKED: Need a design for AddCustomRectFontGlyph() - IM_UNUSED(codepoint); - IM_UNUSED(offset); - IM_UNUSED(advance_x); - return -1; } +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx) { From 8a8d8a7b38f0cb13e711bb3e1be74083f5a968ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Feb 2025 18:25:52 +0100 Subject: [PATCH 491/716] Fonts: Exposed CompactCache(). Hide ClearCache(). --- imgui.cpp | 8 ++++---- imgui.h | 2 +- imgui_draw.cpp | 31 ++++++++++++++++++++----------- imgui_internal.h | 3 ++- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f416223cd10c..3f6c01ded842 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15688,14 +15688,14 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) } SeparatorText("Font Atlas"); - if (Button("Clear Cache")) - atlas->ClearCache(); + if (Button("Compact")) + atlas->CompactCache(); SameLine(); if (Button("Grow")) ImFontAtlasBuildGrowTexture(atlas); SameLine(); - if (Button("Compact")) - ImFontAtlasBuildCompactTexture(atlas); + if (Button("Clear Output")) + ImFontAtlasBuildClearTexture(atlas); for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { diff --git a/imgui.h b/imgui.h index d62f56fa8016..1b60ddc9ceea 100644 --- a/imgui.h +++ b/imgui.h @@ -3521,7 +3521,7 @@ struct ImFontAtlas IMGUI_API void RemoveFont(ImFont* font); IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) - IMGUI_API void ClearCache(); // Clear cached glyphs and textures. Invalidates all AddCustomRectXXX return values. + IMGUI_API void CompactCache(); // Compact cached glyphs and texture. // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2a0a300a76bb..01a02367ba88 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2457,7 +2457,7 @@ void ImTextureData::DestroyPixels() // - Default texture data encoded in ASCII // - ImFontAtlas() // - ImFontAtlas::Clear() -// - ImFontAtlas::ClearCache() +// - ImFontAtlas::CompactCache() // - ImFontAtlas::ClearInputData() // - ImFontAtlas::ClearTexData() // - ImFontAtlas::ClearFonts() @@ -2499,7 +2499,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildAddFont() // - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() // - ImFontAtlasBuildSetupFontSpecialGlyphs() -// - ImFontAtlasBuildDiscardUnusedBakes() +// - ImFontAtlasBuildDiscardBakes() // - ImFontAtlasBuildDiscardFontBakedGlyph() // - ImFontAtlasBuildDiscardFontBaked() // - ImFontAtlasBuildDiscardFont() @@ -2615,15 +2615,14 @@ void ImFontAtlas::Clear() bool backup_renderer_has_textures = RendererHasTextures; RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. ClearTexData(); + if (Builder != NULL) + ImFontAtlasBuildClearTexture(this); RendererHasTextures = backup_renderer_has_textures; } -void ImFontAtlas::ClearCache() +void ImFontAtlas::CompactCache() { - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(this); - ImFontAtlasBuildDestroy(this); - ImFontAtlasBuildAddTexture(this, new_tex_size.x, new_tex_size.y); - ImFontAtlasBuildInit(this); + ImFontAtlasBuildCompactTexture(this); } void ImFontAtlas::ClearInputData() @@ -3682,13 +3681,14 @@ void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font) } } -void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, int gc_frames) +// use unused_frames==0 to discard everything. +void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames) { ImFontAtlasBuilder* builder = atlas->Builder; for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { ImFontBaked* baked = &builder->BakedPool[baked_n]; - if (baked->LastUsedFrame + gc_frames < atlas->Builder->FrameCount && !baked->WantDestroy) + if (baked->LastUsedFrame + unused_frames <= atlas->Builder->FrameCount && !baked->WantDestroy) ImFontAtlasBuildDiscardFontBaked(atlas, baked->ContainerFont, baked); } } @@ -3909,7 +3909,7 @@ void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) // Can some baked contents be ditched? //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n"); ImFontAtlasBuilder* builder = atlas->Builder; - ImFontAtlasBuildDiscardUnusedBakes(atlas, 2); + ImFontAtlasBuildDiscardBakes(atlas, 2); // Currently using a heuristic for repack without growing. if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f) @@ -3952,12 +3952,21 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) return ImVec2i(new_tex_w, new_tex_h); } +// Clear all output. Invalidates all AddCustomRectXXX return values. +void ImFontAtlasBuildClearTexture(ImFontAtlas* atlas) +{ + ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); + ImFontAtlasBuildDestroy(atlas); + ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); + ImFontAtlasBuildInit(atlas); +} + // You should not need to call this manually! // If you think you do, let us know and we can advise about policies auto-compact. void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) { ImFontAtlasBuilder* builder = atlas->Builder; - ImFontAtlasBuildDiscardUnusedBakes(atlas, 1); + ImFontAtlasBuildDiscardBakes(atlas, 0); ImTextureData* old_tex = atlas->TexData; ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); diff --git a/imgui_internal.h b/imgui_internal.h index 7e7a2c6978d2..2f5ba1514ef5 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3761,13 +3761,14 @@ IMGUI_API void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); +IMGUI_API void ImFontAtlasBuildClearTexture(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildDiscardUnusedBakes(ImFontAtlas* atlas, int gc_frames); +IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); IMGUI_API void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); From dc1320df64d4b93e20c8f95b5ad709e6d46cc49e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Feb 2025 11:57:30 +0100 Subject: [PATCH 492/716] Fonts: ImFontFlags: ImFontFlags_NoLoadGlyphs + add ImFontFlags_LockBakedSizes --- imgui.h | 16 +++++++++++++--- imgui_draw.cpp | 21 ++++++++++++++++----- imgui_widgets.cpp | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index 1b60ddc9ceea..fa345e7fea54 100644 --- a/imgui.h +++ b/imgui.h @@ -230,7 +230,8 @@ typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A // - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments. typedef int ImDrawFlags; // -> enum ImDrawFlags_ // Flags: for ImDrawList functions typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList instance -typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas build +typedef int ImFontFlags; // -> enum ImFontFlags_ // Flags: for ImFont +typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for InvisibleButton() typedef int ImGuiChildFlags; // -> enum ImGuiChildFlags_ // Flags: for BeginChild() @@ -3666,6 +3667,15 @@ struct ImFontBaked IMGUI_API void BuildGrowIndex(int new_size); }; +// Font flags +// (in future versions as we redesign font loading API, this will become more important and better documented. for now please consider this as internal/advanced use) +enum ImFontFlags_ +{ + ImFontFlags_None = 0, + ImFontFlags_LockBakedSizes = 1 << 0, // Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. + ImFontFlags_NoLoadGlyphs = 1 << 1, // Disable loading new glyphs. +}; + // Font runtime data and rendering // - ImFontAtlas automatically loads a default embedded font for you if you didn't load one manually. // - Since 1.92.X a font may be rendered as any size! Therefore a font doesn't have one specific size. @@ -3673,9 +3683,10 @@ struct ImFontBaked // - If you used g.Font + g.FontSize (which is frequent from the ImGui layer), you can use g.FontBaked as a shortcut, as g.FontBaked == g.Font->GetFontBaked(g.FontSize). struct ImFont { - // [Internal] Members: Hot ~8-16 bytes + // [Internal] Members: Hot ~12-20 bytes ImFontBaked* LastBaked; // 4-8 // Cache last bound baked. DO NOT USE. Use GetFontBaked(). ImFontAtlas* ContainerAtlas; // 4-8 // What we has been loaded into + ImFontFlags Flags; // 4 // Font flags // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. @@ -3686,7 +3697,6 @@ struct ImFont ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. - bool LockDisableLoading; short LockSingleSrcConfigIdx; // Methods diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 01a02367ba88..6f6f2e4ace10 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2647,7 +2647,7 @@ void ImFontAtlas::ClearInputData() font->Sources = NULL; font->SourcesCount = 0; } - font->LockDisableLoading = true; + font->Flags |= ImFontFlags_NoLoadGlyphs; } Sources.clear(); } @@ -3688,8 +3688,11 @@ void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames) for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { ImFontBaked* baked = &builder->BakedPool[baked_n]; - if (baked->LastUsedFrame + unused_frames <= atlas->Builder->FrameCount && !baked->WantDestroy) - ImFontAtlasBuildDiscardFontBaked(atlas, baked->ContainerFont, baked); + if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount) + continue; + if (baked->WantDestroy || (baked->ContainerFont->Flags & ImFontFlags_LockBakedSizes)) + continue; + ImFontAtlasBuildDiscardFontBaked(atlas, baked->ContainerFont, baked); } } @@ -3816,7 +3819,8 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) //ImFontAtlasDebugWriteTexToDisk(old_tex, "Before Pack"); // Repack, lose discarded rectangle, copy pixels - // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic. + // FIXME-NEWATLAS: This is unstable because packing order is based on RectsIndex + // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic, and fix stability. // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. ImFontAtlasPackInit(atlas); ImVector old_rects; @@ -4172,7 +4176,7 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) ImFont* font = ContainerFont; ImFontBaked* baked = this; ImFontAtlas* atlas = font->ContainerAtlas; - if (font->LockDisableLoading || atlas->Locked) + if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs)) return NULL; //char utf8_buf[5]; @@ -5008,6 +5012,13 @@ ImFontBaked* ImFont::GetFontBaked(float size) return baked; } + // FIXME-BAKED: If loading is locked, find closest match + if (Flags & ImFontFlags_LockBakedSizes) + { + IM_ASSERT(LastBaked); + return LastBaked; + } + // FIXME-BAKED: If atlas is locked, find closest match if (atlas->Locked) IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2304aaf37b3a..6a86c79560a6 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4321,7 +4321,7 @@ void ImGui::PushPasswordFont() ImFont* out_font = &g.InputTextPasswordFont; out_font->Scale = in_font->Scale; out_font->ContainerAtlas = in_font->ContainerAtlas; - out_font->LockDisableLoading = true; + out_font->Flags |= ImFontFlags_NoLoadGlyphs; ImFontBaked* out_baked = out_font->GetFontBaked(in_baked->Size); IM_ASSERT(out_baked->Glyphs.Size <= 1 && out_baked->IndexAdvanceX.Size == 0 && out_baked->IndexLookup.Size == 0); out_baked->Ascent = in_baked->Ascent; From 92993e68c8a401623385ca04724914ae0575afa7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Feb 2025 13:06:05 +0100 Subject: [PATCH 493/716] Fonts: Baked system, fix subsequent sources overriding shared font metrics. --- imgui_draw.cpp | 3 ++- misc/freetype/imgui_freetype.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6f6f2e4ace10..48ecc6b1b8e3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4313,7 +4313,8 @@ static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* { ImFontConfig* src = &font->Sources[src_n]; ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; - + if (src_n != 0) + continue; // FIXME-NEWFONTS: reevaluate how to use sizing metrics // FIXME-NEWFONTS: make use of line gap value float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index e71534c52e68..5de45a75f06a 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -479,8 +479,11 @@ void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked) bd_baked_data->MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * bd_font_data->InvRasterizationDensity; // Output - baked->Ascent = bd_baked_data->Ascender; - baked->Descent = bd_baked_data->Descender; + if (src_n == 0) + { + baked->Ascent = bd_baked_data->Ascender; + baked->Descent = bd_baked_data->Descender; + } } } From 76b252f80a3322a12f39952658b82b17630c018f Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 14:51:37 +0100 Subject: [PATCH 494/716] Fonts: Added ImFontAtlasBakedSetFontGlyphBitmap(). --- imgui_draw.cpp | 43 ++++++++++++++++++-------------- imgui_internal.h | 1 + misc/freetype/imgui_freetype.cpp | 34 +++++++++++-------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 48ecc6b1b8e3..2a9e9a45f45f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4370,9 +4370,10 @@ static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBa const bool is_visible = (x0 != x1 && y0 != y1); // Prepare glyph - ImFontGlyph glyph; - glyph.Codepoint = codepoint; - glyph.AdvanceX = advance * scale_for_layout; + ImFontGlyph glyph_in = {}; + ImFontGlyph* glyph = &glyph_in; + glyph->Codepoint = codepoint; + glyph->AdvanceX = advance * scale_for_layout; // Pack and retrieve position inside texture atlas // (generally based on stbtt_PackFontRangesRenderIntoRects) @@ -4420,25 +4421,18 @@ static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBa // Register glyph // r->x r->y are coordinates inside texture (in pixels) // glyph.X0, glyph.Y0 are drawing coordinates from base text position, and accounting for oversampling. - glyph.X0 = x0 * recip_h + font_off_x; - glyph.Y0 = y0 * recip_v + font_off_y; - glyph.X1 = (x0 + (int)r->w) * recip_h + font_off_x; - glyph.Y1 = (y0 + (int)r->h) * recip_v + font_off_y; - glyph.Visible = true; - glyph.PackId = pack_id; - ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); - - // Copy to texture, post-process and queue update for backend - ImTextureData* tex = atlas->TexData; - IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); - ImFontAtlasTextureBlockConvert(bitmap_pixels, ImTextureFormat_Alpha8, w, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); - ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, &baked->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; - ImFontAtlasTextureBlockPostProcess(&pp_data); - ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); + glyph->X0 = x0 * recip_h + font_off_x; + glyph->Y0 = y0 * recip_v + font_off_y; + glyph->X1 = (x0 + (int)r->w) * recip_h + font_off_x; + glyph->Y1 = (y0 + (int)r->h) * recip_v + font_off_y; + glyph->Visible = true; + glyph->PackId = pack_id; + glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); + ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, glyph, r, bitmap_pixels, ImTextureFormat_Alpha8, w); } else { - ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); + glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); } return true; @@ -4891,6 +4885,17 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked return &glyph; } +// Copy to texture, post-process and queue update for backend +void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImFontAtlasRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch) +{ + ImTextureData* tex = atlas->TexData; + IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); + ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h); + ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, glyph, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h }; + ImFontAtlasTextureBlockPostProcess(&pp_data); + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); +} + void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) { // FIXME-BAKED: Implement AddRemapChar() diff --git a/imgui_internal.h b/imgui_internal.h index 2f5ba1514ef5..9bde7ed43c18 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3777,6 +3777,7 @@ IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* s IMGUI_API bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); +IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImFontAtlasRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 5de45a75f06a..7be3fc1e52fa 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -546,9 +546,10 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked const bool is_visible = (w != 0 && h != 0); // Prepare glyph - ImFontGlyph glyph = {}; - glyph.Codepoint = codepoint; - glyph.AdvanceX = (slot->advance.x / FT_SCALEFACTOR) * bd_font_data->InvRasterizationDensity; + ImFontGlyph glyph_in = {}; + ImFontGlyph* glyph = &glyph_in; + glyph->Codepoint = codepoint; + glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) * bd_font_data->InvRasterizationDensity; // Pack and retrieve position inside texture atlas if (is_visible) @@ -580,26 +581,19 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked // Register glyph float glyph_off_x = (float)face->glyph->bitmap_left; float glyph_off_y = (float)-face->glyph->bitmap_top; - glyph.X0 = glyph_off_x * recip_h + font_off_x; - glyph.Y0 = glyph_off_y * recip_v + font_off_y; - glyph.X1 = (glyph_off_x + w) * recip_h + font_off_x; - glyph.Y1 = (glyph_off_y + h) * recip_v + font_off_y; - glyph.Visible = true; - glyph.Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); - glyph.PackId = pack_id; - ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); - - // Copy to texture, post-process and queue update for backend - ImTextureData* tex = atlas->TexData; - IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); - ImFontAtlasTextureBlockConvert(temp_buffer, ImTextureFormat_RGBA32, w * 4, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h); - ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, &baked->Glyphs.back(), tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), w, h }; - ImFontAtlasTextureBlockPostProcess(&pp_data); - ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); + glyph->X0 = glyph_off_x * recip_h + font_off_x; + glyph->Y0 = glyph_off_y * recip_v + font_off_y; + glyph->X1 = (glyph_off_x + w) * recip_h + font_off_x; + glyph->Y1 = (glyph_off_y + h) * recip_v + font_off_y; + glyph->Visible = true; + glyph->Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); + glyph->PackId = pack_id; + glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); + ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, glyph, r, (const unsigned char*)temp_buffer, ImTextureFormat_RGBA32, w * 4); } else { - ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph); + glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); } return true; } From d59f10d7f50402963c3e80521d2e4caf22278e60 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 15:58:16 +0100 Subject: [PATCH 495/716] Fonts: reinstated ImFontAtlasBuildSetupFontCreateEllipsisFromDot() compatible with baked system, lazily baked. --- imgui.h | 1 + imgui_draw.cpp | 72 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/imgui.h b/imgui.h index fa345e7fea54..46a0b8749fbe 100644 --- a/imgui.h +++ b/imgui.h @@ -3697,6 +3697,7 @@ struct ImFont ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. + bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. short LockSingleSrcConfigIdx; // Methods diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2a9e9a45f45f..bc55b72738f6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2497,7 +2497,8 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildUpdateBasicTexData() // - ImFontAtlasBuildUpdateLinesTexData() // - ImFontAtlasBuildAddFont() -// - ImFontAtlasBuildSetupFontCreateEllipsisFromDot() +// - ImFontAtlasBuildSetupFontBakedEllipsis() +// - ImFontAtlasBuildSetupFontBakedBlanks() // - ImFontAtlasBuildSetupFontSpecialGlyphs() // - ImFontAtlasBuildDiscardBakes() // - ImFontAtlasBuildDiscardFontBakedGlyph() @@ -3528,37 +3529,50 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) return true; } -// Rasterize our own ellipsis character from a dot. +// Create a compact, baked "..." if it doesn't exist, by using the ".". // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. -// FIXME-NEWATLAS: This borrows too much from FontBackend_FontAddGlyph() and suggest that we should add further helpers. -// FIXME-BAKED: prebaked ellipsis -/*static void ImFontAtlasBuildSetupFontCreateEllipsisFromDot(ImFontAtlas* atlas, ImFont* font, const ImFontGlyph* dot_glyph) +// FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoaderGlyph() handlers and suggest that we should add further helpers. +static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, ImFontBaked* baked) { - ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_glyph->PackId); + ImFont* font = baked->ContainerFont; + IM_ASSERT(font->EllipsisChar != 0); + + const ImFontGlyph* dot_glyph = baked->FindGlyphNoFallback((ImWchar)'.'); + if (dot_glyph == NULL) + dot_glyph = baked->FindGlyphNoFallback((ImWchar)0xFF0E); + if (dot_glyph == NULL) + return NULL; + ImFontAtlasRectId dot_r_id = dot_glyph->PackId; // Deep copy to avoid invalidation of glyphs and rect pointers + ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); const int dot_spacing = 1; const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; + ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h); ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); - ImFontGlyph glyph; - glyph.Codepoint = (ImWchar)0x0085; // FIXME: Using arbitrary codepoint. - glyph.AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. - glyph.X0 = dot_glyph->X0; - glyph.Y0 = dot_glyph->Y0; - glyph.X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing; - glyph.Y1 = dot_glyph->Y1; - glyph.Visible = true; - glyph.PackId = pack_id; - ImFontAtlasBuildAddFontGlyph(atlas, font, NULL, &glyph); - font->EllipsisChar = (ImWchar)glyph.Codepoint; + ImFontGlyph glyph_in = {}; + ImFontGlyph* glyph = &glyph_in; + glyph->Codepoint = font->EllipsisChar; + glyph->AdvanceX = ImMax(dot_glyph->AdvanceX, dot_glyph->X0 + dot_step * 3.0f - dot_spacing); // FIXME: Slightly odd for normally mono-space fonts but since this is used for trailing contents. + glyph->X0 = dot_glyph->X0; + glyph->Y0 = dot_glyph->Y0; + glyph->X1 = dot_glyph->X0 + dot_step * 3 - dot_spacing; + glyph->Y1 = dot_glyph->Y1; + glyph->Visible = true; + glyph->PackId = pack_id; + glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, glyph); + dot_glyph = NULL; // Invalidated // Copy to texture, post-process and queue update for backend // FIXME-NEWATLAS-V2: Dot glyph is already post-processed as this point, so this would damage it. + dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); ImTextureData* tex = atlas->TexData; for (int n = 0; n < 3; n++) ImFontAtlasTextureBlockCopy(tex, dot_r->x, dot_r->y, tex, r->x + (dot_r->w + dot_spacing) * n, r->y, dot_r->w, dot_r->h); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); -}*/ + + return glyph; +} static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { @@ -3582,6 +3596,14 @@ static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFo } baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code baked->FallbackAdvanceX = fallback_glyph->AdvanceX; +} + +static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked* baked) +{ + // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews) + ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' '); + if (space_glyph != NULL) + space_glyph->Visible = false; // Setup Tab character. // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?) @@ -3628,11 +3650,8 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im } if (font->EllipsisChar == 0) { - /*const ImWchar dots_chars[] = { (ImWchar)'.', (ImWchar)0xFF0E }; - if (const ImFontGlyph* dot_glyph = LoadFirstExistingGlyph(font, dots_chars, IM_ARRAYSIZE(dots_chars))) - ImFontAtlasBuildSetupFontCreateEllipsisFromDot(atlas, font, dot_glyph); - else*/ - font->EllipsisChar = (ImWchar)' '; + font->EllipsisChar = 0x0085; + font->EllipsisAutoBake = true; } font->LockSingleSrcConfigIdx = -1; } @@ -4162,6 +4181,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon } } +// Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { IM_ASSERT(id >= 0); @@ -4182,6 +4202,12 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); + // Special hook + // FIXME-NEWATLAS: it would be nicer if this used a more standardized way of hooking + if (codepoint == font->EllipsisChar && font->EllipsisAutoBake) + if (ImFontGlyph* glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked)) + return glyph; + // Load from single source or all sources? int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount; ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources; From 1cfc0de31df9b76a01a4c19f958d86dd4633202e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Feb 2025 15:19:23 +0100 Subject: [PATCH 496/716] Fonts: Core allocates per-baked-per-src backend buffers, to allow having custom backend per font source. Backend BakedInit/Destroy/AddGlyph process a single source. --- imgui.h | 2 +- imgui_draw.cpp | 129 ++++++++++++++++++------------- imgui_internal.h | 12 ++- misc/freetype/imgui_freetype.cpp | 120 ++++++++++++---------------- 4 files changed, 134 insertions(+), 129 deletions(-) diff --git a/imgui.h b/imgui.h index 46a0b8749fbe..e1d83d37891b 100644 --- a/imgui.h +++ b/imgui.h @@ -3654,7 +3654,7 @@ struct ImFontBaked int LastUsedFrame; // 4 // // Record of that time this was bounds ImGuiID BakedId; // 4 // ImFont* ContainerFont; // 4-8 // in // Parent font - void* FontBackendData; // 4-8 // // Font backend opaque storage (per baked font) + void* FontLoaderDatas; // 4-8 // // Font loader opaque storage (per baked font * sources): single contiguous buffer allocated by imgui, passed to loader. // Functions IMGUI_API ImFontBaked(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bc55b72738f6..ee88d5f8da8d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3531,7 +3531,7 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) // Create a compact, baked "..." if it doesn't exist, by using the ".". // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. -// FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoaderGlyph() handlers and suggest that we should add further helpers. +// FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoadGlyph() handlers and suggest that we should add further helpers. static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, ImFontBaked* baked) { ImFont* font = baked->ContainerFont; @@ -3670,6 +3670,31 @@ void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImF baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } +ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float size, ImGuiID baked_id) +{ + IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", size); + ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked()); + baked->Size = size; + baked->BakedId = baked_id; + baked->ContainerFont = font; + baked->LastUsedFrame = atlas->Builder->FrameCount; + + // Initialize backend data + size_t loader_data_size = font->SourcesCount * atlas->FontLoader->FontBakedSrcLoaderDataSize; + baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL; + char* backend_user_data_p = (char*)baked->FontLoaderDatas; + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + if (atlas->FontLoader->FontBakedInit) + atlas->FontLoader->FontBakedInit(atlas, src, baked, backend_user_data_p); + backend_user_data_p += atlas->FontLoader->FontBakedSrcLoaderDataSize; + } + + ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked); + return baked; +} + void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { ImFontAtlasBuilder* builder = atlas->Builder; @@ -3679,9 +3704,19 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa if (glyph.PackId >= 0) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); - if (atlas->FontLoader->FontBakedDestroy) - atlas->FontLoader->FontBakedDestroy(atlas, baked); - + char* backend_user_data_p = (char*)baked->FontLoaderDatas; + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + if (atlas->FontLoader->FontBakedDestroy) + atlas->FontLoader->FontBakedDestroy(atlas, src, baked, backend_user_data_p); + backend_user_data_p += atlas->FontLoader->FontBakedSrcLoaderDataSize; + } + if (baked->FontLoaderDatas) + { + IM_FREE(baked->FontLoaderDatas); + baked->FontLoaderDatas = NULL; + } builder->BakedMap.SetVoidPtr(baked->BakedId, NULL); builder->BakedDiscardedCount++; baked->ClearOutputData(); @@ -4017,7 +4052,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) #else IM_ASSERT(0); // Invalid Build function #endif - return; // ImFontAtlasBuildSetupFontBackendIO() automatically call ImFontAtlasBuildInit() + return; // ImFontAtlasBuildSetupFontLoader() automatically call ImFontAtlasBuildInit() } // Create initial texture size @@ -4191,6 +4226,16 @@ ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id return &builder->Rects[index_entry->TargetIndex]; } +// Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries) +static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint) +{ + if (const ImWchar* exclude_list = src->GlyphExcludeRanges) + for (; exclude_list[0] != 0; exclude_list += 2) + if (codepoint >= exclude_list[0] && codepoint <= exclude_list[1]) + return false; + return true; +} + ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) { ImFont* font = ContainerFont; @@ -4214,18 +4259,25 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) // Call backend const ImFontLoader* font_loader = atlas->FontLoader; - if (!font_loader->FontBakedAddGlyph(atlas, baked, srcs, srcs_count, codepoint)) + char* backend_user_data_p = (char*)baked->FontLoaderDatas; + for (int src_n = 0; src_n < srcs_count; src_n++) { - // Mark index as not found, so we don't attempt the search twice - baked->BuildGrowIndex(codepoint + 1); - baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX; - baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; - return NULL; + ImFontConfig* src = &srcs[src_n]; + if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) + if (font_loader->FontBakedAddGlyph(atlas, src, baked, backend_user_data_p, codepoint)) + { + // FIXME: Add hooks for e.g. #7962 + ImFontGlyph* glyph = &baked->Glyphs.back(); + return glyph; + } + backend_user_data_p += font_loader->FontBakedSrcLoaderDataSize; } - // FIXME: Add hooks for e.g. #7962 - ImFontGlyph* glyph = &baked->Glyphs.back(); - return glyph; + // Mark index as not found, so we don't attempt the search twice + baked->BuildGrowIndex(codepoint + 1); + baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX; + baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; + return NULL; } // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b @@ -4330,17 +4382,13 @@ static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFon return glyph_index != 0; } -static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked) +static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*) { IM_UNUSED(atlas); - ImFont* font = baked->ContainerFont; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + if (src->MergeMode == false) { - ImFontConfig* src = &font->Sources[src_n]; - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; - if (src_n != 0) - continue; // FIXME-NEWFONTS: reevaluate how to use sizing metrics // FIXME-NEWFONTS: make use of line gap value float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; @@ -4351,33 +4399,12 @@ static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* } } -// Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries) -bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint) -{ - if (const ImWchar* exclude_list = src->GlyphExcludeRanges) - for (; exclude_list[0] != 0; exclude_list += 2) - if (codepoint >= exclude_list[0] && codepoint <= exclude_list[1]) - return false; - return true; -} - -static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) +static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint) { // Search for first font which has the glyph - ImGui_ImplStbTrueType_FontSrcData* bd_font_data = NULL; - ImFontConfig* src = NULL; - int glyph_index = 0; - for (int src_n = 0; src_n < srcs_count; src_n++) - { - src = &srcs[src_n]; - if (src->GlyphExcludeRanges && !ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) - continue; - bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; - IM_ASSERT(bd_font_data); - glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); - if (glyph_index != 0) - break; - } + ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; + IM_ASSERT(bd_font_data); + int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); if (glyph_index == 0) return false; // Not found @@ -5056,17 +5083,9 @@ ImFontBaked* ImFont::GetFontBaked(float size) IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! // Create new - IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", size); - baked = builder->BakedPool.push_back(ImFontBaked()); - baked->Size = size; - baked->BakedId = baked_id; - baked->ContainerFont = this; - baked->LastUsedFrame = ContainerAtlas->Builder->FrameCount; + baked = ImFontAtlasBuildAddFontBaked(atlas, this, size, baked_id); LastBaked = baked; *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can. - if (atlas->FontLoader->FontBakedInit) - atlas->FontLoader->FontBakedInit(atlas, baked); - ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked); return baked; } diff --git a/imgui_internal.h b/imgui_internal.h index 9bde7ed43c18..caca87463572 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3668,9 +3668,13 @@ struct ImFontLoader bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); - void (*FontBakedInit)(ImFontAtlas* atlas, ImFontBaked* baked); - void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontBaked* baked); - bool (*FontBakedAddGlyph)(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint); + void (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); + void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); + bool (*FontBakedAddGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint); + + // Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations. + // FIXME: At this point the two other types of buffers may be managed by core to be consistent? + size_t FontBakedSrcLoaderDataSize; ImFontLoader() { memset(this, 0, sizeof(*this)); } }; @@ -3770,11 +3774,11 @@ IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontCo IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); IMGUI_API void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font); +IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); -IMGUI_API bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImFontAtlasRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 7be3fc1e52fa..17cd2caaa2fb 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -143,7 +143,7 @@ namespace // | | // |------------- advanceX ----------->| - // Stored in ImFontAtlas::FontLoaderData + // Stored in ImFontAtlas::FontLoaderData. ALLOCATED BY US. struct ImGui_ImplFreeType_Data { FT_Library Library; @@ -151,7 +151,7 @@ namespace ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } }; - // Stored in ImFontBaked::FontBackendData: pointer to SourcesCount instances of this. + // Stored in ImFontBaked::FontLoaderDatas: pointer to SourcesCount instances of this. ALLOCATED BY CORE. struct ImGui_ImplFreeType_FontSrcBakedData { FT_Size FtSize; // This represent a FT_Face with a given size. @@ -166,7 +166,7 @@ namespace ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } }; - // Stored in ImFontConfig::FontLoaderData + // Stored in ImFontConfig::FontLoaderData. ALLOCATED BY US. struct ImGui_ImplFreeType_FontSrcData { bool InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. @@ -437,91 +437,72 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) src->FontLoaderData = NULL; } -void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontBaked* baked) +void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { IM_UNUSED(atlas); - ImFont* font = baked->ContainerFont; const float size = baked->Size; - IM_ASSERT(baked->FontBackendData == NULL); - ImGui_ImplFreeType_FontSrcBakedData* bd_baked_datas = (ImGui_ImplFreeType_FontSrcBakedData*)IM_ALLOC(sizeof(ImGui_ImplFreeType_FontSrcBakedData) * font->SourcesCount); - baked->FontBackendData = bd_baked_datas; - - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; + bd_font_data->BakedLastActivated = baked; + + // We use one FT_Size per (source + baked) combination. + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; + IM_ASSERT(bd_baked_data != NULL); + IM_PLACEMENT_NEW(bd_baked_data) ImGui_ImplFreeType_FontSrcBakedData(); + + FT_New_Size(bd_font_data->FtFace, &bd_baked_data->FtSize); + FT_Activate_Size(bd_baked_data->FtSize); + + // Vuhdo 2017: "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' + // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. + // FT_Set_Pixel_Sizes() doesn't seem to get us the same result." + // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) + FT_Size_RequestRec req; + req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; + req.width = 0; + req.height = (uint32_t)(size * 64 * bd_font_data->RasterizationDensity); + req.horiResolution = 0; + req.vertResolution = 0; + FT_Request_Size(bd_font_data->FtFace, &req); + + // Read metrics + FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; + bd_baked_data->Ascender = (float)FT_CEIL(metrics.ascender) * bd_font_data->InvRasterizationDensity; + bd_baked_data->Descender = (float)FT_CEIL(metrics.descender) * bd_font_data->InvRasterizationDensity; + bd_baked_data->LineSpacing = (float)FT_CEIL(metrics.height) * bd_font_data->InvRasterizationDensity; + bd_baked_data->LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * bd_font_data->InvRasterizationDensity; + bd_baked_data->MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * bd_font_data->InvRasterizationDensity; + + // Output + if (src->MergeMode == false) { - ImFontConfig* src = &font->Sources[src_n]; - ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontBackendData; - bd_font_data->BakedLastActivated = baked; - - // We need one FT_Size per source, so create one ImGui_ImplFreeType_FontBakedData for each source. - ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = &bd_baked_datas[src_n]; - FT_New_Size(bd_font_data->FtFace, &bd_baked_data->FtSize); - FT_Activate_Size(bd_baked_data->FtSize); - - // Vuhdo 2017: "I'm not sure how to deal with font sizes properly. As far as I understand, currently ImGui assumes that the 'pixel_height' - // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. - // FT_Set_Pixel_Sizes() doesn't seem to get us the same result." - // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) - FT_Size_RequestRec req; - req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; - req.width = 0; - req.height = (uint32_t)(size * 64 * bd_font_data->RasterizationDensity); - req.horiResolution = 0; - req.vertResolution = 0; - FT_Request_Size(bd_font_data->FtFace, &req); - - // Read metrics - FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; - bd_baked_data->Ascender = (float)FT_CEIL(metrics.ascender) * bd_font_data->InvRasterizationDensity; - bd_baked_data->Descender = (float)FT_CEIL(metrics.descender) * bd_font_data->InvRasterizationDensity; - bd_baked_data->LineSpacing = (float)FT_CEIL(metrics.height) * bd_font_data->InvRasterizationDensity; - bd_baked_data->LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * bd_font_data->InvRasterizationDensity; - bd_baked_data->MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * bd_font_data->InvRasterizationDensity; - - // Output - if (src_n == 0) - { - baked->Ascent = bd_baked_data->Ascender; - baked->Descent = bd_baked_data->Descender; - } + baked->Ascent = bd_baked_data->Ascender; + baked->Descent = bd_baked_data->Descender; } } -void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontBaked* baked) +void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { IM_UNUSED(atlas); - ImFont* font = baked->ContainerFont; - ImGui_ImplFreeType_FontSrcBakedData* bd_baked_datas = (ImGui_ImplFreeType_FontSrcBakedData*)baked->FontBackendData; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) - FT_Done_Size(bd_baked_datas[src_n].FtSize); - IM_FREE(bd_baked_datas); - baked->FontBackendData = NULL; + IM_UNUSED(baked); + IM_UNUSED(src); + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; + IM_ASSERT(bd_baked_data != NULL); + FT_Done_Size(bd_baked_data->FtSize); + bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE() } -bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* srcs, int srcs_count, ImWchar codepoint) +bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint) { - // Search for first font which has the glyph - ImGui_ImplFreeType_FontSrcData* bd_font_data = NULL; - ImFontConfig* src = NULL; - uint32_t glyph_index = 0; - for (int src_n = 0; src_n < srcs_count; src_n++) - { - src = &srcs[src_n]; - if (src->GlyphExcludeRanges && !ImFontAtlasBuildFilterCodepointForSource(src, codepoint)) - continue; - bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; - glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); - if (glyph_index != 0) - break; - } + ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; + uint32_t glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); if (glyph_index == 0) return false; // Not found if (bd_font_data->BakedLastActivated != baked) { // Activate current size - int src_n = (int)(font_cfg - srcs); - ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = &((ImGui_ImplFreeType_FontSrcBakedData*)baked->FontBackendData)[src_n]; + ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; FT_Activate_Size(bd_baked_data->FtSize); bd_font_data->BakedLastActivated = baked; } @@ -618,6 +599,7 @@ const ImFontLoader* ImGuiFreeType::GetFontLoader() loader.FontBakedInit = ImGui_ImplFreeType_FontBakedInit; loader.FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy; loader.FontBakedAddGlyph = ImGui_ImplFreeType_FontBakedAddGlyph; + loader.FontBakedSrcLoaderDataSize = sizeof(ImGui_ImplFreeType_FontSrcBakedData); return &loader; } From c06a7585a3bfea23f69d791e1f011b3f2c3440fb Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Feb 2025 19:31:13 +0100 Subject: [PATCH 497/716] Fonts: A font source can specify its own loader/backend. --- imgui.h | 2 ++ imgui_draw.cpp | 82 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/imgui.h b/imgui.h index e1d83d37891b..28e84e2a5e4f 100644 --- a/imgui.h +++ b/imgui.h @@ -3444,7 +3444,9 @@ struct ImFontConfig // [Internal] char Name[40]; // Name (strictly to ease debugging) + ImFontFlags Flags; // Font flags (don't use just yet) ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) + const ImFontLoader* FontLoader; // Custom font backend for this source (other use one stored in ImFontAtlas) void* FontLoaderData; // Font loader opaque storage (per font config) IMGUI_API ImFontConfig(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ee88d5f8da8d..3106f2fe7d6b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2607,14 +2607,18 @@ ImFontAtlas::ImFontAtlas() ImFontAtlas::~ImFontAtlas() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - Clear(); + RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. + ClearFonts(); + ClearTexData(); + TexList.clear_delete(); + TexData = NULL; } void ImFontAtlas::Clear() { - ClearFonts(); bool backup_renderer_has_textures = RendererHasTextures; RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. + ClearFonts(); ClearTexData(); if (Builder != NULL) ImFontAtlasBuildClearTexture(this); @@ -2631,8 +2635,9 @@ void ImFontAtlas::ClearInputData() IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); for (ImFontConfig& font_cfg : Sources) { - if (FontLoader && FontLoader->FontSrcDestroy != NULL) - FontLoader->FontSrcDestroy(this, &font_cfg); + const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : FontLoader; + if (loader && loader->FontSrcDestroy != NULL) + loader->FontSrcDestroy(this, &font_cfg); if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas) { IM_FREE(font_cfg.FontData); @@ -2957,7 +2962,7 @@ bool ImFontAtlas::Build() ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0); + IM_ASSERT((font_cfg->FontData != NULL && font_cfg->FontDataSize > 0) || (font_cfg->FontLoader != NULL)); IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); @@ -2971,6 +2976,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) { font = IM_NEW(ImFont)(); font->FontId = FontNextUniqueID++; + font->Flags = font_cfg->Flags; Fonts.push_back(font); } else @@ -2998,6 +3004,9 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!"); IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!"); } + if (font_cfg->FontLoader != NULL) + IM_ASSERT(font_cfg->FontLoader->FontBakedAddGlyph != NULL); + IM_ASSERT(font_cfg->FontLoaderData == NULL); // Round font size // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. @@ -3165,8 +3174,9 @@ void ImFontAtlas::RemoveFont(ImFont* font) for (int src_n = 0; src_n < font->SourcesCount; src_n++) { ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; - if (FontLoader && FontLoader->FontSrcDestroy != NULL) - FontLoader->FontSrcDestroy(this, src); + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : FontLoader; + if (loader && loader->FontSrcDestroy != NULL) + loader->FontSrcDestroy(this, src); if (src->FontData != NULL && src->FontDataOwnedByAtlas) IM_FREE(src->FontData); } @@ -3317,6 +3327,8 @@ void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* ou *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1; } +// Setup main font loader for the atlas +// Every font source (ImFontConfig) will use this unless ImFontConfig::FontLoader specify a custom loader. void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader) { if (atlas->FontLoader == font_loader) @@ -3521,9 +3533,10 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) IM_ASSERT(font->Sources == src); } - const ImFontLoader* font_loader = atlas->FontLoader; - if (!font_loader->FontSrcInit(atlas, src)) - return false; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader->FontSrcInit != NULL) + if (!loader->FontSrcInit(atlas, src)) + return false; ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); return true; @@ -3680,15 +3693,22 @@ ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, floa baked->LastUsedFrame = atlas->Builder->FrameCount; // Initialize backend data - size_t loader_data_size = font->SourcesCount * atlas->FontLoader->FontBakedSrcLoaderDataSize; + size_t loader_data_size = 0; + for (int src_n = 0; src_n < font->SourcesCount; src_n++) // Cannot easily be cached as we allow changing backend + { + ImFontConfig* src = &font->Sources[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + loader_data_size += loader->FontBakedSrcLoaderDataSize; + } baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL; - char* backend_user_data_p = (char*)baked->FontLoaderDatas; + char* loader_data_p = (char*)baked->FontLoaderDatas; for (int src_n = 0; src_n < font->SourcesCount; src_n++) { ImFontConfig* src = &font->Sources[src_n]; - if (atlas->FontLoader->FontBakedInit) - atlas->FontLoader->FontBakedInit(atlas, src, baked, backend_user_data_p); - backend_user_data_p += atlas->FontLoader->FontBakedSrcLoaderDataSize; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader->FontBakedInit) + loader->FontBakedInit(atlas, src, baked, loader_data_p); + loader_data_p += loader->FontBakedSrcLoaderDataSize; } ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked); @@ -3704,13 +3724,14 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa if (glyph.PackId >= 0) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); - char* backend_user_data_p = (char*)baked->FontLoaderDatas; + char* loader_data_p = (char*)baked->FontLoaderDatas; for (int src_n = 0; src_n < font->SourcesCount; src_n++) { ImFontConfig* src = &font->Sources[src_n]; - if (atlas->FontLoader->FontBakedDestroy) - atlas->FontLoader->FontBakedDestroy(atlas, src, baked, backend_user_data_p); - backend_user_data_p += atlas->FontLoader->FontBakedSrcLoaderDataSize; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader->FontBakedDestroy) + loader->FontBakedDestroy(atlas, src, baked, loader_data_p); + loader_data_p += loader->FontBakedSrcLoaderDataSize; } if (baked->FontLoaderDatas) { @@ -4094,9 +4115,12 @@ void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) { for (ImFont* font : atlas->Fonts) font->ClearOutputData(); - if (atlas->FontLoader && atlas->FontLoader->FontSrcDestroy != NULL) - for (ImFontConfig& font_cfg : atlas->Sources) - atlas->FontLoader->FontSrcDestroy(atlas, &font_cfg); + for (ImFontConfig& font_cfg : atlas->Sources) + { + const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : atlas->FontLoader; + if (loader && loader->FontSrcDestroy != NULL) + loader->FontSrcDestroy(atlas, &font_cfg); + } IM_DELETE(atlas->Builder); atlas->Builder = NULL; @@ -4258,19 +4282,19 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources; // Call backend - const ImFontLoader* font_loader = atlas->FontLoader; - char* backend_user_data_p = (char*)baked->FontLoaderDatas; + char* loader_user_data_p = (char*)baked->FontLoaderDatas; for (int src_n = 0; src_n < srcs_count; src_n++) { ImFontConfig* src = &srcs[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) - if (font_loader->FontBakedAddGlyph(atlas, src, baked, backend_user_data_p, codepoint)) + if (loader->FontBakedAddGlyph(atlas, src, baked, loader_user_data_p, codepoint)) { // FIXME: Add hooks for e.g. #7962 ImFontGlyph* glyph = &baked->Glyphs.back(); return glyph; } - backend_user_data_p += font_loader->FontBakedSrcLoaderDataSize; + loader_user_data_p += loader->FontBakedSrcLoaderDataSize; } // Mark index as not found, so we don't attempt the search twice @@ -5017,8 +5041,12 @@ bool ImFont::IsGlyphInFont(ImWchar c) { ImFontAtlas* atlas = ContainerAtlas; for (int src_n = 0; src_n < SourcesCount; src_n++) - if (atlas->FontLoader->FontSrcContainsGlyph(atlas, &Sources[src_n], c)) + { + ImFontConfig* src = &Sources[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c)) return true; + } return false; } From 18c8a93cca8133bf74039b23c2ac30bb185a5cf0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 7 Feb 2025 18:48:01 +0100 Subject: [PATCH 498/716] Fonts: Rework ImFontLoader signatures. InitBaked may return false to signify this size is not supported. --- imgui_draw.cpp | 23 ++++++++++------------- imgui_internal.h | 4 ++-- misc/freetype/imgui_freetype.cpp | 22 ++++++++++------------ 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3106f2fe7d6b..0a6726366beb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3005,7 +3005,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!"); } if (font_cfg->FontLoader != NULL) - IM_ASSERT(font_cfg->FontLoader->FontBakedAddGlyph != NULL); + IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL); IM_ASSERT(font_cfg->FontLoaderData == NULL); // Round font size @@ -4288,12 +4288,8 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) ImFontConfig* src = &srcs[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) - if (loader->FontBakedAddGlyph(atlas, src, baked, loader_user_data_p, codepoint)) - { - // FIXME: Add hooks for e.g. #7962 - ImFontGlyph* glyph = &baked->Glyphs.back(); - return glyph; - } + if (ImFontGlyph* glyph = loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint)) + return glyph; // FIXME: Add hooks for e.g. #7962 loader_user_data_p += loader->FontBakedSrcLoaderDataSize; } @@ -4406,7 +4402,7 @@ static bool ImGui_ImplStbTrueType_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFon return glyph_index != 0; } -static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*) +static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*) { IM_UNUSED(atlas); @@ -4421,16 +4417,17 @@ static void ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig baked->Ascent = ImCeil(unscaled_ascent * scale_for_layout); baked->Descent = ImFloor(unscaled_descent * scale_for_layout); } + return true; } -static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint) +static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint) { // Search for first font which has the glyph ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; IM_ASSERT(bd_font_data); int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); if (glyph_index == 0) - return false; // Not found + return NULL; // Fonts unit to pixels int oversample_h, oversample_v; @@ -4463,7 +4460,7 @@ static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontCo { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); - return false; + return NULL; } ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); @@ -4512,7 +4509,7 @@ static bool ImGui_ImplStbTrueType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontCo glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); } - return true; + return glyph; } const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() @@ -4524,7 +4521,7 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() loader.FontSrcContainsGlyph = ImGui_ImplStbTrueType_FontSrcContainsGlyph; loader.FontBakedInit = ImGui_ImplStbTrueType_FontBakedInit; loader.FontBakedDestroy = NULL; - loader.FontBakedAddGlyph = ImGui_ImplStbTrueType_FontBakedAddGlyph; + loader.FontBakedLoadGlyph = ImGui_ImplStbTrueType_FontBakedLoadGlyph; return &loader; } diff --git a/imgui_internal.h b/imgui_internal.h index caca87463572..40975abd78cc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3668,9 +3668,9 @@ struct ImFontLoader bool (*FontSrcInit)(ImFontAtlas* atlas, ImFontConfig* src); void (*FontSrcDestroy)(ImFontAtlas* atlas, ImFontConfig* src); bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); - void (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); + bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); - bool (*FontBakedAddGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint); + ImFontGlyph* (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint); // Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations. // FIXME: At this point the two other types of buffers may be managed by core to be consistent? diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 17cd2caaa2fb..39919c8e403e 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -437,7 +437,7 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) src->FontLoaderData = NULL; } -void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) +bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { IM_UNUSED(atlas); const float size = baked->Size; @@ -479,6 +479,7 @@ void ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF baked->Ascent = bd_baked_data->Ascender; baked->Descent = bd_baked_data->Descender; } + return true; } void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) @@ -492,12 +493,12 @@ void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE() } -bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint) +ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint) { ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; uint32_t glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); if (glyph_index == 0) - return false; // Not found + return NULL; if (bd_font_data->BakedLastActivated != baked) { @@ -509,18 +510,15 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, const FT_Glyph_Metrics* metrics = bd_font_data->LoadGlyph(codepoint); if (metrics == NULL) - return false; + return NULL; // Render glyph into a bitmap (currently held by FreeType) FT_Face face = bd_font_data->FtFace; FT_GlyphSlot slot = face->glyph; FT_Error error = FT_Render_Glyph(slot, bd_font_data->RenderMode); - if (error != 0) - return false; - const FT_Bitmap* ft_bitmap = &slot->bitmap; - if (ft_bitmap == nullptr) - return false; + if (error != 0 || ft_bitmap == nullptr) + return NULL; const int w = (int)ft_bitmap->width; const int h = (int)ft_bitmap->rows; @@ -540,7 +538,7 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); - return false; + return NULL; } ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); @@ -576,7 +574,7 @@ bool ImGui_ImplFreeType_FontBakedAddGlyph(ImFontAtlas* atlas, ImFontConfig* src, { glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); } - return true; + return glyph; } bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) @@ -598,7 +596,7 @@ const ImFontLoader* ImGuiFreeType::GetFontLoader() loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph; loader.FontBakedInit = ImGui_ImplFreeType_FontBakedInit; loader.FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy; - loader.FontBakedAddGlyph = ImGui_ImplFreeType_FontBakedAddGlyph; + loader.FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph; loader.FontBakedSrcLoaderDataSize = sizeof(ImGui_ImplFreeType_FontSrcBakedData); return &loader; } From 78a17038c2437aeedb29e4654588713896dd4abc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 15:09:46 +0100 Subject: [PATCH 499/716] imgui_freetype: no need to store metrics locally. --- misc/freetype/imgui_freetype.cpp | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 39919c8e403e..fd6920e0c25b 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -155,14 +155,6 @@ namespace struct ImGui_ImplFreeType_FontSrcBakedData { FT_Size FtSize; // This represent a FT_Face with a given size. - - // Metrics - float Ascender; // The pixel extents above the baseline in pixels (typically positive). - float Descender; // The extents below the baseline in pixels (typically negative). - float LineSpacing; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. - float LineGap; // The spacing in pixels between one row's descent and the next row's ascent. - float MaxAdvanceWidth; // This field gives the maximum horizontal cursor advance for all glyphs in the font. - ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } }; @@ -465,19 +457,17 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF req.vertResolution = 0; FT_Request_Size(bd_font_data->FtFace, &req); - // Read metrics - FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; - bd_baked_data->Ascender = (float)FT_CEIL(metrics.ascender) * bd_font_data->InvRasterizationDensity; - bd_baked_data->Descender = (float)FT_CEIL(metrics.descender) * bd_font_data->InvRasterizationDensity; - bd_baked_data->LineSpacing = (float)FT_CEIL(metrics.height) * bd_font_data->InvRasterizationDensity; - bd_baked_data->LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * bd_font_data->InvRasterizationDensity; - bd_baked_data->MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * bd_font_data->InvRasterizationDensity; - // Output if (src->MergeMode == false) { - baked->Ascent = bd_baked_data->Ascender; - baked->Descent = bd_baked_data->Descender; + // Read metrics + FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; + const float scale = bd_font_data->InvRasterizationDensity; + baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). + baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). + //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. + //LineGap = (float)FT_CEIL(metrics.height - metrics.ascender + metrics.descender) * scale; // The spacing in pixels between one row's descent and the next row's ascent. + //MaxAdvanceWidth = (float)FT_CEIL(metrics.max_advance) * scale; // This field gives the maximum horizontal cursor advance for all glyphs in the font. } return true; } @@ -500,7 +490,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon if (glyph_index == 0) return NULL; - if (bd_font_data->BakedLastActivated != baked) + if (bd_font_data->BakedLastActivated != baked) // <-- could use id { // Activate current size ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; From d8a612f73b34fb10a763b50cf1bc48a81447b1d7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 22:32:09 +0100 Subject: [PATCH 500/716] Fonts: Fallback glyph is now lazily loaded on demand (yay!). Moving ImFontBaked:: functions outside of class. --- imgui.h | 5 ++-- imgui_draw.cpp | 79 +++++++++++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/imgui.h b/imgui.h index 28e84e2a5e4f..811125c9715b 100644 --- a/imgui.h +++ b/imgui.h @@ -3652,7 +3652,8 @@ struct ImFontBaked // [Internal] Members: Cold float Ascent, Descent; // 4+4 // out // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled) unsigned int MetricsTotalSurface:26;// 3 // out // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) - unsigned int WantDestroy:1; // 1 // // Queued for destroy + unsigned int WantDestroy:1; // 0 // // Queued for destroy + unsigned int LockLoadingFallback:1; // 0 // // int LastUsedFrame; // 4 // // Record of that time this was bounds ImGuiID BakedId; // 4 // ImFont* ContainerFont; // 4-8 // in // Parent font @@ -3665,8 +3666,6 @@ struct ImFontBaked IMGUI_API ImFontGlyph* FindGlyphNoFallback(ImWchar c); // Return NULL if glyph doesn't exist IMGUI_API float GetCharAdvance(ImWchar c); IMGUI_API bool IsGlyphLoaded(ImWchar c); - IMGUI_API ImFontGlyph* BuildLoadGlyph(ImWchar c); - IMGUI_API void BuildGrowIndex(int new_size); }; // Font flags diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0a6726366beb..54a7acab2dba 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2499,6 +2499,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildAddFont() // - ImFontAtlasBuildSetupFontBakedEllipsis() // - ImFontAtlasBuildSetupFontBakedBlanks() +// - ImFontAtlasBuildSetupFontBakedFallback() // - ImFontAtlasBuildSetupFontSpecialGlyphs() // - ImFontAtlasBuildDiscardBakes() // - ImFontAtlasBuildDiscardFontBakedGlyph() @@ -2527,7 +2528,8 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasPackAddRect() // - ImFontAtlasPackGetRect() //----------------------------------------------------------------------------- -// - ImFont::BuildLoadGlyph() +// - ImFontBaked_BuildGrowIndex() +// - ImFontBaked_BuildLoadGlyph() // - ImFontAtlasDebugLogTextureRequests() //----------------------------------------------------------------------------- // - ImFontAtlasGetFontLoaderForStbTruetype() @@ -3242,7 +3244,7 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); if (baked->IsGlyphLoaded(codepoint)) - ImFontAtlasBuildDiscardFontBakedGlyph(this, font, baked, (ImFontGlyph*)(void*)baked->FindGlyph(codepoint)); + ImFontAtlasBuildDiscardFontBakedGlyph(this, font, baked, baked->FindGlyph(codepoint)); ImFontGlyph glyph; glyph.Codepoint = codepoint; @@ -3367,7 +3369,7 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) IM_ASSERT(ranges != NULL); for (; ranges[0]; ranges += 2) for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 - baked->FindGlyphNoFallback((ImWchar)c); + baked->FindGlyph((ImWchar)c); } } @@ -3587,25 +3589,23 @@ static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, I return glyph; } -static void ImFontAtlasBuildSetupFontBakedSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) +// Load fallback in order to obtain its index +// (this is called from in hot-path so we avoid extraneous parameters to minimize impact on code size) +static void ImFontAtlasBuildSetupFontBakedFallback(ImFontBaked* baked) { - // Mark space as always hidden (not strictly correct/necessary. but some e.g. icons fonts don't have a space. it tends to look neater in previews) - ImFontGlyph* space_glyph = (ImFontGlyph*)(void*)baked->FindGlyphNoFallback((ImWchar)' '); - if (space_glyph != NULL) - space_glyph->Visible = false; - - // Load fallback in order to obtain its index - // FIXME-NEWATLAS: could we use a scheme where this is lazily loaded? IM_ASSERT(baked->FallbackGlyphIndex == -1); + IM_ASSERT(baked->FallbackAdvanceX == 0.0f); + ImFont* font = baked->ContainerFont; ImFontGlyph* fallback_glyph = NULL; if (font->FallbackChar != 0) fallback_glyph = baked->FindGlyphNoFallback(font->FallbackChar); if (fallback_glyph == NULL) { + ImFontGlyph* space_glyph = baked->FindGlyphNoFallback((ImWchar)' '); ImFontGlyph glyph; glyph.Codepoint = 0; glyph.AdvanceX = space_glyph ? space_glyph->AdvanceX : IM_ROUND(baked->Size * 0.40f); - fallback_glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, NULL, &glyph); + fallback_glyph = ImFontAtlasBakedAddFontGlyph(font->ContainerAtlas, baked, NULL, &glyph); } baked->FallbackGlyphIndex = baked->Glyphs.index_from_ptr(fallback_glyph); // Storing index avoid need to update pointer on growth and simplify inner loop code baked->FallbackAdvanceX = fallback_glyph->AdvanceX; @@ -3711,7 +3711,7 @@ ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, floa loader_data_p += loader->FontBakedSrcLoaderDataSize; } - ImFontAtlasBuildSetupFontBakedSpecialGlyphs(atlas, baked->ContainerFont, baked); + ImFontAtlasBuildSetupFontBakedBlanks(atlas, baked); return baked; } @@ -4260,13 +4260,26 @@ static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar return true; } -ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) +static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) { - ImFont* font = ContainerFont; - ImFontBaked* baked = this; + IM_ASSERT(baked->IndexAdvanceX.Size == baked->IndexLookup.Size); + if (new_size <= baked->IndexLookup.Size) + return; + baked->IndexAdvanceX.resize(new_size, -1.0f); + baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); +} + +static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint) +{ + ImFont* font = baked->ContainerFont; ImFontAtlas* atlas = font->ContainerAtlas; if (atlas->Locked || (font->Flags & ImFontFlags_NoLoadGlyphs)) + { + // Lazily load fallback glyph + if (baked->FallbackGlyphIndex == -1 && baked->LockLoadingFallback == 0) + ImFontAtlasBuildSetupFontBakedFallback(baked); return NULL; + } //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); @@ -4293,8 +4306,14 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) loader_user_data_p += loader->FontBakedSrcLoaderDataSize; } + // Lazily load fallback glyph + if (baked->LockLoadingFallback) + return NULL; + if (baked->FallbackGlyphIndex == -1) + ImFontAtlasBuildSetupFontBakedFallback(baked); + // Mark index as not found, so we don't attempt the search twice - baked->BuildGrowIndex(codepoint + 1); + ImFontBaked_BuildGrowIndex(baked, codepoint + 1); baked->IndexAdvanceX[codepoint] = baked->FallbackAdvanceX; baked->IndexLookup[codepoint] = IM_FONTGLYPH_INDEX_NOT_FOUND; return NULL; @@ -4302,10 +4321,10 @@ ImFontGlyph* ImFontBaked::BuildLoadGlyph(ImWchar codepoint) // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b IM_MSVC_RUNTIME_CHECKS_OFF -static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* font, unsigned int codepoint) +static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* baked, unsigned int codepoint) { - ImFontGlyph* glyph = font->BuildLoadGlyph((ImWchar)codepoint); - return glyph ? glyph->AdvanceX : font->FallbackAdvanceX; + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint); + return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX; } IM_MSVC_RUNTIME_CHECKS_RESTORE @@ -4861,15 +4880,6 @@ void ImFontBaked::ClearOutputData() MetricsTotalSurface = 0; } -void ImFontBaked::BuildGrowIndex(int new_size) -{ - IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size); - if (new_size <= IndexLookup.Size) - return; - IndexAdvanceX.resize(new_size, -1.0f); - IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); -} - ImFont::ImFont() { memset(this, 0, sizeof(*this)); @@ -4950,7 +4960,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked // Update lookup tables int codepoint = glyph.Codepoint; - baked->BuildGrowIndex(codepoint + 1); + ImFontBaked_BuildGrowIndex(baked, codepoint + 1); baked->IndexAdvanceX[codepoint] = glyph.AdvanceX; baked->IndexLookup[codepoint] = (ImU16)glyph_idx; const int page_n = codepoint / 8192; @@ -5002,7 +5012,7 @@ ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c) if (i != IM_FONTGLYPH_INDEX_UNUSED) return &Glyphs.Data[i]; } - ImFontGlyph* glyph = BuildLoadGlyph(c); + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex]; } @@ -5017,7 +5027,10 @@ ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c) if (i != IM_FONTGLYPH_INDEX_UNUSED) return &Glyphs.Data[i]; } - return BuildLoadGlyph(c); + LockLoadingFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites. + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); + LockLoadingFallback = false; + return glyph; } bool ImFontBaked::IsGlyphLoaded(ImWchar c) @@ -5060,7 +5073,7 @@ float ImFontBaked::GetCharAdvance(ImWchar c) } // Same as BuildLoadGlyphGetAdvanceOrFallback(): - const ImFontGlyph* glyph = BuildLoadGlyph(c); + const ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); return glyph ? glyph->AdvanceX : FallbackAdvanceX; } IM_MSVC_RUNTIME_CHECKS_RESTORE From ef6beaeff68951a8c0f736843dd6f8a0b638796c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Feb 2025 22:53:33 +0100 Subject: [PATCH 501/716] Fonts: removed LockSingleSrcConfigIdx which isn't needed anymore since we don't load glyphs in ImFontAtlasBuildAddFont(). --- imgui.h | 1 - imgui_draw.cpp | 15 +++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index 811125c9715b..05bda5b54272 100644 --- a/imgui.h +++ b/imgui.h @@ -3699,7 +3699,6 @@ struct ImFont float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. - short LockSingleSrcConfigIdx; // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 54a7acab2dba..ebf42bcb447a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3637,14 +3637,11 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount); IM_UNUSED(atlas); - // While manipulating glyphs during init we want to restrict all searches for one source font. - font->LockSingleSrcConfigIdx = (short)src_idx_in_font; - // Find Fallback character. Actual glyph loaded in GetFontBaked(). const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; if (font->FallbackChar == 0) for (ImWchar candidate_char : fallback_chars) - if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) // FIXME: does not respect LockSingleSrcConfigIdx() + if (candidate_char != 0 && font->IsGlyphInFont(candidate_char)) { font->FallbackChar = (ImWchar)candidate_char; break; @@ -3666,7 +3663,6 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im font->EllipsisChar = 0x0085; font->EllipsisAutoBake = true; } - font->LockSingleSrcConfigIdx = -1; } void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) @@ -4290,15 +4286,11 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep if (ImFontGlyph* glyph = ImFontAtlasBuildSetupFontBakedEllipsis(atlas, baked)) return glyph; - // Load from single source or all sources? - int srcs_count = (font->LockSingleSrcConfigIdx != -1) ? 1 : font->SourcesCount; - ImFontConfig* srcs = (font->LockSingleSrcConfigIdx != -1) ? &font->Sources[font->LockSingleSrcConfigIdx] : font->Sources; - // Call backend char* loader_user_data_p = (char*)baked->FontLoaderDatas; - for (int src_n = 0; src_n < srcs_count; src_n++) + for (int src_n = 0; src_n < font->SourcesCount; src_n++) { - ImFontConfig* src = &srcs[src_n]; + ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) if (ImFontGlyph* glyph = loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint)) @@ -4884,7 +4876,6 @@ ImFont::ImFont() { memset(this, 0, sizeof(*this)); Scale = 1.0f; - LockSingleSrcConfigIdx = -1; } ImFont::~ImFont() From 2bf6879daee8b4f1eae10ee03af953389baae061 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Feb 2025 15:16:19 +0100 Subject: [PATCH 502/716] Fonts: tidying up font scale logic. # Conflicts: # imgui_internal.h --- imgui.cpp | 43 ++++++++++++++++++++++--------------------- imgui_internal.h | 9 ++++++--- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3f6c01ded842..2d5c33753102 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3942,7 +3942,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) FontAtlasOwnedByContext = shared_font_atlas ? false : true; Font = NULL; FontBaked = NULL; - FontSize = /*FontBaseSize = */FontScale = CurrentDpiScale = 0.0f; + FontSize = FontSizeBeforeScaling = FontScale = CurrentDpiScale = 0.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); IO.Fonts->RefCount++; Time = 0.0f; @@ -4375,9 +4375,7 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking if (window) { - // FIXME-BAKED - //g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); - //g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize; + ImGui::UpdateCurrentFontSize(); ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } } @@ -8406,14 +8404,9 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() void ImGui::SetWindowFontScale(float scale) { IM_ASSERT(scale > 0.0f); - // FIXME-BAKED - /* - ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); window->FontWindowScale = scale; - g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize(); - g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize; - */ + UpdateCurrentFontSize(); } void ImGui::PushFocusScope(ImGuiID id) @@ -8608,26 +8601,34 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size) { ImGuiContext& g = *GImGui; g.Font = font; - //g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.FontBaked->Size * g.Font->Scale); - g.FontSize = font_size;// g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; + g.FontSizeBeforeScaling = font_size; + UpdateCurrentFontSize(); + if (font != NULL) { IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); - g.FontBaked = g.Font->GetFontBaked(g.FontSize); - g.FontScale = g.FontSize / g.FontBaked->Size; g.DrawListSharedData.Font = g.Font; - g.DrawListSharedData.FontSize = g.FontSize; - g.DrawListSharedData.FontScale = g.FontScale; ImFontAtlasUpdateDrawListsSharedData(g.Font->ContainerAtlas); if (g.CurrentWindow != NULL) g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexRef); } - else - { - g.FontBaked = NULL; - g.FontScale = 0.0f; - } +} + +void ImGui::UpdateCurrentFontSize() +{ + ImGuiContext& g = *GImGui; + float final_size = g.FontSizeBeforeScaling * g.IO.FontGlobalScale; + final_size *= g.Font->Scale; + if (ImGuiWindow* window = g.CurrentWindow) + final_size *= window->FontWindowScale; + final_size = ImMax(1.0f, IM_ROUND(final_size)); + + g.FontSize = final_size; + g.FontBaked = (g.Font != NULL) ? g.Font->GetFontBaked(g.FontSize) : NULL; + g.FontScale = (g.Font != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; + g.DrawListSharedData.FontSize = g.FontSize; + g.DrawListSharedData.FontScale = g.FontScale; } void ImGui::PushFont(ImFont* font, float font_size) diff --git a/imgui_internal.h b/imgui_internal.h index 40975abd78cc..c0c8002fd6c9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2138,8 +2138,8 @@ struct ImGuiContext ImGuiStyle Style; ImFont* Font; // == FontStack.back().Font ImFontBaked* FontBaked; // == Font->GetFontBaked(FontSize) - float FontSize; // == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window. - //float FontBaseSize; // == io.FontGlobalScale * Font->Scale * Font->FontSize. Base text height. + float FontSize; // == FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale. Current text height. + float FontSizeBeforeScaling; // == value passed to PushFontSize() float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; @@ -2680,9 +2680,11 @@ struct IMGUI_API ImGuiWindow // We don't use g.FontSize because the window may be != g.CurrentWindow. ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); } - //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; } ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight)); } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); } + + // [Obsolete] ImGuiWindow::CalcFontSize() was removed in 1.92.x because error-prone/misleading. You can use window->FontRefSize for a copy of g.FontSize at the time of the last Begin() call for this window. + //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; } }; //----------------------------------------------------------------------------- @@ -3106,6 +3108,7 @@ namespace ImGui // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font, float font_size); + IMGUI_API void UpdateCurrentFontSize(); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } IMGUI_API void PushPasswordFont(); inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. From e98a314e0620346b9d9da14fb88fe9fbd88a74af Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Feb 2025 15:41:26 +0100 Subject: [PATCH 503/716] Textures: Added ImTextureData::UsedRect. # Conflicts: # imgui_internal.h --- imgui.cpp | 9 ++++++--- imgui.h | 3 ++- imgui_draw.cpp | 7 ++++++- imgui_internal.h | 1 + 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2d5c33753102..a8a04080c262 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15724,10 +15724,13 @@ void ImGui::DebugNodeTexture(ImTextureData* tex) ImGuiContext& g = *GImGui; if (TreeNode(tex, "Texture #%03d (%dx%d pixels)", tex->UniqueID, tex->Width, tex->Height)) { + ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; + Checkbox("Show used rect", &cfg->ShowTextureUsedRect); PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); - ImTextureRef tex_id; - tex_id._TexData = tex; // Don't use tex->TexID directly so first frame works. - ImageWithBg(tex_id, ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + ImVec2 p = GetCursorScreenPos(); + ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + if (cfg->ShowTextureUsedRect) + GetWindowDrawList()->AddRect(ImVec2(p.x + tex->UsedRect.x, p.y + tex->UsedRect.y), ImVec2(p.x + tex->UsedRect.x + tex->UsedRect.w, p.y + tex->UsedRect.y + tex->UsedRect.h), IM_COL32(255, 0, 255, 255)); PopStyleVar(); char texid_desc[20]; diff --git a/imgui.h b/imgui.h index 05bda5b54272..1d7cfbc923bc 100644 --- a/imgui.h +++ b/imgui.h @@ -3389,7 +3389,8 @@ struct IMGUI_API ImTextureData unsigned char* Pixels; // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. ImTextureID TexID; // Always use SetTexID() to modify! Identifier stored in ImDrawCmd::GetTexID() and passed to backend RenderDrawData loop. void* BackendUserData; // Convenience storage for backend. Some backends may have enough with TexID. - ImTextureRect UpdateRect; // Bounding box encompassing all individual updates. + ImTextureRect UsedRect; // Bounding box encompassing all past and queued Updates[]. + ImTextureRect UpdateRect; // Bounding box encompassing all queued Updates[]. ImVector Updates; // Array of individual updates. int UnusedFrames; // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. unsigned short RefCount; // Number of contexts using this texture. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ebf42bcb447a..558dd28e482d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2439,6 +2439,7 @@ void ImTextureData::Create(ImTextureFormat format, int w, int h) Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel); IM_ASSERT(Pixels != NULL); memset(Pixels, 0, Width * Height * BytesPerPixel); + UsedRect.x = UsedRect.y = UsedRect.w = UsedRect.h = 0; UpdateRect.x = UpdateRect.y = (unsigned short)~0; UpdateRect.w = UpdateRect.h = 0; } @@ -2918,6 +2919,10 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y); tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x); tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y); + tex->UsedRect.x = ImMin(tex->UsedRect.x, req.x); + tex->UsedRect.y = ImMin(tex->UsedRect.y, req.y); + tex->UsedRect.w = (unsigned short)(ImMax(tex->UsedRect.x + tex->UsedRect.w, req.x + req.w) - tex->UsedRect.x); + tex->UsedRect.h = (unsigned short)(ImMax(tex->UsedRect.y + tex->UsedRect.h, req.y + req.h) - tex->UsedRect.y); atlas->TexIsBuilt = false; // No need to queue if status is _WantCreate @@ -3957,7 +3962,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ old_tex_h = atlas->TexData->Height; // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend? - // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? Could we expose e.g. tex->UsedRect. + // FIXME-NEWATLAS-V2: Does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations? IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h)); IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight)); diff --git a/imgui_internal.h b/imgui_internal.h index c0c8002fd6c9..12f188b68067 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2075,6 +2075,7 @@ struct ImGuiMetricsConfig bool ShowDrawCmdMesh = true; bool ShowDrawCmdBoundingBoxes = true; bool ShowTextEncodingViewer = false; + bool ShowTextureUsedRect = false; int ShowWindowsRectsType = -1; int ShowTablesRectsType = -1; int HighlightMonitorIdx = -1; From 161e2223220b2fa1002c963f1c801ebbb8897316 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 3 Mar 2025 16:14:41 +0100 Subject: [PATCH 504/716] Fonts: GetFontBaked() default to searching for closest size font. --- imgui_draw.cpp | 53 ++++++++++++++++++++++++++++++++++++++---------- imgui_internal.h | 1 + 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 558dd28e482d..c3275550acc1 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3716,6 +3716,30 @@ ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, floa return baked; } +// FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most common case. +ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size) +{ + ImFontAtlasBuilder* builder = atlas->Builder; + ImFontBaked* closest_larger_match = NULL; + ImFontBaked* closest_smaller_match = NULL; + for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + { + ImFontBaked* baked = &builder->BakedPool[baked_n]; + if (baked->ContainerFont != font || baked->WantDestroy) + continue; + if (baked->Size > font_size && (closest_larger_match == NULL || baked->Size < closest_larger_match->Size)) + closest_larger_match = baked; + if (baked->Size < font_size && (closest_smaller_match == NULL || baked->Size > closest_smaller_match->Size)) + closest_smaller_match = baked; + } + if (closest_larger_match) + if (closest_smaller_match == NULL || (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f)) + return closest_larger_match; + if (closest_smaller_match) + return closest_smaller_match; + return NULL; +} + void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { ImFontAtlasBuilder* builder = atlas->Builder; @@ -4976,9 +5000,9 @@ void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } +// FIXME-NEWATLAS: Implement AddRemapChar() which was removed since transitioning to baked logic. void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) { - // FIXME-BAKED: Implement AddRemapChar() IM_UNUSED(from_codepoint); IM_UNUSED(to_codepoint); IM_UNUSED(overwrite_dst); @@ -5092,8 +5116,8 @@ ImFontBaked* ImFont::GetFontBaked(float size) ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; - // FIXME-BAKED: Design for picking a nearest size? - // FIXME-BAKED: Altering font density won't work right away. + // FIXME-NEWATLAS: Design for picking a nearest size based on some criterias? + // FIXME-NEWATLAS: Altering font density won't work right away. ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size); ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); baked = *p_baked_in_map; @@ -5105,17 +5129,24 @@ ImFontBaked* ImFont::GetFontBaked(float size) return baked; } - // FIXME-BAKED: If loading is locked, find closest match - if (Flags & ImFontFlags_LockBakedSizes) + // If atlas is locked, find closest match + // FIXME-OPT: This is not an optimal query. + if ((Flags & ImFontFlags_LockBakedSizes) || atlas->Locked) { - IM_ASSERT(LastBaked); - return LastBaked; + baked = ImFontAtlasBuildGetClosestFontBakedMatch(atlas, this, size); + if (baked != NULL) + { + baked->LastUsedFrame = builder->FrameCount; + LastBaked = baked; + return baked;; + } + if (atlas->Locked) + { + IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! + return NULL; + } } - // FIXME-BAKED: If atlas is locked, find closest match - if (atlas->Locked) - IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! - // Create new baked = ImFontAtlasBuildAddFontBaked(atlas, this, size, baked_id); LastBaked = baked; diff --git a/imgui_internal.h b/imgui_internal.h index 12f188b68067..a7e481629c47 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3779,6 +3779,7 @@ IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); IMGUI_API void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font); IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); +IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy From 0b71339122fabecf925a0a9fb8ca90dacaac71f9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 17:05:24 +0100 Subject: [PATCH 505/716] Demo: Add a "Fonts" section for visibility. --- imgui.cpp | 16 ++++++++++------ imgui_demo.cpp | 4 +--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a8a04080c262..ef311491c8fa 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15640,6 +15640,11 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { ImGuiContext& g = *GImGui; + SeparatorText("Backend Support for Dynamic Fonts"); + BeginDisabled(); + CheckboxFlags("io.BackendFlags: RendererHasTextures", &GetIO().BackendFlags, ImGuiBackendFlags_RendererHasTextures); + EndDisabled(); + SeparatorText("Fonts"); Text("Read "); SameLine(0, 0); @@ -16548,12 +16553,11 @@ void ImGui::DebugNodeFont(ImFont* font) } if (SmallButton("Set as default")) GetIO().FontDefault = font; - if (atlas->Fonts.Size > 1 && !atlas->Locked) - { - SameLine(); - if (SmallButton("Remove")) - atlas->RemoveFont(font); - } + SameLine(); + BeginDisabled(atlas->Fonts.Size <= 1 || atlas->Locked); + if (SmallButton("Remove")) + atlas->RemoveFont(font); + EndDisabled(); // Display details SetNextItemWidth(GetFontSize() * 8); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 55b09a2bfacb..894012903c68 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1745,6 +1745,7 @@ static void DemoWindowWidgetsFonts() { ImFontAtlas* atlas = ImGui::GetIO().Fonts; ImGui::ShowFontAtlas(atlas); + // FIXME-NEWATLAS: Provide a demo to add/create a procedural font? ImGui::TreePop(); } } @@ -8171,9 +8172,6 @@ void ImGui::ShowAboutWindow(bool* p_open) // - ShowStyleEditor() //----------------------------------------------------------------------------- -// Forward declare ShowFontAtlas() which isn't worth putting in public API yet -namespace ImGui { IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); } - // Demo helper function to select among loaded fonts. // Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one. void ImGui::ShowFontSelector(const char* label) From 131f5c57ab1836cdbf0c6962d9d9cfa7ebd34d49 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 17:18:54 +0100 Subject: [PATCH 506/716] Textures: Detect when using a texture that's about to be destroyed. --- imgui.cpp | 5 ++++- imgui_draw.cpp | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index ef311491c8fa..b8dca131cb93 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15733,7 +15733,10 @@ void ImGui::DebugNodeTexture(ImTextureData* tex) Checkbox("Show used rect", &cfg->ShowTextureUsedRect); PushStyleVar(ImGuiStyleVar_ImageBorderSize, ImMax(1.0f, g.Style.ImageBorderSize)); ImVec2 p = GetCursorScreenPos(); - ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); + if (tex->WantDestroyNextFrame) + Dummy(ImVec2((float)tex->Width, (float)tex->Height)); + else + ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); if (cfg->ShowTextureUsedRect) GetWindowDrawList()->AddRect(ImVec2(p.x + tex->UsedRect.x, p.y + tex->UsedRect.y), ImVec2(p.x + tex->UsedRect.x + tex->UsedRect.w, p.y + tex->UsedRect.y + tex->UsedRect.h), IM_COL32(255, 0, 255, 255)); PopStyleVar(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c3275550acc1..4c5a471430bc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -676,6 +676,8 @@ void ImDrawList::PushTexture(ImTextureRef tex_ref) { _TextureStack.push_back(tex_ref); _CmdHeader.TexRef = tex_ref; + if (tex_ref._TexData != NULL) + IM_ASSERT(tex_ref._TexData->WantDestroyNextFrame == false); _OnChangedTexture(); } From dec8d3863abdd126fdce044bb0a0f808f2ae3ba6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 20:08:00 +0100 Subject: [PATCH 507/716] Fonts: Added a ImFontFlags_NoLoadError flag to let user code try file paths. (3611) --- imgui.h | 1 + imgui_draw.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 1d7cfbc923bc..6703c128bd90 100644 --- a/imgui.h +++ b/imgui.h @@ -3676,6 +3676,7 @@ enum ImFontFlags_ ImFontFlags_None = 0, ImFontFlags_LockBakedSizes = 1 << 0, // Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. ImFontFlags_NoLoadGlyphs = 1 << 1, // Disable loading new glyphs. + ImFontFlags_NoLoadError = 1 << 2, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. }; // Font runtime data and rendering diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4c5a471430bc..ec379ffa1268 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3096,7 +3096,8 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0); if (!data) { - IM_ASSERT_USER_ERROR(0, "Could not load font file!"); + if (font_cfg_template == NULL || (font_cfg_template->Flags & ImFontFlags_NoLoadError) == 0) + IM_ASSERT_USER_ERROR(0, "Could not load font file!"); return NULL; } ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); From 93410c47e11c2f9d719a1c87111a1d5b08af6e96 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 5 Mar 2025 18:42:41 +0100 Subject: [PATCH 508/716] Fonts: Fixed various small warnings / build issues. --- imgui.cpp | 2 +- imgui.h | 4 ++-- imgui_draw.cpp | 9 +++++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b8dca131cb93..644275201ec2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16670,7 +16670,7 @@ void ImGui::DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph) if (glyph->PackId >= 0) { ImFontAtlasRect* r = ImFontAtlasPackGetRect(font->ContainerAtlas, glyph->PackId); - Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y);; + Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y); } } diff --git a/imgui.h b/imgui.h index 6703c128bd90..f03a20306269 100644 --- a/imgui.h +++ b/imgui.h @@ -339,7 +339,7 @@ struct ImTextureRef { ImTextureRef() { memset(this, 0, sizeof(*this)); } ImTextureRef(ImTextureID tex_id) { memset(this, 0, sizeof(*this)); _TexID = tex_id; } -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +#if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(ImTextureUserID) ImTextureRef(void* tex_id) { memset(this, 0, sizeof(*this)); _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID //inline operator intptr_t() const { return (intptr_t)_TexID; } // For legacy backends casting to ImTextureID #endif @@ -3406,7 +3406,7 @@ struct IMGUI_API ImTextureData unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } int GetPitch() const { return Width * BytesPerPixel; } - ImTextureRef GetTexRef() const { ImTextureRef tex_ref; tex_ref._TexData = (ImTextureData*)(void*)this; tex_ref._TexID = TexID; return tex_ref; } + ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = TexID; return tex_ref; } ImTextureID GetTexID() const { return TexID; } // Called by Renderer backend diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ec379ffa1268..d51ae9e50364 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -40,6 +40,7 @@ Index of this file: #endif #include // vsnprintf, sscanf, printf +#include // intptr_t // Visual Studio warnings #ifdef _MSC_VER @@ -3193,6 +3194,7 @@ void ImFontAtlas::RemoveFont(ImFont* font) bool removed = Fonts.find_erase(font); IM_ASSERT(removed); + IM_UNUSED(removed); Sources.erase(font->Sources, font->Sources + font->SourcesCount); ImFontAtlasBuildUpdatePointers(this); @@ -3644,6 +3646,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im const int src_idx_in_font = (int)(src - font->Sources); IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount); IM_UNUSED(atlas); + IM_UNUSED(src_idx_in_font); // Find Fallback character. Actual glyph loaded in GetFontBaked(). const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; @@ -3680,9 +3683,10 @@ void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImF ImFontAtlasPackDiscardRect(atlas, glyph->PackId); glyph->PackId = -1; } - ImWchar c = glyph->Codepoint; + ImWchar c = (ImWchar)glyph->Codepoint; IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity IM_ASSERT(glyph >= baked->Glyphs.Data && glyph < baked->Glyphs.Data + baked->Glyphs.Size); + IM_UNUSED(font); baked->IndexLookup[c] = IM_FONTGLYPH_INDEX_UNUSED; baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } @@ -4371,6 +4375,7 @@ void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas) IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update %d regions, texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, tex->Updates.Size, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); for (const ImTextureRect& r : tex->Updates) { + IM_UNUSED(r); IM_ASSERT(r.x >= 0 && r.y >= 0); IM_ASSERT(r.x + r.w <= tex->Width && r.y + r.h <= tex->Height); // In theory should subtract PackPadding but it's currently part of atlas and mid-frame change would wreck assert. //IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: update (% 4d..%-4d)->(% 4d..%-4d), texid=0x%" IM_PRIX64 ", backend_data=0x%" IM_PRIX64 "\n", tex->UniqueID, r.x, r.y, r.x + r.w, r.y + r.h, tex->TexID, (ImU64)(intptr_t)tex->BackendUserData); @@ -5141,7 +5146,7 @@ ImFontBaked* ImFont::GetFontBaked(float size) { baked->LastUsedFrame = builder->FrameCount; LastBaked = baked; - return baked;; + return baked; } if (atlas->Locked) { From da51485e17e08ef156aada958bf05b4e27b0d739 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Mar 2025 18:15:25 +0100 Subject: [PATCH 509/716] Fonts: Obsolete GetGlyphRangesXXX() functions. Update font documentation. --- docs/FONTS.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ imgui.h | 5 ++++- imgui_draw.cpp | 3 +++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index 514af0799300..9b783dcdc178 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -12,6 +12,7 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo ## Index - [Troubleshooting](#troubleshooting) +- [New! Dynamic Fonts system in 1.92 (March 2025)](#new-dynamic-fonts-system-in-192-march-2025) - [How should I handle DPI in my application?](#how-should-i-handle-dpi-in-my-application) - [Fonts Loading Instructions](#fonts-loading-instructions) - [Loading Font Data from Memory](#loading-font-data-from-memory) @@ -43,6 +44,8 @@ See [About UTF-8 Encoding](#about-utf-8-encoding). Use the encoding viewer to co ### (3) Missing glyph ranges. +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary.** + You need to load a font with explicit glyph ranges if you want to use non-ASCII characters. See [Fonts Loading Instructions](#fonts-loading-instructions). Use [Debug Tools](#debug-tools) confirm loaded fonts and loaded glyph ranges. This is a current constraint of Dear ImGui (which we will lift in the future): when loading a font you need to specify which characters glyphs to load. @@ -50,6 +53,8 @@ All loaded fonts glyphs are rendered into a single texture atlas ahead of time. ### (4) Font atlas texture fails to upload to GPU. +🆕 **Since 1.92, with an up to date backend: atlas is built incrementally and dynamically resized, this is less likely to happen** + This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty white rectangles.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. ![empty squares](https://github.com/user-attachments/assets/68b50fb5-8b9d-4c38-baec-6ac384f06d26) @@ -63,6 +68,22 @@ Some solutions: Future versions of Dear ImGui should solve this problem. +##### [Return to Index](#index) + +--------------------------------------- + +## New! Dynamic Fonts system in 1.92 (March 2025+) + +v1.92 will introduce a newer, dynamic font system. It requires backend to support the `ImGuiBackendFlags_HasTextures` feature: +- Users of icons, Asian and non-English languages do not need to pre-build all glyphs ahead of time. Saving on loading time, memory, and also reducing issues with missing glyphs. Specifying glyph ranges is not needed anymore. +- PushFontSize() may be used anytime to change font size. +- Packing custom rectangles is more convenient as pixels may be written to immediately. +- Any update to fonts previously required backend specific calls to re-upload the texture, and said calls were not portable across backends. It is now possible to scale fonts etc. in a way that doesn't require you to make backend-specific calls. +- It is possible to plug a custom loader/backend to any font source. + +See [#8465](https://github.com/ocornut/imgui/issues/8465) for more details. + + ##### [Return to Index](#index) --------------------------------------- @@ -131,6 +152,8 @@ io.Fonts->Build(); **Add a fourth parameter to bake specific font ranges only:** +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary. All the GetGlyphRangesXXX() functions are marked obsolete.** + ```cpp // Basic Latin, Extended Latin io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, nullptr, io.Fonts->GetGlyphRangesDefault()); @@ -145,10 +168,20 @@ See [Using Custom Glyph Ranges](#using-custom-glyph-ranges) section to create yo **Example loading and using a Japanese font:** +🆕 **Since 1.92, with an up to date backend:** + +```cpp +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f); +``` + +**Before 1.92, or without an up to date backend:** + ```cpp ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); ``` + ```cpp ImGui::Text(u8"こんにちは!テスト %d", 123); if (ImGui::Button(u8"ロード")) @@ -215,6 +248,8 @@ To refer to the icon UTF-8 codepoints from your C++ code, you may use those head So you can use `ICON_FA_SEARCH` as a string that will render as a "Search" icon. +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary. You can omit this parameter.** + Example Setup: ```cpp // Merge icons into default tool font @@ -289,6 +324,8 @@ io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\seguiemj.ttf", 16.0f, &cfg, ra ## Using Custom Glyph Ranges +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary, so this is not needed.** + You can use the `ImFontGlyphRangesBuilder` helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. ```cpp ImVector ranges; @@ -308,6 +345,15 @@ io.Fonts->Build(); // Build the atlas while ## Using Custom Colorful Icons +🆕 **Since 1.92, with an up to date backend: this system has been revamped.** + +TL;DR; With the new system, it is recommended that you create a custom `ImFontLoader` and register your fonts with it. +`AddCustomRectFontGlyph()` has been obsolete because its API does not make much sense with resizable fonts. + +You can ask questions in [#8466](https://github.com/ocornut/imgui/issues/8466). + +🆕 **Before 1.92:** + As an alternative to rendering colorful glyphs using imgui_freetype with `ImGuiFreeTypeBuilderFlags_LoadColor`, you may allocate your own space in the texture atlas and write yourself into it. **(This is a BETA api, use if you are familiar with dear imgui and with your rendering backend)** - You can use the `ImFontAtlas::AddCustomRect()` and `ImFontAtlas::AddCustomRectFontGlyph()` api to register rectangles that will be packed into the font atlas texture. Register them before building the atlas, then call Build()`. diff --git a/imgui.h b/imgui.h index f03a20306269..8f01ff7efc3e 100644 --- a/imgui.h +++ b/imgui.h @@ -3553,11 +3553,13 @@ struct ImFontAtlas // Glyph Ranges //------------------------------------------- + // Since 1.92: specifying glyph ranges is only useful/necessary if your backend doesn't support ImGuiBackendFlags_HasTextures! + IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) // NB: Make sure that your string are UTF-8 and NOT in your local code page. // Read https://github.com/ocornut/imgui/blob/master/docs/FONTS.md/#about-utf-8-encoding for details. // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data. - IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin IMGUI_API const ImWchar* GetGlyphRangesGreek(); // Default + Greek and Coptic IMGUI_API const ImWchar* GetGlyphRangesKorean(); // Default + Korean characters IMGUI_API const ImWchar* GetGlyphRangesJapanese(); // Default + Hiragana, Katakana, Half-Width, Selection of 2999 Ideographs @@ -3566,6 +3568,7 @@ struct ImFontAtlas IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters +#endif //------------------------------------------- // [ALPHA] Custom Rectangles/Glyphs API diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d51ae9e50364..c99dbb5a8494 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4579,6 +4579,7 @@ const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() // [SECTION] ImFontAtlas: glyph ranges helpers //------------------------------------------------------------------------- // - GetGlyphRangesDefault() +// Obsolete functions since 1.92: // - GetGlyphRangesGreek() // - GetGlyphRangesKorean() // - GetGlyphRangesChineseFull() @@ -4600,6 +4601,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesDefault() return &ranges[0]; } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS const ImWchar* ImFontAtlas::GetGlyphRangesGreek() { static const ImWchar ranges[] = @@ -4849,6 +4851,7 @@ const ImWchar* ImFontAtlas::GetGlyphRangesVietnamese() }; return &ranges[0]; } +#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS //----------------------------------------------------------------------------- // [SECTION] ImFontGlyphRangesBuilder From c98e3c0effe9887d29c426560da8803be005c069 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Mar 2025 18:39:32 +0100 Subject: [PATCH 510/716] Fonts: ImFontConfig::GlyphExcludeRanges is owner and copied. --- imgui.cpp | 6 ++++++ imgui.h | 2 +- imgui_draw.cpp | 24 +++++++++++++++--------- imgui_internal.h | 2 ++ 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 644275201ec2..cb546e4ba445 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2011,6 +2011,12 @@ char* ImStrdup(const char* str) return (char*)memcpy(buf, (const void*)str, len + 1); } +void* ImMemdup(const void* src, size_t size) +{ + void* dst = IM_ALLOC(size); + return memcpy(dst, src, size); +} + char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src) { size_t dst_buf_size = p_dst_size ? *p_dst_size : ImStrlen(dst) + 1; diff --git a/imgui.h b/imgui.h index 8f01ff7efc3e..550af74ba76e 100644 --- a/imgui.h +++ b/imgui.h @@ -3434,7 +3434,7 @@ struct ImFontConfig //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - const ImWchar* GlyphExcludeRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. + const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c99dbb5a8494..f154e5628d63 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2644,11 +2644,7 @@ void ImFontAtlas::ClearInputData() const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : FontLoader; if (loader && loader->FontSrcDestroy != NULL) loader->FontSrcDestroy(this, &font_cfg); - if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas) - { - IM_FREE(font_cfg.FontData); - font_cfg.FontData = NULL; - } + ImFontAtlasBuildDiscardFontSource(this, &font_cfg); } // When clearing this we lose access to the font name and other information used to build the font. @@ -2969,6 +2965,17 @@ bool ImFontAtlas::Build() } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +void ImFontAtlasBuildDiscardFontSource(ImFontAtlas* atlas, ImFontConfig* src) +{ + IM_UNUSED(atlas); + if (src->FontDataOwnedByAtlas) + IM_FREE(src->FontData); + if (src->GlyphExcludeRanges) + IM_FREE((void*)src->GlyphExcludeRanges); + src->FontData = NULL; + src->GlyphExcludeRanges = NULL; +} + ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); @@ -3001,9 +3008,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) new_font_cfg.DstFont = font; if (!new_font_cfg.FontDataOwnedByAtlas) { - new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize); new_font_cfg.FontDataOwnedByAtlas = true; - memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); + new_font_cfg.FontData = ImMemdup(font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); } // Sanity check @@ -3013,6 +3019,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) for (const ImWchar* p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) {} IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!"); IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!"); + new_font_cfg.GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1)); } if (font_cfg->FontLoader != NULL) IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL); @@ -3029,8 +3036,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) if (!ImFontAtlasBuildAddFont(this, &new_font_cfg)) { // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) - if (new_font_cfg.FontDataOwnedByAtlas) - IM_FREE(new_font_cfg.FontData); + ImFontAtlasBuildDiscardFontSource(this, &new_font_cfg); Sources.pop_back(); if (!font_cfg->MergeMode) { diff --git a/imgui_internal.h b/imgui_internal.h index a7e481629c47..6252ee818b50 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -389,6 +389,7 @@ IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); // Case insensitive compare to a certain count. IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); // Copy to a certain count and always zero terminate (strncpy doesn't). IMGUI_API char* ImStrdup(const char* str); // Duplicate a string. +IMGUI_API void* ImMemdup(const void* src, size_t size); // Duplicate a chunk of memory. IMGUI_API char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str); // Copy in provided buffer, recreate buffer if needed. IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end, char c); // Find first occurrence of 'c' in string range. IMGUI_API const char* ImStreolRange(const char* str, const char* str_end); // End end-of-line @@ -3778,6 +3779,7 @@ IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontCo IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); IMGUI_API void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font); +IMGUI_API void ImFontAtlasBuildDiscardFontSource(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); From 40f988ce2a23e64be2831abe94f28345ce60e7a2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Mar 2025 19:57:49 +0100 Subject: [PATCH 511/716] Fonts: in ShowFontAtlas() preserve open-state for latest texture. Improve debug display. --- imgui.cpp | 20 ++++++++++++-------- imgui_draw.cpp | 17 ++++++++++++++--- imgui_internal.h | 5 ++++- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cb546e4ba445..466ab28c7bf7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15420,7 +15420,8 @@ static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImG // - RenderViewportsThumbnails() [Internal] // - DebugTextEncoding() // - MetricsHelpMarker() [Internal] -// - ShowFontAtlas() [Internal] +// - ShowFontAtlas() [Internal but called by Demo!] +// - DebugNodeTexture() [Internal] // - ShowMetricsWindow() // - DebugNodeColumns() [Internal] // - DebugNodeDrawList() [Internal] @@ -15722,18 +15723,20 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) Text("incl. Discarded rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsDiscardedCount, atlas->Builder->RectsDiscardedSurface, discarded_surface_sqrt, discarded_surface_sqrt); // Texture list - for (ImTextureData* tex : atlas->TexList) + // (ensure the last texture always use the same ID, so we can keep it open neatly) + for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { - PushID(tex); - DebugNodeTexture(tex); - PopID(); + if (tex_n == atlas->TexList.Size - 1) + SetNextItemOpen(true, ImGuiCond_Once); + DebugNodeTexture(atlas->TexList[tex_n], atlas->TexList.Size - 1 - tex_n); } } -void ImGui::DebugNodeTexture(ImTextureData* tex) +void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id) { ImGuiContext& g = *GImGui; - if (TreeNode(tex, "Texture #%03d (%dx%d pixels)", tex->UniqueID, tex->Width, tex->Height)) + PushID(int_id); + if (TreeNode("", "Texture #%03d (%dx%d pixels)", tex->UniqueID, tex->Width, tex->Height)) { ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; Checkbox("Show used rect", &cfg->ShowTextureUsedRect); @@ -15748,12 +15751,13 @@ void ImGui::DebugNodeTexture(ImTextureData* tex) PopStyleVar(); char texid_desc[20]; - Text("Format = %d", tex->Format); + Text("Format = %s (%d)", ImTextureDataGetFormatName(tex->Format), tex->Format); Text("TexID = %s", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID)); Text("BackendUserData = %p", tex->BackendUserData); Text("UseColors = %d", tex->UseColors); TreePop(); } + PopID(); } void ImGui::ShowMetricsWindow(bool* p_open) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f154e5628d63..04a00c422807 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2420,7 +2420,7 @@ ImFontConfig::ImFontConfig() // - ImTextureData::DestroyPixels() //----------------------------------------------------------------------------- -static int GetTextureFormatBytesPerPixel(ImTextureFormat format) +int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format) { switch (format) { @@ -2431,13 +2431,24 @@ static int GetTextureFormatBytesPerPixel(ImTextureFormat format) return 0; } +const char* ImTextureDataGetFormatName(ImTextureFormat format) +{ + switch (format) + { + case ImTextureFormat_Alpha8: return "Alpha8"; + case ImTextureFormat_RGBA32: return "RGBA32"; + } + return "N/A"; +} + + void ImTextureData::Create(ImTextureFormat format, int w, int h) { DestroyPixels(); Format = format; Width = w; Height = h; - BytesPerPixel = GetTextureFormatBytesPerPixel(format); + BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format); UseColors = false; Pixels = (unsigned char*)IM_ALLOC(Width * Height * BytesPerPixel); IM_ASSERT(Pixels != NULL); @@ -2798,7 +2809,7 @@ void ImFontAtlasTextureBlockConvert(const unsigned char* src_pixels, ImTextureFo IM_ASSERT(src_pixels != NULL && dst_pixels != NULL); if (src_fmt == dst_fmt) { - int line_sz = w * GetTextureFormatBytesPerPixel(src_fmt); + int line_sz = w * ImTextureDataGetFormatBytesPerPixel(src_fmt); for (int ny = h; ny > 0; ny--, src_pixels += src_pitch, dst_pixels += dst_pitch) memcpy(dst_pixels, src_pixels, line_sz); } diff --git a/imgui_internal.h b/imgui_internal.h index 6252ee818b50..c1857aafba02 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3625,7 +3625,7 @@ namespace ImGui IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); - IMGUI_API void DebugNodeTexture(ImTextureData* tex); + IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id); // ID used to facilitate persisting the "current" texture. IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); IMGUI_API void DebugNodeTable(ImGuiTable* table); @@ -3809,6 +3809,9 @@ IMGUI_API void ImFontAtlasTextureBlockFill(ImTextureData* dst_tex, IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, int src_x, int src_y, ImTextureData* dst_tex, int dst_x, int dst_y, int w, int h); IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); +IMGUI_API int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format); +IMGUI_API const char* ImTextureDataGetFormatName(ImTextureFormat format); + #ifndef IMGUI_DISABLE_DEBUG_TOOLS IMGUI_API void ImFontAtlasDebugLogTextureRequests(ImFontAtlas* atlas); #endif From 41a0e991f0ea621b93cfe3672a274147a5457a72 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Mar 2025 20:34:18 +0100 Subject: [PATCH 512/716] Fonts: Added UI to edit FreeType loader flags. Added ImFontAtlasBuildReloadAll() / ImFontAtlasBuildReloadFont() --- imgui.cpp | 26 +++++++++++++++++++++++--- imgui_draw.cpp | 22 +++++++++++++++++++--- imgui_internal.h | 5 ++++- misc/freetype/imgui_freetype.cpp | 18 +++++++++++++++++- misc/freetype/imgui_freetype.h | 3 +++ 5 files changed, 66 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 466ab28c7bf7..1d1ad86507ec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15639,7 +15639,7 @@ static void MetricsHelpMarker(const char* desc) } #ifdef IMGUI_ENABLE_FREETYPE -namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); } +namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); IMGUI_API bool DebugEditFontBuilderFlags(unsigned int* p_font_builder_flags); } #endif // [DEBUG] List fonts in a font atlas and display its texture @@ -15682,6 +15682,12 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) const ImFontLoader* loader_freetype = ImGuiFreeType::GetFontLoader(); if (RadioButton("FreeType", loader_current == loader_freetype)) ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); + if (loader_current == loader_freetype) + { + Text("Shared FreeType Loader Flags:"); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&atlas->FontBuilderFlags)) + ImFontAtlasBuildReloadAll(atlas); + } #else BeginDisabled(); RadioButton("FreeType", false); @@ -16585,10 +16591,24 @@ void ImGui::DebugNodeFont(ImFont* font) char c_str[5]; Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); + for (int src_n = 0; src_n < font->SourcesCount; src_n++) if (ImFontConfig* src = &font->Sources[src_n]) - BulletText("Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", - src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); + if (TreeNode(src, "Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", + src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y)) + { + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + Text("Loader: '%s'", loader->Name ? loader->Name : "N/A"); +#ifdef IMGUI_ENABLE_FREETYPE + if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0) + { + Text("FreeType Loader Flags: 0x%08X", src->FontBuilderFlags); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&src->FontBuilderFlags)) + ImFontAtlasBuildReloadFont(atlas, src); + } +#endif + TreePop(); + } // Display all glyphs of the fonts in separate pages of 256 characters for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 04a00c422807..c7418cfca6a5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2519,7 +2519,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildDiscardBakes() // - ImFontAtlasBuildDiscardFontBakedGlyph() // - ImFontAtlasBuildDiscardFontBaked() -// - ImFontAtlasBuildDiscardFont() +// - ImFontAtlasBuildDiscardFontBakes() //----------------------------------------------------------------------------- // - ImFontAtlasAddDrawListSharedData() // - ImFontAtlasRemoveDrawListSharedData() @@ -3551,6 +3551,22 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ //----------------------------------------------------------------------------------------------------------------------------- +void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas) +{ + const ImFontLoader* main_loader = atlas->FontLoader; + ImFontAtlasBuildSetupFontLoader(atlas, NULL); + ImFontAtlasBuildSetupFontLoader(atlas, main_loader); +} + +void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src) +{ + // FIXME-NEWATLAS: rebuild single font not supported yet. + IM_UNUSED(src); + ImFontAtlasBuildReloadAll(atlas); +} + +//----------------------------------------------------------------------------------------------------------------------------- + bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) { ImFont* font = src->DstFont; @@ -3794,7 +3810,7 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa font->LastBaked = NULL; } -void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasBuildDiscardFontBakes(ImFontAtlas* atlas, ImFont* font) { if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) @@ -4943,7 +4959,7 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { if (ImFontAtlas* atlas = ContainerAtlas) - ImFontAtlasBuildDiscardFont(atlas, this); + ImFontAtlasBuildDiscardFontBakes(atlas, this); FallbackChar = EllipsisChar = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); LastBaked = NULL; diff --git a/imgui_internal.h b/imgui_internal.h index c1857aafba02..c92aea66678e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3775,10 +3775,13 @@ IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas); // Reinit/rebuild, notably if font loader params have changed. +IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src); // Reinit/rebuild, notably if font loader params have changed. + IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); -IMGUI_API void ImFontAtlasBuildDiscardFont(ImFontAtlas* atlas, ImFont* font); +IMGUI_API void ImFontAtlasBuildDiscardFontBakes(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDiscardFontSource(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index fd6920e0c25b..edd6bdd1441d 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -578,7 +578,7 @@ bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* s const ImFontLoader* ImGuiFreeType::GetFontLoader() { static ImFontLoader loader; - loader.Name = "freetype"; + loader.Name = "FreeType"; loader.LoaderInit = ImGui_ImplFreeType_LoaderInit; loader.LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown; loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit; @@ -598,6 +598,22 @@ void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* u GImGuiFreeTypeAllocatorUserData = user_data; } +bool ImGuiFreeType::DebugEditFontBuilderFlags(unsigned int* p_font_loader_flags) +{ + bool edited = false; + edited |= ImGui::CheckboxFlags("NoHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_NoHinting); + edited |= ImGui::CheckboxFlags("NoAutoHint", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_NoAutoHint); + edited |= ImGui::CheckboxFlags("ForceAutoHint",p_font_loader_flags, ImGuiFreeTypeBuilderFlags_ForceAutoHint); + edited |= ImGui::CheckboxFlags("LightHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_LightHinting); + edited |= ImGui::CheckboxFlags("MonoHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_MonoHinting); + edited |= ImGui::CheckboxFlags("Bold", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Bold); + edited |= ImGui::CheckboxFlags("Oblique", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Oblique); + edited |= ImGui::CheckboxFlags("Monochrome", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Monochrome); + edited |= ImGui::CheckboxFlags("LoadColor", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_LoadColor); + edited |= ImGui::CheckboxFlags("Bitmap", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Bitmap); + return edited; +} + #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG // For more details, see https://gitlab.freedesktop.org/freetype/freetype-demos/-/blob/master/src/rsvg-port.c // The original code from the demo is licensed under CeCILL-C Free Software License Agreement (https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/LICENSE.TXT) diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 2d7b3a34fd38..b4e9ba1fdf70 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -49,6 +49,9 @@ namespace ImGuiFreeType // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired. IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr); + // Display UI to edit FontBuilderFlags in ImFontAtlas (shared) or ImFontConfig (single source) + IMGUI_API bool DebugEditFontBuilderFlags(unsigned int* p_font_loader_flags); + // Obsolete names (will be removed soon) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS //static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE' From 735d31e54a481e4ca6c90630ee6eb338999364d5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 6 Mar 2025 20:50:00 +0100 Subject: [PATCH 513/716] Demo: Exposed some basic UI in demo for sanity. --- imgui_demo.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 894012903c68..43c3cf9db235 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -430,6 +430,17 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); + ImGui::SeparatorText("dynamic_fonts branch"); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 5); + ImGui::DragFloat("io.FontGlobalScale", &ImGui::GetIO().FontGlobalScale, 0.05f, 0.5f, 5.0f); + ImGui::BulletText("This is scaling font only. General scaling will come later."); + ImGui::BulletText("Load an actual font that's not the default for best result!"); + ImGui::BulletText("See 'Widgets->Fonts' below for more.."); + ImGui::BulletText("Current font loader: '%s'", ImGui::GetIO().Fonts->FontLoaderName); + ImGui::BulletText("Please submit feedback:"); ImGui::SameLine(); + ImGui::TextLinkOpenURL("https://github.com/ocornut/imgui/issues/8465"); + ImGui::Spacing(); + IMGUI_DEMO_MARKER("Help"); if (ImGui::CollapsingHeader("Help")) { From 8ea0ae454f1fe427c4968b9b562d66c0f40a6ca4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 9 Mar 2025 21:36:44 +0100 Subject: [PATCH 514/716] Fonts: fixed a bug using size specified by secondary font sources. --- imgui_draw.cpp | 2 ++ misc/freetype/imgui_freetype.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c7418cfca6a5..52aeeee9d0d4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4460,6 +4460,8 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else bd_font_data->ScaleFactor = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); + if (src > src->DstFont->Sources) + bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0].SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit return true; } diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index edd6bdd1441d..7264fc2637d6 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -432,7 +432,7 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { IM_UNUSED(atlas); - const float size = baked->Size; + const float size = baked->Size * (src->SizePixels / baked->ContainerFont->Sources[0].SizePixels); // FIXME-NEWATLAS: Should tidy up that a bit ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; bd_font_data->BakedLastActivated = baked; From 52a6863771df71a0a1031512eea8f1b37b9311f1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 10 Mar 2025 10:55:29 +0100 Subject: [PATCH 515/716] Textures: ImTextureData pixels are not immediately destroyed on setting ImTextureStatus_WantDestroy. --- imgui_draw.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 52aeeee9d0d4..df4429d9fb89 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2780,9 +2780,9 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy) { // Request destroy. Keep bool as it allows us to keep track of things. + // We don't destroy pixels right away, as backend may have an in-flight copy from RAM. IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); tex->Status = ImTextureStatus_WantDestroy; - tex->DestroyPixels(); } // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering. @@ -2794,9 +2794,10 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) remove_from_list = true; - // Remove + // Destroy and remove if (remove_from_list) { + tex->DestroyPixels(); IM_DELETE(tex); atlas->TexList.erase(atlas->TexList.begin() + tex_n); tex_n--; From 144f444217576121f1b16dba18a20e715ad01cf0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Mar 2025 11:46:18 +0100 Subject: [PATCH 516/716] Fonts: fixed memory leaks, shutting down font loader, and on AddFont() failure in FreeType backend. --- imgui.h | 3 +-- imgui_draw.cpp | 14 ++++++++------ misc/freetype/imgui_freetype.cpp | 4 ++++ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index 550af74ba76e..cdb27e7e9945 100644 --- a/imgui.h +++ b/imgui.h @@ -3711,7 +3711,7 @@ struct ImFont IMGUI_API ImFontBaked* GetFontBaked(float font_size); // Get or create baked data for given size IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return Sources ? Sources->Name : ""; } + const char* GetDebugName() const { return Sources ? Sources[0].Name : ""; } // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. @@ -3720,7 +3720,6 @@ struct ImFont IMGUI_API const char* CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); - #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(Sources[0].SizePixels * scale, text, text_end, wrap_width); } #endif diff --git a/imgui_draw.cpp b/imgui_draw.cpp index df4429d9fb89..88f623c8b7a5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3034,7 +3034,10 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) new_font_cfg.GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1)); } if (font_cfg->FontLoader != NULL) + { IM_ASSERT(font_cfg->FontLoader->FontBakedLoadGlyph != NULL); + IM_ASSERT(font_cfg->FontLoader->LoaderInit == NULL && font_cfg->FontLoader->LoaderShutdown == NULL); // FIXME-NEWATLAS: Unsupported yet. + } IM_ASSERT(font_cfg->FontLoaderData == NULL); // Round font size @@ -3369,11 +3372,6 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); - if (atlas->FontLoader && atlas->FontLoader->LoaderShutdown) - { - atlas->FontLoader->LoaderShutdown(atlas); - IM_ASSERT(atlas->FontLoaderData == NULL); - } atlas->FontLoader = font_loader; atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL"; if (atlas->FontLoader && atlas->FontLoader->LoaderInit) @@ -4187,7 +4185,11 @@ void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) if (loader && loader->FontSrcDestroy != NULL) loader->FontSrcDestroy(atlas, &font_cfg); } - + if (atlas->FontLoader && atlas->FontLoader->LoaderShutdown) + { + atlas->FontLoader->LoaderShutdown(atlas); + IM_ASSERT(atlas->FontLoaderData == NULL); + } IM_DELETE(atlas->Builder); atlas->Builder = NULL; } diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 7264fc2637d6..72140f9522a0 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -416,7 +416,11 @@ bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) src->FontLoaderData = bd_font_data; if (!bd_font_data->InitFont(bd->Library, src, atlas->FontBuilderFlags)) + { + IM_DELETE(bd_font_data); + src->FontLoaderData = NULL; return false; + } return true; } From 7ac1bff482b6c982df4cc4a9a2e1b1503c6cfa88 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 11 Mar 2025 19:54:33 +0100 Subject: [PATCH 517/716] Fonts: fixed an issue calling legacy ImFontAtlas::Clear(). --- imgui_draw.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 88f623c8b7a5..f6cf1f4a689a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2637,8 +2637,6 @@ void ImFontAtlas::Clear() RendererHasTextures = false; // Full Clear() is supported, but ClearTexData() only isn't. ClearFonts(); ClearTexData(); - if (Builder != NULL) - ImFontAtlasBuildClearTexture(this); RendererHasTextures = backup_renderer_has_textures; } @@ -3374,8 +3372,6 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon atlas->FontLoader = font_loader; atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL"; - if (atlas->FontLoader && atlas->FontLoader->LoaderInit) - atlas->FontLoader->LoaderInit(atlas); ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); ImFontAtlasBuildInit(atlas); @@ -4140,8 +4136,12 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) return; // ImFontAtlasBuildSetupFontLoader() automatically call ImFontAtlasBuildInit() } + IM_ASSERT(atlas->FontLoaderData == NULL); + if (atlas->FontLoader && atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); + // Create initial texture size - if (atlas->TexData == NULL) + if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL) ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); ImFontAtlasBuilder* builder = atlas->Builder; // Do not move above From e76cfe5aad93e52b00302f3a9182c64336ab7169 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 16:30:20 +0100 Subject: [PATCH 518/716] Fonts: fixed implicit init when calling AddCustomRectRegular(). LoaderShutdown match BuildDestroy. --- imgui_draw.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f6cf1f4a689a..873e77508109 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3231,6 +3231,9 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); + if (Builder == NULL) + ImFontAtlasBuildInit(this); + ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id < 0) return -1; @@ -4185,7 +4188,7 @@ void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) if (loader && loader->FontSrcDestroy != NULL) loader->FontSrcDestroy(atlas, &font_cfg); } - if (atlas->FontLoader && atlas->FontLoader->LoaderShutdown) + if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { atlas->FontLoader->LoaderShutdown(atlas); IM_ASSERT(atlas->FontLoaderData == NULL); From b12c42e75db8deeb56dff989f90bd7413f5d39b9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 16:50:19 +0100 Subject: [PATCH 519/716] Fonts: change uses of ImFontAtlasRect to ImTextureRect for simplicity. --- imgui.cpp | 2 +- imgui_draw.cpp | 40 ++++++++++++++------------------ imgui_internal.h | 12 +++------- misc/freetype/imgui_freetype.cpp | 2 +- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1d1ad86507ec..ef3abcb46a04 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16699,7 +16699,7 @@ void ImGui::DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph) Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1); if (glyph->PackId >= 0) { - ImFontAtlasRect* r = ImFontAtlasPackGetRect(font->ContainerAtlas, glyph->PackId); + ImTextureRect* r = ImFontAtlasPackGetRect(font->ContainerAtlas, glyph->PackId); Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y); } } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 873e77508109..cea3bc07a6f3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3237,7 +3237,7 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id < 0) return -1; - ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); + ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); return r_id; @@ -3271,7 +3271,7 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id < 0) return -1; - ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); + ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); @@ -3295,11 +3295,7 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx) { - IM_STATIC_ASSERT(offsetof(ImTextureRect, x) == offsetof(ImFontAtlasRect, x)); - IM_STATIC_ASSERT(offsetof(ImTextureRect, y) == offsetof(ImFontAtlasRect, y)); - IM_STATIC_ASSERT(offsetof(ImTextureRect, w) == offsetof(ImFontAtlasRect, w)); - IM_STATIC_ASSERT(offsetof(ImTextureRect, h) == offsetof(ImFontAtlasRect, h)); - return (ImTextureRect*)(void*)ImFontAtlasPackGetRect(this, idx); + return ImFontAtlasPackGetRect(this, idx); } void ImFontAtlas::CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const @@ -3316,7 +3312,7 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) return false; - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, atlas->Builder->PackIdMouseCursors); ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->x, (float)r->y); ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1]; *out_size = size; @@ -3453,7 +3449,7 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); if (builder->PackIdMouseCursors < 0) return; - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); // Draw to texture if (add_and_draw) @@ -3489,7 +3485,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); if (builder->PackIdLinesTexData < 0) return; - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); // Register texture region for thick lines // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row @@ -3599,12 +3595,12 @@ static ImFontGlyph* ImFontAtlasBuildSetupFontBakedEllipsis(ImFontAtlas* atlas, I if (dot_glyph == NULL) return NULL; ImFontAtlasRectId dot_r_id = dot_glyph->PackId; // Deep copy to avoid invalidation of glyphs and rect pointers - ImFontAtlasRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); + ImTextureRect* dot_r = ImFontAtlasPackGetRect(atlas, dot_r_id); const int dot_spacing = 1; const float dot_step = (dot_glyph->X1 - dot_glyph->X0) + dot_spacing; ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, (dot_r->w * 3 + dot_spacing * 2), dot_r->h); - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); ImFontGlyph glyph_in = {}; ImFontGlyph* glyph = &glyph_in; @@ -3961,7 +3957,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) // FIXME-NEWATLAS-V2: Repacking in batch would be beneficial to packing heuristic, and fix stability. // FIXME-NEWATLAS-TESTS: Test calling RepackTexture with size too small to fits existing rects. ImFontAtlasPackInit(atlas); - ImVector old_rects; + ImVector old_rects; ImVector old_index = builder->RectsIndex; old_rects.swap(builder->Rects); @@ -3969,7 +3965,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) { if (index_entry.Used == false) continue; - ImFontAtlasRect& old_r = old_rects[index_entry.TargetIndex]; + ImTextureRect& old_r = old_rects[index_entry.TargetIndex]; if (old_r.w == 0 && old_r.h == 0) continue; ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, &index_entry); @@ -3986,7 +3982,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) return; } IM_ASSERT(new_r_id == builder->RectsIndex.index_from_ptr(&index_entry)); - ImFontAtlasRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id); + ImTextureRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id); ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h); } IM_ASSERT(old_rects.Size == builder->Rects.Size + builder->RectsDiscardedCount); @@ -3998,7 +3994,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs) if (glyph.PackId != -1) { - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); glyph.U0 = (r->x) * atlas->TexUvScale.x; glyph.V0 = (r->y) * atlas->TexUvScale.y; glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; @@ -4244,7 +4240,7 @@ void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; IM_ASSERT(index_entry->Used && index_entry->TargetIndex >= 0); - ImFontAtlasRect* rect = ImFontAtlasPackGetRect(atlas, id); + ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id); index_entry->Used = false; index_entry->TargetIndex = builder->RectsIndexFreeListStart; @@ -4268,7 +4264,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon builder->MaxRectSize.y = ImMax(builder->MaxRectSize.y, h); // Pack - ImFontAtlasRect r = { 0, 0, (unsigned short)w, (unsigned short)h }; + ImTextureRect r = { 0, 0, (unsigned short)w, (unsigned short)h }; for (int attempts_remaining = 3; attempts_remaining >= 0; attempts_remaining--) { // Try packing @@ -4312,7 +4308,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon } // Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. -ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) +ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { IM_ASSERT(id >= 0); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; @@ -4551,7 +4547,7 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); return NULL; } - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); // Render stbtt_GetGlyphBitmapBox(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, &x0, &y0, &x1, &y1); @@ -4999,7 +4995,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked // Set UV from packed rectangle if (in_glyph->PackId >= 0) { - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, in_glyph->PackId); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, in_glyph->PackId); IM_ASSERT(in_glyph->U0 == 0.0f && in_glyph->V0 == 0.0f && in_glyph->U1 == 0.0f && in_glyph->V1 == 0.0f); glyph.U0 = (r->x) * atlas->TexUvScale.x; glyph.V0 = (r->y) * atlas->TexUvScale.y; @@ -5042,7 +5038,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked } // Copy to texture, post-process and queue update for backend -void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImFontAtlasRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch) +void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch) { ImTextureData* tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); diff --git a/imgui_internal.h b/imgui_internal.h index c92aea66678e..940473abe273 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -143,7 +143,6 @@ struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawListSharedData; // Data shared between all ImDrawList instances struct ImFontAtlasBuilder; // Internal storage for incrementally packing and building a ImFontAtlas struct ImFontAtlasPostProcessData; // Data available to potential texture post-processing functions -struct ImFontAtlasRect; // Packed rectangle (same as ImTextureRect) struct ImFontAtlasRectEntry; // Packed rectangle lookup entry // ImGui @@ -3692,11 +3691,6 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -struct ImFontAtlasRect -{ - unsigned short x, y; - unsigned short w, h; -}; typedef int ImFontAtlasRectId; // <0 when invalid // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) @@ -3734,7 +3728,7 @@ struct ImFontAtlasBuilder { stbrp_context_opaque PackContext; // Actually 'stbrp_context' but we don't want to define this in the header file. ImVector PackNodes; - ImVector Rects; + ImVector Rects; ImVector RectsIndex; // ImFontAtlasRectId -> index into Rects[] ImVector TempBuffer; // Misc scratch buffer int RectsIndexFreeListStart;// First unused entry @@ -3791,12 +3785,12 @@ IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* a IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); -IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImFontAtlasRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); +IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); -IMGUI_API ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); +IMGUI_API ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 72140f9522a0..5151a90d5991 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -534,7 +534,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); return NULL; } - ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); // Render pixels to our temporary buffer atlas->Builder->TempBuffer.resize(w * h * 4); From 85d050758024d04bf8f3911bafce4bee433cf0c0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 16:54:39 +0100 Subject: [PATCH 520/716] Fonts: narrowed invalid value for ImFontAtlasRectId to -1 a we will change implementation. --- imgui.h | 2 +- imgui_draw.cpp | 22 +++++++++++----------- imgui_internal.h | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/imgui.h b/imgui.h index cdb27e7e9945..c3e568cfee9a 100644 --- a/imgui.h +++ b/imgui.h @@ -3577,7 +3577,7 @@ struct ImFontAtlas // You can request arbitrary rectangles to be packed into the atlas, for your own purpose. // You can request your rectangles to be mapped as font glyph (given a font + Unicode point), // so you can render e.g. custom colorful icons and use them as regular glyphs. - // - Since 1.92.X, packing is done immediately in the function call. Returns >= on success, <0 on error. + // - Since 1.92.X, packing is done immediately in the function call. Returns -1 on error. // - You can render your pixels into the texture right after calling the AddCustomRectXXX() functions. // - If your backend supports ImGuiBackendFlags_RendererHasTextures: // Texture may be resized, so you cannot cache UV coordinates: always use CalcCustomRectUV(). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index cea3bc07a6f3..92c6b0655059 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3235,7 +3235,7 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) ImFontAtlasBuildInit(this); ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); - if (r_id < 0) + if (r_id == -1) return -1; ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) @@ -3269,7 +3269,7 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im ImFontBaked* baked = font->GetFontBaked(font_size); ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); - if (r_id < 0) + if (r_id == -1) return -1; ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) @@ -3447,7 +3447,7 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ if (add_and_draw) builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); - if (builder->PackIdMouseCursors < 0) + if (builder->PackIdMouseCursors == -1) return; ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); @@ -3483,7 +3483,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ ImFontAtlasBuilder* builder = atlas->Builder; if (add_and_draw) builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); - if (builder->PackIdLinesTexData < 0) + if (builder->PackIdLinesTexData == -1) return; ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); @@ -3705,7 +3705,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) { - if (glyph->PackId >= 0) + if (glyph->PackId != -1) { ImFontAtlasPackDiscardRect(atlas, glyph->PackId); glyph->PackId = -1; @@ -3780,7 +3780,7 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); for (ImFontGlyph& glyph : baked->Glyphs) - if (glyph.PackId >= 0) + if (glyph.PackId != -1) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); char* loader_data_p = (char*)baked->FontLoaderDatas; @@ -4235,7 +4235,7 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r // This is expected to be called in batches and followed by a repack void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { - IM_ASSERT(id >= 0); + IM_ASSERT(id != -1); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; IM_ASSERT(index_entry->Used && index_entry->TargetIndex >= 0); @@ -4310,7 +4310,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon // Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { - IM_ASSERT(id >= 0); + IM_ASSERT(id != -1); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; IM_ASSERT(index_entry->Used); @@ -4541,10 +4541,10 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, const int w = (x1 - x0 + oversample_h - 1); const int h = (y1 - y0 + oversample_v - 1); ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); - if (pack_id < 0) + if (pack_id == -1) { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) - IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); + IM_ASSERT_USER_ERROR(pack_id != -1, "Out of texture memory."); return NULL; } ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); @@ -4993,7 +4993,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. // Set UV from packed rectangle - if (in_glyph->PackId >= 0) + if (in_glyph->PackId != -1) { ImTextureRect* r = ImFontAtlasPackGetRect(atlas, in_glyph->PackId); IM_ASSERT(in_glyph->U0 == 0.0f && in_glyph->V0 == 0.0f && in_glyph->U1 == 0.0f && in_glyph->V1 == 0.0f); diff --git a/imgui_internal.h b/imgui_internal.h index 940473abe273..6d13087f49d2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3691,7 +3691,7 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -typedef int ImFontAtlasRectId; // <0 when invalid +typedef int ImFontAtlasRectId; // -1 when invalid // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) // User are returned ImFontAtlasRectId values which are meant to be persistent. From f816b861fc506d2d438868d4bc0667cd65ab8ae8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 17:10:52 +0100 Subject: [PATCH 521/716] (Breaking) Fonts: rename GetCustomRectByIndex() to GetCustomRect(). Made return struct const. --- docs/FONTS.md | 7 ++----- imgui.h | 28 ++++++++++++++-------------- imgui_draw.cpp | 6 +++--- imgui_internal.h | 4 +++- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index 9b783dcdc178..452499059403 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -357,7 +357,7 @@ You can ask questions in [#8466](https://github.com/ocornut/imgui/issues/8466). As an alternative to rendering colorful glyphs using imgui_freetype with `ImGuiFreeTypeBuilderFlags_LoadColor`, you may allocate your own space in the texture atlas and write yourself into it. **(This is a BETA api, use if you are familiar with dear imgui and with your rendering backend)** - You can use the `ImFontAtlas::AddCustomRect()` and `ImFontAtlas::AddCustomRectFontGlyph()` api to register rectangles that will be packed into the font atlas texture. Register them before building the atlas, then call Build()`. -- You can then use `ImFontAtlas::GetCustomRectByIndex(int)` to query the position/size of your rectangle within the texture, and blit/copy any graphics data of your choice into those rectangles. +- You can then use `ImFontAtlas::GetCustomRect(int)` to query the position/size of your rectangle within the texture, and blit/copy any graphics data of your choice into those rectangles. - This API is beta because it is likely to change in order to support multi-dpi (multiple viewports on multiple monitors with varying DPI scale). #### Pseudo-code: @@ -377,9 +377,7 @@ int tex_width, tex_height; io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_width, &tex_height); for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++) -{ - int rect_id = rect_ids[rect_n]; - if (const ImFontAtlasCustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) + if (const ImTextureRect* rect = io.Fonts->GetCustomRect(rect_ids[rect_n])) { // Fill the custom rectangle with red pixels (in reality you would draw/copy your bitmap data here!) for (int y = 0; y < rect->Height; y++) @@ -389,7 +387,6 @@ for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++) *p++ = IM_COL32(255, 0, 0, 255); } } -} ``` ##### [Return to Index](#index) diff --git a/imgui.h b/imgui.h index c3e568cfee9a..2a781b7659b1 100644 --- a/imgui.h +++ b/imgui.h @@ -3574,24 +3574,24 @@ struct ImFontAtlas // [ALPHA] Custom Rectangles/Glyphs API //------------------------------------------- - // You can request arbitrary rectangles to be packed into the atlas, for your own purpose. - // You can request your rectangles to be mapped as font glyph (given a font + Unicode point), - // so you can render e.g. custom colorful icons and use them as regular glyphs. - // - Since 1.92.X, packing is done immediately in the function call. Returns -1 on error. + // Register and retrieve custom rectangles + // - You can request arbitrary rectangles to be packed into the atlas, for your own purpose. + // - You can request your rectangles to be mapped as font glyph (given a font + Unicode point), + // so you can render e.g. custom colorful icons and use them as regular glyphs. + // - Since 1.92.X, packing is done immediately in the function call. // - You can render your pixels into the texture right after calling the AddCustomRectXXX() functions. - // - If your backend supports ImGuiBackendFlags_RendererHasTextures: - // Texture may be resized, so you cannot cache UV coordinates: always use CalcCustomRectUV(). - // - If you render colored output into your AddCustomRectRegular() rectangle: set 'atlas->TexPixelsUseColors = true' - // as this may help some backends decide of preferred texture format. + // - Texture may be resized, so you cannot cache UV coordinates: always use CalcCustomRectUV()! + // - If you render colored output into your AddCustomRectRegular() rectangle: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. - // - Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. - IMGUI_API int AddCustomRectRegular(int width, int height); + // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI settings. + IMGUI_API int AddCustomRectRegular(int width, int height); // Register a rectangle. Return -1 on error. + IMGUI_API const ImTextureRect* GetCustomRect(int id); // Get rectangle coordinate in current texture. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); - IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); + inline const ImTextureRect* GetCustomRectByIndex(int id) { return GetCustomRect(id); } #endif - IMGUI_API ImTextureRect* GetCustomRectByIndex(int index); - IMGUI_API void CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; + IMGUI_API void CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; //------------------------------------------- // Members diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 92c6b0655059..c83d5b94af5d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2500,7 +2500,7 @@ void ImTextureData::DestroyPixels() //----------------------------------------------------------------------------- // - ImFontAtlas::AddCustomRectRegular() // - ImFontAtlas::AddCustomRectFontGlyph() -// - ImFontAtlas::GetCustomRectByIndex() +// - ImFontAtlas::GetCustomRect() // - ImFontAtlas::CalcCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- @@ -3293,9 +3293,9 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -ImTextureRect* ImFontAtlas::GetCustomRectByIndex(int idx) +const ImTextureRect* ImFontAtlas::GetCustomRect(int id) { - return ImFontAtlasPackGetRect(this, idx); + return ImFontAtlasPackGetRect(this, (ImFontAtlasRectId)id); } void ImFontAtlas::CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const diff --git a/imgui_internal.h b/imgui_internal.h index 6d13087f49d2..045064363635 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3691,7 +3691,9 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -typedef int ImFontAtlasRectId; // -1 when invalid +// An identifier to a rectangle in the atlas. -1 when invalid. +// The rectangle may move, use GetCustomRect() to retrieve it. +typedef int ImFontAtlasRectId; // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) // User are returned ImFontAtlasRectId values which are meant to be persistent. From 4048494aa1dfb61858ca96247542b1e4b8b2e958 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 17:28:13 +0100 Subject: [PATCH 522/716] Fonts: rename ImFontAtlasBuildClearTexture() to ImFontAtlasBuildClear(). --- imgui.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ef3abcb46a04..5e51dfa55be4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15714,7 +15714,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) ImFontAtlasBuildGrowTexture(atlas); SameLine(); if (Button("Clear Output")) - ImFontAtlasBuildClearTexture(atlas); + ImFontAtlasBuildClear(atlas); for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c83d5b94af5d..20151496ef4e 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4091,7 +4091,7 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) } // Clear all output. Invalidates all AddCustomRectXXX return values. -void ImFontAtlasBuildClearTexture(ImFontAtlas* atlas) +void ImFontAtlasBuildClear(ImFontAtlas* atlas) { ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); diff --git a/imgui_internal.h b/imgui_internal.h index 045064363635..dfd11f6dc19d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3762,11 +3762,11 @@ IMGUI_API void ImFontAtlasBuildMain(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* font_loader); IMGUI_API void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char); +IMGUI_API void ImFontAtlasBuildClear(ImFontAtlas* atlas); // Clear output and custom rects IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); IMGUI_API void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); -IMGUI_API void ImFontAtlasBuildClearTexture(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); From 41517bca0c42e7fa5ab3207c528a988f0bc556b1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 13 Mar 2025 19:14:10 +0100 Subject: [PATCH 523/716] (Breaking) Fonts: renamed CalcCustomRectUV() to GetCustomRectUV() for simplicity. --- imgui.h | 27 ++++++++++++++++----------- imgui_draw.cpp | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/imgui.h b/imgui.h index 2a781b7659b1..44f48c263894 100644 --- a/imgui.h +++ b/imgui.h @@ -3580,18 +3580,17 @@ struct ImFontAtlas // so you can render e.g. custom colorful icons and use them as regular glyphs. // - Since 1.92.X, packing is done immediately in the function call. // - You can render your pixels into the texture right after calling the AddCustomRectXXX() functions. - // - Texture may be resized, so you cannot cache UV coordinates: always use CalcCustomRectUV()! + // - Texture may be resized, so you cannot cache UV coordinates: always use GetCustomRectUV()! // - If you render colored output into your AddCustomRectRegular() rectangle: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI settings. + // - Pre-1.92 names: + // - AddCustomRectFontGlyph() --> Use custom ImFontLoader inside ImFontConfig + // - GetCustomRectByIndex() --> Use GetCustomRect() + // - CalcCustomRectUV() --> Use GetCustomRectUV() IMGUI_API int AddCustomRectRegular(int width, int height); // Register a rectangle. Return -1 on error. IMGUI_API const ImTextureRect* GetCustomRect(int id); // Get rectangle coordinate in current texture. -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); - IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); - inline const ImTextureRect* GetCustomRectByIndex(int id) { return GetCustomRect(id); } -#endif - IMGUI_API void CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const; + IMGUI_API void GetCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const; // Get UV coordinates for a given rectangle //------------------------------------------- // Members @@ -3633,10 +3632,16 @@ struct ImFontAtlas int RefCount; // Number of contexts using this atlas // [Obsolete] - //int TexDesiredWidth; // OBSOLETED in 1.92.X (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) - //typedef ImTextureRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X - //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ - //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig + IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X + inline const ImTextureRect* GetCustomRectByIndex(int id) { return GetCustomRect(id); } // OBSOLETED in 1.92.X + inline void CalcCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const { return GetCustomRectUV(r, out_uv_min, out_uv_max); } // OBSOLETED in 1.92.X +#endif + //int TexDesiredWidth; // OBSOLETED in 1.92.X (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) + //typedef ImTextureRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X + //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ + //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; // Font runtime data for a given size diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 20151496ef4e..3207c92c7435 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3298,7 +3298,7 @@ const ImTextureRect* ImFontAtlas::GetCustomRect(int id) return ImFontAtlasPackGetRect(this, (ImFontAtlasRectId)id); } -void ImFontAtlas::CalcCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +void ImFontAtlas::GetCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const { IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates *out_uv_min = ImVec2((float)rect->x * TexUvScale.x, (float)rect->y * TexUvScale.y); From cc65015e4e1ecd7fffb4e8838bb2d9da2b9deecd Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 17:18:05 +0100 Subject: [PATCH 524/716] Fonts: fixed crashing password fields. # Conflicts: # imgui_internal.h --- imgui.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 4 +++- imgui_widgets.cpp | 44 +++++++++++++++++++++++++------------------- 4 files changed, 30 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5e51dfa55be4..f65cd777c92b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4086,6 +4086,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) MouseCursor = ImGuiMouseCursor_Arrow; MouseStationaryTimer = 0.0f; + InputTextPasswordFontBackupFlags = ImFontFlags_None; TempInputId = 0; memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue)); BeginMenuDepth = BeginComboDepth = 0; @@ -4284,7 +4285,6 @@ void ImGui::Shutdown() g.MenusIdSubmittedThisFrame.clear(); g.InputTextState.ClearFreeMemory(); g.InputTextDeactivatedState.ClearFreeMemory(); - g.InputTextPasswordFont.ContainerAtlas = NULL; g.SettingsWindows.clear(); g.SettingsHandlers.clear(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3207c92c7435..fa15be25ec04 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4136,7 +4136,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) } IM_ASSERT(atlas->FontLoaderData == NULL); - if (atlas->FontLoader && atlas->FontLoader->LoaderInit) + if (atlas->FontLoader->LoaderInit) atlas->FontLoader->LoaderInit(atlas); // Create initial texture size diff --git a/imgui_internal.h b/imgui_internal.h index dfd11f6dc19d..83a16aa9d3d7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2391,7 +2391,8 @@ struct ImGuiContext // Widget state ImGuiInputTextState InputTextState; ImGuiInputTextDeactivatedState InputTextDeactivatedState; - ImFont InputTextPasswordFont; + ImFontBaked InputTextPasswordFontBackupBaked; + ImFontFlags InputTextPasswordFontBackupFlags; ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiDataTypeStorage DataTypeZeroValue; // 0 for all data types int BeginMenuDepth; @@ -3112,6 +3113,7 @@ namespace ImGui IMGUI_API void UpdateCurrentFontSize(); inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } IMGUI_API void PushPasswordFont(); + IMGUI_API void PopPasswordFont(); inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents. IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 6a86c79560a6..91d50933f2a2 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4314,23 +4314,29 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons void ImGui::PushPasswordFont() { ImGuiContext& g = *GImGui; - ImFont* in_font = g.Font; - ImFontBaked* in_baked = g.FontBaked; - ImFontGlyph glyph = *in_baked->FindGlyph('*'); - glyph.PackId = -1; - ImFont* out_font = &g.InputTextPasswordFont; - out_font->Scale = in_font->Scale; - out_font->ContainerAtlas = in_font->ContainerAtlas; - out_font->Flags |= ImFontFlags_NoLoadGlyphs; - ImFontBaked* out_baked = out_font->GetFontBaked(in_baked->Size); - IM_ASSERT(out_baked->Glyphs.Size <= 1 && out_baked->IndexAdvanceX.Size == 0 && out_baked->IndexLookup.Size == 0); - out_baked->Ascent = in_baked->Ascent; - out_baked->Descent = in_baked->Descent; - out_baked->Glyphs.resize(0); - out_baked->Glyphs.push_back(glyph); - out_baked->FallbackGlyphIndex = 0; - out_baked->FallbackAdvanceX = glyph.AdvanceX; - PushFont(out_font); + ImFontBaked* backup = &g.InputTextPasswordFontBackupBaked; + IM_ASSERT(backup->IndexAdvanceX.Size == 0 && backup->IndexLookup.Size == 0); + ImFontGlyph* glyph = g.FontBaked->FindGlyph('*'); + g.InputTextPasswordFontBackupFlags = g.Font->Flags; + backup->FallbackGlyphIndex = g.FontBaked->FallbackGlyphIndex; + backup->FallbackAdvanceX = g.FontBaked->FallbackAdvanceX; + backup->IndexLookup.swap(g.FontBaked->IndexLookup); + backup->IndexAdvanceX.swap(g.FontBaked->IndexAdvanceX); + g.Font->Flags |= ImFontFlags_NoLoadGlyphs; + g.FontBaked->FallbackGlyphIndex = g.FontBaked->Glyphs.index_from_ptr(glyph); + g.FontBaked->FallbackAdvanceX = glyph->AdvanceX; +} + +void ImGui::PopPasswordFont() +{ + ImGuiContext& g = *GImGui; + ImFontBaked* backup = &g.InputTextPasswordFontBackupBaked; + g.Font->Flags = g.InputTextPasswordFontBackupFlags; + g.FontBaked->FallbackGlyphIndex = backup->FallbackGlyphIndex; + g.FontBaked->FallbackAdvanceX = backup->FallbackAdvanceX; + g.FontBaked->IndexLookup.swap(backup->IndexLookup); + g.FontBaked->IndexAdvanceX.swap(backup->IndexAdvanceX); + IM_ASSERT(backup->IndexAdvanceX.Size == 0 && backup->IndexLookup.Size == 0); } // Return false to discard a character. @@ -5232,7 +5238,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (new_is_displaying_hint != is_displaying_hint) { if (is_password && !is_displaying_hint) - PopFont(); + PopPasswordFont(); is_displaying_hint = new_is_displaying_hint; if (is_password && !is_displaying_hint) PushPasswordFont(); @@ -5423,7 +5429,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } if (is_password && !is_displaying_hint) - PopFont(); + PopPasswordFont(); if (is_multiline) { From 8bd1fc4f04b8e2ae62ebdd76de128b2929b16fa0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 17 Mar 2025 22:08:58 +0100 Subject: [PATCH 525/716] Textures: Added ImTextureRef::GetTexID() mostly for consistency. Without it the logic may seem more confusing to grok for end-user. --- imgui.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 44f48c263894..14396377ec12 100644 --- a/imgui.h +++ b/imgui.h @@ -343,6 +343,7 @@ struct ImTextureRef ImTextureRef(void* tex_id) { memset(this, 0, sizeof(*this)); _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID //inline operator intptr_t() const { return (intptr_t)_TexID; } // For legacy backends casting to ImTextureID #endif + inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. // Members ImTextureData* _TexData; // Texture, generally owned by a ImFontAtlas @@ -3072,7 +3073,7 @@ struct ImDrawCmd // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) // Since 1.92: removed ImDrawCmd::TextureId field, the getter function must be used! // If for some reason you non C++ tech stack makes it difficult to call it, we may decide to separate the fields in ImDrawCmd. - inline ImTextureID GetTexID() const; + inline ImTextureID GetTexID() const; // == (TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID }; // Vertex layout @@ -3735,7 +3736,12 @@ struct ImFont IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; -// Added indirection to avoid patching ImDrawCmd after texture updates. +// We added an indirection to avoid patching ImDrawCmd after texture updates but this could be a solution too. +inline ImTextureID ImTextureRef::GetTexID() const +{ + return _TexData ? _TexData->TexID : _TexID; +} + inline ImTextureID ImDrawCmd::GetTexID() const { // If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92) From e41bf16ff155f0626c32d7b2ea158a1880847fda Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 18 Mar 2025 18:03:40 +0100 Subject: [PATCH 526/716] Fonts: fixed ImTextureID() being zero-cleared instead of using ImTextureUserID_Invalid. . --- imgui.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index 14396377ec12..ba9c16b22641 100644 --- a/imgui.h +++ b/imgui.h @@ -337,11 +337,11 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or IM_MSVC_RUNTIME_CHECKS_OFF struct ImTextureRef { - ImTextureRef() { memset(this, 0, sizeof(*this)); } - ImTextureRef(ImTextureID tex_id) { memset(this, 0, sizeof(*this)); _TexID = tex_id; } -#if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(ImTextureUserID) - ImTextureRef(void* tex_id) { memset(this, 0, sizeof(*this)); _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID - //inline operator intptr_t() const { return (intptr_t)_TexID; } // For legacy backends casting to ImTextureID + ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; } + ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; } +#if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(ImTextureID) + ImTextureRef(void* tex_id) { _TexData = NULL; _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID + //inline operator intptr_t() const { return (intptr_t)_TexID; } // For legacy backends casting to ImTextureID #endif inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. From 0fff7ceda450994b221df7538ea9d934b17a5611 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 14:06:08 +0100 Subject: [PATCH 527/716] Fonts: comments, tweaks, minor amends. Comments, tweaks --- imgui.cpp | 2 +- imgui.h | 88 +++++++++++++++++++++++++++++++------------------- imgui_demo.cpp | 18 +++++++---- 3 files changed, 67 insertions(+), 41 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f65cd777c92b..0e5a4c775c19 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16552,7 +16552,7 @@ void ImGui::DebugNodeFont(ImFont* font) ImGuiContext& g = *GImGui; ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; ImFontAtlas* atlas = font->ContainerAtlas; - bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->Sources ? font->Sources[0].Name : "", font->SourcesCount); + bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->GetDebugName(), font->SourcesCount); // Display preview text if (!opened) diff --git a/imgui.h b/imgui.h index ba9c16b22641..f8e5b6c5560f 100644 --- a/imgui.h +++ b/imgui.h @@ -311,29 +311,44 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // [SECTION] Texture identifiers (ImTextureID, ImTextureRef) //----------------------------------------------------------------------------- -// ImTextureID: user data for renderer backend to identify a texture [Compile-time configurable type] +// ImTextureID = backend specific, low-level identifier for a texture uploaded in GPU/graphics system. +// [Compile-time configurable type] // Overview: -// - Backend and user/app code provides ImTextureID values that gets stored inside draw commands (ImDrawCmd) during the ImGui frame. -// - Backend uses ImDrawCmd::GetTexID() to retrieve the ImTextureID value during rendering. Then, they can bind the textures of each draw command. +// - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value. +// (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint'; +// Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). +// - User may submit their own textures to e.g. ImGui::Image() function by passing the same type. +// - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside +// ImTextureRef, which is stored inside ImDrawCmd. // Configuring the type: -// - To use something else than a 64-bit value: override with e.g. '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file. // - This can be whatever to you want it to be! read the FAQ entry about textures for details. -// - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various constructors if you like. You will need to implement ==/!= operators. +// - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various +// constructors if you like. You will need to implement ==/!= operators. // History: // - In v1.91.4 (2024/10/08): the default type for ImTextureID was changed from 'void*' to 'ImU64'. This allowed backends requirig 64-bit worth of data to build on 32-bit architectures. Use intermediary intptr_t cast and read FAQ if you have casting warnings. +// - In v1.92.0 (2025/XX/XX): added ImTextureRef which carry either a ImTextureID either a pointer to internal texture atlas. All user facing functions taking ImTextureID changed to ImTextureRef #ifndef ImTextureID typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. #endif -// Define this to another value if you need value of 0 to be valid. +// Define this if you need 0 to be a valid ImTextureID for your backend. #ifndef ImTextureID_Invalid #define ImTextureID_Invalid ((ImTextureID)0) #endif -// ImTextureRef contains: -// - a texture/atlas pointer, typically when created by Dear ImGui itself. -// - OR a raw ImTextureID value (user/backend identifier), typically when created by user code to load images. -// There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this to be useful to the end-user. +// ImTextureRef = higher-level identifier for a texture. +// The identifier is valid even before the texture has been uploaded to the GPU/graphics system. +// This is what gets passed to functions such as ImGui::Image(), ImDrawList::AddImage(). +// This is what gets stored in draw commands (ImDrawCmd) to identify a texture during rendering. +// - When a texture is created by user code (e.g. custom images), we directly stores the low-level ImTextureID. +// - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection +// to extract the ImTextureID value during rendering, after texture upload has happened. +// - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this +// to be useful to the end-user, and it would be erroneously called by many legacy code. +// - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. +// - Binding generators for languages such as C (which don't have constructors), should provide a helper: +// inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } IM_MSVC_RUNTIME_CHECKS_OFF struct ImTextureRef { @@ -341,13 +356,12 @@ struct ImTextureRef ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; } #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(ImTextureID) ImTextureRef(void* tex_id) { _TexData = NULL; _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID - //inline operator intptr_t() const { return (intptr_t)_TexID; } // For legacy backends casting to ImTextureID #endif inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. - // Members - ImTextureData* _TexData; // Texture, generally owned by a ImFontAtlas - ImTextureID _TexID; // _OR_ Underlying texture identifier for backend, if already uploaded (otherwise pulled from _TexData) + // Members (either are set, never both!) + ImTextureData* _TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded. + ImTextureID _TexID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui::Image() calls. }; IM_MSVC_RUNTIME_CHECKS_RESTORE @@ -604,7 +618,7 @@ namespace ImGui IMGUI_API bool TextLinkOpenURL(const char* label, const char* url = NULL); // hyperlink text button, automatically open file/url when clicked // Widgets: Images - // - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + // - Read about ImTextureID/ImTextureRef here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples // - 'uv0' and 'uv1' are texture coordinates. Read about them from the same link above. // - Image() pads adds style.ImageBorderSize on each side, ImageButton() adds style.FramePadding on each side. // - ImageButton() draws a background based on regular Button() color + optionally an inner background if specified. @@ -2817,7 +2831,8 @@ static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return IM_MSVC_RUNTIME_CHECKS_RESTORE #endif -// Helpers: ImTexture ==/!= operators provided as convenience (not strictly necessary) +// Helpers: ImTextureRef ==/!= operators provided as convenience +// (note that _TexID and _TexData are never set simultaneously) static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } //#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // For legacy backends @@ -3072,7 +3087,6 @@ struct ImDrawCmd // Since 1.83: returns ImTextureID associated with this draw call. Warning: DO NOT assume this is always same as 'TextureId' (we will change this function for an upcoming feature) // Since 1.92: removed ImDrawCmd::TextureId field, the getter function must be used! - // If for some reason you non C++ tech stack makes it difficult to call it, we may decide to separate the fields in ImDrawCmd. inline ImTextureID GetTexID() const; // == (TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID }; @@ -3295,8 +3309,8 @@ struct ImDrawList // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - //IMGUI_API void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.x - //IMGUI_API void PopTextureID() { PopTexture(); } // RENAMED in 1.92.x + IMGUI_API void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.x + IMGUI_API void PopTextureID() { PopTexture(); } // RENAMED in 1.92.x #endif //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) //inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) @@ -3344,7 +3358,11 @@ struct ImDrawData }; //----------------------------------------------------------------------------- -// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData +// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData) +//----------------------------------------------------------------------------- +// In principle, the only data types that user/application code should care about are 'ImTextureRef' and 'ImTextureID'. +// They are defined above in this header file. Read their description to the difference between ImTextureRef and ImTextureID. +// FOR ALL OTHER ImTextureXXXX TYPES: ONLY CORE LIBRARY AND RENDERER BACKENDS NEED TO KNOW AND CARE ABOUT THEM. //----------------------------------------------------------------------------- // We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. @@ -3355,7 +3373,7 @@ enum ImTextureFormat ImTextureFormat_Alpha8, // 1 component per pixel, each is unsigned 8-bit. Total size = TexWidth * TexHeight }; -// Status of a texture +// Status of a texture to communicate with Renderer Backend. enum ImTextureStatus { ImTextureStatus_OK, @@ -3366,7 +3384,7 @@ enum ImTextureStatus }; // Coordinates of a rectangle within a texture. -// When a texture is in ImTextureStatus_WantUpdates state, we provide a list of individual rectangles to copy to GPU texture. +// When a texture is in ImTextureStatus_WantUpdates state, we provide a list of individual rectangles to copy to the graphics system. // You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box. struct ImTextureRect { @@ -3375,7 +3393,8 @@ struct ImTextureRect }; // Specs and pixel storage for a texture used by Dear ImGui. -// The renderer backend will generally create a GPU-side version of this. +// This is only useful for (1) core library and (2) backends. End-user/applications do not need to care about this. +// Renderer Backends will create a GPU-side version of this. // Why does we store two identifiers: TexID and BackendUserData? // - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. // - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. @@ -3407,7 +3426,7 @@ struct IMGUI_API ImTextureData unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } int GetPitch() const { return Width * BytesPerPixel; } - ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = TexID; return tex_ref; } + ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = TexID; return tex_ref; } // FIXME-TEXREF ImTextureID GetTexID() const { return TexID; } // Called by Renderer backend @@ -3502,7 +3521,7 @@ enum ImFontAtlasFlags_ // It is the rendering backend responsibility to upload texture into your graphics API: // - ImGui_ImplXXXX_RenderDrawData() functions generally iterate platform_io->Textures[] to create/update/destroy each ImTextureData instance. // - Backend then set ImTextureData's TexID and BackendUserData. -// - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details. +// - Texture id are passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID/ImTextureRef for more details. // Legacy path: // - Call Build() + GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data. // - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API. @@ -3554,7 +3573,7 @@ struct ImFontAtlas // Glyph Ranges //------------------------------------------- - // Since 1.92: specifying glyph ranges is only useful/necessary if your backend doesn't support ImGuiBackendFlags_HasTextures! + // Since 1.92: specifying glyph ranges is only useful/necessary if your backend doesn't support ImGuiBackendFlags_RendererHasTextures! IMGUI_API const ImWchar* GetGlyphRangesDefault(); // Basic Latin, Extended Latin #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list) @@ -3607,9 +3626,14 @@ struct ImFontAtlas int TexMaxHeight; // Maximum desired texture height. Must be a power of two. Default to 8192. void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). + // Output + ImTextureRef TexRef; // Current texture identifier == TexData->GetTexRef(). +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImTextureRef& TexID = TexRef; // RENAMED in 1.92.x +#endif + ImTextureData* TexData; // Current texture. + // [Internal] - ImTextureRef TexRef; // User data to refer to the latest texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure. - ImTextureData* TexData; // Current texture ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! bool Locked; // Marked as locked during ImGui::NewFrame()..EndFrame() scope if TexUpdates are not supported. Any attempt to modify the atlas will assert. bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. @@ -3622,10 +3646,8 @@ struct ImFontAtlas ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID int FontNextUniqueID; // Next value to be stored in ImFont->SourceID - ImVector DrawListSharedDatas; - - // [Internal] Font builder - ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public + ImVector DrawListSharedDatas; // List of users for this atlas. Typically one per Dear ImGui context. + ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public and may be discarded when rebuilding. const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name void* FontLoaderData; // Font backend opaque storage @@ -3717,7 +3739,7 @@ struct ImFont IMGUI_API ImFontBaked* GetFontBaked(float font_size); // Get or create baked data for given size IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return Sources ? Sources[0].Name : ""; } + const char* GetDebugName() const { return Sources ? Sources[0].Name : ""; } // Fill ImFontConfig::Name. // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 43c3cf9db235..dda817eb8924 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1777,13 +1777,12 @@ static void DemoWindowWidgetsImages() "Hover the texture for a zoomed view!"); // Below we are displaying the font texture because it is the only texture we have access to inside the demo! - // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that - // will be passed to the rendering backend via the ImDrawCmd structure. + // Read description about ImTextureID/ImTextureRef and FAQ for details about texture identifiers. // If you use one of the default imgui_impl_XXXX.cpp rendering backend, they all have comments at the top - // of their respective source file to specify what they expect to be stored in ImTextureID, for example: - // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer + // of their respective source file to specify what they are using as texture identifier, for example: + // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc. - // More: + // So with the DirectX11 backend, you call ImGui::Image() with a 'ID3D11ShaderResourceView*' cast to ImTextureID. // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers // to ImGui::Image(), and gather width/height through your own functions, etc. // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer, @@ -1791,14 +1790,19 @@ static void DemoWindowWidgetsImages() // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage(). // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples + + // Grab the current texture identifier used by the font atlas. ImTextureRef my_tex_id = io.Fonts->TexRef; + + // Regular user code should never have to care about TexData-> fields, but since we want to display the entire texture here, we pull Width/Height from it. float my_tex_w = (float)io.Fonts->TexData->Width; float my_tex_h = (float)io.Fonts->TexData->Height; + { ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h); ImVec2 pos = ImGui::GetCursorScreenPos(); - ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left - ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right + ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left + ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right ImGui::PushStyleVar(ImGuiStyleVar_ImageBorderSize, IM_MAX(1.0f, ImGui::GetStyle().ImageBorderSize)); ImGui::ImageWithBg(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); if (ImGui::BeginItemTooltip()) From a548cd9934e4064b9eb4c7565973499fc5357fa0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 15:00:13 +0100 Subject: [PATCH 528/716] Fonts: avoid both ImTextureRef fields being set simultaneously. --- imgui.h | 5 +++-- imgui_draw.cpp | 6 ++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/imgui.h b/imgui.h index f8e5b6c5560f..320f4f1c1b1e 100644 --- a/imgui.h +++ b/imgui.h @@ -3426,7 +3426,7 @@ struct IMGUI_API ImTextureData unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } int GetPitch() const { return Width * BytesPerPixel; } - ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = TexID; return tex_ref; } // FIXME-TEXREF + ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = ImTextureID_Invalid; return tex_ref; } ImTextureID GetTexID() const { return TexID; } // Called by Renderer backend @@ -3761,6 +3761,7 @@ struct ImFont // We added an indirection to avoid patching ImDrawCmd after texture updates but this could be a solution too. inline ImTextureID ImTextureRef::GetTexID() const { + IM_ASSERT(!(_TexData != NULL && _TexID != ImTextureID_Invalid)); return _TexData ? _TexData->TexID : _TexID; } @@ -3768,7 +3769,7 @@ inline ImTextureID ImDrawCmd::GetTexID() const { // If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92) // must iterate and handle ImTextureData requests stored in ImDrawData::Textures[]. - ImTextureID tex_id = TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID; + ImTextureID tex_id = TexRef._TexData ? TexRef._TexData->TexID : TexRef._TexID; // == TexRef.GetTexID() above. if (TexRef._TexData != NULL) IM_ASSERT(tex_id != ImTextureID_Invalid && "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!"); return tex_id; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index fa15be25ec04..8ecc2ecdb6dc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2615,7 +2615,6 @@ ImFontAtlas::ImFontAtlas() TexMaxWidth = 8192; TexMaxHeight = 8192; RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update. - TexRef._TexData = NULL;// this; TexNextUniqueID = 1; FontNextUniqueID = 1; Builder = NULL; @@ -3882,9 +3881,8 @@ static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex) atlas->TexData = tex; atlas->TexUvScale = ImVec2(1.0f / tex->Width, 1.0f / tex->Height); atlas->TexRef._TexData = tex; - //atlas->TexID._TexID = tex->TexID; // <-- We intentionally don't do that and leave it 0, to allow late upload. - ImTextureRef new_tex_ref = atlas->TexRef; - ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, new_tex_ref); + //atlas->TexRef._TexID = tex->TexID; // <-- We intentionally don't do that. It would be misleading and betray promise that both fields aren't set. + ImFontAtlasUpdateDrawListsTextures(atlas, old_tex_ref, atlas->TexRef); } // Create a new texture, discard previous one From cb4c03756a825516f66ddd6e981ef284ab6a20ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 19:57:03 +0100 Subject: [PATCH 529/716] Fonts: detect if backend assign to texture on creation but doesn't update Status. --- imgui_draw.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8ecc2ecdb6dc..991b45f8d865 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2765,10 +2765,12 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) tex->UpdateRect.x = tex->UpdateRect.y = (unsigned short)~0; tex->UpdateRect.w = tex->UpdateRect.h = 0; } + if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures) + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK."); if (tex->Status == ImTextureStatus_Destroyed) { - IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!"); if (tex->WantDestroyNextFrame) remove_from_list = true; // Destroy was scheduled by us else From 5460903f9674b9ed8fb31802f44032ca1cdff7aa Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 19 Mar 2025 20:12:02 +0100 Subject: [PATCH 530/716] Fonts: awkwardly alias old TexID name to TexRef using an union (may backtrack and just keep old name) --- imgui.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 320f4f1c1b1e..a04ac423a3b8 100644 --- a/imgui.h +++ b/imgui.h @@ -3627,9 +3627,10 @@ struct ImFontAtlas void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // Output - ImTextureRef TexRef; // Current texture identifier == TexData->GetTexRef(). #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - ImTextureRef& TexID = TexRef; // RENAMED in 1.92.x + union { ImTextureRef TexRef; ImTextureRef TexID; }; // Current texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.x +#else + ImTextureRef TexRef; // Current texture identifier == TexData->GetTexRef(). #endif ImTextureData* TexData; // Current texture. From 2de15dc64bd3e6a3d4fc1746721b97b2cf6ef11b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Mar 2025 15:44:35 +0100 Subject: [PATCH 531/716] Fonts: fixed legacy backend path preloading all sources sizes erroneously + failing to use ellipsis. --- imgui_draw.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 991b45f8d865..e23431584a58 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3383,16 +3383,22 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) { atlas->Builder->PreloadedAllGlyphsRanges = true; for (ImFont* font : atlas->Fonts) + { + ImFontConfig* src = &font->Sources[0]; + ImFontBaked* baked = font->GetFontBaked(src->SizePixels); + if (font->FallbackChar != 0) + baked->FindGlyph(font->FallbackChar); + if (font->EllipsisChar != 0) + baked->FindGlyph(font->EllipsisChar); for (int src_n = 0; src_n < font->SourcesCount; src_n++) { - ImFontConfig* src = &font->Sources[src_n]; - ImFontBaked* baked = font->GetFontBaked(src->SizePixels); + src = &font->Sources[src_n]; const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); - IM_ASSERT(ranges != NULL); for (; ranges[0]; ranges += 2) for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 baked->FindGlyph((ImWchar)c); } + } } void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) From 168b97c2912e7261bd26af09619cc1a60bc05954 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 20 Mar 2025 15:45:27 +0100 Subject: [PATCH 532/716] Fonts: removed size rounding in AddFont() which breaks relative sizing of merged fonts (8502) # Conflicts: # imgui.cpp --- imgui.cpp | 7 ++++++- imgui_draw.cpp | 12 ++++++------ imgui_internal.h | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0e5a4c775c19..334ace32c829 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8628,7 +8628,12 @@ void ImGui::UpdateCurrentFontSize() final_size *= g.Font->Scale; if (ImGuiWindow* window = g.CurrentWindow) final_size *= window->FontWindowScale; - final_size = ImMax(1.0f, IM_ROUND(final_size)); + + // Round font size + // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. + // - We may support it better later and remove this rounding. + final_size = GetRoundedFontSize(final_size); + final_size = ImMax(1.0f, final_size); g.FontSize = final_size; g.FontBaked = (g.Font != NULL) ? g.Font->GetFontBaked(g.FontSize) : NULL; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e23431584a58..db95fd14d510 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3024,6 +3024,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) } // Sanity check + // We don't round cfg.SizePixels yet as relative size of merged fonts are used afterwards. if (font_cfg->GlyphExcludeRanges != NULL) { int size = 0; @@ -3039,12 +3040,6 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) } IM_ASSERT(font_cfg->FontLoaderData == NULL); - // Round font size - // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. - // - Note that using io.FontGlobalScale or SetWindowFontScale(), with are legacy-ish, partially supported features, can still lead to unrounded sizes. - // - We may support it better later and remove this rounding. - new_font_cfg.SizePixels = ImTrunc(new_font_cfg.SizePixels); - // Pointers to Sources are otherwise dangling ImFontAtlasBuildUpdatePointers(this); if (!ImFontAtlasBuildAddFont(this, &new_font_cfg)) @@ -5164,6 +5159,11 @@ ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) ImFontBaked* ImFont::GetFontBaked(float size) { ImFontBaked* baked = LastBaked; + + // Round font size + // - ImGui::PushFontSize() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges) + size = ImGui::GetRoundedFontSize(size); + if (baked && baked->Size == size) return baked; diff --git a/imgui_internal.h b/imgui_internal.h index 83a16aa9d3d7..6c46fde5ca98 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3111,6 +3111,7 @@ namespace ImGui // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font, float font_size); IMGUI_API void UpdateCurrentFontSize(); + inline float GetRoundedFontSize(float size) { return IM_ROUND(size); } inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } IMGUI_API void PushPasswordFont(); IMGUI_API void PopPasswordFont(); From 44498825cd9a5bf8c3f2e7c5b4bb439b537fb91e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 21 Mar 2025 19:13:23 +0100 Subject: [PATCH 533/716] (Breaking) Fonts: PushFont() default to preserve current font size. --- imgui.cpp | 11 ++++++++--- imgui.h | 12 +++++++++--- imgui_draw.cpp | 3 ++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 334ace32c829..20ebdc56a3fb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8582,7 +8582,7 @@ void ImGui::UpdateFontsNewFrame() atlas->Locked = true; // We do this really unusual thing of calling *push_front()*, the reason behind that we want to support the PushFont()/NewFrame()/PopFont() idiom. - ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->Sources[0].SizePixels }; + ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->DefaultSize }; g.FontStack.push_front(font_stack_data); if (g.FontStack.Size == 1) ImGui::SetCurrentFont(font_stack_data.Font, font_stack_data.FontSize); @@ -8647,8 +8647,13 @@ void ImGui::PushFont(ImFont* font, float font_size) ImGuiContext& g = *GImGui; if (font == NULL) font = GetDefaultFont(); - if (font_size < 0.0f) - font_size = font->Sources[0].SizePixels; // g.FontSize; + if (font_size <= 0.0f) + { + if (font->Flags & ImFontFlags_UseDefaultSize) + font_size = font->DefaultSize; // Legacy: use default font size. Same as doing PushFont(font, font->DefaultSize). // FIXME-NEWATLAS + else + font_size = g.FontSizeBeforeScaling; // Keep current font size + } g.FontStack.push_back({ font, font_size }); SetCurrentFont(font, font_size); } diff --git a/imgui.h b/imgui.h index a04ac423a3b8..5e1737a5d229 100644 --- a/imgui.h +++ b/imgui.h @@ -491,9 +491,13 @@ namespace ImGui IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. // Parameters stacks (font) - IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. + // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. + // - Before 1.92: PushFont() always used font default size. + // - Since 1.92: PushFont() preserve the current shared font size. + // - To use old behavior: use 'PushFont(font, font->DefaultSize)' in call site, or set 'ImFontConfig::Flags |= ImFontFlags_UseDefaultSize' before calling AddFont(). + IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. Use font->DefaultSize to revert to font default size. IMGUI_API void PopFont(); - IMGUI_API void PushFontSize(float size); + IMGUI_API void PushFontSize(float font_size); IMGUI_API void PopFontSize(); // Parameters stacks (shared) @@ -3709,6 +3713,7 @@ enum ImFontFlags_ ImFontFlags_LockBakedSizes = 1 << 0, // Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. ImFontFlags_NoLoadGlyphs = 1 << 1, // Disable loading new glyphs. ImFontFlags_NoLoadError = 1 << 2, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. + ImFontFlags_UseDefaultSize = 1 << 3, // Legacy compatibility: make PushFont() calls without explicit size use font->DefaultSize instead of current font size. }; // Font runtime data and rendering @@ -3726,6 +3731,7 @@ struct ImFont // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. ImGuiID FontId; // Unique identifier for the font + float DefaultSize; // 4 // in // Default font size short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). @@ -3750,7 +3756,7 @@ struct ImFont IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(Sources[0].SizePixels * scale, text, text_end, wrap_width); } + inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(DefaultSize * scale, text, text_end, wrap_width); } #endif // [Internal] Don't use! diff --git a/imgui_draw.cpp b/imgui_draw.cpp index db95fd14d510..4a7bff240a0d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3005,6 +3005,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) font = IM_NEW(ImFont)(); font->FontId = FontNextUniqueID++; font->Flags = font_cfg->Flags; + font->DefaultSize = font_cfg->SizePixels; Fonts.push_back(font); } else @@ -3248,7 +3249,7 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height) // myfont->Flags |= ImFontFlags_LockBakedSizes; int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { - float font_size = font->Sources[0].SizePixels; + float font_size = font->DefaultSize; return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset); } // FIXME: we automatically set glyph.Colored=true by default. From 9324961cd28bb2690a6f9867ba098c771750769c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 26 Mar 2025 14:38:49 +0100 Subject: [PATCH 534/716] Fonts: fixed calling AddFontXXX not invalidating texture for legacy backends. --- imgui_draw.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4a7bff240a0d..8535c32c2830 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3580,6 +3580,7 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) if (!loader->FontSrcInit(atlas, src)) return false; + atlas->TexIsBuilt = false; // For legacy backends ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); return true; } From fc870811333e4d6d2d8f0e78e26247762020d5f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 22 Mar 2025 15:15:10 +0100 Subject: [PATCH 535/716] Fonts: fixed GetCustomRectUV(). Fixing typo. Broken by fe598f7 --- imgui_draw.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8535c32c2830..fe639e99ba4c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2501,7 +2501,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::AddCustomRectRegular() // - ImFontAtlas::AddCustomRectFontGlyph() // - ImFontAtlas::GetCustomRect() -// - ImFontAtlas::CalcCustomRectUV() +// - ImFontAtlas::GetCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- // - ImFontAtlasBuildMain() @@ -3298,8 +3298,10 @@ const ImTextureRect* ImFontAtlas::GetCustomRect(int id) void ImFontAtlas::GetCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const { IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates - *out_uv_min = ImVec2((float)rect->x * TexUvScale.x, (float)rect->y * TexUvScale.y); - *out_uv_max = ImVec2((float)(rect->x + rect->w) * TexUvScale.x, (float)(rect->y + rect->w) * TexUvScale.y); + ImVec2 pos = ImVec2((float)rect->x, (float)rect->y); + ImVec2 size = ImVec2((float)rect->w, (float)rect->h); + *out_uv_min = (pos) * TexUvScale; + *out_uv_max = (pos + size) * TexUvScale; } bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) From 253dff76565b10491ccc2205706b033bb7f209af Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 30 Mar 2025 16:00:29 +0200 Subject: [PATCH 536/716] Fonts: Comments. --- imgui.h | 41 +++++++++++++++++++++++------------------ imgui_internal.h | 2 +- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/imgui.h b/imgui.h index 5e1737a5d229..ae488a177ed2 100644 --- a/imgui.h +++ b/imgui.h @@ -3484,9 +3484,9 @@ struct ImFontGlyph unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. unsigned int Codepoint : 30; // 0x0000..0x10FFFF - float AdvanceX; // Horizontal distance to advance layout with - float X0, Y0, X1, Y1; // Glyph corners - float U0, V0, U1, V1; // Texture coordinates + float AdvanceX; // Horizontal distance to advance cursor/layout position. + float X0, Y0, X1, Y1; // Glyph corners. Offsets from current cursor/layout position. + float U0, V0, U1, V1; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRectUV() with PackId. int PackId; // [Internal] ImFontAtlasRectId value (FIXME: Cold data, could be moved elsewhere?) ImFontGlyph() { memset(this, 0, sizeof(*this)); PackId = -1; } @@ -3600,21 +3600,23 @@ struct ImFontAtlas // Register and retrieve custom rectangles // - You can request arbitrary rectangles to be packed into the atlas, for your own purpose. - // - You can request your rectangles to be mapped as font glyph (given a font + Unicode point), - // so you can render e.g. custom colorful icons and use them as regular glyphs. - // - Since 1.92.X, packing is done immediately in the function call. - // - You can render your pixels into the texture right after calling the AddCustomRectXXX() functions. + // - Since 1.92.X, packing is done immediately in the function call (previously packing was done during the Build call) + // - You can render your pixels into the texture right after calling the AddCustomRect() functions. // - Texture may be resized, so you cannot cache UV coordinates: always use GetCustomRectUV()! - // - If you render colored output into your AddCustomRectRegular() rectangle: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. + // VERY IMPORTANT: + // - RECTANGLE DATA AND UV COORDINATES MAY BE INVALIDATED BY *ANY* CALL TO IMGUI FUNCTIONS (e.g. ImGui::Text call) OR BY atlas->AddCustomRectegular(). NEVER CACHE THOSE!!! + // - RECTANGLE DATA AND UV COORDINATES ARE ASSOCIATED TO THE CURRENT TEXTURE IDENTIFIER AKA 'atlas->TexRef'. Both are typically invalidated at the same time. + // - If you render colored output into your AddCustomRect() rectangle: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI settings. - // - Pre-1.92 names: - // - AddCustomRectFontGlyph() --> Use custom ImFontLoader inside ImFontConfig + // - (Pre-1.92 names) ------------> (1.92 names) // - GetCustomRectByIndex() --> Use GetCustomRect() // - CalcCustomRectUV() --> Use GetCustomRectUV() + // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig + // - ImFontAtlasCustomRect --> ImTextureRect IMGUI_API int AddCustomRectRegular(int width, int height); // Register a rectangle. Return -1 on error. - IMGUI_API const ImTextureRect* GetCustomRect(int id); // Get rectangle coordinate in current texture. - IMGUI_API void GetCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const; // Get UV coordinates for a given rectangle + IMGUI_API const ImTextureRect* GetCustomRect(int id); // Get rectangle coordinate in current texture. Valid immediately, never store this (read above)! + IMGUI_API void GetCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const; // Get UV coordinates for a given rectangle. Valid immediately, never store this (read above)! //------------------------------------------- // Members @@ -3631,12 +3633,14 @@ struct ImFontAtlas void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas). // Output -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - union { ImTextureRef TexRef; ImTextureRef TexID; }; // Current texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.x + // - Because textures are dynamically created/resized, the current texture identifier may changed at *ANY TIME* during the frame. + // - This should not affect you as you can always use the latest value. But note that any precomputed UV coordinates are only valid for the current TexRef. +#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImTextureRef TexRef; // Latest texture identifier == TexData->GetTexRef(). #else - ImTextureRef TexRef; // Current texture identifier == TexData->GetTexRef(). + union { ImTextureRef TexRef; ImTextureRef TexID; }; // Latest texture identifier == TexData->GetTexRef(). // RENAMED TexID to TexRef in 1.92.x #endif - ImTextureData* TexData; // Current texture. + ImTextureData* TexData; // Latest texture. // [Internal] ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead! @@ -3644,8 +3648,8 @@ struct ImFontAtlas bool RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context. bool TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. bool TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process. - ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight) - ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel + ImVec2 TexUvScale; // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight). May change as new texture gets created. + ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel. May change as new texture gets created. ImVector Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font. ImVector Sources; // Source/configuration data ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines @@ -3661,6 +3665,7 @@ struct ImFontAtlas // [Obsolete] #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + // Legacy: You can request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. --> Prefer using a custom ImFontLoader. IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X inline const ImTextureRect* GetCustomRectByIndex(int id) { return GetCustomRect(id); } // OBSOLETED in 1.92.X diff --git a/imgui_internal.h b/imgui_internal.h index 6c46fde5ca98..aa5da5777ed3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3695,7 +3695,7 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); //----------------------------------------------------------------------------- // An identifier to a rectangle in the atlas. -1 when invalid. -// The rectangle may move, use GetCustomRect() to retrieve it. +// The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it. typedef int ImFontAtlasRectId; // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) From f40274702dcf15985c257b6b32677bfe7bae1595 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 17:03:03 +0200 Subject: [PATCH 537/716] (Breaking) Fonts: renamed AddCustomRectRegular() -> AddCustomRect(). --- imgui.h | 4 +++- imgui_draw.cpp | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index ae488a177ed2..cbf353dd8e2d 100644 --- a/imgui.h +++ b/imgui.h @@ -3612,9 +3612,10 @@ struct ImFontAtlas // - (Pre-1.92 names) ------------> (1.92 names) // - GetCustomRectByIndex() --> Use GetCustomRect() // - CalcCustomRectUV() --> Use GetCustomRectUV() + // - AddCustomRectRegular() --> Renamed to AddCustomRect() // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig // - ImFontAtlasCustomRect --> ImTextureRect - IMGUI_API int AddCustomRectRegular(int width, int height); // Register a rectangle. Return -1 on error. + IMGUI_API int AddCustomRect(int width, int height); // Register a rectangle. Return -1 on error. IMGUI_API const ImTextureRect* GetCustomRect(int id); // Get rectangle coordinate in current texture. Valid immediately, never store this (read above)! IMGUI_API void GetCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const; // Get UV coordinates for a given rectangle. Valid immediately, never store this (read above)! @@ -3666,6 +3667,7 @@ struct ImFontAtlas // [Obsolete] #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy: You can request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. --> Prefer using a custom ImFontLoader. + IMGUI_API int AddCustomRectRegular(int width, int height) { return AddCustomRect(width, height); } // RENAMED in 1.92.X IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X inline const ImTextureRect* GetCustomRectByIndex(int id) { return GetCustomRect(id); } // OBSOLETED in 1.92.X diff --git a/imgui_draw.cpp b/imgui_draw.cpp index fe639e99ba4c..0a39cfabed2f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2498,7 +2498,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::RemoveFont() // - ImFontAtlasBuildNotifySetFont() //----------------------------------------------------------------------------- -// - ImFontAtlas::AddCustomRectRegular() +// - ImFontAtlas::AddCustomRect() // - ImFontAtlas::AddCustomRectFontGlyph() // - ImFontAtlas::GetCustomRect() // - ImFontAtlas::GetCustomRectUV() @@ -3223,7 +3223,7 @@ void ImFontAtlas::RemoveFont(ImFont* font) ImFontAtlasBuildNotifySetFont(this, font, new_current_font); } -int ImFontAtlas::AddCustomRectRegular(int width, int height) +int ImFontAtlas::AddCustomRect(int width, int height) { IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); From db30e1b5b6d55423a967fe6b6947bf6296f08786 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 17:36:24 +0200 Subject: [PATCH 538/716] (Breaking) Fonts: rework GetCustomRect() api. Reintroduce ImFontAtlasRect. --- imgui.h | 48 ++++++++++++++++++++++++++++++------------------ imgui_draw.cpp | 22 +++++++++++----------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/imgui.h b/imgui.h index cbf353dd8e2d..fbd9d5b6c442 100644 --- a/imgui.h +++ b/imgui.h @@ -172,6 +172,7 @@ struct ImDrawVert; // A single vertex (pos + uv + col = 20 byte 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 struct ImFontAtlasBuilder; // Opaque storage for building a ImFontAtlas +struct ImFontAtlasRect; // Output of ImFontAtlas::GetCustomRect() when using custom rectangles. struct ImFontBaked; // Baked data for a ImFont at a given size. struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) @@ -3486,7 +3487,7 @@ struct ImFontGlyph unsigned int Codepoint : 30; // 0x0000..0x10FFFF float AdvanceX; // Horizontal distance to advance cursor/layout position. float X0, Y0, X1, Y1; // Glyph corners. Offsets from current cursor/layout position. - float U0, V0, U1, V1; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRectUV() with PackId. + float U0, V0, U1, V1; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. int PackId; // [Internal] ImFontAtlasRectId value (FIXME: Cold data, could be moved elsewhere?) ImFontGlyph() { memset(this, 0, sizeof(*this)); PackId = -1; } @@ -3508,6 +3509,17 @@ struct ImFontGlyphRangesBuilder IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges }; +// Output of ImFontAtlas::GetCustomRect() when using custom rectangles. +// Those values may not be cached/stored as they are only valid for the current value of atlas->TexRef +struct ImFontAtlasRect +{ + unsigned short x, y; // Position (in current texture) + unsigned short w, h; // Size + ImVec2 uv0, uv1; // UV coordinates (in current texture) + + ImFontAtlasRect() { memset(this, 0, sizeof(*this)); } +}; + // Flags for ImFontAtlas build enum ImFontAtlasFlags_ { @@ -3602,22 +3614,21 @@ struct ImFontAtlas // - You can request arbitrary rectangles to be packed into the atlas, for your own purpose. // - Since 1.92.X, packing is done immediately in the function call (previously packing was done during the Build call) // - You can render your pixels into the texture right after calling the AddCustomRect() functions. - // - Texture may be resized, so you cannot cache UV coordinates: always use GetCustomRectUV()! - // VERY IMPORTANT: - // - RECTANGLE DATA AND UV COORDINATES MAY BE INVALIDATED BY *ANY* CALL TO IMGUI FUNCTIONS (e.g. ImGui::Text call) OR BY atlas->AddCustomRectegular(). NEVER CACHE THOSE!!! - // - RECTANGLE DATA AND UV COORDINATES ARE ASSOCIATED TO THE CURRENT TEXTURE IDENTIFIER AKA 'atlas->TexRef'. Both are typically invalidated at the same time. - // - If you render colored output into your AddCustomRect() rectangle: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. + // - VERY IMPORTANT: + // - Texture may be created/resized at any time when calling ImGui or ImFontAtlas functions. + // - IT WILL INVALIDATE RECTANGLE DATA SUCH AS UV COORDINATES. Always use latest values from GetCustomRect(). + // - UV coordinates are associated to the current texture identifier aka 'atlas->TexRef'. Both TexRef and UV coordinates are typically changed at the same time. + // - If you render colored output into your custom rectangles: set 'atlas->TexPixelsUseColors = true' as this may help some backends decide of preferred texture format. // - Read docs/FONTS.md for more details about using colorful icons. // - Note: this API may be reworked further in order to facilitate supporting e.g. multi-monitor, varying DPI settings. // - (Pre-1.92 names) ------------> (1.92 names) // - GetCustomRectByIndex() --> Use GetCustomRect() - // - CalcCustomRectUV() --> Use GetCustomRectUV() + // - CalcCustomRectUV() --> Use GetCustomRect() and read uv0, uv1 fields. // - AddCustomRectRegular() --> Renamed to AddCustomRect() // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig - // - ImFontAtlasCustomRect --> ImTextureRect - IMGUI_API int AddCustomRect(int width, int height); // Register a rectangle. Return -1 on error. - IMGUI_API const ImTextureRect* GetCustomRect(int id); // Get rectangle coordinate in current texture. Valid immediately, never store this (read above)! - IMGUI_API void GetCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const; // Get UV coordinates for a given rectangle. Valid immediately, never store this (read above)! + // - ImFontAtlasCustomRect --> Renamed to ImFontAtlasRect + IMGUI_API int AddCustomRect(int width, int height); // Register a rectangle. Return -1 on error. + IMGUI_API bool GetCustomRect(int id, ImFontAtlasRect* out_r) const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! //------------------------------------------- // Members @@ -3667,14 +3678,15 @@ struct ImFontAtlas // [Obsolete] #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy: You can request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. --> Prefer using a custom ImFontLoader. - IMGUI_API int AddCustomRectRegular(int width, int height) { return AddCustomRect(width, height); } // RENAMED in 1.92.X - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig - IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X - inline const ImTextureRect* GetCustomRectByIndex(int id) { return GetCustomRect(id); } // OBSOLETED in 1.92.X - inline void CalcCustomRectUV(const ImTextureRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const { return GetCustomRectUV(r, out_uv_min, out_uv_max); } // OBSOLETED in 1.92.X + ImFontAtlasRect TempRect; // For old GetCustomRectByIndex() API + inline int AddCustomRectRegular(int w, int h) { return AddCustomRect(w, h); } // RENAMED in 1.92.X + inline const ImFontAtlasRect* GetCustomRectByIndex(int id) { return GetCustomRect(id, &TempRect) ? &TempRect : NULL; } // OBSOLETED in 1.92.X + inline void CalcCustomRectUV(const ImFontAtlasRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const { *out_uv_min = r->uv0; *out_uv_max = r->uv1; } // OBSOLETED in 1.92.X + IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig + IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // ADDED AND OBSOLETED in 1.92.X #endif //int TexDesiredWidth; // OBSOLETED in 1.92.X (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) - //typedef ImTextureRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X + //typedef ImFontAtlasRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ }; @@ -3996,7 +4008,7 @@ namespace ImGui // - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h // - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() // We could make ImTextureRect an union to use old names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. -typedef ImTextureRect ImFontAtlasCustomRect; +typedef ImFontAtlasRect ImFontAtlasCustomRect; /*struct ImFontAtlasCustomRect { unsigned short X, Y; // Output // Packed position in Atlas diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0a39cfabed2f..f6849701c74f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2501,7 +2501,6 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::AddCustomRect() // - ImFontAtlas::AddCustomRectFontGlyph() // - ImFontAtlas::GetCustomRect() -// - ImFontAtlas::GetCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- // - ImFontAtlasBuildMain() @@ -3290,18 +3289,19 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -const ImTextureRect* ImFontAtlas::GetCustomRect(int id) -{ - return ImFontAtlasPackGetRect(this, (ImFontAtlasRectId)id); -} - -void ImFontAtlas::GetCustomRectUV(const ImTextureRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const +bool ImFontAtlas::GetCustomRect(int id, ImFontAtlasRect* out_r) const { + ImTextureRect* r = ImFontAtlasPackGetRect((ImFontAtlas*)this, (ImFontAtlasRectId)id); + if (r == NULL) + return false; IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates - ImVec2 pos = ImVec2((float)rect->x, (float)rect->y); - ImVec2 size = ImVec2((float)rect->w, (float)rect->h); - *out_uv_min = (pos) * TexUvScale; - *out_uv_max = (pos + size) * TexUvScale; + out_r->x = r->x; + out_r->y = r->y; + out_r->w = r->w; + out_r->h = r->h; + out_r->uv0 = ImVec2((float)(r->x), (float)(r->y)) * TexUvScale; + out_r->uv1 = ImVec2((float)(r->x + r->w), (float)(r->y + r->h)) * TexUvScale; + return true; } bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]) From 69d28f867cdc04e2ade221ea14304058fe4055d7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 18:36:32 +0200 Subject: [PATCH 539/716] Fonts: added ImFontAtlasRectId_Invalid == -1 --- imgui_draw.cpp | 34 +++++++++++++++++----------------- imgui_internal.h | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f6849701c74f..7556fc593e00 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3231,8 +3231,8 @@ int ImFontAtlas::AddCustomRect(int width, int height) ImFontAtlasBuildInit(this); ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); - if (r_id == -1) - return -1; + if (r_id == ImFontAtlasRectId_Invalid) + return ImFontAtlasRectId_Invalid; ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); @@ -3265,8 +3265,8 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im ImFontBaked* baked = font->GetFontBaked(font_size); ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); - if (r_id == -1) - return -1; + if (r_id == ImFontAtlasRectId_Invalid) + return ImFontAtlasRectId_Invalid; ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); if (RendererHasTextures) ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); @@ -3452,7 +3452,7 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ if (add_and_draw) builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); - if (builder->PackIdMouseCursors == -1) + if (builder->PackIdMouseCursors == ImFontAtlasRectId_Invalid) return; ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); @@ -3488,7 +3488,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ ImFontAtlasBuilder* builder = atlas->Builder; if (add_and_draw) builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); - if (builder->PackIdLinesTexData == -1) + if (builder->PackIdLinesTexData == ImFontAtlasRectId_Invalid) return; ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); @@ -3711,10 +3711,10 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) { - if (glyph->PackId != -1) + if (glyph->PackId != ImFontAtlasRectId_Invalid) { ImFontAtlasPackDiscardRect(atlas, glyph->PackId); - glyph->PackId = -1; + glyph->PackId = ImFontAtlasRectId_Invalid; } ImWchar c = (ImWchar)glyph->Codepoint; IM_ASSERT(font->FallbackChar != c && font->EllipsisChar != c); // Unsupported for simplicity @@ -3786,7 +3786,7 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); for (ImFontGlyph& glyph : baked->Glyphs) - if (glyph.PackId != -1) + if (glyph.PackId != ImFontAtlasRectId_Invalid) ImFontAtlasPackDiscardRect(atlas, glyph.PackId); char* loader_data_p = (char*)baked->FontLoaderDatas; @@ -3974,7 +3974,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) if (old_r.w == 0 && old_r.h == 0) continue; ImFontAtlasRectId new_r_id = ImFontAtlasPackAddRect(atlas, old_r.w, old_r.h, &index_entry); - if (new_r_id == -1) + if (new_r_id == ImFontAtlasRectId_Invalid) { // Undo, grow texture and try repacking again. // FIXME-NEWATLAS-TESTS: This is a very rarely exercised path! It needs to be automatically tested properly. @@ -3997,7 +3997,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) // Patch glyphs UV for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) for (ImFontGlyph& glyph : builder->BakedPool[baked_n].Glyphs) - if (glyph.PackId != -1) + if (glyph.PackId != ImFontAtlasRectId_Invalid) { ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); glyph.U0 = (r->x) * atlas->TexUvScale.x; @@ -4240,7 +4240,7 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r // This is expected to be called in batches and followed by a repack void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { - IM_ASSERT(id != -1); + IM_ASSERT(id != ImFontAtlasRectId_Invalid); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; IM_ASSERT(index_entry->Used && index_entry->TargetIndex >= 0); @@ -4286,7 +4286,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon if (attempts_remaining == 0 || builder->LockDisableResize) { IMGUI_DEBUG_LOG_FONT("[font] Failed packing %dx%d rectangle. Returning fallback.\n", w, h); - return -1; + return ImFontAtlasRectId_Invalid; } // Resize or repack atlas! (this should be a rare event) @@ -4315,7 +4315,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon // Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { - IM_ASSERT(id != -1); + IM_ASSERT(id != ImFontAtlasRectId_Invalid); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; IM_ASSERT(index_entry->Used); @@ -4546,10 +4546,10 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, const int w = (x1 - x0 + oversample_h - 1); const int h = (y1 - y0 + oversample_v - 1); ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); - if (pack_id == -1) + if (pack_id == ImFontAtlasRectId_Invalid) { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) - IM_ASSERT_USER_ERROR(pack_id != -1, "Out of texture memory."); + IM_ASSERT_USER_ERROR(pack_id != ImFontAtlasRectId_Invalid, "Out of texture memory."); return NULL; } ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); @@ -4998,7 +4998,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. // Set UV from packed rectangle - if (in_glyph->PackId != -1) + if (in_glyph->PackId != ImFontAtlasRectId_Invalid) { ImTextureRect* r = ImFontAtlasPackGetRect(atlas, in_glyph->PackId); IM_ASSERT(in_glyph->U0 == 0.0f && in_glyph->V0 == 0.0f && in_glyph->U1 == 0.0f && in_glyph->V1 == 0.0f); diff --git a/imgui_internal.h b/imgui_internal.h index aa5da5777ed3..a064a8dab7d2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3697,6 +3697,7 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // An identifier to a rectangle in the atlas. -1 when invalid. // The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it. typedef int ImFontAtlasRectId; +#define ImFontAtlasRectId_Invalid -1 // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) // User are returned ImFontAtlasRectId values which are meant to be persistent. From e9cf3de58ff7e53e82d08bfd2dc7615bcb8a002e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 18:37:11 +0200 Subject: [PATCH 540/716] Fonts: moved ImFontAtlasRectId back to public API. --- imgui.h | 18 ++++++++++++------ imgui_draw.cpp | 6 +++--- imgui_internal.h | 5 ----- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/imgui.h b/imgui.h index fbd9d5b6c442..ce5decfa4cdd 100644 --- a/imgui.h +++ b/imgui.h @@ -3509,8 +3509,14 @@ struct ImFontGlyphRangesBuilder IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges }; +// An identifier to a rectangle in the atlas. -1 when invalid. +// The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it. +typedef int ImFontAtlasRectId; +#define ImFontAtlasRectId_Invalid -1 + // Output of ImFontAtlas::GetCustomRect() when using custom rectangles. // Those values may not be cached/stored as they are only valid for the current value of atlas->TexRef +// (this is in theory derived from ImTextureRect but we use separate structures for reasons) struct ImFontAtlasRect { unsigned short x, y; // Position (in current texture) @@ -3627,8 +3633,8 @@ struct ImFontAtlas // - AddCustomRectRegular() --> Renamed to AddCustomRect() // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig // - ImFontAtlasCustomRect --> Renamed to ImFontAtlasRect - IMGUI_API int AddCustomRect(int width, int height); // Register a rectangle. Return -1 on error. - IMGUI_API bool GetCustomRect(int id, ImFontAtlasRect* out_r) const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! + IMGUI_API ImFontAtlasRectId AddCustomRect(int width, int height); // Register a rectangle. Return -1 (ImFontAtlasRectId_Invalid) on error. + IMGUI_API bool GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! //------------------------------------------- // Members @@ -3679,11 +3685,11 @@ struct ImFontAtlas #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // Legacy: You can request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs. --> Prefer using a custom ImFontLoader. ImFontAtlasRect TempRect; // For old GetCustomRectByIndex() API - inline int AddCustomRectRegular(int w, int h) { return AddCustomRect(w, h); } // RENAMED in 1.92.X - inline const ImFontAtlasRect* GetCustomRectByIndex(int id) { return GetCustomRect(id, &TempRect) ? &TempRect : NULL; } // OBSOLETED in 1.92.X + inline ImFontAtlasRectId AddCustomRectRegular(int w, int h) { return AddCustomRect(w, h); } // RENAMED in 1.92.X + inline const ImFontAtlasRect* GetCustomRectByIndex(ImFontAtlasRectId id) { return GetCustomRect(id, &TempRect) ? &TempRect : NULL; } // OBSOLETED in 1.92.X inline void CalcCustomRectUV(const ImFontAtlasRect* r, ImVec2* out_uv_min, ImVec2* out_uv_max) const { *out_uv_min = r->uv0; *out_uv_max = r->uv1; } // OBSOLETED in 1.92.X - IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig - IMGUI_API int AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // ADDED AND OBSOLETED in 1.92.X + IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig + IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // ADDED AND OBSOLETED in 1.92.X #endif //int TexDesiredWidth; // OBSOLETED in 1.92.X (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) //typedef ImFontAtlasRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7556fc593e00..83db3576b84b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3222,7 +3222,7 @@ void ImFontAtlas::RemoveFont(ImFont* font) ImFontAtlasBuildNotifySetFont(this, font, new_current_font); } -int ImFontAtlas::AddCustomRect(int width, int height) +ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height) { IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); @@ -3289,9 +3289,9 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImFontAtlas::GetCustomRect(int id, ImFontAtlasRect* out_r) const +bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const { - ImTextureRect* r = ImFontAtlasPackGetRect((ImFontAtlas*)this, (ImFontAtlasRectId)id); + ImTextureRect* r = ImFontAtlasPackGetRect((ImFontAtlas*)this, id); if (r == NULL) return false; IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates diff --git a/imgui_internal.h b/imgui_internal.h index a064a8dab7d2..7389c0216092 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3694,11 +3694,6 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -// An identifier to a rectangle in the atlas. -1 when invalid. -// The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it. -typedef int ImFontAtlasRectId; -#define ImFontAtlasRectId_Invalid -1 - // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) // User are returned ImFontAtlasRectId values which are meant to be persistent. // We handle this with an indirection. While Rects[] may be in theory shuffled, compacted etc., RectsIndex[] cannot it is keyed by ImFontAtlasRectId. From 23dc46c4f8bf6aaf83d70f54441916404bf1aba5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 19:24:59 +0200 Subject: [PATCH 541/716] Fonts: added RemoveCustomRect(). + internally add ImFontAtlasPackReuseRectEntry() --- imgui.h | 1 + imgui_draw.cpp | 29 +++++++++++++++++++---------- imgui_internal.h | 4 ++-- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/imgui.h b/imgui.h index ce5decfa4cdd..a3d70bb98e3f 100644 --- a/imgui.h +++ b/imgui.h @@ -3634,6 +3634,7 @@ struct ImFontAtlas // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig // - ImFontAtlasCustomRect --> Renamed to ImFontAtlasRect IMGUI_API ImFontAtlasRectId AddCustomRect(int width, int height); // Register a rectangle. Return -1 (ImFontAtlasRectId_Invalid) on error. + IMGUI_API void RemoveCustomRect(ImFontAtlasRectId id); // Unregister a rectangle. Existing pixels will stay in texture until resized / garbage collected. IMGUI_API bool GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! //------------------------------------------- diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 83db3576b84b..7cc1351fbc14 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2499,8 +2499,10 @@ void ImTextureData::DestroyPixels() // - ImFontAtlasBuildNotifySetFont() //----------------------------------------------------------------------------- // - ImFontAtlas::AddCustomRect() -// - ImFontAtlas::AddCustomRectFontGlyph() +// - ImFontAtlas::RemoveCustomRect() // - ImFontAtlas::GetCustomRect() +// - ImFontAtlas::AddCustomRectFontGlyph() [legacy] +// - ImFontAtlas::AddCustomRectFontGlyphForSize() [legacy] // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- // - ImFontAtlasBuildMain() @@ -2538,6 +2540,7 @@ void ImTextureData::DestroyPixels() //----------------------------------------------------------------------------- // - ImFontAtlasPackInit() // - ImFontAtlasPackAllocRectEntry() +// - ImFontAtlasPackReuseRectEntry() // - ImFontAtlasPackDiscardRect() // - ImFontAtlasPackAddRect() // - ImFontAtlasPackGetRect() @@ -3239,6 +3242,12 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height) return r_id; } +void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id) +{ + IM_ASSERT(id != ImFontAtlasRectId_Invalid); + ImFontAtlasPackDiscardRect(this, id); +} + #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // This API does not make sense anymore with scalable fonts. // - Prefer adding a font source (ImFontConfig) using a custom/procedural loader. @@ -4095,7 +4104,7 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) return ImVec2i(new_tex_w, new_tex_h); } -// Clear all output. Invalidates all AddCustomRectXXX return values. +// Clear all output. Invalidates all AddCustomRect() return values! void ImFontAtlasBuildClear(ImFontAtlas* atlas) { ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); @@ -4237,6 +4246,13 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r return (ImFontAtlasRectId)index_idx; } +static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFontAtlasRectEntry* overwrite_entry) +{ + IM_ASSERT(overwrite_entry->Used); + overwrite_entry->TargetIndex = atlas->Builder->Rects.Size - 1; + return atlas->Builder->RectsIndex.index_from_ptr(overwrite_entry); +} + // This is expected to be called in batches and followed by a repack void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { @@ -4300,16 +4316,9 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon builder->Rects.push_back(r); if (overwrite_entry != NULL) - { - // Write into an existing entry instead of adding one (used during repack) - IM_ASSERT(overwrite_entry->Used); - overwrite_entry->TargetIndex = builder->Rects.Size - 1; - return builder->RectsIndex.index_from_ptr(overwrite_entry); - } + return ImFontAtlasPackReuseRectEntry(atlas, overwrite_entry); // Write into an existing entry instead of adding one (used during repack) else - { return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1); - } } // Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. diff --git a/imgui_internal.h b/imgui_internal.h index 7389c0216092..0a9961a45eda 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3701,8 +3701,8 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // Having this also makes it easier to e.g. sort rectangles during repack. struct ImFontAtlasRectEntry { - int TargetIndex : 31; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list. - unsigned int Used : 1; + int TargetIndex : 31; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list. + unsigned int Used : 1; }; // Data available to potential texture post-processing functions From 074bf39e403fd4123b605bd8062624876381e59f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 21:43:15 +0200 Subject: [PATCH 542/716] Fonts: GC Compact All exposed in Metrics->Memory Allocations includes compacting texture data. --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 20ebdc56a3fb..00bb950fcbb6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4394,6 +4394,7 @@ void ImGui::GcCompactTransientMiscBuffers() g.MultiSelectTempDataStacked = 0; g.MultiSelectTempData.clear_destruct(); TableGcCompactSettings(); + g.IO.Fonts->CompactCache(); } // Free up/compact internal window buffers, we can use this when a window becomes unused. From 1ea9ff36771ef4d77566f4f738404ea20573ea4b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 22:18:42 +0200 Subject: [PATCH 543/716] Fonts: add optional out parameter to AddCustomRect() --- imgui.h | 2 +- imgui_draw.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/imgui.h b/imgui.h index a3d70bb98e3f..001cc414d506 100644 --- a/imgui.h +++ b/imgui.h @@ -3633,7 +3633,7 @@ struct ImFontAtlas // - AddCustomRectRegular() --> Renamed to AddCustomRect() // - AddCustomRectFontGlyph() --> Prefer using custom ImFontLoader inside ImFontConfig // - ImFontAtlasCustomRect --> Renamed to ImFontAtlasRect - IMGUI_API ImFontAtlasRectId AddCustomRect(int width, int height); // Register a rectangle. Return -1 (ImFontAtlasRectId_Invalid) on error. + IMGUI_API ImFontAtlasRectId AddCustomRect(int width, int height, ImFontAtlasRect* out_r = NULL);// Register a rectangle. Return -1 (ImFontAtlasRectId_Invalid) on error. IMGUI_API void RemoveCustomRect(ImFontAtlasRectId id); // Unregister a rectangle. Existing pixels will stay in texture until resized / garbage collected. IMGUI_API bool GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const; // Get rectangle coordinates for current texture. Valid immediately, never store this (read above)! diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7cc1351fbc14..945122b35448 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3225,7 +3225,8 @@ void ImFontAtlas::RemoveFont(ImFont* font) ImFontAtlasBuildNotifySetFont(this, font, new_current_font); } -ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height) +// At it is common to do an AddCustomRect() followed by a GetCustomRect(), we provide an optional 'ImFontAtlasRect* out_r = NULL' argument to retrieve the info straight away. +ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasRect* out_r) { IM_ASSERT(width > 0 && width <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF); @@ -3236,9 +3237,14 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height) ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); if (r_id == ImFontAtlasRectId_Invalid) return ImFontAtlasRectId_Invalid; - ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); + if (out_r != NULL) + GetCustomRect(r_id, out_r); + if (RendererHasTextures) + { + ImTextureRect* r = ImFontAtlasPackGetRect(this, r_id); ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); + } return r_id; } @@ -4321,7 +4327,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1); } -// Important: don'return pointer valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. +// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { IM_ASSERT(id != ImFontAtlasRectId_Invalid); From 526a5d0f8a6363c850fc82aaca1645109cb9336f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 2 Apr 2025 15:10:11 +0200 Subject: [PATCH 544/716] Fonts: tidying up. --- imgui_draw.cpp | 22 +++++++++------------- imgui_internal.h | 14 +++++++------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 945122b35448..f3a79b4e7776 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2654,17 +2654,14 @@ void ImFontAtlas::ClearInputData() const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : FontLoader; if (loader && loader->FontSrcDestroy != NULL) loader->FontSrcDestroy(this, &font_cfg); - ImFontAtlasBuildDiscardFontSource(this, &font_cfg); + ImFontAtlasBuildDestroyFontSourceData(this, &font_cfg); } - // When clearing this we lose access to the font name and other information used to build the font. for (ImFont* font : Fonts) { - if (font->Sources >= Sources.Data && font->Sources < Sources.Data + Sources.Size) - { - font->Sources = NULL; - font->SourcesCount = 0; - } + // When clearing this we lose access to the font name and other information used to build the font. + font->Sources = NULL; + font->SourcesCount = 0; font->Flags |= ImFontFlags_NoLoadGlyphs; } Sources.clear(); @@ -2978,14 +2975,14 @@ bool ImFontAtlas::Build() } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -void ImFontAtlasBuildDiscardFontSource(ImFontAtlas* atlas, ImFontConfig* src) +void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src) { IM_UNUSED(atlas); if (src->FontDataOwnedByAtlas) IM_FREE(src->FontData); + src->FontData = NULL; if (src->GlyphExcludeRanges) IM_FREE((void*)src->GlyphExcludeRanges); - src->FontData = NULL; src->GlyphExcludeRanges = NULL; } @@ -3048,7 +3045,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) if (!ImFontAtlasBuildAddFont(this, &new_font_cfg)) { // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) - ImFontAtlasBuildDiscardFontSource(this, &new_font_cfg); + ImFontAtlasBuildDestroyFontSourceData(this, &new_font_cfg); Sources.pop_back(); if (!font_cfg->MergeMode) { @@ -3593,9 +3590,8 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) } const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; - if (loader->FontSrcInit != NULL) - if (!loader->FontSrcInit(atlas, src)) - return false; + if (loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) + return false; atlas->TexIsBuilt = false; // For legacy backends ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); diff --git a/imgui_internal.h b/imgui_internal.h index 0a9961a45eda..41b99b438128 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3770,20 +3770,20 @@ IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); +IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); +IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy +IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); +IMGUI_API void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas); // Reinit/rebuild, notably if font loader params have changed. IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src); // Reinit/rebuild, notably if font loader params have changed. -IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); -IMGUI_API void ImFontAtlasBuildDiscardFontBakes(ImFontAtlas* atlas, ImFont* font); -IMGUI_API void ImFontAtlasBuildDiscardFontSource(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); +IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); +IMGUI_API void ImFontAtlasBuildDiscardFontBakes(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); -IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy -IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); From fb5c53708075709a4f859d8b5721893aad89a244 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 3 Apr 2025 19:10:16 +0200 Subject: [PATCH 545/716] Fonts: changing loader/backend or loader flags may be done without losing custom rects. Sharing more code. --- imgui.cpp | 27 ++++++++++++----- imgui_draw.cpp | 77 ++++++++++++++++++++++++------------------------ imgui_internal.h | 4 +-- 3 files changed, 60 insertions(+), 48 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 00bb950fcbb6..a713390c341b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15695,9 +15695,16 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); if (loader_current == loader_freetype) { - Text("Shared FreeType Loader Flags:"); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&atlas->FontBuilderFlags)) - ImFontAtlasBuildReloadAll(atlas); + unsigned int loader_flags = atlas->FontBuilderFlags; + Text("Shared FreeType Loader Flags: 0x%08", loader_flags); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) + { + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildDestroyFontOutput(atlas, font); + atlas->FontBuilderFlags = loader_flags; + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildInitFontOutput(atlas, font); + } } #else BeginDisabled(); @@ -15724,8 +15731,9 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (Button("Grow")) ImFontAtlasBuildGrowTexture(atlas); SameLine(); - if (Button("Clear Output")) + if (Button("Clear All")) ImFontAtlasBuildClear(atlas); + SetItemTooltip("Destroy cache and custom rectangles."); for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { @@ -16613,9 +16621,14 @@ void ImGui::DebugNodeFont(ImFont* font) #ifdef IMGUI_ENABLE_FREETYPE if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0) { - Text("FreeType Loader Flags: 0x%08X", src->FontBuilderFlags); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&src->FontBuilderFlags)) - ImFontAtlasBuildReloadFont(atlas, src); + unsigned int loader_flags = src->FontBuilderFlags; + Text("FreeType Loader Flags: 0x%08X", loader_flags); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) + { + ImFontAtlasBuildDestroyFontOutput(atlas, font); + src->FontBuilderFlags = loader_flags; + ImFontAtlasBuildInitFontOutput(atlas, font); + } } #endif TreePop(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f3a79b4e7776..b1683e2041e8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2649,14 +2649,11 @@ void ImFontAtlas::CompactCache() void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); + + for (ImFont* font : Fonts) + ImFontAtlasBuildDestroyFontOutput(this, font); for (ImFontConfig& font_cfg : Sources) - { - const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : FontLoader; - if (loader && loader->FontSrcDestroy != NULL) - loader->FontSrcDestroy(this, &font_cfg); ImFontAtlasBuildDestroyFontSourceData(this, &font_cfg); - } - for (ImFont* font : Fonts) { // When clearing this we lose access to the font name and other information used to build the font. @@ -3197,15 +3194,9 @@ void ImFontAtlas::RemoveFont(ImFont* font) IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); font->ClearOutputData(); + ImFontAtlasBuildDestroyFontOutput(this, font); for (int src_n = 0; src_n < font->SourcesCount; src_n++) - { - ImFontConfig* src = (ImFontConfig*)(void*)&font->Sources[src_n]; - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : FontLoader; - if (loader && loader->FontSrcDestroy != NULL) - loader->FontSrcDestroy(this, src); - if (src->FontData != NULL && src->FontDataOwnedByAtlas) - IM_FREE(src->FontData); - } + ImFontAtlasBuildDestroyFontSourceData(this, &font->Sources[src_n]); bool removed = Fonts.find_erase(font); IM_ASSERT(removed); @@ -3376,15 +3367,19 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon return; IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); - // Note that texture size estimate is likely incorrect in this situation, as FreeType backend doesn't use oversampling. - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); - ImFontAtlasBuildDestroy(atlas); + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildDestroyFontOutput(atlas, font); + if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) + atlas->FontLoader->LoaderShutdown(atlas); atlas->FontLoader = font_loader; atlas->FontLoaderName = font_loader ? font_loader->Name : "NULL"; + IM_ASSERT(atlas->FontLoaderData == NULL); - ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); - ImFontAtlasBuildInit(atlas); + if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); + for (ImFont* font : atlas->Fonts) + ImFontAtlasBuildInitFontOutput(atlas, font); } // Preload all glyph ranges for legacy backends. @@ -3562,18 +3557,31 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ //----------------------------------------------------------------------------------------------------------------------------- -void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas) +bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font) { - const ImFontLoader* main_loader = atlas->FontLoader; - ImFontAtlasBuildSetupFontLoader(atlas, NULL); - ImFontAtlasBuildSetupFontLoader(atlas, main_loader); + bool ret = true; + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader && loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) + ret = false; + } + IM_ASSERT(ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call. + return ret; } -void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src) +// Keep source/input FontData +void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font) { - // FIXME-NEWATLAS: rebuild single font not supported yet. - IM_UNUSED(src); - ImFontAtlasBuildReloadAll(atlas); + font->ClearOutputData(); + for (int src_n = 0; src_n < font->SourcesCount; src_n++) + { + ImFontConfig* src = &font->Sources[src_n]; + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader && loader->FontSrcDestroy != NULL) + loader->FontSrcDestroy(atlas, src); + } } //----------------------------------------------------------------------------------------------------------------------------- @@ -4148,13 +4156,8 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) #else IM_ASSERT(0); // Invalid Build function #endif - return; // ImFontAtlasBuildSetupFontLoader() automatically call ImFontAtlasBuildInit() } - IM_ASSERT(atlas->FontLoaderData == NULL); - if (atlas->FontLoader->LoaderInit) - atlas->FontLoader->LoaderInit(atlas); - // Create initial texture size if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL) ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); @@ -4165,6 +4168,8 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) { IM_ASSERT(atlas->Builder == NULL); builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); + if (atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); } ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); @@ -4193,13 +4198,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) { for (ImFont* font : atlas->Fonts) - font->ClearOutputData(); - for (ImFontConfig& font_cfg : atlas->Sources) - { - const ImFontLoader* loader = font_cfg.FontLoader ? font_cfg.FontLoader : atlas->FontLoader; - if (loader && loader->FontSrcDestroy != NULL) - loader->FontSrcDestroy(atlas, &font_cfg); - } + ImFontAtlasBuildDestroyFontOutput(atlas, font); if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { atlas->FontLoader->LoaderShutdown(atlas); diff --git a/imgui_internal.h b/imgui_internal.h index 41b99b438128..009f6f9c9736 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3774,9 +3774,9 @@ IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontCo IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); +IMGUI_API bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font); // Using DestroyFontOutput/InitFontOutput sequence useful notably if font loader params have changed +IMGUI_API void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildReloadAll(ImFontAtlas* atlas); // Reinit/rebuild, notably if font loader params have changed. -IMGUI_API void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFontConfig* src); // Reinit/rebuild, notably if font loader params have changed. IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); From 12599da53df30612a7f13f6b1c0532a4d9e67b81 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 15:16:59 +0200 Subject: [PATCH 546/716] Fonts: do not mark whole ImTextureData struct as IMGUI_API to fix warning when used in ImVector<> (8559) --- imgui.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 001cc414d506..3d9ff1b729d7 100644 --- a/imgui.h +++ b/imgui.h @@ -3403,7 +3403,7 @@ struct ImTextureRect // Why does we store two identifiers: TexID and BackendUserData? // - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. // - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. -struct IMGUI_API ImTextureData +struct ImTextureData { ImTextureStatus Status; // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! ImTextureFormat Format; // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 @@ -3425,8 +3425,8 @@ struct IMGUI_API ImTextureData // Functions ImTextureData() { memset(this, 0, sizeof(*this)); } ~ImTextureData() { DestroyPixels(); } - void Create(ImTextureFormat format, int w, int h); - void DestroyPixels(); + IMGUI_API void Create(ImTextureFormat format, int w, int h); + IMGUI_API void DestroyPixels(); unsigned char* GetPixels() { IM_ASSERT(Pixels != NULL); return Pixels; } unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } From d789263e08383beab8a6482109071712792316f3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Apr 2025 18:42:06 +0200 Subject: [PATCH 547/716] Fonts: internal rendering uses higher level functions. --- imgui_draw.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b1683e2041e8..562a4b6e45a3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3461,7 +3461,8 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); if (builder->PackIdMouseCursors == ImFontAtlasRectId_Invalid) return; - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors); + ImFontAtlasRect r; + atlas->GetCustomRect(builder->PackIdMouseCursors, &r); // Draw to texture if (add_and_draw) @@ -3469,19 +3470,19 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) { // 2x2 white pixels - ImFontAtlasBuildRenderBitmapFromString(atlas, r->x, r->y, 2, 2, "XX" "XX", 'X'); + ImFontAtlasBuildRenderBitmapFromString(atlas, r.x, r.y, 2, 2, "XX" "XX", 'X'); } else { // 2x2 white pixels + mouse cursors - const int x_for_white = r->x; - const int x_for_black = r->x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r->y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.'); - ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r->y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); + const int x_for_white = r.x; + const int x_for_black = r.x + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; + ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.'); + ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); } } - ImFontAtlasTextureBlockQueueUpload(atlas, atlas->TexData, r->x, r->y, r->w, r->h); - atlas->TexUvWhitePixel = ImVec2((r->x + 0.5f) * atlas->TexUvScale.x, (r->y + 0.5f) * atlas->TexUvScale.y); + ImFontAtlasTextureBlockQueueUpload(atlas, atlas->TexData, r.x, r.y, r.w, r.h); + atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y); } static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_draw) @@ -3497,7 +3498,8 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); if (builder->PackIdLinesTexData == ImFontAtlasRectId_Invalid) return; - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData); + ImFontAtlasRect r; + atlas->GetCustomRect(builder->PackIdLinesTexData, &r); // Register texture region for thick lines // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row @@ -3508,18 +3510,18 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle int y = n; int line_width = n; - int pad_left = (r->w - line_width) / 2; - int pad_right = r->w - (pad_left + line_width); + int pad_left = (r.w - line_width) / 2; + int pad_right = r.w - (pad_left + line_width); // Write each slice - IM_ASSERT(pad_left + line_width + pad_right == r->w && y < r->h); // Make sure we're inside the texture bounds before we start writing pixels + IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels if (add_and_draw) { switch (tex->Format) { case ImTextureFormat_Alpha8: { - ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r->x, r->y + y); + ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); for (int i = 0; i < pad_left; i++) *(write_ptr + i) = 0x00; @@ -3532,7 +3534,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ } case ImTextureFormat_RGBA32: { - ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r->x, r->y + y); + ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); for (int i = 0; i < pad_left; i++) *(write_ptr + i) = IM_COL32(255, 255, 255, 0); @@ -3547,12 +3549,12 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ } // Calculate UVs for this line - ImVec2 uv0 = ImVec2((float)(r->x + pad_left - 1), (float)(r->y + y)) * atlas->TexUvScale; - ImVec2 uv1 = ImVec2((float)(r->x + pad_left + line_width + 1), (float)(r->y + y + 1)) * atlas->TexUvScale; + ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 1), (float)(r.y + y)) * atlas->TexUvScale; + ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 1), (float)(r.y + y + 1)) * atlas->TexUvScale; float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); } - ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r.x, r.y, r.w, r.h); } //----------------------------------------------------------------------------------------------------------------------------- From e8035b94e5c739cfd0d1d8bb52ece31629ccb3bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Apr 2025 17:16:40 +0200 Subject: [PATCH 548/716] Fonts: misc tidying up. --- imgui_draw.cpp | 72 +++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 562a4b6e45a3..a20d63bd0d56 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3451,11 +3451,10 @@ void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, in static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_draw) { - ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); - // Pack and store identifier so we can refresh UV coordinates on texture resize. // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing. ImFontAtlasBuilder* builder = atlas->Builder; + ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); if (add_and_draw) builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); @@ -3480,8 +3479,10 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.'); ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); } + ImFontAtlasTextureBlockQueueUpload(atlas, atlas->TexData, r.x, r.y, r.w, r.h); } - ImFontAtlasTextureBlockQueueUpload(atlas, atlas->TexData, r.x, r.y, r.w, r.h); + + // Refresh UV coordinates atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y); } @@ -3490,71 +3491,64 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) return; - ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); - // Pack and store identifier so we can refresh UV coordinates on texture resize. + ImTextureData* tex = atlas->TexData; ImFontAtlasBuilder* builder = atlas->Builder; + ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); if (add_and_draw) builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); if (builder->PackIdLinesTexData == ImFontAtlasRectId_Invalid) return; + ImFontAtlasRect r; atlas->GetCustomRect(builder->PackIdLinesTexData, &r); // Register texture region for thick lines // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them - ImTextureData* tex = atlas->TexData; for (int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row { // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle - int y = n; - int line_width = n; - int pad_left = (r.w - line_width) / 2; - int pad_right = r.w - (pad_left + line_width); + const int y = n; + const int line_width = n; + const int pad_left = (r.w - line_width) / 2; + const int pad_right = r.w - (pad_left + line_width); + IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels // Write each slice - IM_ASSERT(pad_left + line_width + pad_right == r.w && y < r.h); // Make sure we're inside the texture bounds before we start writing pixels - if (add_and_draw) + if (add_and_draw && tex->Format == ImTextureFormat_Alpha8) { - switch (tex->Format) - { - case ImTextureFormat_Alpha8: - { - ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); - for (int i = 0; i < pad_left; i++) - *(write_ptr + i) = 0x00; + ImU8* write_ptr = (ImU8*)tex->GetPixelsAt(r.x, r.y + y); + for (int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; - for (int i = 0; i < line_width; i++) - *(write_ptr + pad_left + i) = 0xFF; + for (int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; - for (int i = 0; i < pad_right; i++) - *(write_ptr + pad_left + line_width + i) = 0x00; - break; - } - case ImTextureFormat_RGBA32: - { - ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); - for (int i = 0; i < pad_left; i++) - *(write_ptr + i) = IM_COL32(255, 255, 255, 0); + for (int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else if (add_and_draw && tex->Format == ImTextureFormat_RGBA32) + { + ImU32* write_ptr = (ImU32*)(void*)tex->GetPixelsAt(r.x, r.y + y); + for (int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32(255, 255, 255, 0); - for (int i = 0; i < line_width; i++) - *(write_ptr + pad_left + i) = IM_COL32_WHITE; + for (int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; - for (int i = 0; i < pad_right; i++) - *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); - break; - } - } + for (int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32(255, 255, 255, 0); } - // Calculate UVs for this line + // Refresh UV coordinates ImVec2 uv0 = ImVec2((float)(r.x + pad_left - 1), (float)(r.y + y)) * atlas->TexUvScale; ImVec2 uv1 = ImVec2((float)(r.x + pad_left + line_width + 1), (float)(r.y + y + 1)) * atlas->TexUvScale; float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); } - ImFontAtlasTextureBlockQueueUpload(atlas, tex, r.x, r.y, r.w, r.h); + if (add_and_draw) + ImFontAtlasTextureBlockQueueUpload(atlas, tex, r.x, r.y, r.w, r.h); } //----------------------------------------------------------------------------------------------------------------------------- From 0436fba13cea6ad527c3fcbf6a6e20c6a490fd78 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 31 Mar 2025 22:38:05 +0200 Subject: [PATCH 549/716] Fonts: fixed compaction gc-ing baked fonts used in the current frame + rename. --- imgui_draw.cpp | 23 ++++++++++++----------- imgui_internal.h | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a20d63bd0d56..3feba78a1354 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3983,7 +3983,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) for (ImFontAtlasRectEntry& index_entry : builder->RectsIndex) { - if (index_entry.Used == false) + if (index_entry.IsUsed == false) continue; ImTextureRect& old_r = old_rects[index_entry.TargetIndex]; if (old_r.w == 0 && old_r.h == 0) @@ -4124,7 +4124,7 @@ void ImFontAtlasBuildClear(ImFontAtlas* atlas) void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) { ImFontAtlasBuilder* builder = atlas->Builder; - ImFontAtlasBuildDiscardBakes(atlas, 0); + ImFontAtlasBuildDiscardBakes(atlas, 1); ImTextureData* old_tex = atlas->TexData; ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); @@ -4235,19 +4235,20 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r { index_idx = builder->RectsIndexFreeListStart; index_entry = &builder->RectsIndex[index_idx]; - IM_ASSERT(index_entry->Used == false); + IM_ASSERT(index_entry->IsUsed == false); builder->RectsIndexFreeListStart = index_entry->TargetIndex; } index_entry->TargetIndex = rect_idx; - index_entry->Used = 1; + index_entry->IsUsed = 1; return (ImFontAtlasRectId)index_idx; } -static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFontAtlasRectEntry* overwrite_entry) +// Overwrite existing entry +static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFontAtlasRectEntry* index_entry) { - IM_ASSERT(overwrite_entry->Used); - overwrite_entry->TargetIndex = atlas->Builder->Rects.Size - 1; - return atlas->Builder->RectsIndex.index_from_ptr(overwrite_entry); + IM_ASSERT(index_entry->IsUsed); + index_entry->TargetIndex = atlas->Builder->Rects.Size - 1; + return atlas->Builder->RectsIndex.index_from_ptr(index_entry); } // This is expected to be called in batches and followed by a repack @@ -4256,10 +4257,10 @@ void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) IM_ASSERT(id != ImFontAtlasRectId_Invalid); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; - IM_ASSERT(index_entry->Used && index_entry->TargetIndex >= 0); + IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0); ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id); - index_entry->Used = false; + index_entry->IsUsed = false; index_entry->TargetIndex = builder->RectsIndexFreeListStart; const int pack_padding = atlas->TexGlyphPadding; @@ -4324,7 +4325,7 @@ ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) IM_ASSERT(id != ImFontAtlasRectId_Invalid); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; - IM_ASSERT(index_entry->Used); + IM_ASSERT(index_entry->IsUsed); return &builder->Rects[index_entry->TargetIndex]; } diff --git a/imgui_internal.h b/imgui_internal.h index 009f6f9c9736..3e519325aa13 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3702,7 +3702,7 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); struct ImFontAtlasRectEntry { int TargetIndex : 31; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list. - unsigned int Used : 1; + unsigned int IsUsed : 1; }; // Data available to potential texture post-processing functions From ed2bb2cff08d4d1e9b26bf744902b2131fa5fc4b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Apr 2025 17:16:06 +0200 Subject: [PATCH 550/716] Fonts: encode additional data in ImFontAtlasRectId to detect invalid id + added Rects debug browser. --- imgui.cpp | 41 ++++++++++++++++++++++++++++++++++-- imgui.h | 2 +- imgui_draw.cpp | 54 +++++++++++++++++++++++++++++++++++++----------- imgui_internal.h | 14 +++++++++++-- 4 files changed, 94 insertions(+), 17 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a713390c341b..881d40727d8c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15747,17 +15747,47 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) Text("Packed rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsPackedCount, atlas->Builder->RectsPackedSurface, packed_surface_sqrt, packed_surface_sqrt); Text("incl. Discarded rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsDiscardedCount, atlas->Builder->RectsDiscardedSurface, discarded_surface_sqrt, discarded_surface_sqrt); + ImFontAtlasRectId highlight_r_id = ImFontAtlasRectId_Invalid; + if (TreeNode("Rects Index", "Rects Index (%d)", atlas->Builder->RectsPackedCount)) // <-- Use count of used rectangles + { + PushStyleVar(ImGuiStyleVar_ImageBorderSize, 1.0f); + if (BeginTable("##table", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY, ImVec2(0.0f, GetTextLineHeightWithSpacing() * 12))) + { + for (const ImFontAtlasRectEntry& entry : atlas->Builder->RectsIndex) + if (entry.IsUsed) + { + ImFontAtlasRectId id = ImFontAtlasRectId_Make(atlas->Builder->RectsIndex.index_from_ptr(&entry), entry.Generation); + ImFontAtlasRect r = {}; + atlas->GetCustomRect(id, &r); + const char* buf; + ImFormatStringToTempBuffer(&buf, NULL, "ID:%08X, used:%d, { w:%3d, h:%3d } { x:%4d, y:%4d }", id, entry.IsUsed, r.w, r.h, r.x, r.y); + TableNextColumn(); + Selectable(buf); + if (IsItemHovered()) + highlight_r_id = id; + TableNextColumn(); + Image(atlas->TexID, ImVec2(r.w, r.h), r.uv0, r.uv1); + } + EndTable(); + } + PopStyleVar(); + TreePop(); + } + // Texture list // (ensure the last texture always use the same ID, so we can keep it open neatly) + ImFontAtlasRect highlight_r; + if (highlight_r_id != ImFontAtlasRectId_Invalid) + atlas->GetCustomRect(highlight_r_id, &highlight_r); for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { if (tex_n == atlas->TexList.Size - 1) SetNextItemOpen(true, ImGuiCond_Once); - DebugNodeTexture(atlas->TexList[tex_n], atlas->TexList.Size - 1 - tex_n); + DebugNodeTexture(atlas->TexList[tex_n], atlas->TexList.Size - 1 - tex_n, (highlight_r_id != ImFontAtlasRectId_Invalid) ? &highlight_r : NULL); } } -void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id) +void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect) { ImGuiContext& g = *GImGui; PushID(int_id); @@ -15773,6 +15803,13 @@ void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id) ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); if (cfg->ShowTextureUsedRect) GetWindowDrawList()->AddRect(ImVec2(p.x + tex->UsedRect.x, p.y + tex->UsedRect.y), ImVec2(p.x + tex->UsedRect.x + tex->UsedRect.w, p.y + tex->UsedRect.y + tex->UsedRect.h), IM_COL32(255, 0, 255, 255)); + if (highlight_rect != NULL) + { + ImRect r_outer(p.x, p.y, p.x + tex->Width, p.y + tex->Height); + ImRect r_inner(p.x + highlight_rect->x, p.y + highlight_rect->y, p.x + highlight_rect->x + highlight_rect->w, p.y + highlight_rect->y + highlight_rect->h); + RenderRectFilledWithHole(GetWindowDrawList(), r_outer, r_inner, IM_COL32(0, 0, 0, 100), 0.0f); + GetWindowDrawList()->AddRect(r_inner.Min - ImVec2(1, 1), r_inner.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255)); + } PopStyleVar(); char texid_desc[20]; diff --git a/imgui.h b/imgui.h index 3d9ff1b729d7..2a0cf3546dea 100644 --- a/imgui.h +++ b/imgui.h @@ -3509,7 +3509,7 @@ struct ImFontGlyphRangesBuilder IMGUI_API void BuildRanges(ImVector* out_ranges); // Output new ranges }; -// An identifier to a rectangle in the atlas. -1 when invalid. +// An opaque identifier to a rectangle in the atlas. -1 when invalid. // The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it. typedef int ImFontAtlasRectId; #define ImFontAtlasRectId_Invalid -1 diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3feba78a1354..f1d1cf0b25f3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3238,7 +3238,8 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasR void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id) { - IM_ASSERT(id != ImFontAtlasRectId_Invalid); + if (ImFontAtlasPackGetRectSafe(this, id) == NULL) + return; ImFontAtlasPackDiscardRect(this, id); } @@ -3294,10 +3295,12 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const { - ImTextureRect* r = ImFontAtlasPackGetRect((ImFontAtlas*)this, id); + ImTextureRect* r = ImFontAtlasPackGetRectSafe((ImFontAtlas*)this, id); if (r == NULL) return false; IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates + if (out_r == NULL) + return true; out_r->x = r->x; out_r->y = r->y; out_r->w = r->w; @@ -4001,7 +4004,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) ImFontAtlasBuildGrowTexture(atlas, w, h); // Recurse return; } - IM_ASSERT(new_r_id == builder->RectsIndex.index_from_ptr(&index_entry)); + IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder->RectsIndex.index_from_ptr(&index_entry)); ImTextureRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id); ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h); } @@ -4230,17 +4233,18 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r builder->RectsIndex.resize(builder->RectsIndex.Size + 1); index_idx = builder->RectsIndex.Size - 1; index_entry = &builder->RectsIndex[index_idx]; + memset(index_entry, 0, sizeof(*index_entry)); } else { index_idx = builder->RectsIndexFreeListStart; index_entry = &builder->RectsIndex[index_idx]; - IM_ASSERT(index_entry->IsUsed == false); + IM_ASSERT(index_entry->IsUsed == false && index_entry->Generation > 0); // Generation is incremented during DiscardRect builder->RectsIndexFreeListStart = index_entry->TargetIndex; } index_entry->TargetIndex = rect_idx; index_entry->IsUsed = 1; - return (ImFontAtlasRectId)index_idx; + return ImFontAtlasRectId_Make(index_idx, index_entry->Generation); } // Overwrite existing entry @@ -4248,23 +4252,29 @@ static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFon { IM_ASSERT(index_entry->IsUsed); index_entry->TargetIndex = atlas->Builder->Rects.Size - 1; - return atlas->Builder->RectsIndex.index_from_ptr(index_entry); + int index_idx = atlas->Builder->RectsIndex.index_from_ptr(index_entry); + return ImFontAtlasRectId_Make(index_idx, index_entry->Generation); } // This is expected to be called in batches and followed by a repack void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { IM_ASSERT(id != ImFontAtlasRectId_Invalid); - ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; - ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; - IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0); ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id); + if (rect == NULL) + return; + + ImFontAtlasBuilder* builder = atlas->Builder; + int index_idx = ImFontAtlasRectId_GetIndex(id); + ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; + IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0); index_entry->IsUsed = false; index_entry->TargetIndex = builder->RectsIndexFreeListStart; + index_entry->Generation++; const int pack_padding = atlas->TexGlyphPadding; - builder->RectsIndexFreeListStart = id; + builder->RectsIndexFreeListStart = index_idx; builder->RectsDiscardedCount++; builder->RectsDiscardedSurface += (rect->w + pack_padding) * (rect->h + pack_padding); rect->w = rect->h = 0; // Clear rectangle so it won't be packed again @@ -4319,16 +4329,36 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1); } -// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. +// Generally for non-user facing functions: assert on invalid ID. ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { IM_ASSERT(id != ImFontAtlasRectId_Invalid); + int index_idx = ImFontAtlasRectId_GetIndex(id); + int generation = ImFontAtlasRectId_GetGeneration(id); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; - ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id]; + ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; + IM_ASSERT(index_entry->Generation == generation); IM_ASSERT(index_entry->IsUsed); return &builder->Rects[index_entry->TargetIndex]; } +// For user-facing functions: return NULL on invalid ID. +// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers. +ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id) +{ + if (id == ImFontAtlasRectId_Invalid) + return NULL; + int index_idx = ImFontAtlasRectId_GetIndex(id); + int generation = ImFontAtlasRectId_GetGeneration(id); + ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; + if (index_idx >= builder->RectsIndex.Size) + return NULL; + ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; + if (index_entry->Generation != generation || !index_entry->IsUsed) + return NULL; + return &builder->Rects[index_entry->TargetIndex]; +} + // Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries) static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint) { diff --git a/imgui_internal.h b/imgui_internal.h index 3e519325aa13..cb8ba516907b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3627,7 +3627,7 @@ namespace ImGui IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); - IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id); // ID used to facilitate persisting the "current" texture. + IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect = NULL); // ID used to facilitate persisting the "current" texture. IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); IMGUI_API void DebugNodeTable(ImGuiTable* table); @@ -3694,6 +3694,14 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- +// Refer to ImFontAtlasPackGetRect() to better understand how this works. +#define ImFontAtlasRectId_IndexMask_ (0x000FFFFF) // 20-bits: index to access builder->RectsIndex[]. +#define ImFontAtlasRectId_GenerationMask_ (0x3FF00000) // 10-bits: entry generation, so each ID is unique and get can safely detected old identifiers. +#define ImFontAtlasRectId_GenerationShift_ (20) +inline int ImFontAtlasRectId_GetIndex(ImFontAtlasRectId id) { return id & ImFontAtlasRectId_IndexMask_; } +inline int ImFontAtlasRectId_GetGeneration(ImFontAtlasRectId id) { return (id & ImFontAtlasRectId_GenerationMask_) >> ImFontAtlasRectId_GenerationShift_; } +inline ImFontAtlasRectId ImFontAtlasRectId_Make(int index_idx, int gen_idx) { IM_ASSERT(index_idx < ImFontAtlasRectId_IndexMask_ && gen_idx < (ImFontAtlasRectId_GenerationMask_ >> ImFontAtlasRectId_GenerationShift_)); return (ImFontAtlasRectId)(index_idx | (gen_idx << ImFontAtlasRectId_GenerationShift_)); } + // Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles) // User are returned ImFontAtlasRectId values which are meant to be persistent. // We handle this with an indirection. While Rects[] may be in theory shuffled, compacted etc., RectsIndex[] cannot it is keyed by ImFontAtlasRectId. @@ -3701,7 +3709,8 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // Having this also makes it easier to e.g. sort rectangles during repack. struct ImFontAtlasRectEntry { - int TargetIndex : 31; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list. + int TargetIndex : 20; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list. + int Generation : 10; // Increased each time the entry is reused for a new rectangle. unsigned int IsUsed : 1; }; @@ -3792,6 +3801,7 @@ IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_s IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); IMGUI_API ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id); +IMGUI_API ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count); From cdfa537adf060c1d3fe13c87ad4ed25d967e814b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 14 Apr 2025 16:20:31 +0200 Subject: [PATCH 551/716] Fonts: packing of shared basic/line/cursor data uses more public API. --- imgui_draw.cpp | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f1d1cf0b25f3..b7507821ef22 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3452,23 +3452,21 @@ void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, in } } -static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_draw) +static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas) { // Pack and store identifier so we can refresh UV coordinates on texture resize. // FIXME-NEWATLAS: User/custom rects where user code wants to store UV coordinates will need to do the same thing. ImFontAtlasBuilder* builder = atlas->Builder; ImVec2i pack_size = (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) ? ImVec2i(2, 2) : ImVec2i(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H); - if (add_and_draw) - builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); - if (builder->PackIdMouseCursors == ImFontAtlasRectId_Invalid) - return; ImFontAtlasRect r; - atlas->GetCustomRect(builder->PackIdMouseCursors, &r); - - // Draw to texture + bool add_and_draw = (atlas->GetCustomRect(builder->PackIdMouseCursors, &r) == false); if (add_and_draw) { + builder->PackIdMouseCursors = atlas->AddCustomRect(pack_size.x, pack_size.y, &r); + IM_ASSERT(builder->PackIdMouseCursors != ImFontAtlasRectId_Invalid); + + // Draw to texture if (atlas->Flags & ImFontAtlasFlags_NoMouseCursors) { // 2x2 white pixels @@ -3482,14 +3480,13 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_ ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_white, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.'); ImFontAtlasBuildRenderBitmapFromString(atlas, x_for_black, r.y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X'); } - ImFontAtlasTextureBlockQueueUpload(atlas, atlas->TexData, r.x, r.y, r.w, r.h); } // Refresh UV coordinates atlas->TexUvWhitePixel = ImVec2((r.x + 0.5f) * atlas->TexUvScale.x, (r.y + 0.5f) * atlas->TexUvScale.y); } -static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_draw) +static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) { if (atlas->Flags & ImFontAtlasFlags_NoBakedLines) return; @@ -3497,14 +3494,15 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ // Pack and store identifier so we can refresh UV coordinates on texture resize. ImTextureData* tex = atlas->TexData; ImFontAtlasBuilder* builder = atlas->Builder; - ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); - if (add_and_draw) - builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y); - if (builder->PackIdLinesTexData == ImFontAtlasRectId_Invalid) - return; ImFontAtlasRect r; - atlas->GetCustomRect(builder->PackIdLinesTexData, &r); + bool add_and_draw = atlas->GetCustomRect(builder->PackIdLinesTexData, &r) == false; + if (add_and_draw) + { + ImVec2i pack_size = ImVec2i(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1); + builder->PackIdLinesTexData = atlas->AddCustomRect(pack_size.x, pack_size.y, &r); + IM_ASSERT(builder->PackIdLinesTexData != ImFontAtlasRectId_Invalid); + } // Register texture region for thick lines // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row @@ -3550,8 +3548,6 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_ float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v); } - if (add_and_draw) - ImFontAtlasTextureBlockQueueUpload(atlas, tex, r.x, r.y, r.w, r.h); } //----------------------------------------------------------------------------------------------------------------------------- @@ -4025,8 +4021,8 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) } // Update other cached UV - ImFontAtlasBuildUpdateLinesTexData(atlas, false); - ImFontAtlasBuildUpdateBasicTexData(atlas, false); + ImFontAtlasBuildUpdateLinesTexData(atlas); + ImFontAtlasBuildUpdateBasicTexData(atlas); builder->LockDisableResize = false; ImFontAtlasUpdateDrawListsSharedData(atlas); @@ -4176,8 +4172,8 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) ImFontAtlasPackInit(atlas); // Add required texture data - ImFontAtlasBuildUpdateLinesTexData(atlas, true); - ImFontAtlasBuildUpdateBasicTexData(atlas, true); + ImFontAtlasBuildUpdateLinesTexData(atlas); + ImFontAtlasBuildUpdateBasicTexData(atlas); // Register fonts if (builder_is_new) From c43b138a6988ada530d03b821cfdbc8a578149d2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Apr 2025 15:00:35 +0200 Subject: [PATCH 552/716] Fonts: no need to load current baked on SkipItems window? + removed unused field. Avoid baked staying active after GC. Might cause issues. # Conflicts: # imgui.cpp --- imgui.cpp | 6 +++++- imgui_internal.h | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 881d40727d8c..e2765edacda5 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8625,9 +8625,13 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size) void ImGui::UpdateCurrentFontSize() { ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + if (window != NULL && window->SkipItems) + return; + float final_size = g.FontSizeBeforeScaling * g.IO.FontGlobalScale; final_size *= g.Font->Scale; - if (ImGuiWindow* window = g.CurrentWindow) + if (window != NULL) final_size *= window->FontWindowScale; // Round font size diff --git a/imgui_internal.h b/imgui_internal.h index cb8ba516907b..c4e064052b0e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2144,7 +2144,6 @@ struct ImGuiContext float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; - ImVectorTextures; double Time; int FrameCount; int FrameCountEnded; From eb650c468a42b71ff83d1b3405068ad4c8cebbf6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Apr 2025 16:47:54 +0200 Subject: [PATCH 553/716] Fonts: fixed unused variable warning. --- imgui_draw.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b7507821ef22..f982df4e6f0f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4330,10 +4330,9 @@ ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id) { IM_ASSERT(id != ImFontAtlasRectId_Invalid); int index_idx = ImFontAtlasRectId_GetIndex(id); - int generation = ImFontAtlasRectId_GetGeneration(id); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; - IM_ASSERT(index_entry->Generation == generation); + IM_ASSERT(index_entry->Generation == ImFontAtlasRectId_GetGeneration(id)); IM_ASSERT(index_entry->IsUsed); return &builder->Rects[index_entry->TargetIndex]; } @@ -4345,12 +4344,11 @@ ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId if (id == ImFontAtlasRectId_Invalid) return NULL; int index_idx = ImFontAtlasRectId_GetIndex(id); - int generation = ImFontAtlasRectId_GetGeneration(id); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; if (index_idx >= builder->RectsIndex.Size) return NULL; ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx]; - if (index_entry->Generation != generation || !index_entry->IsUsed) + if (index_entry->Generation != ImFontAtlasRectId_GetGeneration(id) || !index_entry->IsUsed) return NULL; return &builder->Rects[index_entry->TargetIndex]; } From 7840e453b58f8b0950166e67adce8df15ddebfa2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Apr 2025 16:53:12 +0200 Subject: [PATCH 554/716] Fonts: ImFontAtlasBuildInit() is always called with atlas->Builder == NULL. --- imgui_draw.cpp | 22 +++++++--------------- imgui_internal.h | 2 +- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f982df4e6f0f..f78ff990119a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3552,6 +3552,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) //----------------------------------------------------------------------------------------------------------------------------- +// Was tempted to lazily init FontSrc but wouldn't save much + makes it more complicated to detect invalid data at AddFont() bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font) { bool ret = true; @@ -4157,15 +4158,9 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL) ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); - ImFontAtlasBuilder* builder = atlas->Builder; // Do not move above - const bool builder_is_new = (builder == NULL); - if (builder_is_new) - { - IM_ASSERT(atlas->Builder == NULL); - builder = atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); - if (atlas->FontLoader->LoaderInit) - atlas->FontLoader->LoaderInit(atlas); - } + atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); + if (atlas->FontLoader->LoaderInit) + atlas->FontLoader->LoaderInit(atlas); ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); @@ -4176,12 +4171,9 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) ImFontAtlasBuildUpdateBasicTexData(atlas); // Register fonts - if (builder_is_new) - { - ImFontAtlasBuildUpdatePointers(atlas); - for (ImFontConfig& cfg : atlas->Sources) - ImFontAtlasBuildAddFont(atlas, &cfg); - } + ImFontAtlasBuildUpdatePointers(atlas); + for (ImFontConfig& cfg : atlas->Sources) + ImFontAtlasBuildAddFont(atlas, &cfg); // Update UV coordinates etc. stored in bound ImDrawListSharedData instance ImFontAtlasUpdateDrawListsSharedData(atlas); diff --git a/imgui_internal.h b/imgui_internal.h index c4e064052b0e..7c615d323100 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3753,7 +3753,7 @@ struct ImFontAtlasBuilder // Cache of all ImFontBaked ImStableVector BakedPool; - ImGuiStorage BakedMap; + ImGuiStorage BakedMap; // BakedId --> ImFontBaked* int BakedDiscardedCount; // Custom rectangle identifiers From bcd1a94b89c478de8beee33d92e30ed00e5cda50 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 17 Apr 2025 17:48:29 +0200 Subject: [PATCH 555/716] Fonts: Extract ImFontAtlasBuildGetFontBaked() out of ImFont::GetFontBaked() mostly for consistency with upcoming changes + tweak locals in AddFont(). --- imgui.cpp | 2 +- imgui.h | 2 +- imgui_draw.cpp | 87 ++++++++++++++++++++++++------------------------ imgui_internal.h | 1 + 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e2765edacda5..2b8c8f8db2d0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15770,7 +15770,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (IsItemHovered()) highlight_r_id = id; TableNextColumn(); - Image(atlas->TexID, ImVec2(r.w, r.h), r.uv0, r.uv1); + Image(atlas->TexRef, ImVec2(r.w, r.h), r.uv0, r.uv1); } EndTable(); } diff --git a/imgui.h b/imgui.h index 2a0cf3546dea..6ae7c9e52048 100644 --- a/imgui.h +++ b/imgui.h @@ -3673,7 +3673,7 @@ struct ImFontAtlas ImVector Sources; // Source/configuration data ImVec4 TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1]; // UVs for baked anti-aliased lines int TexNextUniqueID; // Next value to be stored in TexData->UniqueID - int FontNextUniqueID; // Next value to be stored in ImFont->SourceID + int FontNextUniqueID; // Next value to be stored in ImFont->FontID ImVector DrawListSharedDatas; // List of users for this atlas. Typically one per Dear ImGui context. ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public and may be discarded when rebuilding. const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! diff --git a/imgui_draw.cpp b/imgui_draw.cpp index f78ff990119a..dffe5ccf57ee 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2983,12 +2983,12 @@ void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src src->GlyphExcludeRanges = NULL; } -ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) +ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); - IM_ASSERT((font_cfg->FontData != NULL && font_cfg->FontDataSize > 0) || (font_cfg->FontLoader != NULL)); - IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); - IM_ASSERT(font_cfg->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); + IM_ASSERT((font_cfg_in->FontData != NULL && font_cfg_in->FontDataSize > 0) || (font_cfg_in->FontLoader != NULL)); + IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); + IM_ASSERT(font_cfg_in->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); // Lazily create builder on the first call to AddFont if (Builder == NULL) @@ -2996,12 +2996,12 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) // Create new font ImFont* font; - if (!font_cfg->MergeMode) + if (!font_cfg_in->MergeMode) { font = IM_NEW(ImFont)(); font->FontId = FontNextUniqueID++; - font->Flags = font_cfg->Flags; - font->DefaultSize = font_cfg->SizePixels; + font->Flags = font_cfg_in->Flags; + font->DefaultSize = font_cfg_in->SizePixels; Fonts.push_back(font); } else @@ -3010,14 +3010,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) font = Fonts.back(); } - Sources.push_back(*font_cfg); - ImFontConfig& new_font_cfg = Sources.back(); - if (new_font_cfg.DstFont == NULL) - new_font_cfg.DstFont = font; - if (!new_font_cfg.FontDataOwnedByAtlas) + Sources.push_back(*font_cfg_in); + ImFontConfig* font_cfg = &Sources.back(); + if (font_cfg->DstFont == NULL) + font_cfg->DstFont = font; + if (font_cfg->FontDataOwnedByAtlas == false) { - new_font_cfg.FontDataOwnedByAtlas = true; - new_font_cfg.FontData = ImMemdup(font_cfg->FontData, (size_t)new_font_cfg.FontDataSize); + font_cfg->FontDataOwnedByAtlas = true; + font_cfg->FontData = ImMemdup(font_cfg->FontData, (size_t)font_cfg->FontDataSize); } // Sanity check @@ -3028,7 +3028,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) for (const ImWchar* p = font_cfg->GlyphExcludeRanges; p[0] != 0; p++, size++) {} IM_ASSERT((size & 1) == 0 && "GlyphExcludeRanges[] size must be multiple of two!"); IM_ASSERT((size <= 64) && "GlyphExcludeRanges[] size must be small!"); - new_font_cfg.GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1)); + font_cfg->GlyphExcludeRanges = (ImWchar*)ImMemdup(font_cfg->GlyphExcludeRanges, sizeof(font_cfg->GlyphExcludeRanges[0]) * (size + 1)); } if (font_cfg->FontLoader != NULL) { @@ -3038,12 +3038,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) IM_ASSERT(font_cfg->FontLoaderData == NULL); // Pointers to Sources are otherwise dangling + font->SourcesCount++; ImFontAtlasBuildUpdatePointers(this); - if (!ImFontAtlasBuildAddFont(this, &new_font_cfg)) + if (!ImFontAtlasBuildAddFont(this, font_cfg)) { // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) - ImFontAtlasBuildDestroyFontSourceData(this, &new_font_cfg); + ImFontAtlasBuildDestroyFontSourceData(this, font_cfg); Sources.pop_back(); + font->SourcesCount--; if (!font_cfg->MergeMode) { IM_DELETE(font); @@ -3051,8 +3053,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg) } return NULL; } - - return new_font_cfg.DstFont; + return font; } // Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder) @@ -3416,11 +3417,7 @@ void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) ImFontConfig* src = &atlas->Sources[src_n]; ImFont* font = src->DstFont; if (!src->MergeMode) - { font->Sources = src; - font->SourcesCount = 0; - } - font->SourcesCount++; } } @@ -3739,11 +3736,11 @@ void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImF baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } -ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float size, ImGuiID baked_id) +ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id) { - IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", size); + IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", font_size); ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked()); - baked->Size = size; + baked->Size = font_size; baked->BakedId = baked_id; baked->ContainerFont = font; baked->LastUsedFrame = atlas->Builder->FrameCount; @@ -5021,10 +5018,10 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. // Set UV from packed rectangle - if (in_glyph->PackId != ImFontAtlasRectId_Invalid) + if (glyph.PackId != ImFontAtlasRectId_Invalid) { - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, in_glyph->PackId); - IM_ASSERT(in_glyph->U0 == 0.0f && in_glyph->V0 == 0.0f && in_glyph->U1 == 0.0f && in_glyph->V1 == 0.0f); + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); + IM_ASSERT(glyph.U0 == 0.0f && glyph.V0 == 0.0f && glyph.U1 == 0.0f && glyph.V1 == 0.0f); glyph.U0 = (r->x) * atlas->TexUvScale.x; glyph.V0 = (r->y) * atlas->TexUvScale.y; glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; @@ -5196,31 +5193,35 @@ ImFontBaked* ImFont::GetFontBaked(float size) ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; + baked = ImFontAtlasBuildGetFontBaked(atlas, this, size); + if (baked == NULL) + return NULL; + baked->LastUsedFrame = builder->FrameCount; + LastBaked = baked; + return baked; +} - // FIXME-NEWATLAS: Design for picking a nearest size based on some criterias? +ImFontBaked* ImFontAtlasBuildGetFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size) +{ + // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria? // FIXME-NEWATLAS: Altering font density won't work right away. - ImGuiID baked_id = ImFontAtlasBakedGetId(FontId, size); + ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size); + ImFontAtlasBuilder* builder = atlas->Builder; ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); - baked = *p_baked_in_map; + ImFontBaked* baked = *p_baked_in_map; if (baked != NULL) { - IM_ASSERT(baked->Size == size && baked->ContainerFont == this && baked->BakedId == baked_id); - baked->LastUsedFrame = builder->FrameCount; - LastBaked = baked; + IM_ASSERT(baked->Size == font_size && baked->ContainerFont == font && baked->BakedId == baked_id); return baked; } // If atlas is locked, find closest match // FIXME-OPT: This is not an optimal query. - if ((Flags & ImFontFlags_LockBakedSizes) || atlas->Locked) + if ((font->Flags & ImFontFlags_LockBakedSizes) || atlas->Locked) { - baked = ImFontAtlasBuildGetClosestFontBakedMatch(atlas, this, size); + baked = ImFontAtlasBuildGetClosestFontBakedMatch(atlas, font, font_size); if (baked != NULL) - { - baked->LastUsedFrame = builder->FrameCount; - LastBaked = baked; return baked; - } if (atlas->Locked) { IM_ASSERT(!atlas->Locked && "Cannot use dynamic font size with a locked ImFontAtlas!"); // Locked because rendering backend does not support ImGuiBackendFlags_RendererHasTextures! @@ -5229,10 +5230,8 @@ ImFontBaked* ImFont::GetFontBaked(float size) } // Create new - baked = ImFontAtlasBuildAddFontBaked(atlas, this, size, baked_id); - LastBaked = baked; + baked = ImFontAtlasBuildAddFontBaked(atlas, font, font_size, baked_id); *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can. - return baked; } diff --git a/imgui_internal.h b/imgui_internal.h index 7c615d323100..7f9420cda475 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3786,6 +3786,7 @@ IMGUI_API bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, I IMGUI_API void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API ImFontBaked* ImFontAtlasBuildGetFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size); IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); From c4fa9bb61fb69fa5f322b3e621baedfd101a72a6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 21 Apr 2025 18:06:50 +0200 Subject: [PATCH 556/716] Fonts: add ImFontGlyph::SourceIdx. Extract code out of DebugNodeFont() into DebugNodeFontGlyphesForSrcMask(). (src_mask unused in this commit) --- imgui.cpp | 100 +++++++++++++++++++++++++---------------------- imgui.h | 3 +- imgui_draw.cpp | 6 ++- imgui_internal.h | 1 + 4 files changed, 62 insertions(+), 48 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2b8c8f8db2d0..66b0609cdb92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16700,52 +16700,7 @@ void ImGui::DebugNodeFont(ImFont* font) src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); } - ImDrawList* draw_list = GetWindowDrawList(); - const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); - const float cell_size = baked->Size * 1; - const float cell_spacing = GetStyle().ItemSpacing.y; - for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) - { - // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) - // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT - // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) - if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191)) - { - base += 8192 - 256; - continue; - } - - int count = 0; - for (unsigned int n = 0; n < 256; n++) - if (baked->IsGlyphLoaded((ImWchar)(base + n))) - count++; - if (count <= 0) - continue; - if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) - continue; - - // Draw a 16x16 grid of glyphs - ImVec2 base_pos = GetCursorScreenPos(); - for (unsigned int n = 0; n < 256; n++) - { - // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions - // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. - ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); - ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); - const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL; - draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); - if (!glyph) - continue; - font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); - if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) - { - DebugNodeFontGlyph(font, glyph); - EndTooltip(); - } - } - Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); - TreePop(); - } + DebugNodeFontGlyphesForSrcMask(font, baked, ~0); TreePop(); } PopID(); @@ -16754,6 +16709,57 @@ void ImGui::DebugNodeFont(ImFont* font) Unindent(); } +void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask) +{ + ImDrawList* draw_list = GetWindowDrawList(); + const ImU32 glyph_col = GetColorU32(ImGuiCol_Text); + const float cell_size = baked->Size * 1; + const float cell_spacing = GetStyle().ItemSpacing.y; + for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256) + { + // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k) + // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT + // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here) + if (!(base & 8191) && font->IsGlyphRangeUnused(base, base + 8191)) + { + base += 8192 - 256; + continue; + } + + int count = 0; + for (unsigned int n = 0; n < 256; n++) + if (const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL) + if (src_mask & (1 << glyph->SourceIdx)) + count++; + if (count <= 0) + continue; + if (!TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph")) + continue; + + // Draw a 16x16 grid of glyphs + ImVec2 base_pos = GetCursorScreenPos(); + for (unsigned int n = 0; n < 256; n++) + { + // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions + // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string. + ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing)); + ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size); + const ImFontGlyph* glyph = baked->IsGlyphLoaded((ImWchar)(base + n)) ? baked->FindGlyph((ImWchar)(base + n)) : NULL; + draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50)); + if (!glyph || (src_mask & (1 << glyph->SourceIdx)) == 0) + continue; + font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n)); + if (IsMouseHoveringRect(cell_p1, cell_p2) && BeginTooltip()) + { + DebugNodeFontGlyph(font, glyph); + EndTooltip(); + } + } + Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16)); + TreePop(); + } +} + void ImGui::DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph) { Text("Codepoint: U+%04X", glyph->Codepoint); @@ -16767,6 +16773,7 @@ void ImGui::DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph) ImTextureRect* r = ImFontAtlasPackGetRect(font->ContainerAtlas, glyph->PackId); Text("PackId: %d (%dx%d rect at %d,%d)", glyph->PackId, r->w, r->h, r->x, r->y); } + Text("SourceIdx: %d", glyph->SourceIdx); } // [DEBUG] Display contents of ImGuiStorage @@ -17429,6 +17436,7 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns*) {} void ImGui::DebugNodeDrawList(ImGuiWindow*, ImGuiViewportP*, const ImDrawList*, const char*) {} void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeFont(ImFont*) {} +void ImGui::DebugNodeFontGlyphesForSrcMask(ImFont*, ImFontBaked*, int) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} diff --git a/imgui.h b/imgui.h index 6ae7c9e52048..f99eaedd3365 100644 --- a/imgui.h +++ b/imgui.h @@ -3484,7 +3484,8 @@ struct ImFontGlyph { unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. - unsigned int Codepoint : 30; // 0x0000..0x10FFFF + unsigned int SourceIdx : 4; // Index of source in parent font + unsigned int Codepoint : 26; // 0x0000..0x10FFFF float AdvanceX; // Horizontal distance to advance cursor/layout position. float X0, Y0, X1, Y1; // Glyph corners. Offsets from current cursor/layout position. float U0, V0, U1, V1; // Texture coordinates for the current value of ImFontAtlas->TexRef. Cached equivalent of calling GetCustomRect() with PackId. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dffe5ccf57ee..a0c34901dcea 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4390,7 +4390,11 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) if (ImFontGlyph* glyph = loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint)) - return glyph; // FIXME: Add hooks for e.g. #7962 + { + // FIXME: Add hooks for e.g. #7962 + glyph->SourceIdx = src_n; + return glyph; + } loader_user_data_p += loader->FontBakedSrcLoaderDataSize; } diff --git a/imgui_internal.h b/imgui_internal.h index 7f9420cda475..137ba7d46660 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3625,6 +3625,7 @@ namespace ImGui IMGUI_API void DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, const ImDrawList* draw_list, const char* label); IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb); IMGUI_API void DebugNodeFont(ImFont* font); + IMGUI_API void DebugNodeFontGlyphesForSrcMask(ImFont* font, ImFontBaked* baked, int src_mask); IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph); IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect = NULL); // ID used to facilitate persisting the "current" texture. IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); From 890fff92fd071e2c70139205e065eca0c1061761 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Apr 2025 12:08:28 +0200 Subject: [PATCH 557/716] Fonts: rename many internal functions for consistency. No other changes. --- imgui.cpp | 10 ++-- imgui_draw.cpp | 118 +++++++++++++++++++++++------------------------ imgui_internal.h | 38 +++++++-------- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 66b0609cdb92..8f7c8fe62cd4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15704,10 +15704,10 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) { for (ImFont* font : atlas->Fonts) - ImFontAtlasBuildDestroyFontOutput(atlas, font); + ImFontAtlasFontDestroyOutput(atlas, font); atlas->FontBuilderFlags = loader_flags; for (ImFont* font : atlas->Fonts) - ImFontAtlasBuildInitFontOutput(atlas, font); + ImFontAtlasFontInitOutput(atlas, font); } } #else @@ -15733,7 +15733,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) atlas->CompactCache(); SameLine(); if (Button("Grow")) - ImFontAtlasBuildGrowTexture(atlas); + ImFontAtlasTextureGrow(atlas); SameLine(); if (Button("Clear All")) ImFontAtlasBuildClear(atlas); @@ -16666,9 +16666,9 @@ void ImGui::DebugNodeFont(ImFont* font) Text("FreeType Loader Flags: 0x%08X", loader_flags); if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) { - ImFontAtlasBuildDestroyFontOutput(atlas, font); + ImFontAtlasFontDestroyOutput(atlas, font); src->FontBuilderFlags = loader_flags; - ImFontAtlasBuildInitFontOutput(atlas, font); + ImFontAtlasFontInitOutput(atlas, font); } } #endif diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a0c34901dcea..40ae02ed524d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2643,7 +2643,7 @@ void ImFontAtlas::Clear() void ImFontAtlas::CompactCache() { - ImFontAtlasBuildCompactTexture(this); + ImFontAtlasTextureCompact(this); } void ImFontAtlas::ClearInputData() @@ -2651,9 +2651,9 @@ void ImFontAtlas::ClearInputData() IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); for (ImFont* font : Fonts) - ImFontAtlasBuildDestroyFontOutput(this, font); + ImFontAtlasFontDestroyOutput(this, font); for (ImFontConfig& font_cfg : Sources) - ImFontAtlasBuildDestroyFontSourceData(this, &font_cfg); + ImFontAtlasFontDestroySourceData(this, &font_cfg); for (ImFont* font : Fonts) { // When clearing this we lose access to the font name and other information used to build the font. @@ -2972,17 +2972,6 @@ bool ImFontAtlas::Build() } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src) -{ - IM_UNUSED(atlas); - if (src->FontDataOwnedByAtlas) - IM_FREE(src->FontData); - src->FontData = NULL; - if (src->GlyphExcludeRanges) - IM_FREE((void*)src->GlyphExcludeRanges); - src->GlyphExcludeRanges = NULL; -} - ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); @@ -3040,10 +3029,10 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) // Pointers to Sources are otherwise dangling font->SourcesCount++; ImFontAtlasBuildUpdatePointers(this); - if (!ImFontAtlasBuildAddFont(this, font_cfg)) + if (!ImFontAtlasFontInitSource(this, font_cfg)) { // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) - ImFontAtlasBuildDestroyFontSourceData(this, font_cfg); + ImFontAtlasFontDestroySourceData(this, font_cfg); Sources.pop_back(); font->SourcesCount--; if (!font_cfg->MergeMode) @@ -3195,9 +3184,9 @@ void ImFontAtlas::RemoveFont(ImFont* font) IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); font->ClearOutputData(); - ImFontAtlasBuildDestroyFontOutput(this, font); + ImFontAtlasFontDestroyOutput(this, font); for (int src_n = 0; src_n < font->SourcesCount; src_n++) - ImFontAtlasBuildDestroyFontSourceData(this, &font->Sources[src_n]); + ImFontAtlasFontDestroySourceData(this, &font->Sources[src_n]); bool removed = Fonts.find_erase(font); IM_ASSERT(removed); @@ -3251,14 +3240,14 @@ void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id) // ImFont* myfont = io.Fonts->AddFontFromFileTTF(....); // myfont->GetFontBaked(16.0f); // myfont->Flags |= ImFontFlags_LockBakedSizes; -int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) +ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { float font_size = font->DefaultSize; return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset); } // FIXME: we automatically set glyph.Colored=true by default. // If you need to alter this, you can write 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph(). -int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) +ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { #ifdef IMGUI_USE_WCHAR32 IM_ASSERT(codepoint <= IM_UNICODE_CODEPOINT_MAX); @@ -3277,7 +3266,7 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im ImFontAtlasTextureBlockQueueUpload(this, TexData, r->x, r->y, r->w, r->h); if (baked->IsGlyphLoaded(codepoint)) - ImFontAtlasBuildDiscardFontBakedGlyph(this, font, baked, baked->FindGlyph(codepoint)); + ImFontAtlasBakedDiscardFontGlyph(this, font, baked, baked->FindGlyph(codepoint)); ImFontGlyph glyph; glyph.Codepoint = codepoint; @@ -3337,9 +3326,9 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); if (atlas->TexData && atlas->TexData->Format != atlas->TexDesiredFormat) { - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); + ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); - ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); + ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y); } if (atlas->Builder == NULL) @@ -3372,7 +3361,7 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); for (ImFont* font : atlas->Fonts) - ImFontAtlasBuildDestroyFontOutput(atlas, font); + ImFontAtlasFontDestroyOutput(atlas, font); if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) atlas->FontLoader->LoaderShutdown(atlas); @@ -3383,7 +3372,7 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderInit) atlas->FontLoader->LoaderInit(atlas); for (ImFont* font : atlas->Fonts) - ImFontAtlasBuildInitFontOutput(atlas, font); + ImFontAtlasFontInitOutput(atlas, font); } // Preload all glyph ranges for legacy backends. @@ -3550,7 +3539,7 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) //----------------------------------------------------------------------------------------------------------------------------- // Was tempted to lazily init FontSrc but wouldn't save much + makes it more complicated to detect invalid data at AddFont() -bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font) +bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font) { bool ret = true; for (int src_n = 0; src_n < font->SourcesCount; src_n++) @@ -3565,7 +3554,7 @@ bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font) } // Keep source/input FontData -void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font) { font->ClearOutputData(); for (int src_n = 0; src_n < font->SourcesCount; src_n++) @@ -3579,7 +3568,7 @@ void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font) //----------------------------------------------------------------------------------------------------------------------------- -bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) +bool ImFontAtlasFontInitSource(ImFontAtlas* atlas, ImFontConfig* src) { ImFont* font = src->DstFont; if (src->MergeMode == false) @@ -3599,6 +3588,17 @@ bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src) return true; } +void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src) +{ + IM_UNUSED(atlas); + if (src->FontDataOwnedByAtlas) + IM_FREE(src->FontData); + src->FontData = NULL; + if (src->GlyphExcludeRanges) + IM_FREE((void*)src->GlyphExcludeRanges); + src->GlyphExcludeRanges = NULL; +} + // Create a compact, baked "..." if it doesn't exist, by using the ".". // This may seem overly complicated right now but the point is to exercise and improve a technique which should be increasingly used. // FIXME-NEWATLAS: This borrows too much from FontLoader's FontLoadGlyph() handlers and suggest that we should add further helpers. @@ -3721,7 +3721,7 @@ void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, Im } } -void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) +void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph) { if (glyph->PackId != ImFontAtlasRectId_Invalid) { @@ -3736,7 +3736,7 @@ void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImF baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } -ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id) +ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id) { IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", font_size); ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked()); @@ -3769,7 +3769,7 @@ ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, floa } // FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most common case. -ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size) +ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size) { ImFontAtlasBuilder* builder = atlas->Builder; ImFontBaked* closest_larger_match = NULL; @@ -3792,7 +3792,7 @@ ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont return NULL; } -void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) +void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked) { ImFontAtlasBuilder* builder = atlas->Builder; IMGUI_DEBUG_LOG_FONT("[font] Discard baked %.2f for \"%s\"\n", baked->Size, font->GetDebugName()); @@ -3822,14 +3822,14 @@ void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBa font->LastBaked = NULL; } -void ImFontAtlasBuildDiscardFontBakes(ImFontAtlas* atlas, ImFont* font) +void ImFontAtlasFontDiscardOutputBakes(ImFontAtlas* atlas, ImFont* font) { if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { ImFontBaked* baked = &builder->BakedPool[baked_n]; if (baked->ContainerFont == font && !baked->WantDestroy) - ImFontAtlasBuildDiscardFontBaked(atlas, font, baked); + ImFontAtlasBakedDiscard(atlas, font, baked); } } @@ -3844,7 +3844,7 @@ void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames) continue; if (baked->WantDestroy || (baked->ContainerFont->Flags & ImFontFlags_LockBakedSizes)) continue; - ImFontAtlasBuildDiscardFontBaked(atlas, baked->ContainerFont, baked); + ImFontAtlasBakedDiscard(atlas, baked->ContainerFont, baked); } } @@ -3905,7 +3905,7 @@ static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex) } // Create a new texture, discard previous one -ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h) +ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h) { ImTextureData* old_tex = atlas->TexData; ImTextureData* new_tex; @@ -3955,13 +3955,13 @@ static void ImFontAtlasDebugWriteTexToDisk(ImTextureData* tex, const char* descr } #endif -void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) +void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h) { ImFontAtlasBuilder* builder = atlas->Builder; builder->LockDisableResize = true; ImTextureData* old_tex = atlas->TexData; - ImTextureData* new_tex = ImFontAtlasBuildAddTexture(atlas, w, h); + ImTextureData* new_tex = ImFontAtlasTextureAdd(atlas, w, h); new_tex->UseColors = old_tex->UseColors; IMGUI_DEBUG_LOG_FONT("[font] Texture #%03d: resize+repack %dx%d => Texture #%03d: %dx%d\n", old_tex->UniqueID, old_tex->Width, old_tex->Height, new_tex->UniqueID, new_tex->Width, new_tex->Height); //for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) @@ -3995,7 +3995,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) builder->Rects.swap(old_rects); builder->RectsIndex = old_index; ImFontAtlasBuildSetTexture(atlas, old_tex); - ImFontAtlasBuildGrowTexture(atlas, w, h); // Recurse + ImFontAtlasTextureGrow(atlas, w, h); // Recurse return; } IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder->RectsIndex.index_from_ptr(&index_entry)); @@ -4027,7 +4027,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h) //ImFontAtlasDebugWriteTexToDisk(new_tex, "After Pack"); } -void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_h) +void ImFontAtlasTextureGrow(ImFontAtlas* atlas, int old_tex_w, int old_tex_h) { //ImFontAtlasDebugWriteTexToDisk(atlas->TexData, "Before Grow"); ImFontAtlasBuilder* builder = atlas->Builder; @@ -4056,10 +4056,10 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_ if (new_tex_w == old_tex_w && new_tex_h == old_tex_h) return; - ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h); + ImFontAtlasTextureRepack(atlas, new_tex_w, new_tex_h); } -void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) +void ImFontAtlasTextureMakeSpace(ImFontAtlas* atlas) { // Can some baked contents be ditched? //IMGUI_DEBUG_LOG_FONT("[font] ImFontAtlasBuildMakeSpace()\n"); @@ -4068,12 +4068,12 @@ void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas) // Currently using a heuristic for repack without growing. if (builder->RectsDiscardedSurface < builder->RectsPackedSurface * 0.20f) - ImFontAtlasBuildGrowTexture(atlas); + ImFontAtlasTextureGrow(atlas); else - ImFontAtlasBuildRepackTexture(atlas, atlas->TexData->Width, atlas->TexData->Height); + ImFontAtlasTextureRepack(atlas, atlas->TexData->Width, atlas->TexData->Height); } -ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) +ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas) { int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth); int min_h = ImUpperPowerOfTwo(atlas->TexMinHeight); @@ -4110,26 +4110,26 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas) // Clear all output. Invalidates all AddCustomRect() return values! void ImFontAtlasBuildClear(ImFontAtlas* atlas) { - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); + ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas); ImFontAtlasBuildDestroy(atlas); - ImFontAtlasBuildAddTexture(atlas, new_tex_size.x, new_tex_size.y); + ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y); ImFontAtlasBuildInit(atlas); } // You should not need to call this manually! // If you think you do, let us know and we can advise about policies auto-compact. -void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas) +void ImFontAtlasTextureCompact(ImFontAtlas* atlas) { ImFontAtlasBuilder* builder = atlas->Builder; ImFontAtlasBuildDiscardBakes(atlas, 1); ImTextureData* old_tex = atlas->TexData; ImVec2i old_tex_size = ImVec2i(old_tex->Width, old_tex->Height); - ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas); + ImVec2i new_tex_size = ImFontAtlasTextureGetSizeEstimate(atlas); if (builder->RectsDiscardedCount == 0 && new_tex_size.x == old_tex_size.x && new_tex_size.y == old_tex_size.y) return; - ImFontAtlasBuildRepackTexture(atlas, new_tex_size.x, new_tex_size.y); + ImFontAtlasTextureRepack(atlas, new_tex_size.x, new_tex_size.y); } // Start packing over current empty texture @@ -4153,7 +4153,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) // Create initial texture size if (atlas->TexData == NULL || atlas->TexData->Pixels == NULL) - ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); + ImFontAtlasTextureAdd(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight)); atlas->Builder = IM_NEW(ImFontAtlasBuilder)(); if (atlas->FontLoader->LoaderInit) @@ -4170,7 +4170,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) // Register fonts ImFontAtlasBuildUpdatePointers(atlas); for (ImFontConfig& cfg : atlas->Sources) - ImFontAtlasBuildAddFont(atlas, &cfg); + ImFontAtlasFontInitSource(atlas, &cfg); // Update UV coordinates etc. stored in bound ImDrawListSharedData instance ImFontAtlasUpdateDrawListsSharedData(atlas); @@ -4182,7 +4182,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) void ImFontAtlasBuildDestroy(ImFontAtlas* atlas) { for (ImFont* font : atlas->Fonts) - ImFontAtlasBuildDestroyFontOutput(atlas, font); + ImFontAtlasFontDestroyOutput(atlas, font); if (atlas->Builder && atlas->FontLoader && atlas->FontLoader->LoaderShutdown) { atlas->FontLoader->LoaderShutdown(atlas); @@ -4299,7 +4299,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon } // Resize or repack atlas! (this should be a rare event) - ImFontAtlasBuildMakeSpace(atlas); + ImFontAtlasTextureMakeSpace(atlas); } builder->MaxRectBounds.x = ImMax(builder->MaxRectBounds.x, r.x + r.w + pack_padding); @@ -4992,7 +4992,7 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { if (ImFontAtlas* atlas = ContainerAtlas) - ImFontAtlasBuildDiscardFontBakes(atlas, this); + ImFontAtlasFontDiscardOutputBakes(atlas, this); FallbackChar = EllipsisChar = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); LastBaked = NULL; @@ -5197,7 +5197,7 @@ ImFontBaked* ImFont::GetFontBaked(float size) ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; - baked = ImFontAtlasBuildGetFontBaked(atlas, this, size); + baked = ImFontAtlasBakedGetOrAdd(atlas, this, size); if (baked == NULL) return NULL; baked->LastUsedFrame = builder->FrameCount; @@ -5205,7 +5205,7 @@ ImFontBaked* ImFont::GetFontBaked(float size) return baked; } -ImFontBaked* ImFontAtlasBuildGetFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size) +ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size) { // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria? // FIXME-NEWATLAS: Altering font density won't work right away. @@ -5223,7 +5223,7 @@ ImFontBaked* ImFontAtlasBuildGetFontBaked(ImFontAtlas* atlas, ImFont* font, floa // FIXME-OPT: This is not an optimal query. if ((font->Flags & ImFontFlags_LockBakedSizes) || atlas->Locked) { - baked = ImFontAtlasBuildGetClosestFontBakedMatch(atlas, font, font_size); + baked = ImFontAtlasBakedGetClosestMatch(atlas, font, font_size); if (baked != NULL) return baked; if (atlas->Locked) @@ -5234,7 +5234,7 @@ ImFontBaked* ImFontAtlasBuildGetFontBaked(ImFontAtlas* atlas, ImFont* font, floa } // Create new - baked = ImFontAtlasBuildAddFontBaked(atlas, font, font_size, baked_id); + baked = ImFontAtlasBakedAdd(atlas, font, font_size, baked_id); *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can. return baked; } diff --git a/imgui_internal.h b/imgui_internal.h index 137ba7d46660..3274940c0ed8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3772,32 +3772,32 @@ IMGUI_API void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char); IMGUI_API void ImFontAtlasBuildClear(ImFontAtlas* atlas); // Clear output and custom rects -IMGUI_API ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h); -IMGUI_API void ImFontAtlasBuildMakeSpace(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h); -IMGUI_API void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); -IMGUI_API void ImFontAtlasBuildCompactTexture(ImFontAtlas* atlas); -IMGUI_API ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas); - -IMGUI_API bool ImFontAtlasBuildAddFont(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h); +IMGUI_API void ImFontAtlasTextureMakeSpace(ImFontAtlas* atlas); +IMGUI_API void ImFontAtlasTextureRepack(ImFontAtlas* atlas, int w, int h); +IMGUI_API void ImFontAtlasTextureGrow(ImFontAtlas* atlas, int old_w = -1, int old_h = -1); +IMGUI_API void ImFontAtlasTextureCompact(ImFontAtlas* atlas); +IMGUI_API ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas); + IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); -IMGUI_API bool ImFontAtlasBuildInitFontOutput(ImFontAtlas* atlas, ImFont* font); // Using DestroyFontOutput/InitFontOutput sequence useful notably if font loader params have changed -IMGUI_API void ImFontAtlasBuildDestroyFontOutput(ImFontAtlas* atlas, ImFont* font); -IMGUI_API void ImFontAtlasBuildDestroyFontSourceData(ImFontAtlas* atlas, ImFontConfig* src); - -IMGUI_API ImFontBaked* ImFontAtlasBuildGetFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size); -IMGUI_API ImFontBaked* ImFontAtlasBuildAddFontBaked(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); -IMGUI_API ImFontBaked* ImFontAtlasBuildGetClosestFontBakedMatch(ImFontAtlas* atlas, ImFont* font, float font_size); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); -IMGUI_API void ImFontAtlasBuildDiscardFontBakes(ImFontAtlas* atlas, ImFont* font); -IMGUI_API void ImFontAtlasBuildDiscardFontBaked(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); -IMGUI_API void ImFontAtlasBuildDiscardFontBakedGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); +IMGUI_API bool ImFontAtlasFontInitSource(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font); // Using FontDestroyOutput/FontInitOutput sequence useful notably if font loader params have changed +IMGUI_API void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font); +IMGUI_API void ImFontAtlasFontDiscardOutputBakes(ImFontAtlas* atlas, ImFont* font); + +IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); +IMGUI_API ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size); +IMGUI_API ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size); +IMGUI_API ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); +IMGUI_API void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); +IMGUI_API void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); -IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas); IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL); From e7efe94fd2fe8c8707ad2692083f26c64062b624 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 22 Apr 2025 17:56:00 +0200 Subject: [PATCH 558/716] Fonts: shallow rework of ImFontAtlasBakedAddFontGlyph() to facilitate upcoming change. --- imgui.h | 2 +- imgui_draw.cpp | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/imgui.h b/imgui.h index f99eaedd3365..b63b0ed4e548 100644 --- a/imgui.h +++ b/imgui.h @@ -3479,7 +3479,7 @@ struct ImFontConfig }; // Hold rendering data for one glyph. -// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) +// (Note: some language parsers may fail to convert the bitfield members, in this case maybe drop store a single u32 or we can rework this) struct ImFontGlyph { unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 40ae02ed524d..c311b18afed8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5013,23 +5013,23 @@ bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last) // x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero. // Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis). -// 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. +// - 'src' is not necessarily == 'this->Sources' because multiple source fonts+configs can be used to build one target font. ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph) { int glyph_idx = baked->Glyphs.Size; baked->Glyphs.push_back(*in_glyph); - ImFontGlyph& glyph = baked->Glyphs[glyph_idx]; + ImFontGlyph* glyph = &baked->Glyphs[glyph_idx]; IM_ASSERT(baked->Glyphs.Size < 0xFFFE); // IndexLookup[] hold 16-bit values and -1/-2 are reserved. // Set UV from packed rectangle - if (glyph.PackId != ImFontAtlasRectId_Invalid) - { - ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph.PackId); - IM_ASSERT(glyph.U0 == 0.0f && glyph.V0 == 0.0f && glyph.U1 == 0.0f && glyph.V1 == 0.0f); - glyph.U0 = (r->x) * atlas->TexUvScale.x; - glyph.V0 = (r->y) * atlas->TexUvScale.y; - glyph.U1 = (r->x + r->w) * atlas->TexUvScale.x; - glyph.V1 = (r->y + r->h) * atlas->TexUvScale.y; + if (glyph->PackId != ImFontAtlasRectId_Invalid) + { + ImTextureRect* r = ImFontAtlasPackGetRect(atlas, glyph->PackId); + IM_ASSERT(glyph->U0 == 0.0f && glyph->V0 == 0.0f && glyph->U1 == 0.0f && glyph->V1 == 0.0f); + glyph->U0 = (r->x) * atlas->TexUvScale.x; + glyph->V0 = (r->y) * atlas->TexUvScale.y; + glyph->U1 = (r->x + r->w) * atlas->TexUvScale.x; + glyph->V1 = (r->y + r->h) * atlas->TexUvScale.y; baked->MetricsTotalSurface += r->w * r->h; } @@ -5037,12 +5037,12 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked { // Clamp & recenter if needed const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; - float advance_x = ImClamp(glyph.AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); - if (advance_x != glyph.AdvanceX) + float advance_x = ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); + if (advance_x != glyph->AdvanceX) { - float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph.AdvanceX) * 0.5f) : (advance_x - glyph.AdvanceX) * 0.5f; - glyph.X0 += char_off_x; - glyph.X1 += char_off_x; + float char_off_x = src->PixelSnapH ? ImTrunc((advance_x - glyph->AdvanceX) * 0.5f) : (advance_x - glyph->AdvanceX) * 0.5f; + glyph->X0 += char_off_x; + glyph->X1 += char_off_x; } // Snap to pixel @@ -5050,20 +5050,20 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked advance_x = IM_ROUND(advance_x); // Bake spacing - glyph.AdvanceX = advance_x + src->GlyphExtraAdvanceX; + glyph->AdvanceX = advance_x + src->GlyphExtraAdvanceX; } - if (glyph.Colored) + if (glyph->Colored) atlas->TexPixelsUseColors = atlas->TexData->UseColors = true; // Update lookup tables - int codepoint = glyph.Codepoint; + const int codepoint = glyph->Codepoint; ImFontBaked_BuildGrowIndex(baked, codepoint + 1); - baked->IndexAdvanceX[codepoint] = glyph.AdvanceX; + baked->IndexAdvanceX[codepoint] = glyph->AdvanceX; baked->IndexLookup[codepoint] = (ImU16)glyph_idx; const int page_n = codepoint / 8192; baked->ContainerFont->Used8kPagesMap[page_n >> 3] |= 1 << (page_n & 7); - return &glyph; + return glyph; } // Copy to texture, post-process and queue update for backend From 2b0d49a9054d21bc5cea57a8b21b8a7e4c885b43 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Apr 2025 17:54:16 +0200 Subject: [PATCH 559/716] Fonts: make ImFont::Sources a vector. Later it should become a ImSpan<> --- imgui.cpp | 44 +++++++++---------- imgui.h | 5 +-- imgui_draw.cpp | 72 ++++++++++++++------------------ misc/freetype/imgui_freetype.cpp | 4 +- 4 files changed, 58 insertions(+), 67 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8f7c8fe62cd4..04cb11264b5e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16612,7 +16612,7 @@ void ImGui::DebugNodeFont(ImFont* font) ImGuiContext& g = *GImGui; ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; ImFontAtlas* atlas = font->ContainerAtlas; - bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->GetDebugName(), font->SourcesCount); + bool opened = TreeNode(font, "Font: \"%s\": %d sources(s)", font->GetDebugName(), font->Sources.Size); // Display preview text if (!opened) @@ -16652,28 +16652,30 @@ void ImGui::DebugNodeFont(ImFont* font) Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); Text("Ellipsis character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->EllipsisChar), font->EllipsisChar); - for (int src_n = 0; src_n < font->SourcesCount; src_n++) - if (ImFontConfig* src = &font->Sources[src_n]) - if (TreeNode(src, "Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", - src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y)) - { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; - Text("Loader: '%s'", loader->Name ? loader->Name : "N/A"); + for (int src_n = 0; src_n < font->Sources.Size; src_n++) + { + ImFontConfig* src = font->Sources[src_n]; + if (TreeNode(src, "Input %d: \'%s\', Oversample: %d,%d, PixelSnapH: %d, Offset: (%.1f,%.1f)", + src_n, src->Name, src->OversampleH, src->OversampleV, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y)) + { + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + Text("Loader: '%s'", loader->Name ? loader->Name : "N/A"); #ifdef IMGUI_ENABLE_FREETYPE - if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0) + if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0) + { + unsigned int loader_flags = src->FontBuilderFlags; + Text("FreeType Loader Flags: 0x%08X", loader_flags); + if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) { - unsigned int loader_flags = src->FontBuilderFlags; - Text("FreeType Loader Flags: 0x%08X", loader_flags); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) - { - ImFontAtlasFontDestroyOutput(atlas, font); - src->FontBuilderFlags = loader_flags; - ImFontAtlasFontInitOutput(atlas, font); - } + ImFontAtlasFontDestroyOutput(atlas, font); + src->FontBuilderFlags = loader_flags; + ImFontAtlasFontInitOutput(atlas, font); } -#endif - TreePop(); } +#endif + TreePop(); + } + } // Display all glyphs of the fonts in separate pages of 256 characters for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++) @@ -16691,9 +16693,9 @@ void ImGui::DebugNodeFont(ImFont* font) const int surface_sqrt = (int)ImSqrt((float)baked->MetricsTotalSurface); Text("Ascent: %f, Descent: %f, Ascent-Descent: %f", baked->Ascent, baked->Descent, baked->Ascent - baked->Descent); Text("Texture Area: about %d px ~%dx%d px", baked->MetricsTotalSurface, surface_sqrt, surface_sqrt); - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + for (int src_n = 0; src_n < font->Sources.Size; src_n++) { - ImFontConfig* src = &font->Sources[src_n]; + ImFontConfig* src = font->Sources[src_n]; int oversample_h, oversample_v; ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v); BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", diff --git a/imgui.h b/imgui.h index b63b0ed4e548..005c9c01b2dd 100644 --- a/imgui.h +++ b/imgui.h @@ -3759,8 +3759,7 @@ struct ImFont // Conceptually Sources[] is the list of font sources merged to create this font. ImGuiID FontId; // Unique identifier for the font float DefaultSize; // 4 // in // Default font size - short SourcesCount; // 2 // in // Number of ImFontConfig involved in creating this font. Usually 1, or >1 when merging multiple font sources into one ImFont. - ImFontConfig* Sources; // 4-8 // in // Pointer within ContainerAtlas->Sources[], to SourcesCount instances + ImVector Sources; // 16 // in // List of sources. Pointers within ContainerAtlas->Sources[] ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() @@ -3773,7 +3772,7 @@ struct ImFont IMGUI_API ImFontBaked* GetFontBaked(float font_size); // Get or create baked data for given size IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } - const char* GetDebugName() const { return Sources ? Sources[0].Name : ""; } // Fill ImFontConfig::Name. + const char* GetDebugName() const { return Sources.Size ? Sources[0]->Name : ""; } // Fill ImFontConfig::Name. // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c311b18afed8..30bdba58c451 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2657,8 +2657,7 @@ void ImFontAtlas::ClearInputData() for (ImFont* font : Fonts) { // When clearing this we lose access to the font name and other information used to build the font. - font->Sources = NULL; - font->SourcesCount = 0; + font->Sources.clear(); font->Flags |= ImFontFlags_NoLoadGlyphs; } Sources.clear(); @@ -3027,14 +3026,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) IM_ASSERT(font_cfg->FontLoaderData == NULL); // Pointers to Sources are otherwise dangling - font->SourcesCount++; + font->Sources.push_back(font_cfg); ImFontAtlasBuildUpdatePointers(this); if (!ImFontAtlasFontInitSource(this, font_cfg)) { // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) ImFontAtlasFontDestroySourceData(this, font_cfg); Sources.pop_back(); - font->SourcesCount--; + font->Sources.pop_back(); if (!font_cfg->MergeMode) { IM_DELETE(font); @@ -3185,14 +3184,16 @@ void ImFontAtlas::RemoveFont(ImFont* font) font->ClearOutputData(); ImFontAtlasFontDestroyOutput(this, font); - for (int src_n = 0; src_n < font->SourcesCount; src_n++) - ImFontAtlasFontDestroySourceData(this, &font->Sources[src_n]); + for (ImFontConfig* src : font->Sources) + { + ImFontAtlasFontDestroySourceData(this, src); + Sources.erase(src); + } bool removed = Fonts.find_erase(font); IM_ASSERT(removed); IM_UNUSED(removed); - Sources.erase(font->Sources, font->Sources + font->SourcesCount); ImFontAtlasBuildUpdatePointers(this); font->ContainerAtlas = NULL; @@ -3278,7 +3279,7 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float glyph.Visible = true; glyph.Colored = true; // FIXME: Arbitrary glyph.PackId = r_id; - ImFontAtlasBakedAddFontGlyph(this, baked, &font->Sources[0], &glyph); + ImFontAtlasBakedAddFontGlyph(this, baked, font->Sources[0], &glyph); return r_id; } #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS @@ -3382,15 +3383,13 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) atlas->Builder->PreloadedAllGlyphsRanges = true; for (ImFont* font : atlas->Fonts) { - ImFontConfig* src = &font->Sources[0]; - ImFontBaked* baked = font->GetFontBaked(src->SizePixels); + ImFontBaked* baked = font->GetFontBaked(font->Sources[0]->SizePixels); if (font->FallbackChar != 0) baked->FindGlyph(font->FallbackChar); if (font->EllipsisChar != 0) baked->FindGlyph(font->EllipsisChar); - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + for (ImFontConfig* src : font->Sources) { - src = &font->Sources[src_n]; const ImWchar* ranges = src->GlyphRanges ? src->GlyphRanges : atlas->GetGlyphRangesDefault(); for (; ranges[0]; ranges += 2) for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560 @@ -3399,15 +3398,13 @@ void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) } } +// FIXME: May make ImFont::Sources a ImSpan<> and move ownership to ImFontAtlas void ImFontAtlasBuildUpdatePointers(ImFontAtlas* atlas) { - for (int src_n = 0; src_n < atlas->Sources.Size; src_n++) - { - ImFontConfig* src = &atlas->Sources[src_n]; - ImFont* font = src->DstFont; - if (!src->MergeMode) - font->Sources = src; - } + for (ImFont* font : atlas->Fonts) + font->Sources.resize(0); + for (ImFontConfig& src : atlas->Sources) + src.DstFont->Sources.push_back(&src); } // Render a white-colored bitmap encoded in a string @@ -3542,9 +3539,8 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas) bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font) { bool ret = true; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + for (ImFontConfig* src : font->Sources) { - ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader && loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) ret = false; @@ -3557,9 +3553,8 @@ bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font) void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font) { font->ClearOutputData(); - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + for (ImFontConfig* src : font->Sources) { - ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader && loader->FontSrcDestroy != NULL) loader->FontSrcDestroy(atlas, src); @@ -3576,7 +3571,7 @@ bool ImFontAtlasFontInitSource(ImFontAtlas* atlas, ImFontConfig* src) font->ClearOutputData(); //font->FontSize = src->SizePixels; font->ContainerAtlas = atlas; - IM_ASSERT(font->Sources == src); + IM_ASSERT(font->Sources[0] == src); } const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; @@ -3688,10 +3683,8 @@ static void ImFontAtlasBuildSetupFontBakedBlanks(ImFontAtlas* atlas, ImFontBaked // (note that this is called again for fonts with MergeMode) void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) { - const int src_idx_in_font = (int)(src - font->Sources); - IM_ASSERT(src_idx_in_font >= 0 && src_idx_in_font < font->SourcesCount); IM_UNUSED(atlas); - IM_UNUSED(src_idx_in_font); + IM_ASSERT(font->Sources.contains(src)); // Find Fallback character. Actual glyph loaded in GetFontBaked(). const ImWchar fallback_chars[] = { font->FallbackChar, (ImWchar)IM_UNICODE_CODEPOINT_INVALID, (ImWchar)'?', (ImWchar)' ' }; @@ -3747,17 +3740,15 @@ ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_si // Initialize backend data size_t loader_data_size = 0; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) // Cannot easily be cached as we allow changing backend + for (ImFontConfig* src : font->Sources) // Cannot easily be cached as we allow changing backend { - ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; loader_data_size += loader->FontBakedSrcLoaderDataSize; } baked->FontLoaderDatas = (loader_data_size > 0) ? IM_ALLOC(loader_data_size) : NULL; char* loader_data_p = (char*)baked->FontLoaderDatas; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + for (ImFontConfig* src : font->Sources) { - ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontBakedInit) loader->FontBakedInit(atlas, src, baked, loader_data_p); @@ -3802,9 +3793,8 @@ void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* bake ImFontAtlasPackDiscardRect(atlas, glyph.PackId); char* loader_data_p = (char*)baked->FontLoaderDatas; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + for (ImFontConfig* src : font->Sources) { - ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontBakedDestroy) loader->FontBakedDestroy(atlas, src, baked, loader_data_p); @@ -4384,9 +4374,9 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep // Call backend char* loader_user_data_p = (char*)baked->FontLoaderDatas; - for (int src_n = 0; src_n < font->SourcesCount; src_n++) + int src_n = 0; + for (ImFontConfig* src : font->Sources) { - ImFontConfig* src = &font->Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) if (ImFontGlyph* glyph = loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint)) @@ -4396,6 +4386,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep return glyph; } loader_user_data_p += loader->FontBakedSrcLoaderDataSize; + src_n++; } // Lazily load fallback glyph @@ -4491,8 +4482,8 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else bd_font_data->ScaleFactor = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); - if (src > src->DstFont->Sources) - bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0].SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit + if (src != src->DstFont->Sources[0]) + bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit return true; } @@ -4594,7 +4585,7 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, if (oversample_v > 1) stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v); - const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; + const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; float font_off_x = (src->GlyphOffset.x * offsets_scale); float font_off_y = (src->GlyphOffset.y * offsets_scale); if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. @@ -5036,7 +5027,7 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked if (src != NULL) { // Clamp & recenter if needed - const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; + const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; float advance_x = ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); if (advance_x != glyph->AdvanceX) { @@ -5147,9 +5138,8 @@ bool ImFontBaked::IsGlyphLoaded(ImWchar c) bool ImFont::IsGlyphInFont(ImWchar c) { ImFontAtlas* atlas = ContainerAtlas; - for (int src_n = 0; src_n < SourcesCount; src_n++) + for (ImFontConfig* src : Sources) { - ImFontConfig* src = &Sources[src_n]; const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (loader->FontSrcContainsGlyph != NULL && loader->FontSrcContainsGlyph(atlas, src, c)) return true; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 5151a90d5991..b4263fc82e3f 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -436,7 +436,7 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { IM_UNUSED(atlas); - const float size = baked->Size * (src->SizePixels / baked->ContainerFont->Sources[0].SizePixels); // FIXME-NEWATLAS: Should tidy up that a bit + const float size = baked->Size * (src->SizePixels / baked->ContainerFont->Sources[0]->SizePixels); // FIXME-NEWATLAS: Should tidy up that a bit ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; bd_font_data->BakedLastActivated = baked; @@ -541,7 +541,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data; bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w); - const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0].SizePixels; + const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; float font_off_x = (src->GlyphOffset.x * offsets_scale); float font_off_y = (src->GlyphOffset.y * offsets_scale) + baked->Ascent; if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. From 5310f5fba347d32572206fe80439314507c90ab1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 24 Apr 2025 18:27:55 +0200 Subject: [PATCH 560/716] Fonts: rework toward reducing reliance on ImFontConfig::DstFont since we ought to separate them. --- imgui_draw.cpp | 35 +++++++++++++++++++++-------------- imgui_internal.h | 3 ++- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 30bdba58c451..7bb6ae108df7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2998,10 +2998,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) font = Fonts.back(); } + // Add to list Sources.push_back(*font_cfg_in); ImFontConfig* font_cfg = &Sources.back(); if (font_cfg->DstFont == NULL) font_cfg->DstFont = font; + font->Sources.push_back(font_cfg); + ImFontAtlasBuildUpdatePointers(this); // Pointers to Sources are otherwise dangling after we called Sources.push_back(). + if (font_cfg->FontDataOwnedByAtlas == false) { font_cfg->FontDataOwnedByAtlas = true; @@ -3025,10 +3029,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) } IM_ASSERT(font_cfg->FontLoaderData == NULL); - // Pointers to Sources are otherwise dangling - font->Sources.push_back(font_cfg); - ImFontAtlasBuildUpdatePointers(this); - if (!ImFontAtlasFontInitSource(this, font_cfg)) + if (!ImFontAtlasFontSourceInit(this, font_cfg)) { // Rollback (this is a fragile/rarely exercised code-path. TestSuite's "misc_atlas_add_invalid_font" aim to test this) ImFontAtlasFontDestroySourceData(this, font_cfg); @@ -3041,6 +3042,8 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) } return NULL; } + ImFontAtlasFontSourceAddToFont(this, font, font_cfg); + return font; } @@ -3563,9 +3566,16 @@ void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font) //----------------------------------------------------------------------------------------------------------------------------- -bool ImFontAtlasFontInitSource(ImFontAtlas* atlas, ImFontConfig* src) +bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src) +{ + const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; + if (loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) + return false; + return true; +} + +void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src) { - ImFont* font = src->DstFont; if (src->MergeMode == false) { font->ClearOutputData(); @@ -3573,14 +3583,8 @@ bool ImFontAtlasFontInitSource(ImFontAtlas* atlas, ImFontConfig* src) font->ContainerAtlas = atlas; IM_ASSERT(font->Sources[0] == src); } - - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; - if (loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) - return false; - atlas->TexIsBuilt = false; // For legacy backends ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, font, src); - return true; } void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src) @@ -4104,6 +4108,11 @@ void ImFontAtlasBuildClear(ImFontAtlas* atlas) ImFontAtlasBuildDestroy(atlas); ImFontAtlasTextureAdd(atlas, new_tex_size.x, new_tex_size.y); ImFontAtlasBuildInit(atlas); + for (ImFontConfig& src : atlas->Sources) + ImFontAtlasFontSourceInit(atlas, &src); + for (ImFont* font : atlas->Fonts) + for (ImFontConfig* src : font->Sources) + ImFontAtlasFontSourceAddToFont(atlas, font, src); } // You should not need to call this manually! @@ -4159,8 +4168,6 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) // Register fonts ImFontAtlasBuildUpdatePointers(atlas); - for (ImFontConfig& cfg : atlas->Sources) - ImFontAtlasFontInitSource(atlas, &cfg); // Update UV coordinates etc. stored in bound ImDrawListSharedData instance ImFontAtlasUpdateDrawListsSharedData(atlas); diff --git a/imgui_internal.h b/imgui_internal.h index 3274940c0ed8..28e9074886b2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3784,7 +3784,8 @@ IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* a IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); -IMGUI_API bool ImFontAtlasFontInitSource(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src); +IMGUI_API void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font); // Using FontDestroyOutput/FontInitOutput sequence useful notably if font loader params have changed IMGUI_API void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font); From 6a455e1281535bc7d79eb40445892b7894fbbbac Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 26 Apr 2025 17:05:36 +0200 Subject: [PATCH 561/716] imgui_freetype: moving data out of ImGui_ImplFreeType_FontSrcData. The reasoning behind that we would ideally transition ImGui_ImplFreeType_FontSrcData to be shared between fonts using same source. --- misc/freetype/imgui_freetype.cpp | 45 +++++++++++++------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index b4263fc82e3f..a667f458d009 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -151,17 +151,11 @@ namespace ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } }; - // Stored in ImFontBaked::FontLoaderDatas: pointer to SourcesCount instances of this. ALLOCATED BY CORE. - struct ImGui_ImplFreeType_FontSrcBakedData - { - FT_Size FtSize; // This represent a FT_Face with a given size. - ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } - }; - // Stored in ImFontConfig::FontLoaderData. ALLOCATED BY US. struct ImGui_ImplFreeType_FontSrcData { - bool InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_user_flags); // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + bool InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_user_flags); void CloseFont(); const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch); @@ -170,15 +164,19 @@ namespace // Members FT_Face FtFace; - unsigned int UserFlags; // = ImFontConfig::RasterizerFlags + ImGuiFreeTypeBuilderFlags UserFlags; // = ImFontConfig::FontBuilderFlags FT_Int32 LoadFlags; - FT_Render_Mode RenderMode; - float RasterizationDensity; - float InvRasterizationDensity; ImFontBaked* BakedLastActivated; }; - bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, unsigned int extra_font_builder_flags) + // Stored in ImFontBaked::FontLoaderDatas: pointer to SourcesCount instances of this. ALLOCATED BY CORE. + struct ImGui_ImplFreeType_FontSrcBakedData + { + FT_Size FtSize; // This represent a FT_Face with a given size. + ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } + }; + + bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_font_builder_flags) { FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (uint32_t)src->FontDataSize, (uint32_t)src->FontNo, &FtFace); if (error != 0) @@ -188,7 +186,7 @@ namespace return false; // Convert to FreeType flags (NB: Bold and Oblique are processed separately) - UserFlags = src->FontBuilderFlags | extra_font_builder_flags; + UserFlags = (ImGuiFreeTypeBuilderFlags)(src->FontBuilderFlags | extra_font_builder_flags); LoadFlags = 0; if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) @@ -210,17 +208,9 @@ namespace else LoadFlags |= FT_LOAD_TARGET_NORMAL; - if (UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome) - RenderMode = FT_RENDER_MODE_MONO; - else - RenderMode = FT_RENDER_MODE_NORMAL; - if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) LoadFlags |= FT_LOAD_COLOR; - RasterizationDensity = src->RasterizerDensity; - InvRasterizationDensity = 1.0f / RasterizationDensity; - return true; } @@ -415,7 +405,7 @@ bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) IM_ASSERT(src->FontLoaderData == NULL); src->FontLoaderData = bd_font_data; - if (!bd_font_data->InitFont(bd->Library, src, atlas->FontBuilderFlags)) + if (!bd_font_data->InitFont(bd->Library, src, (ImGuiFreeTypeBuilderFlags)atlas->FontBuilderFlags)) { IM_DELETE(bd_font_data); src->FontLoaderData = NULL; @@ -456,7 +446,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF FT_Size_RequestRec req; req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; - req.height = (uint32_t)(size * 64 * bd_font_data->RasterizationDensity); + req.height = (uint32_t)(size * 64 * src->RasterizerDensity); req.horiResolution = 0; req.vertResolution = 0; FT_Request_Size(bd_font_data->FtFace, &req); @@ -466,7 +456,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF { // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; - const float scale = bd_font_data->InvRasterizationDensity; + const float scale = 1.0f / src->RasterizerDensity; baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. @@ -509,7 +499,8 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon // Render glyph into a bitmap (currently held by FreeType) FT_Face face = bd_font_data->FtFace; FT_GlyphSlot slot = face->glyph; - FT_Error error = FT_Render_Glyph(slot, bd_font_data->RenderMode); + FT_Render_Mode render_mode = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome) ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL; + FT_Error error = FT_Render_Glyph(slot, render_mode); const FT_Bitmap* ft_bitmap = &slot->bitmap; if (error != 0 || ft_bitmap == nullptr) return NULL; @@ -522,7 +513,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon ImFontGlyph glyph_in = {}; ImFontGlyph* glyph = &glyph_in; glyph->Codepoint = codepoint; - glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) * bd_font_data->InvRasterizationDensity; + glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) / src->RasterizerDensity; // Pack and retrieve position inside texture atlas if (is_visible) From 42e7bb80b642b48c7a5c54775be3bec19bac571b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 26 Apr 2025 17:24:38 +0200 Subject: [PATCH 562/716] imgui_freetype: removed anonymous namespace + extracting two functions outside of ImGui_ImplFreeType_FontSrcData. --- misc/freetype/imgui_freetype.cpp | 361 +++++++++++++++---------------- 1 file changed, 178 insertions(+), 183 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index a667f458d009..8ad2d6ceaf59 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -110,210 +110,205 @@ static FT_Error ImGuiLunasvgPortPresetSlot(FT_GlyphSlot slot, FT_Bool cache, FT_ #define FT_CEIL(X) (((X + 63) & -64) / 64) // From SDL_ttf: Handy routines for converting from fixed point #define FT_SCALEFACTOR 64.0f -namespace +// Glyph metrics: +// -------------- +// +// xmin xmax +// | | +// |<-------- width -------->| +// | | +// | +-------------------------+----------------- ymax +// | | ggggggggg ggggg | ^ ^ +// | | g:::::::::ggg::::g | | | +// | | g:::::::::::::::::g | | | +// | | g::::::ggggg::::::gg | | | +// | | g:::::g g:::::g | | | +// offsetX -|-------->| g:::::g g:::::g | offsetY | +// | | g:::::g g:::::g | | | +// | | g::::::g g:::::g | | | +// | | g:::::::ggggg:::::g | | | +// | | g::::::::::::::::g | | height +// | | gg::::::::::::::g | | | +// baseline ---*---------|---- gggggggg::::::g-----*-------- | +// / | | g:::::g | | +// origin | | gggggg g:::::g | | +// | | g:::::gg gg:::::g | | +// | | g::::::ggg:::::::g | | +// | | gg:::::::::::::g | | +// | | ggg::::::ggg | | +// | | gggggg | v +// | +-------------------------+----------------- ymin +// | | +// |------------- advanceX ----------->| + +// Stored in ImFontAtlas::FontLoaderData. ALLOCATED BY US. +struct ImGui_ImplFreeType_Data { - // Glyph metrics: - // -------------- - // - // xmin xmax - // | | - // |<-------- width -------->| - // | | - // | +-------------------------+----------------- ymax - // | | ggggggggg ggggg | ^ ^ - // | | g:::::::::ggg::::g | | | - // | | g:::::::::::::::::g | | | - // | | g::::::ggggg::::::gg | | | - // | | g:::::g g:::::g | | | - // offsetX -|-------->| g:::::g g:::::g | offsetY | - // | | g:::::g g:::::g | | | - // | | g::::::g g:::::g | | | - // | | g:::::::ggggg:::::g | | | - // | | g::::::::::::::::g | | height - // | | gg::::::::::::::g | | | - // baseline ---*---------|---- gggggggg::::::g-----*-------- | - // / | | g:::::g | | - // origin | | gggggg g:::::g | | - // | | g:::::gg gg:::::g | | - // | | g::::::ggg:::::::g | | - // | | gg:::::::::::::g | | - // | | ggg::::::ggg | | - // | | gggggg | v - // | +-------------------------+----------------- ymin - // | | - // |------------- advanceX ----------->| - - // Stored in ImFontAtlas::FontLoaderData. ALLOCATED BY US. - struct ImGui_ImplFreeType_Data - { - FT_Library Library; - FT_MemoryRec_ MemoryManager; - ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } - }; + FT_Library Library; + FT_MemoryRec_ MemoryManager; + ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } +}; - // Stored in ImFontConfig::FontLoaderData. ALLOCATED BY US. - struct ImGui_ImplFreeType_FontSrcData - { - // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. - bool InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_user_flags); - void CloseFont(); - const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); - void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch); - ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); } - ~ImGui_ImplFreeType_FontSrcData() { CloseFont(); } - - // Members - FT_Face FtFace; - ImGuiFreeTypeBuilderFlags UserFlags; // = ImFontConfig::FontBuilderFlags - FT_Int32 LoadFlags; - ImFontBaked* BakedLastActivated; - }; - - // Stored in ImFontBaked::FontLoaderDatas: pointer to SourcesCount instances of this. ALLOCATED BY CORE. - struct ImGui_ImplFreeType_FontSrcBakedData - { - FT_Size FtSize; // This represent a FT_Face with a given size. - ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } - }; +// Stored in ImFontConfig::FontLoaderData. ALLOCATED BY US. +struct ImGui_ImplFreeType_FontSrcData +{ + // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. + bool InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_user_flags); + void CloseFont(); + ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); } + ~ImGui_ImplFreeType_FontSrcData() { CloseFont(); } + + // Members + FT_Face FtFace; + ImGuiFreeTypeBuilderFlags UserFlags; // = ImFontConfig::FontBuilderFlags + FT_Int32 LoadFlags; + ImFontBaked* BakedLastActivated; +}; - bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_font_builder_flags) - { - FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (uint32_t)src->FontDataSize, (uint32_t)src->FontNo, &FtFace); - if (error != 0) - return false; - error = FT_Select_Charmap(FtFace, FT_ENCODING_UNICODE); - if (error != 0) - return false; - - // Convert to FreeType flags (NB: Bold and Oblique are processed separately) - UserFlags = (ImGuiFreeTypeBuilderFlags)(src->FontBuilderFlags | extra_font_builder_flags); - - LoadFlags = 0; - if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) - LoadFlags |= FT_LOAD_NO_BITMAP; - - if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting) - LoadFlags |= FT_LOAD_NO_HINTING; - else - src->PixelSnapH = true; // FIXME: A bit weird to do this this way. - - if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint) - LoadFlags |= FT_LOAD_NO_AUTOHINT; - if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint) - LoadFlags |= FT_LOAD_FORCE_AUTOHINT; - if (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting) - LoadFlags |= FT_LOAD_TARGET_LIGHT; - else if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting) - LoadFlags |= FT_LOAD_TARGET_MONO; - else - LoadFlags |= FT_LOAD_TARGET_NORMAL; - - if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) - LoadFlags |= FT_LOAD_COLOR; - - return true; - } +// Stored in ImFontBaked::FontLoaderDatas: pointer to SourcesCount instances of this. ALLOCATED BY CORE. +struct ImGui_ImplFreeType_FontSrcBakedData +{ + FT_Size FtSize; // This represent a FT_Face with a given size. + ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } +}; + +bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_font_builder_flags) +{ + FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (uint32_t)src->FontDataSize, (uint32_t)src->FontNo, &FtFace); + if (error != 0) + return false; + error = FT_Select_Charmap(FtFace, FT_ENCODING_UNICODE); + if (error != 0) + return false; + + // Convert to FreeType flags (NB: Bold and Oblique are processed separately) + UserFlags = (ImGuiFreeTypeBuilderFlags)(src->FontBuilderFlags | extra_font_builder_flags); + + LoadFlags = 0; + if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) + LoadFlags |= FT_LOAD_NO_BITMAP; + + if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting) + LoadFlags |= FT_LOAD_NO_HINTING; + else + src->PixelSnapH = true; // FIXME: A bit weird to do this this way. + + if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint) + LoadFlags |= FT_LOAD_NO_AUTOHINT; + if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint) + LoadFlags |= FT_LOAD_FORCE_AUTOHINT; + if (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting) + LoadFlags |= FT_LOAD_TARGET_LIGHT; + else if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting) + LoadFlags |= FT_LOAD_TARGET_MONO; + else + LoadFlags |= FT_LOAD_TARGET_NORMAL; - void ImGui_ImplFreeType_FontSrcData::CloseFont() + if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) + LoadFlags |= FT_LOAD_COLOR; + + return true; +} + +void ImGui_ImplFreeType_FontSrcData::CloseFont() +{ + if (FtFace) { - if (FtFace) - { - FT_Done_Face(FtFace); - FtFace = nullptr; - } + FT_Done_Face(FtFace); + FtFace = nullptr; } +} - const FT_Glyph_Metrics* ImGui_ImplFreeType_FontSrcData::LoadGlyph(uint32_t codepoint) - { - uint32_t glyph_index = FT_Get_Char_Index(FtFace, codepoint); - if (glyph_index == 0) - return nullptr; - - // If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts. - // - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 - // - https://github.com/ocornut/imgui/issues/4567 - // - https://github.com/ocornut/imgui/issues/4566 - // You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version. - FT_Error error = FT_Load_Glyph(FtFace, glyph_index, LoadFlags); - if (error) - return nullptr; - - // Need an outline for this to work - FT_GlyphSlot slot = FtFace->glyph; +static const FT_Glyph_Metrics* ImGui_ImplFreeType_LoadGlyph(ImGui_ImplFreeType_FontSrcData* src_data, uint32_t codepoint) +{ + uint32_t glyph_index = FT_Get_Char_Index(src_data->FtFace, codepoint); + if (glyph_index == 0) + return nullptr; + + // If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts. + // - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076 + // - https://github.com/ocornut/imgui/issues/4567 + // - https://github.com/ocornut/imgui/issues/4566 + // You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version. + FT_Error error = FT_Load_Glyph(src_data->FtFace, glyph_index, src_data->LoadFlags); + if (error) + return nullptr; + + // Need an outline for this to work + FT_GlyphSlot slot = src_data->FtFace->glyph; #if defined(IMGUI_ENABLE_FREETYPE_LUNASVG) || defined(IMGUI_ENABLE_FREETYPE_PLUTOSVG) - IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); + IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP || slot->format == FT_GLYPH_FORMAT_SVG); #else #if ((FREETYPE_MAJOR >= 2) && (FREETYPE_MINOR >= 12)) - IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); + IM_ASSERT(slot->format != FT_GLYPH_FORMAT_SVG && "The font contains SVG glyphs, you'll need to enable IMGUI_ENABLE_FREETYPE_PLUTOSVG or IMGUI_ENABLE_FREETYPE_LUNASVG in imconfig.h and install required libraries in order to use this font"); #endif - IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); + IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE || slot->format == FT_GLYPH_FORMAT_BITMAP); #endif // IMGUI_ENABLE_FREETYPE_LUNASVG - // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) - if (UserFlags & ImGuiFreeTypeBuilderFlags_Bold) - FT_GlyphSlot_Embolden(slot); - if (UserFlags & ImGuiFreeTypeBuilderFlags_Oblique) - { - FT_GlyphSlot_Oblique(slot); - //FT_BBox bbox; - //FT_Outline_Get_BBox(&slot->outline, &bbox); - //slot->metrics.width = bbox.xMax - bbox.xMin; - //slot->metrics.height = bbox.yMax - bbox.yMin; - } - - return &slot->metrics; + // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) + if (src_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bold) + FT_GlyphSlot_Embolden(slot); + if (src_data->UserFlags & ImGuiFreeTypeBuilderFlags_Oblique) + { + FT_GlyphSlot_Oblique(slot); + //FT_BBox bbox; + //FT_Outline_Get_BBox(&slot->outline, &bbox); + //slot->metrics.width = bbox.xMax - bbox.xMin; + //slot->metrics.height = bbox.yMax - bbox.yMin; } - void ImGui_ImplFreeType_FontSrcData::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch) - { - IM_ASSERT(ft_bitmap != nullptr); - const uint32_t w = ft_bitmap->width; - const uint32_t h = ft_bitmap->rows; - const uint8_t* src = ft_bitmap->buffer; - const uint32_t src_pitch = ft_bitmap->pitch; + return &slot->metrics; +} - switch (ft_bitmap->pixel_mode) +static void ImGui_ImplFreeType_BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch) +{ + IM_ASSERT(ft_bitmap != nullptr); + const uint32_t w = ft_bitmap->width; + const uint32_t h = ft_bitmap->rows; + const uint8_t* src = ft_bitmap->buffer; + const uint32_t src_pitch = ft_bitmap->pitch; + + switch (ft_bitmap->pixel_mode) + { + case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel. { - case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel. - { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - for (uint32_t x = 0; x < w; x++) - dst[x] = IM_COL32(255, 255, 255, src[x]); - break; - } - case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB. + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + for (uint32_t x = 0; x < w; x++) + dst[x] = IM_COL32(255, 255, 255, src[x]); + break; + } + case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB. + { + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) { - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + uint8_t bits = 0; + const uint8_t* bits_ptr = src; + for (uint32_t x = 0; x < w; x++, bits <<= 1) { - uint8_t bits = 0; - const uint8_t* bits_ptr = src; - for (uint32_t x = 0; x < w; x++, bits <<= 1) - { - if ((x & 7) == 0) - bits = *bits_ptr++; - dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? 255 : 0); - } + if ((x & 7) == 0) + bits = *bits_ptr++; + dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? 255 : 0); } - break; } - case FT_PIXEL_MODE_BGRA: - { - // FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good. - #define DE_MULTIPLY(color, alpha) ImMin((ImU32)(255.0f * (float)color / (float)(alpha + FLT_MIN) + 0.5f), 255u) - for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - for (uint32_t x = 0; x < w; x++) - { - uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; - dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a); - } - #undef DE_MULTIPLY - break; - } - default: - IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!"); + break; } + case FT_PIXEL_MODE_BGRA: + { + // FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good. + #define DE_MULTIPLY(color, alpha) ImMin((ImU32)(255.0f * (float)color / (float)(alpha + FLT_MIN) + 0.5f), 255u) + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + for (uint32_t x = 0; x < w; x++) + { + uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; + dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a); + } + #undef DE_MULTIPLY + break; + } + default: + IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!"); } -} // namespace +} // FreeType memory allocation callbacks static void* FreeType_Alloc(FT_Memory /*memory*/, long size) @@ -492,7 +487,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon bd_font_data->BakedLastActivated = baked; } - const FT_Glyph_Metrics* metrics = bd_font_data->LoadGlyph(codepoint); + const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, codepoint); if (metrics == NULL) return NULL; @@ -530,7 +525,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon // Render pixels to our temporary buffer atlas->Builder->TempBuffer.resize(w * h * 4); uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data; - bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w); + ImGui_ImplFreeType_BlitGlyph(ft_bitmap, temp_buffer, w); const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; float font_off_x = (src->GlyphOffset.x * offsets_scale); From 8140a9d8a69951dd99ba3bc1bcac73350cec412c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Apr 2025 15:33:44 +0200 Subject: [PATCH 563/716] Fonts: comments on ImTextureData fields. --- imgui.cpp | 59 +++++++++++++++++++++++++++++++++++-------------------- imgui.h | 36 +++++++++++++++++---------------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 04cb11264b5e..6c6ead519b72 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -298,7 +298,7 @@ CODE // Any application code here ImGui::Text("Hello, world!"); - // Render dear imgui into screen + // Render dear imgui into framebuffer ImGui::Render(); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); g_pSwapChain->Present(1, 0); @@ -311,24 +311,14 @@ CODE EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE - // Application init: create a dear imgui context, setup some options, load fonts + // Application init: create a Dear ImGui context, setup some options, load fonts ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); - // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. - // TODO: Fill optional fields of the io structure later. - // TODO: Load TTF/OTF fonts if you don't want to use the default font. - - // Build and load the texture atlas into a texture - // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) - int width, height; - unsigned char* pixels = nullptr; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + // TODO: set io.ConfigXXX values, e.g. + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable keyboard controls - // At this point you've got the texture data and you need to upload that to your graphic system: - // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. - // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. - MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) - io.Fonts->SetTexID((void*)texture); + // TODO: Load TTF/OTF fonts if you don't want to use the default font. + io.Fonts->AddFontFromFileTTF("NotoSans.ttf", 18.0f); // Application main loop while (true) @@ -351,12 +341,19 @@ CODE MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); MyGameRender(); // may use any Dear ImGui functions as well! - // Render dear imgui, swap buffers + // End the dear imgui frame // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) - ImGui::EndFrame(); + ImGui::EndFrame(); // this is automatically called by Render(), but available ImGui::Render(); + + // Update textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->Status != ImTextureStatus_OK) + MyImGuiBackend_UpdateTexture(tex); + + // Render dear imgui contents, swap buffers ImDrawData* draw_data = ImGui::GetDrawData(); - MyImGuiRenderFunction(draw_data); + MyImGuiBackend_RenderDrawData(draw_data); SwapBuffers(); } @@ -367,12 +364,32 @@ CODE you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! Please read the FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" about this. - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE --------------------------------------------- The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. - void MyImGuiRenderFunction(ImDrawData* draw_data) + void MyImGuiBackend_UpdateTexture(ImTextureData* tex) + { + if (tex->Status == ImTextureStatus_WantCreate) + { + // create texture based on tex->Width/Height/Pixels + // call tex->SetTexID() to specify backend-specific identifiers + // tex->Status = ImTextureStatus_OK; + } + if (tex->Status == ImTextureStatus_WantUpdates) + { + // update texture blocks based on tex->UpdateRect + // tex->Status = ImTextureStatus_OK; + } + if (tex->Status == ImTextureStatus_WantDestroy) + { + // destroy texture + // call tex->SetTexID(ImTextureID_Invalid) + // tex->Status = ImTextureStatus_Destroyed; + } + } + + void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) { // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. diff --git a/imgui.h b/imgui.h index 005c9c01b2dd..e38cce77184d 100644 --- a/imgui.h +++ b/imgui.h @@ -3079,7 +3079,7 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c struct ImDrawCmd { ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates - ImTextureRef TexRef; // 16 // User-provided texture ID. Set by user in ImFontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + ImTextureRef TexRef; // 16 // Reference to a font/texture atlas (where backend called ImTextureData::SetTexID()) or to a user-provided texture ID (via e.g. ImGui::Image() calls). Both will lead to a ImTextureID value. unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. unsigned int IdxOffset; // 4 // Start offset in index buffer. unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. @@ -3403,24 +3403,26 @@ struct ImTextureRect // Why does we store two identifiers: TexID and BackendUserData? // - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. // - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. + // In columns below: who reads/writes each fields? 'r'=read, 'w'=write, 'core'=main library, 'backend'=renderer backend struct ImTextureData { - ImTextureStatus Status; // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! - ImTextureFormat Format; // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 - int Width; // Texture width - int Height; // Texture height - int BytesPerPixel; // 4 or 1 - int UniqueID; // Sequential index to facilitate identifying a texture when debugging/printing. Only unique per atlas. - unsigned char* Pixels; // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. - ImTextureID TexID; // Always use SetTexID() to modify! Identifier stored in ImDrawCmd::GetTexID() and passed to backend RenderDrawData loop. - void* BackendUserData; // Convenience storage for backend. Some backends may have enough with TexID. - ImTextureRect UsedRect; // Bounding box encompassing all past and queued Updates[]. - ImTextureRect UpdateRect; // Bounding box encompassing all queued Updates[]. - ImVector Updates; // Array of individual updates. - int UnusedFrames; // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. - unsigned short RefCount; // Number of contexts using this texture. - bool UseColors; // Tell whether our texture data is known to use colors (rather than just white + alpha). - bool WantDestroyNextFrame; // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. + //------------------------------------------ core / backend --------------------------------------- + int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. + ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! + void* BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID. + ImTextureID TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. + ImTextureFormat Format; // w r // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 + int Width; // w r // Texture width + int Height; // w r // Texture height + int BytesPerPixel; // w r // 4 or 1 + unsigned char* Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. + ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[]. + ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[]. + ImVector Updates; // w r // Array of individual updates. + int UnusedFrames; // w r // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. + unsigned short RefCount; // w r // Number of contexts using this texture. Used during backend shutdown. + bool UseColors; // w r // Tell whether our texture data is known to use colors (rather than just white + alpha). + bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. // Functions ImTextureData() { memset(this, 0, sizeof(*this)); } From b32ef3c05dab094995944b982cbb38328628ab2a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 30 Apr 2025 21:29:09 +0200 Subject: [PATCH 564/716] Fonts: make RasterizerDensity a dynamic field. (temporarily exposed as SetFontRasterizerDensity()). # Conflicts: # imgui.cpp # imgui.h --- imgui.cpp | 20 ++++++++++++---- imgui.h | 10 ++++---- imgui_draw.cpp | 40 ++++++++++++++++++-------------- imgui_internal.h | 13 +++++++---- misc/freetype/imgui_freetype.cpp | 12 ++++++---- 5 files changed, 60 insertions(+), 35 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 6c6ead519b72..68560fdb6ca7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3966,6 +3966,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Font = NULL; FontBaked = NULL; FontSize = FontSizeBeforeScaling = FontScale = CurrentDpiScale = 0.0f; + FontRasterizerDensity = 1.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); IO.Fonts->RefCount++; Time = 0.0f; @@ -8656,14 +8657,25 @@ void ImGui::UpdateCurrentFontSize() // - We may support it better later and remove this rounding. final_size = GetRoundedFontSize(final_size); final_size = ImMax(1.0f, final_size); - + if (g.Font != NULL) + g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; + g.FontBaked = (g.Font != NULL) ? g.Font->GetFontBaked(final_size) : NULL; g.FontSize = final_size; - g.FontBaked = (g.Font != NULL) ? g.Font->GetFontBaked(g.FontSize) : NULL; g.FontScale = (g.Font != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontScale; } +// FIXME-DPI: Not sure how to expose this. It may be automatically applied based on current viewport, if we had this information stored in viewport or monitor. +void ImGui::SetFontRasterizerDensity(float rasterizer_density) +{ + ImGuiContext& g = *GImGui; + if (g.FontRasterizerDensity == rasterizer_density) + return; + g.FontRasterizerDensity = rasterizer_density; + UpdateCurrentFontSize(); +} + void ImGui::PushFont(ImFont* font, float font_size) { ImGuiContext& g = *GImGui; @@ -16701,7 +16713,7 @@ void ImGui::DebugNodeFont(ImFont* font) if (baked->ContainerFont != font) continue; PushID(baked_n); - if (TreeNode("Glyphs", "Baked at %.2fpx: %d glyphs%s", baked->Size, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) + if (TreeNode("Glyphs", "Baked at { %.2fpx, d.%.1f }: %d glyphs%s", baked->Size, baked->RasterizerDensity, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) { if (SmallButton("Load all")) for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++) @@ -16714,7 +16726,7 @@ void ImGui::DebugNodeFont(ImFont* font) { ImFontConfig* src = font->Sources[src_n]; int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v); + ImFontAtlasBuildGetOversampleFactors(src, baked, &oversample_h, &oversample_v); BulletText("Input %d: \'%s\', Oversample: (%d=>%d,%d=>%d), PixelSnapH: %d, Offset: (%.1f,%.1f)", src_n, src->Name, src->OversampleH, oversample_h, src->OversampleV, oversample_v, src->PixelSnapH, src->GlyphOffset.x, src->GlyphOffset.y); } diff --git a/imgui.h b/imgui.h index e38cce77184d..9bf4db914d6d 100644 --- a/imgui.h +++ b/imgui.h @@ -3467,7 +3467,7 @@ struct ImFontConfig float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. - float RasterizerDensity; // 1.0f // DPI scale for rasterization, not altering other font metrics: make it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. + float RasterizerDensity; // 1.0f // DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] @@ -3709,6 +3709,7 @@ struct ImFontBaked ImVector IndexAdvanceX; // 12-16 // out // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // FindGlyph(FallbackChar)->AdvanceX float Size; // 4 // in // Height of characters/line, set during loading (doesn't change after loading) + float RasterizerDensity; // 4 // in // Density this is baked at // [Internal] Members: Hot ~28/36 bytes (for RenderText loop) ImVector IndexLookup; // 12-16 // out // Sparse. Index glyphs by Unicode code-point. @@ -3753,9 +3754,10 @@ enum ImFontFlags_ struct ImFont { // [Internal] Members: Hot ~12-20 bytes - ImFontBaked* LastBaked; // 4-8 // Cache last bound baked. DO NOT USE. Use GetFontBaked(). - ImFontAtlas* ContainerAtlas; // 4-8 // What we has been loaded into - ImFontFlags Flags; // 4 // Font flags + ImFontBaked* LastBaked; // 4-8 // Cache last bound baked. NEVER USE DIRECTLY. Use GetFontBaked(). + ImFontAtlas* ContainerAtlas; // 4-8 // What we have been loaded into. + ImFontFlags Flags; // 4 // Font flags. + float CurrentRasterizerDensity; // Current rasterizer density. This is a varying state of the font. // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7bb6ae108df7..14440592e072 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3349,10 +3349,11 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) atlas->TexIsBuilt = true; } -void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v) +void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v) { // Automatically disable horizontal oversampling over size 36 - *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : ((size * src->RasterizerDensity > 36.0f) || src->PixelSnapH) ? 1 : 2; + const float raster_size = baked->Size * baked->RasterizerDensity * src->RasterizerDensity; + *out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (raster_size > 36.0f || src->PixelSnapH) ? 1 : 2; *out_oversample_v = (src->OversampleV != 0) ? src->OversampleV : 1; } @@ -3733,11 +3734,12 @@ void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBa baked->IndexAdvanceX[c] = baked->FallbackAdvanceX; } -ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id) +ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density, ImGuiID baked_id) { IMGUI_DEBUG_LOG_FONT("[font] Created baked %.2fpx\n", font_size); ImFontBaked* baked = atlas->Builder->BakedPool.push_back(ImFontBaked()); baked->Size = font_size; + baked->RasterizerDensity = font_rasterizer_density; baked->BakedId = baked_id; baked->ContainerFont = font; baked->LastUsedFrame = atlas->Builder->FrameCount; @@ -3764,7 +3766,7 @@ ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_si } // FIXME-OPT: This is not a fast query. Adding a BakedCount field in Font might allow to take a shortcut for the most common case. -ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size) +ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density) { ImFontAtlasBuilder* builder = atlas->Builder; ImFontBaked* closest_larger_match = NULL; @@ -3774,6 +3776,8 @@ ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, f ImFontBaked* baked = &builder->BakedPool[baked_n]; if (baked->ContainerFont != font || baked->WantDestroy) continue; + if (baked->RasterizerDensity != font_rasterizer_density) + continue; if (baked->Size > font_size && (closest_larger_match == NULL || baked->Size < closest_larger_match->Size)) closest_larger_match = baked; if (baked->Size < font_size && (closest_smaller_match == NULL || baked->Size > closest_smaller_match->Size)) @@ -4543,10 +4547,11 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, // Fonts unit to pixels int oversample_h, oversample_v; - ImFontAtlasBuildGetOversampleFactors(src, baked->Size, &oversample_h, &oversample_v); + ImFontAtlasBuildGetOversampleFactors(src, baked, &oversample_h, &oversample_v); const float scale_for_layout = bd_font_data->ScaleFactor * baked->Size; - const float scale_for_raster_x = bd_font_data->ScaleFactor * baked->Size * src->RasterizerDensity * oversample_h; - const float scale_for_raster_y = bd_font_data->ScaleFactor * baked->Size * src->RasterizerDensity * oversample_v; + const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; + const float scale_for_raster_x = bd_font_data->ScaleFactor * baked->Size * rasterizer_density * oversample_h; + const float scale_for_raster_y = bd_font_data->ScaleFactor * baked->Size * rasterizer_density * oversample_v; // Obtain size and advance int x0, y0, x1, y1; @@ -4601,8 +4606,8 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, font_off_y = IM_ROUND(font_off_y); font_off_x += stbtt__oversample_shift(oversample_h); font_off_y += stbtt__oversample_shift(oversample_v) + IM_ROUND(baked->Ascent); - float recip_h = 1.0f / (oversample_h * src->RasterizerDensity); - float recip_v = 1.0f / (oversample_v * src->RasterizerDensity); + float recip_h = 1.0f / (oversample_h * rasterizer_density); + float recip_v = 1.0f / (oversample_v * rasterizer_density); // Register glyph // r->x r->y are coordinates inside texture (in pixels) @@ -5172,11 +5177,12 @@ float ImFontBaked::GetCharAdvance(ImWchar c) } IM_MSVC_RUNTIME_CHECKS_RESTORE -ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size) +ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterizer_density) { - struct { ImGuiID FontId; float BakedSize; } hashed_data; + struct { ImGuiID FontId; float BakedSize; float RasterizerDensity; } hashed_data; hashed_data.FontId = font_id; hashed_data.BakedSize = baked_size; + hashed_data.RasterizerDensity = rasterizer_density; return ImHashData(&hashed_data, sizeof(hashed_data)); } @@ -5189,12 +5195,12 @@ ImFontBaked* ImFont::GetFontBaked(float size) // - ImGui::PushFontSize() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges) size = ImGui::GetRoundedFontSize(size); - if (baked && baked->Size == size) + if (baked && baked->Size == size && baked->RasterizerDensity == CurrentRasterizerDensity) return baked; ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; - baked = ImFontAtlasBakedGetOrAdd(atlas, this, size); + baked = ImFontAtlasBakedGetOrAdd(atlas, this, size, CurrentRasterizerDensity); if (baked == NULL) return NULL; baked->LastUsedFrame = builder->FrameCount; @@ -5202,11 +5208,11 @@ ImFontBaked* ImFont::GetFontBaked(float size) return baked; } -ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size) +ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density) { // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria? // FIXME-NEWATLAS: Altering font density won't work right away. - ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size); + ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size, font_rasterizer_density); ImFontAtlasBuilder* builder = atlas->Builder; ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); ImFontBaked* baked = *p_baked_in_map; @@ -5220,7 +5226,7 @@ ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float fo // FIXME-OPT: This is not an optimal query. if ((font->Flags & ImFontFlags_LockBakedSizes) || atlas->Locked) { - baked = ImFontAtlasBakedGetClosestMatch(atlas, font, font_size); + baked = ImFontAtlasBakedGetClosestMatch(atlas, font, font_size, font_rasterizer_density); if (baked != NULL) return baked; if (atlas->Locked) @@ -5231,7 +5237,7 @@ ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float fo } // Create new - baked = ImFontAtlasBakedAdd(atlas, font, font_size, baked_id); + baked = ImFontAtlasBakedAdd(atlas, font, font_size, font_rasterizer_density, baked_id); *p_baked_in_map = baked; // To avoid 'builder->BakedMap.SetVoidPtr(baked_id, baked);' while we can. return baked; } diff --git a/imgui_internal.h b/imgui_internal.h index 28e9074886b2..fbd0ec148773 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2142,6 +2142,7 @@ struct ImGuiContext float FontSize; // == FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale. Current text height. float FontSizeBeforeScaling; // == value passed to PushFontSize() float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. + float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; double Time; @@ -3109,6 +3110,8 @@ namespace ImGui // Fonts, drawing IMGUI_API void SetCurrentFont(ImFont* font, float font_size); + IMGUI_API void SetFontRasterizerDensity(float rasterizer_density); + inline float GetFontRasterizerDensity() { return GImGui->FontRasterizerDensity; } IMGUI_API void UpdateCurrentFontSize(); inline float GetRoundedFontSize(float size) { return IM_ROUND(size); } inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } @@ -3781,7 +3784,7 @@ IMGUI_API ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy -IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, float size, int* out_oversample_h, int* out_oversample_v); +IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); IMGUI_API bool ImFontAtlasFontSourceInit(ImFontAtlas* atlas, ImFontConfig* src); @@ -3791,10 +3794,10 @@ IMGUI_API bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont IMGUI_API void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font); IMGUI_API void ImFontAtlasFontDiscardOutputBakes(ImFontAtlas* atlas, ImFont* font); -IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size); -IMGUI_API ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size); -IMGUI_API ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size); -IMGUI_API ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, ImGuiID baked_id); +IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterizer_density); +IMGUI_API ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density); +IMGUI_API ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density); +IMGUI_API ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density, ImGuiID baked_id); IMGUI_API void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); IMGUI_API void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 8ad2d6ceaf59..121320b09623 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -438,10 +438,11 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF // is a maximum height of an any given glyph, i.e. it's the sum of font's ascender and descender. Seems strange to me. // FT_Set_Pixel_Sizes() doesn't seem to get us the same result." // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) + const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; FT_Size_RequestRec req; req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; - req.height = (uint32_t)(size * 64 * src->RasterizerDensity); + req.height = (uint32_t)(size * 64 * rasterizer_density); req.horiResolution = 0; req.vertResolution = 0; FT_Request_Size(bd_font_data->FtFace, &req); @@ -451,7 +452,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF { // Read metrics FT_Size_Metrics metrics = bd_baked_data->FtSize->metrics; - const float scale = 1.0f / src->RasterizerDensity; + const float scale = 1.0f / rasterizer_density; baked->Ascent = (float)FT_CEIL(metrics.ascender) * scale; // The pixel extents above the baseline in pixels (typically positive). baked->Descent = (float)FT_CEIL(metrics.descender) * scale; // The extents below the baseline in pixels (typically negative). //LineSpacing = (float)FT_CEIL(metrics.height) * scale; // The baseline-to-baseline distance. Note that it usually is larger than the sum of the ascender and descender taken as absolute values. There is also no guarantee that no glyphs extend above or below subsequent baselines when using this distance. Think of it as a value the designer of the font finds appropriate. @@ -503,12 +504,13 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon const int w = (int)ft_bitmap->width; const int h = (int)ft_bitmap->rows; const bool is_visible = (w != 0 && h != 0); + const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; // Prepare glyph ImFontGlyph glyph_in = {}; ImFontGlyph* glyph = &glyph_in; glyph->Codepoint = codepoint; - glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) / src->RasterizerDensity; + glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density; // Pack and retrieve position inside texture atlas if (is_visible) @@ -534,8 +536,8 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon font_off_x = IM_ROUND(font_off_x); if (src->PixelSnapV) font_off_y = IM_ROUND(font_off_y); - float recip_h = 1.0f / src->RasterizerDensity; - float recip_v = 1.0f / src->RasterizerDensity; + float recip_h = 1.0f / rasterizer_density; + float recip_v = 1.0f / rasterizer_density; // Register glyph float glyph_off_x = (float)face->glyph->bitmap_left; From 4dec946ae671099bbf0e846778b7aebdb7b481d8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 5 May 2025 20:58:38 +0200 Subject: [PATCH 565/716] Fonts: don't pretend to half recover from OOM for now + debug log filename on load failure. --- imgui_draw.cpp | 5 ++++- misc/freetype/imgui_freetype.cpp | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 14440592e072..2cec1439d425 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3102,7 +3102,10 @@ ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, if (!data) { if (font_cfg_template == NULL || (font_cfg_template->Flags & ImFontFlags_NoLoadError) == 0) + { + IMGUI_DEBUG_LOG("While loading '%s'\n", filename); IM_ASSERT_USER_ERROR(0, "Could not load font file!"); + } return NULL; } ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig(); @@ -4576,7 +4579,7 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, if (pack_id == ImFontAtlasRectId_Invalid) { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) - IM_ASSERT_USER_ERROR(pack_id != ImFontAtlasRectId_Invalid, "Out of texture memory."); + IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory."); return NULL; } ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 121320b09623..afd3e0cecc8c 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -516,10 +516,10 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon if (is_visible) { ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h); - if (pack_id < 0) + if (pack_id == ImFontAtlasRectId_Invalid) { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) - IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory."); + IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory."); return NULL; } ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); From 8523cbdf58f1851c007751cf7e43317fb146a259 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 May 2025 17:03:52 +0200 Subject: [PATCH 566/716] Fonts: rework ImFontLoader::FontBakedLoadGlyph() interface --- imgui_draw.cpp | 42 +++++++++++++++----------------- imgui_internal.h | 4 +-- misc/freetype/imgui_freetype.cpp | 36 ++++++++++++--------------- 3 files changed, 36 insertions(+), 46 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2cec1439d425..968dc47d4656 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4393,12 +4393,15 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep { const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) - if (ImFontGlyph* glyph = loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint)) + { + ImFontGlyph glyph_buf; + if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf)) { // FIXME: Add hooks for e.g. #7962 - glyph->SourceIdx = src_n; - return glyph; + glyph_buf.SourceIdx = src_n; + return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); } + } loader_user_data_p += loader->FontBakedSrcLoaderDataSize; src_n++; } @@ -4539,14 +4542,14 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig return true; } -static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint) +static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph) { // Search for first font which has the glyph ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; IM_ASSERT(bd_font_data); int glyph_index = stbtt_FindGlyphIndex(&bd_font_data->FontInfo, (int)codepoint); if (glyph_index == 0) - return NULL; + return false; // Fonts unit to pixels int oversample_h, oversample_v; @@ -4564,10 +4567,8 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, const bool is_visible = (x0 != x1 && y0 != y1); // Prepare glyph - ImFontGlyph glyph_in = {}; - ImFontGlyph* glyph = &glyph_in; - glyph->Codepoint = codepoint; - glyph->AdvanceX = advance * scale_for_layout; + out_glyph->Codepoint = codepoint; + out_glyph->AdvanceX = advance * scale_for_layout; // Pack and retrieve position inside texture atlas // (generally based on stbtt_PackFontRangesRenderIntoRects) @@ -4580,7 +4581,7 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory."); - return NULL; + return false; } ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); @@ -4615,21 +4616,16 @@ static ImFontGlyph* ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, // Register glyph // r->x r->y are coordinates inside texture (in pixels) // glyph.X0, glyph.Y0 are drawing coordinates from base text position, and accounting for oversampling. - glyph->X0 = x0 * recip_h + font_off_x; - glyph->Y0 = y0 * recip_v + font_off_y; - glyph->X1 = (x0 + (int)r->w) * recip_h + font_off_x; - glyph->Y1 = (y0 + (int)r->h) * recip_v + font_off_y; - glyph->Visible = true; - glyph->PackId = pack_id; - glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); - ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, glyph, r, bitmap_pixels, ImTextureFormat_Alpha8, w); - } - else - { - glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); + out_glyph->X0 = x0 * recip_h + font_off_x; + out_glyph->Y0 = y0 * recip_v + font_off_y; + out_glyph->X1 = (x0 + (int)r->w) * recip_h + font_off_x; + out_glyph->Y1 = (y0 + (int)r->h) * recip_v + font_off_y; + out_glyph->Visible = true; + out_glyph->PackId = pack_id; + ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, out_glyph, r, bitmap_pixels, ImTextureFormat_Alpha8, w); } - return glyph; + return true; } const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype() diff --git a/imgui_internal.h b/imgui_internal.h index fbd0ec148773..00cb159d2efe 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3669,7 +3669,7 @@ namespace ImGui // Hooks and storage for a given font backend. // This structure is likely to evolve as we add support for incremental atlas updates. -// Conceptually this could be in ImGuiPlatformIO, but we are far from ready to make this public. +// Conceptually this could be public, but API is still going to be evolve. struct ImFontLoader { const char* Name; @@ -3680,7 +3680,7 @@ struct ImFontLoader bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); - ImFontGlyph* (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint); + bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph); // Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations. // FIXME: At this point the two other types of buffers may be managed by core to be consistent? diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index afd3e0cecc8c..a0fc9692636b 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -473,12 +473,12 @@ void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE() } -ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint) +bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph) { ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; uint32_t glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); if (glyph_index == 0) - return NULL; + return false; if (bd_font_data->BakedLastActivated != baked) // <-- could use id { @@ -490,7 +490,7 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, codepoint); if (metrics == NULL) - return NULL; + return false; // Render glyph into a bitmap (currently held by FreeType) FT_Face face = bd_font_data->FtFace; @@ -507,10 +507,8 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; // Prepare glyph - ImFontGlyph glyph_in = {}; - ImFontGlyph* glyph = &glyph_in; - glyph->Codepoint = codepoint; - glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density; + out_glyph->Codepoint = codepoint; + out_glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density; // Pack and retrieve position inside texture atlas if (is_visible) @@ -542,21 +540,17 @@ ImFontGlyph* ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontCon // Register glyph float glyph_off_x = (float)face->glyph->bitmap_left; float glyph_off_y = (float)-face->glyph->bitmap_top; - glyph->X0 = glyph_off_x * recip_h + font_off_x; - glyph->Y0 = glyph_off_y * recip_v + font_off_y; - glyph->X1 = (glyph_off_x + w) * recip_h + font_off_x; - glyph->Y1 = (glyph_off_y + h) * recip_v + font_off_y; - glyph->Visible = true; - glyph->Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); - glyph->PackId = pack_id; - glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); - ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, glyph, r, (const unsigned char*)temp_buffer, ImTextureFormat_RGBA32, w * 4); + out_glyph->X0 = glyph_off_x * recip_h + font_off_x; + out_glyph->Y0 = glyph_off_y * recip_v + font_off_y; + out_glyph->X1 = (glyph_off_x + w) * recip_h + font_off_x; + out_glyph->Y1 = (glyph_off_y + h) * recip_v + font_off_y; + out_glyph->Visible = true; + out_glyph->Colored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); + out_glyph->PackId = pack_id; + ImFontAtlasBakedSetFontGlyphBitmap(atlas, baked, src, out_glyph, r, (const unsigned char*)temp_buffer, ImTextureFormat_RGBA32, w * 4); } - else - { - glyph = ImFontAtlasBakedAddFontGlyph(atlas, baked, src, glyph); - } - return glyph; + + return true; } bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) From 89e880dfd18d7a7ebfc684831d787f6b620db6c7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 May 2025 17:35:20 +0200 Subject: [PATCH 567/716] Fonts: adding ImFontHooks for codepoint remapping. --- imgui.h | 3 +++ imgui_draw.cpp | 16 +++++++++++++++- imgui_internal.h | 12 ++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/imgui.h b/imgui.h index 9bf4db914d6d..8cf3f7ff4595 100644 --- a/imgui.h +++ b/imgui.h @@ -177,6 +177,7 @@ struct ImFontBaked; // Baked data for a ImFont at a given size. struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data +struct ImFontHooks; // Opaque interface to font hooks struct ImFontLoader; // Opaque interface to a font loading backend (stb_truetype, FreeType etc.). struct ImTextureData; // Specs and pixel storage for a texture used by Dear ImGui. struct ImTextureRect; // Coordinates of a rectangle within a texture. @@ -3682,6 +3683,7 @@ struct ImFontAtlas const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name void* FontLoaderData; // Font backend opaque storage + const ImFontHooks* FontHooks; // Shared font hooks for all fonts. unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. int RefCount; // Number of contexts using this atlas @@ -3769,6 +3771,7 @@ struct ImFont float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. + const ImFontHooks* FontHooks; // 8 // in // Custom font hooks for the font. // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 968dc47d4656..8661de76207d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4365,6 +4365,14 @@ static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); } +static void ImFont_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c) +{ + if (font->FontHooks && font->FontHooks->FontHookRemapCodepoint != NULL) + font->FontHooks->FontHookRemapCodepoint(atlas, font, c); + else if (atlas->FontHooks && atlas->FontHooks->FontHookRemapCodepoint != NULL) + atlas->FontHooks->FontHookRemapCodepoint(atlas, font, c); +} + static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint) { ImFont* font = baked->ContainerFont; @@ -4377,6 +4385,10 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep return NULL; } + // User remapping hooks + ImWchar src_codepoint = codepoint; + ImFont_FontHookRemapCodepoint(atlas, font, &codepoint); + //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); @@ -4398,6 +4410,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf)) { // FIXME: Add hooks for e.g. #7962 + glyph_buf.Codepoint = src_codepoint; glyph_buf.SourceIdx = src_n; return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); } @@ -5079,7 +5092,7 @@ void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } -// FIXME-NEWATLAS: Implement AddRemapChar() which was removed since transitioning to baked logic. +// FIXME: Use ImFontHooks::FontHookRemapCodepoint() hooks. void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) { IM_UNUSED(from_codepoint); @@ -5149,6 +5162,7 @@ bool ImFontBaked::IsGlyphLoaded(ImWchar c) bool ImFont::IsGlyphInFont(ImWchar c) { ImFontAtlas* atlas = ContainerAtlas; + ImFont_FontHookRemapCodepoint(atlas, this, &c); for (ImFontConfig* src : Sources) { const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; diff --git a/imgui_internal.h b/imgui_internal.h index 00cb159d2efe..b486430addc2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -37,7 +37,7 @@ Index of this file: // [SECTION] Tab bar, Tab item support // [SECTION] Table support // [SECTION] ImGui internal API -// [SECTION] ImFontLoader +// [SECTION] ImFontLoader, ImFontHooks // [SECTION] ImFontAtlas internal API // [SECTION] Test Engine specific hooks (imgui_test_engine) @@ -3664,7 +3664,7 @@ namespace ImGui //----------------------------------------------------------------------------- -// [SECTION] ImFontLoader +// [SECTION] ImFontLoader, ImFontHooks //----------------------------------------------------------------------------- // Hooks and storage for a given font backend. @@ -3693,6 +3693,14 @@ struct ImFontLoader IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); #endif +// User hooks +// Conceptually this could be public, but API is still going to be evolve. +struct ImFontHooks +{ + // Modify codepoint to map to another value. + void (*FontHookRemapCodepoint)(ImFontAtlas* atlas, ImFont* font, ImWchar* io_codepoint); +}; + //----------------------------------------------------------------------------- // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- From f6735c223c469ac0952fbf0f2bf336f8f43e3fe1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 8 May 2025 17:59:18 +0200 Subject: [PATCH 568/716] Fonts: remove ImFontHooks in favor of a AddRemapChar() implementation. --- imgui.h | 6 ++---- imgui_draw.cpp | 33 ++++++++------------------------- imgui_internal.h | 12 ++---------- 3 files changed, 12 insertions(+), 39 deletions(-) diff --git a/imgui.h b/imgui.h index 8cf3f7ff4595..4639e2c2e070 100644 --- a/imgui.h +++ b/imgui.h @@ -177,7 +177,6 @@ struct ImFontBaked; // Baked data for a ImFont at a given size. struct ImFontConfig; // Configuration data when adding a font or merging fonts struct ImFontGlyph; // A single font glyph (code point + coordinates within in ImFontAtlas + offset) struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data -struct ImFontHooks; // Opaque interface to font hooks struct ImFontLoader; // Opaque interface to a font loading backend (stb_truetype, FreeType etc.). struct ImTextureData; // Specs and pixel storage for a texture used by Dear ImGui. struct ImTextureRect; // Coordinates of a rectangle within a texture. @@ -3683,7 +3682,6 @@ struct ImFontAtlas const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name void* FontLoaderData; // Font backend opaque storage - const ImFontHooks* FontHooks; // Shared font hooks for all fonts. unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. int RefCount; // Number of contexts using this atlas @@ -3771,7 +3769,7 @@ struct ImFont float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. - const ImFontHooks* FontHooks; // 8 // in // Custom font hooks for the font. + ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapChar(), otherwise empty. // Methods IMGUI_API ImFont(); @@ -3794,7 +3792,7 @@ struct ImFont // [Internal] Don't use! IMGUI_API void ClearOutputData(); - IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst);// , bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built. + IMGUI_API void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint); // Makes 'from_codepoint' character points to 'to_codepoint' glyph. IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8661de76207d..541043dd48f6 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4365,12 +4365,11 @@ static void ImFontBaked_BuildGrowIndex(ImFontBaked* baked, int new_size) baked->IndexLookup.resize(new_size, IM_FONTGLYPH_INDEX_UNUSED); } -static void ImFont_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c) +static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, ImWchar* c) { - if (font->FontHooks && font->FontHooks->FontHookRemapCodepoint != NULL) - font->FontHooks->FontHookRemapCodepoint(atlas, font, c); - else if (atlas->FontHooks && atlas->FontHooks->FontHookRemapCodepoint != NULL) - atlas->FontHooks->FontHookRemapCodepoint(atlas, font, c); + IM_UNUSED(atlas); + if (font->RemapPairs.Data.Size != 0) + *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c); } static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint) @@ -4387,7 +4386,7 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep // User remapping hooks ImWchar src_codepoint = codepoint; - ImFont_FontHookRemapCodepoint(atlas, font, &codepoint); + ImFontAtlas_FontHookRemapCodepoint(atlas, font, &codepoint); //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildLoadGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); @@ -5092,25 +5091,9 @@ void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); } -// FIXME: Use ImFontHooks::FontHookRemapCodepoint() hooks. -void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint, bool overwrite_dst) +void ImFont::AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) { - IM_UNUSED(from_codepoint); - IM_UNUSED(to_codepoint); - IM_UNUSED(overwrite_dst); - /* - IM_ASSERT(IndexLookup.Size > 0); // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function. - unsigned int index_size = (unsigned int)IndexLookup.Size; - - if (from_codepoint < index_size && IndexLookup.Data[from_codepoint] == (ImU16)-1 && !overwrite_dst) // 'from_codepoint' already exists - return; - if (to_codepoint >= index_size && from_codepoint >= index_size) // both 'from_codepoint' and 'to_codepoint' don't exist -> no-op - return; - - BuildGrowIndex(from_codepoint + 1); - IndexLookup[from_codepoint] = (to_codepoint < index_size) ? IndexLookup.Data[to_codepoint] : (ImU16)-1; - IndexAdvanceX[from_codepoint] = (to_codepoint < index_size) ? IndexAdvanceX.Data[to_codepoint] : 1.0f; - */ + RemapPairs.SetInt((ImGuiID)from_codepoint, (int)to_codepoint); } // Find glyph, load if necessary, return fallback if missing @@ -5162,7 +5145,7 @@ bool ImFontBaked::IsGlyphLoaded(ImWchar c) bool ImFont::IsGlyphInFont(ImWchar c) { ImFontAtlas* atlas = ContainerAtlas; - ImFont_FontHookRemapCodepoint(atlas, this, &c); + ImFontAtlas_FontHookRemapCodepoint(atlas, this, &c); for (ImFontConfig* src : Sources) { const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; diff --git a/imgui_internal.h b/imgui_internal.h index b486430addc2..00cb159d2efe 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -37,7 +37,7 @@ Index of this file: // [SECTION] Tab bar, Tab item support // [SECTION] Table support // [SECTION] ImGui internal API -// [SECTION] ImFontLoader, ImFontHooks +// [SECTION] ImFontLoader // [SECTION] ImFontAtlas internal API // [SECTION] Test Engine specific hooks (imgui_test_engine) @@ -3664,7 +3664,7 @@ namespace ImGui //----------------------------------------------------------------------------- -// [SECTION] ImFontLoader, ImFontHooks +// [SECTION] ImFontLoader //----------------------------------------------------------------------------- // Hooks and storage for a given font backend. @@ -3693,14 +3693,6 @@ struct ImFontLoader IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); #endif -// User hooks -// Conceptually this could be public, but API is still going to be evolve. -struct ImFontHooks -{ - // Modify codepoint to map to another value. - void (*FontHookRemapCodepoint)(ImFontAtlas* atlas, ImFont* font, ImWchar* io_codepoint); -}; - //----------------------------------------------------------------------------- // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- From 46fa9e8efb4e09244704699e69c0487915ec7812 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 9 May 2025 21:55:07 +0200 Subject: [PATCH 569/716] Fonts: Debug display status. Fixed truncated raw texture id. Fixed FormatTextureIDForDebugDisplay(). Comments. --- imgui.cpp | 27 ++++++++++++++++++--------- imgui_draw.cpp | 16 +++++++++++++++- imgui_internal.h | 1 + 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 68560fdb6ca7..92f0f92bff05 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15666,7 +15666,7 @@ static const char* FormatTextureIDForDebugDisplay(char* buf, int buf_size, const char* buf_end = buf + buf_size; if (cmd->TexRef._TexData != NULL) buf += ImFormatString(buf, buf_end - buf, "#%03d: ", cmd->TexRef._TexData->UniqueID); - return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), cmd->GetTexID()); + return FormatTextureIDForDebugDisplay(buf, (int)(buf_end - buf), cmd->TexRef.GetTexID()); // Calling TexRef::GetTexID() to avoid assert of cmd->GetTexID() } // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds. @@ -15690,18 +15690,26 @@ namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); IMGUI_A void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { ImGuiContext& g = *GImGui; + ImGuiIO& io = g.IO; + + Text("Read "); SameLine(0, 0); + TextLinkOpenURL("https://www.dearimgui.com/faq/"); SameLine(0, 0); + Text(" for details on font loading."); SeparatorText("Backend Support for Dynamic Fonts"); BeginDisabled(); - CheckboxFlags("io.BackendFlags: RendererHasTextures", &GetIO().BackendFlags, ImGuiBackendFlags_RendererHasTextures); + CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); + EndDisabled(); + + BeginDisabled((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); + SetNextItemWidth(GetFontSize() * 5); + DragFloat("io.FontGlobalScale", &io.FontGlobalScale, 0.05f, 0.5f, 5.0f); + BulletText("This is scaling font only. General scaling will come later."); + BulletText("Load an actual font that's not the default for best result!"); + BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("https://github.com/ocornut/imgui/issues/8465"); EndDisabled(); SeparatorText("Fonts"); - Text("Read "); - SameLine(0, 0); - TextLinkOpenURL("https://www.dearimgui.com/faq/"); - SameLine(0, 0); - Text(" for details on font loading."); ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; Checkbox("Show font preview", &cfg->ShowFontPreview); @@ -15845,7 +15853,8 @@ void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRe } PopStyleVar(); - char texid_desc[20]; + char texid_desc[30]; + Text("Status = %s (%d)", ImTextureDataGetStatusName(tex->Status), tex->Status); Text("Format = %s (%d)", ImTextureDataGetFormatName(tex->Format), tex->Format); Text("TexID = %s", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID)); Text("BackendUserData = %p", tex->BackendUserData); @@ -16545,7 +16554,7 @@ void ImGui::DebugNodeDrawList(ImGuiWindow* window, ImGuiViewportP* viewport, con continue; } - char texid_desc[20]; + char texid_desc[30]; FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), pcmd); char buf[300]; ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex %s, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)", diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 541043dd48f6..a76767b9b4d4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2431,6 +2431,19 @@ int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format) return 0; } +const char* ImTextureDataGetStatusName(ImTextureStatus status) +{ + switch (status) + { + case ImTextureStatus_OK: return "OK"; + case ImTextureStatus_Destroyed: return "Destroyed"; + case ImTextureStatus_WantCreate: return "WantCreate"; + case ImTextureStatus_WantUpdates: return "WantUpdates"; + case ImTextureStatus_WantDestroy: return "WantDestroy"; + } + return "N/A"; +} + const char* ImTextureDataGetFormatName(ImTextureFormat format) { switch (format) @@ -2441,7 +2454,6 @@ const char* ImTextureDataGetFormatName(ImTextureFormat format) return "N/A"; } - void ImTextureData::Create(ImTextureFormat format, int w, int h) { DestroyPixels(); @@ -3156,6 +3168,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed return font; } +// On font removal we need to remove references (otherwise we could queue removal?) // We allow old_font == new_font which forces updating all values (e.g. sizes) static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font) { @@ -3884,6 +3897,7 @@ void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex } // Update texture coordinates in all draw list shared context +// FIXME-NEWATLAS FIXME-OPT: Doesn't seem necessary to update for all, only one bound to current context? void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) { for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) diff --git a/imgui_internal.h b/imgui_internal.h index 00cb159d2efe..5f2a06fe4f90 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3823,6 +3823,7 @@ IMGUI_API void ImFontAtlasTextureBlockCopy(ImTextureData* src_tex, IMGUI_API void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, int x, int y, int w, int h); IMGUI_API int ImTextureDataGetFormatBytesPerPixel(ImTextureFormat format); +IMGUI_API const char* ImTextureDataGetStatusName(ImTextureStatus status); IMGUI_API const char* ImTextureDataGetFormatName(ImTextureFormat format); #ifndef IMGUI_DISABLE_DEBUG_TOOLS From 65e60399794295d28b552941114f41da8be148a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 9 May 2025 22:46:39 +0200 Subject: [PATCH 570/716] Fonts: remove unnecessary ImDrawListSharedData::FontAtlas which is actually getting in the way of using multiple atlases. --- imgui_draw.cpp | 7 ++----- imgui_internal.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index a76767b9b4d4..eaba28b06c26 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3865,16 +3865,14 @@ void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames) // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) { - IM_ASSERT(!atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == NULL); + IM_ASSERT(!atlas->DrawListSharedDatas.contains(data)); atlas->DrawListSharedDatas.push_back(data); - data->FontAtlas = atlas; } void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) { - IM_ASSERT(atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == atlas); + IM_ASSERT(atlas->DrawListSharedDatas.contains(data)); atlas->DrawListSharedDatas.find_erase(data); - data->FontAtlas = NULL; } // Update texture identifier in all active draw lists @@ -3902,7 +3900,6 @@ void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) { for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) { - shared_data->FontAtlas = atlas; shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; shared_data->TexUvLines = atlas->TexUvLines; } diff --git a/imgui_internal.h b/imgui_internal.h index 5f2a06fe4f90..f145fd01267a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -838,7 +838,6 @@ struct IMGUI_API ImDrawListSharedData { ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel) const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->TexUvLines) - ImFontAtlas* FontAtlas; // Current font atlas ImFont* Font; // Current/default font (optional, for simplified AddText overload) float FontSize; // Current/default font size (optional, for simplified AddText overload) float FontScale; // Current/default font scale (== FontSize / Font->FontSize) From fad5280d4c131f3ebbbc30f6d1dc0d4e8463df4c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 11 May 2025 23:51:45 +0200 Subject: [PATCH 571/716] Fonts: fixed broken support for legacy backend due to a mismatch with initial pre-build baked id. --- imgui.cpp | 2 +- imgui.h | 2 +- imgui_draw.cpp | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 92f0f92bff05..bd01afed5d1b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8657,7 +8657,7 @@ void ImGui::UpdateCurrentFontSize() // - We may support it better later and remove this rounding. final_size = GetRoundedFontSize(final_size); final_size = ImMax(1.0f, final_size); - if (g.Font != NULL) + if (g.Font != NULL && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; g.FontBaked = (g.Font != NULL) ? g.Font->GetFontBaked(final_size) : NULL; g.FontSize = final_size; diff --git a/imgui.h b/imgui.h index 4639e2c2e070..71e49efe4a7a 100644 --- a/imgui.h +++ b/imgui.h @@ -3467,7 +3467,7 @@ struct ImFontConfig float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. - float RasterizerDensity; // 1.0f // DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. + float RasterizerDensity; // 1.0f // (Legacy: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported). DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index eaba28b06c26..65485fb20681 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3002,6 +3002,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) font->FontId = FontNextUniqueID++; font->Flags = font_cfg_in->Flags; font->DefaultSize = font_cfg_in->SizePixels; + font->CurrentRasterizerDensity = font_cfg_in->RasterizerDensity; Fonts.push_back(font); } else From 91ed6e67b439b9dabc213ab2a05e4f88c70e526a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 9 May 2025 22:17:48 +0200 Subject: [PATCH 572/716] Fonts: fixed support for multiple atlases. Moved FontAtlasOwnedByContext to OwnerContext # Conflicts: # imgui.cpp # imgui_internal.h --- imgui.cpp | 91 +++++++++++++++++++++++++++++------------------- imgui.h | 1 + imgui_internal.h | 4 ++- 3 files changed, 59 insertions(+), 37 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bd01afed5d1b..d796900881ff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3962,13 +3962,13 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) InputTextState.Ctx = this; Initialized = false; - FontAtlasOwnedByContext = shared_font_atlas ? false : true; Font = NULL; FontBaked = NULL; FontSize = FontSizeBeforeScaling = FontScale = CurrentDpiScale = 0.0f; FontRasterizerDensity = 1.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); - IO.Fonts->RefCount++; + if (shared_font_atlas == NULL) + IO.Fonts->OwnerContext = this; Time = 0.0f; FrameCount = 0; FrameCountEnded = FrameCountRendered = -1; @@ -4226,8 +4226,9 @@ void ImGui::Initialize() // ImDrawList/ImFontAtlas are designed to function without ImGui, and 99% of it works without an ImGui context. // But this link allows us to facilitate/handle a few edge cases better. + ImFontAtlas* atlas = g.IO.Fonts; g.DrawListSharedData.Context = &g; - ImFontAtlasAddDrawListSharedData(g.IO.Fonts, &g.DrawListSharedData); + RegisterFontAtlas(atlas); g.Initialized = true; } @@ -4240,17 +4241,15 @@ void ImGui::Shutdown() IM_ASSERT_USER_ERROR(g.IO.BackendRendererUserData == NULL, "Forgot to shutdown Renderer backend?"); // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame) - if (ImFontAtlas* atlas = g.IO.Fonts) + for (ImFontAtlas* atlas : g.FontAtlases) { - ImFontAtlasRemoveDrawListSharedData(atlas, &g.DrawListSharedData); - atlas->RefCount--; - if (g.FontAtlasOwnedByContext) + UnregisterFontAtlas(atlas); + if (atlas->OwnerContext == &g) { atlas->Locked = false; IM_DELETE(atlas); } } - g.IO.Fonts = NULL; g.DrawListSharedData.TempBuffer.clear(); // Cleanup of other data are conditional on actually having initialized Dear ImGui. @@ -4412,7 +4411,8 @@ void ImGui::GcCompactTransientMiscBuffers() g.MultiSelectTempDataStacked = 0; g.MultiSelectTempData.clear_destruct(); TableGcCompactSettings(); - g.IO.Fonts->CompactCache(); + for (ImFontAtlas* atlas : g.FontAtlases) + atlas->CompactCache(); } // Free up/compact internal window buffers, we can use this when a window becomes unused. @@ -5210,29 +5210,27 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) static void ImGui::UpdateTexturesNewFrame() { ImGuiContext& g = *GImGui; - ImFontAtlas* atlas = g.IO.Fonts; - if (g.FontAtlasOwnedByContext) - { - atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; - ImFontAtlasUpdateNewFrame(atlas, g.FrameCount); - } + for (ImFontAtlas* atlas : g.FontAtlases) + if (atlas->OwnerContext == &g) + { + atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; + ImFontAtlasUpdateNewFrame(atlas, g.FrameCount); + } } // Build a single texture list -// We want to avoid user reading from atlas->TexList[] in order to facilitate better support for multiple atlases. static void ImGui::UpdateTexturesEndFrame() { ImGuiContext& g = *GImGui; - ImFontAtlas* atlas = g.IO.Fonts; g.PlatformIO.Textures.resize(0); - g.PlatformIO.Textures.reserve(atlas->TexList.Size); - for (ImTextureData* tex : atlas->TexList) - { - // We provide this information so backends can decide whether to destroy textures. - // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized. - tex->RefCount = (unsigned short)atlas->RefCount; - g.PlatformIO.Textures.push_back(tex); - } + for (ImFontAtlas* atlas : g.FontAtlases) + for (ImTextureData* tex : atlas->TexList) + { + // We provide this information so backends can decide whether to destroy textures. + // This means in practice that if N imgui contexts are created with a shared atlas, we assume all of them have a backend initialized. + tex->RefCount = (unsigned short)atlas->RefCount; + g.PlatformIO.Textures.push_back(tex); + } } // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. @@ -5810,8 +5808,8 @@ void ImGui::EndFrame() UpdateTexturesEndFrame(); // Unlock font atlas - ImFontAtlas* atlas = g.IO.Fonts; - atlas->Locked = false; + for (ImFontAtlas* atlas : g.FontAtlases) + atlas->Locked = false; // Clear Input data for next frame g.IO.MousePosPrev = g.IO.MousePos; @@ -5890,7 +5888,8 @@ void ImGui::Render() #ifndef IMGUI_DISABLE_DEBUG_TOOLS if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) - ImFontAtlasDebugLogTextureRequests(g.IO.Fonts); + for (ImFontAtlas* atlas : g.FontAtlases) + ImFontAtlasDebugLogTextureRequests(atlas); #endif CallContextHooks(&g, ImGuiContextHookType_RenderPost); @@ -8596,9 +8595,9 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) void ImGui::UpdateFontsNewFrame() { ImGuiContext& g = *GImGui; - ImFontAtlas* atlas = g.IO.Fonts; if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) - atlas->Locked = true; + for (ImFontAtlas* atlas : g.FontAtlases) + atlas->Locked = true; // We do this really unusual thing of calling *push_front()*, the reason behind that we want to support the PushFont()/NewFrame()/PopFont() idiom. ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->DefaultSize }; @@ -8614,6 +8613,25 @@ void ImGui::UpdateFontsEndFrame() PopFont(); } +void ImGui::RegisterFontAtlas(ImFontAtlas* atlas) +{ + ImGuiContext& g = *GImGui; + if (g.FontAtlases.Size == 0) + IM_ASSERT(atlas == g.IO.Fonts); + atlas->RefCount++; + g.FontAtlases.push_back(atlas); + ImFontAtlasAddDrawListSharedData(atlas, &g.DrawListSharedData); +} + +void ImGui::UnregisterFontAtlas(ImFontAtlas* atlas) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(atlas->RefCount > 0); + ImFontAtlasRemoveDrawListSharedData(atlas, &g.DrawListSharedData); + g.FontAtlases.find_erase(atlas); + atlas->RefCount--; +} + // Use ImDrawList::_SetTexture(), making our shared g.FontStack[] authoritative against window-local ImDrawList. // - Whereas ImDrawList::PushTexture()/PopTexture() is not to be used across Begin() calls. // - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did... @@ -8670,6 +8688,7 @@ void ImGui::UpdateCurrentFontSize() void ImGui::SetFontRasterizerDensity(float rasterizer_density) { ImGuiContext& g = *GImGui; + IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures); if (g.FontRasterizerDensity == rasterizer_density) return; g.FontRasterizerDensity = rasterizer_density; @@ -16104,12 +16123,12 @@ void ImGui::ShowMetricsWindow(bool* p_open) } // Details for Fonts - ImFontAtlas* atlas = g.IO.Fonts; - if (TreeNode("Fonts", "Fonts (%d), Textures (%d)", atlas->Fonts.Size, atlas->TexList.Size)) - { - ShowFontAtlas(atlas); - TreePop(); - } + for (ImFontAtlas* atlas : g.FontAtlases) + if (TreeNode((void*)atlas, "Fonts (%d), Textures (%d)", atlas->Fonts.Size, atlas->TexList.Size)) + { + ShowFontAtlas(atlas); + TreePop(); + } // Details for Popups if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) diff --git a/imgui.h b/imgui.h index 71e49efe4a7a..4ae0bd84bccc 100644 --- a/imgui.h +++ b/imgui.h @@ -3684,6 +3684,7 @@ struct ImFontAtlas void* FontLoaderData; // Font backend opaque storage unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. int RefCount; // Number of contexts using this atlas + ImGuiContext* OwnerContext; // Context which own the atlas will be in charge of updating and destroying it. // [Obsolete] #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_internal.h b/imgui_internal.h index f145fd01267a..fc44490d45c1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2132,10 +2132,10 @@ struct ImGuiContextHook struct ImGuiContext { bool Initialized; - bool FontAtlasOwnedByContext; // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it. ImGuiIO IO; ImGuiPlatformIO PlatformIO; ImGuiStyle Style; + ImVector FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas) ImFont* Font; // == FontStack.back().Font ImFontBaked* FontBaked; // == Font->GetFontBaked(FontSize) float FontSize; // == FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale. Current text height. @@ -3108,6 +3108,8 @@ namespace ImGui IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags); // Fonts, drawing + IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas); + IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void SetCurrentFont(ImFont* font, float font_size); IMGUI_API void SetFontRasterizerDensity(float rasterizer_density); inline float GetFontRasterizerDensity() { return GImGui->FontRasterizerDensity; } From 39f6c793b33aefa7769d262b3a12610fb49bd7ef Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 12 May 2025 10:22:15 +0200 Subject: [PATCH 573/716] Fonts: proof of concept support for user textures. # Conflicts: # imgui.h # imgui_internal.h --- imgui.cpp | 15 +++++++++++++++ imgui.h | 2 +- imgui_internal.h | 6 ++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index d796900881ff..2a4001d654f3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5231,6 +5231,8 @@ static void ImGui::UpdateTexturesEndFrame() tex->RefCount = (unsigned short)atlas->RefCount; g.PlatformIO.Textures.push_back(tex); } + for (ImTextureData* tex : g.UserTextures) + g.PlatformIO.Textures.push_back(tex); } // Called once a frame. Followed by SetCurrentFont() which sets up the remaining data. @@ -8613,6 +8615,19 @@ void ImGui::UpdateFontsEndFrame() PopFont(); } +void ImGui::RegisterUserTexture(ImTextureData* tex) +{ + ImGuiContext& g = *GImGui; + IM_ASSERT(tex->RefCount > 0); + g.UserTextures.push_back(tex); +} + +void ImGui::UnregisterUserTexture(ImTextureData* tex) +{ + ImGuiContext& g = *GImGui; + g.UserTextures.find_erase(tex); +} + void ImGui::RegisterFontAtlas(ImFontAtlas* atlas) { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index 4ae0bd84bccc..3a8d05377da7 100644 --- a/imgui.h +++ b/imgui.h @@ -3905,7 +3905,7 @@ struct ImGuiPlatformIO // Textures list (the list is updated by calling ImGui::EndFrame or ImGui::Render) // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which points to this. The array is available here mostly because backends will want to destroy textures on shutdown. - ImVector Textures; // List of textures used by Dear ImGui (most often 1). + ImVector Textures; // List of textures used by Dear ImGui (most often 1) + contents of external texture list is automatically appended into this. }; // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). diff --git a/imgui_internal.h b/imgui_internal.h index fc44490d45c1..a390add196d3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2426,6 +2426,10 @@ struct ImGuiContext ImGuiPlatformImeData PlatformImeData; // Data updated by current frame. Will be applied at end of the frame. For some backends, this is required to have WantVisible=true in order to receive text message. ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data. When changed we call the platform_io.Platform_SetImeDataFn() handler. + // Extensions + // FIXME: We could provide an API to register one slot in an array held in ImGuiContext? + ImVector UserTextures; // List of textures created/managed by user or third-party extension. Automatically appended into platform_io.Textures[]. + // Settings bool SettingsLoaded; float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero @@ -3108,6 +3112,8 @@ namespace ImGui IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags); // Fonts, drawing + IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture + IMGUI_API void UnregisterUserTexture(ImTextureData* tex); IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void SetCurrentFont(ImFont* font, float font_size); From 1b51a88bba9315f656ad9280bd98caddac0dc243 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 May 2025 16:08:05 +0200 Subject: [PATCH 574/716] Fonts: moved compare operators to internal. Removed commented out ones aimed legacy backends: not needed anymore since we didn't rename ImTextureID. --- imgui.h | 9 --------- imgui_internal.h | 5 +++++ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/imgui.h b/imgui.h index 3a8d05377da7..c431a8320cc5 100644 --- a/imgui.h +++ b/imgui.h @@ -2836,15 +2836,6 @@ static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return IM_MSVC_RUNTIME_CHECKS_RESTORE #endif -// Helpers: ImTextureRef ==/!= operators provided as convenience -// (note that _TexID and _TexData are never set simultaneously) -static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } -static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } -//#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS // For legacy backends -//static inline bool operator==(ImTextureID lhs, const ImTextureRef& rhs) { return lhs == rhs._TexID && rhs._TexData == NULL; } -//static inline bool operator==(const ImTextureRef& lhs, ImTextureID rhs) { return lhs._TexID == rhs && lhs._TexData == NULL; } -//#endif - // Helpers macros to generate 32-bit encoded colors // - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. // - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. diff --git a/imgui_internal.h b/imgui_internal.h index a390add196d3..7c63057347f1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3704,6 +3704,11 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- +// Helpers: ImTextureRef ==/!= operators provided as convenience +// (note that _TexID and _TexData are never set simultaneously) +static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } +static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } + // Refer to ImFontAtlasPackGetRect() to better understand how this works. #define ImFontAtlasRectId_IndexMask_ (0x000FFFFF) // 20-bits: index to access builder->RectsIndex[]. #define ImFontAtlasRectId_GenerationMask_ (0x3FF00000) // 10-bits: entry generation, so each ID is unique and get can safely detected old identifiers. From ea756ede16fde3634ea3099cfd379fa2692d9625 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 15 May 2025 16:14:08 +0200 Subject: [PATCH 575/716] Fonts: reorder ImFontFlags according likelihood of being useful. --- imgui.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/imgui.h b/imgui.h index c431a8320cc5..61056bb6ffc2 100644 --- a/imgui.h +++ b/imgui.h @@ -3732,10 +3732,10 @@ struct ImFontBaked enum ImFontFlags_ { ImFontFlags_None = 0, - ImFontFlags_LockBakedSizes = 1 << 0, // Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. - ImFontFlags_NoLoadGlyphs = 1 << 1, // Disable loading new glyphs. - ImFontFlags_NoLoadError = 1 << 2, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. - ImFontFlags_UseDefaultSize = 1 << 3, // Legacy compatibility: make PushFont() calls without explicit size use font->DefaultSize instead of current font size. + ImFontFlags_UseDefaultSize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use font->DefaultSize instead of current font size. + ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. + ImFontFlags_NoLoadGlyphs = 1 << 2, // Disable loading new glyphs. + ImFontFlags_LockBakedSizes = 1 << 3, // Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. }; // Font runtime data and rendering @@ -3788,13 +3788,14 @@ struct ImFont IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; -// We added an indirection to avoid patching ImDrawCmd after texture updates but this could be a solution too. +// This is provided for consistency (but we don't actually use this) inline ImTextureID ImTextureRef::GetTexID() const { IM_ASSERT(!(_TexData != NULL && _TexID != ImTextureID_Invalid)); return _TexData ? _TexData->TexID : _TexID; } +// Using an indirection to avoid patching ImDrawCmd after a SetTexID() call (but this could be an alternative solution too) inline ImTextureID ImDrawCmd::GetTexID() const { // If you are getting this assert: A renderer backend with support for ImGuiBackendFlags_RendererHasTextures (1.92) From 5ee984555984979e39e0fd5584be6dc442686499 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 16 May 2025 18:04:44 +0200 Subject: [PATCH 576/716] Fonts: automatically set current rasterizer density to viewport density. Effectively should fix most things on macOS. # Conflicts: # imgui.cpp # imgui.h --- docs/FONTS.md | 2 +- imgui.cpp | 6 +++++- imgui.h | 13 +++++++------ imgui_draw.cpp | 47 ++++++++++++++++++++++++++--------------------- 4 files changed, 39 insertions(+), 29 deletions(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index 452499059403..baa53adde641 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -130,7 +130,7 @@ ImGui::PopFont(); **For advanced options create a ImFontConfig structure and pass it to the AddFont() function (it will be copied internally):** ```cpp ImFontConfig config; -config.RasterizerDensity = 2.0f; +config.OversampleH = 1.0f; ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); ``` diff --git a/imgui.cpp b/imgui.cpp index 2a4001d654f3..58455df8d39b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4398,6 +4398,8 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking if (window) { + if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) + g.FontRasterizerDensity = window->Viewport->FramebufferScale.x; // == SetFontRasterizerDensity() ImGui::UpdateCurrentFontSize(); ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } @@ -8699,7 +8701,8 @@ void ImGui::UpdateCurrentFontSize() g.DrawListSharedData.FontScale = g.FontScale; } -// FIXME-DPI: Not sure how to expose this. It may be automatically applied based on current viewport, if we had this information stored in viewport or monitor. +// Exposed in case user may want to override setting density. +// IMPORTANT: Begin()/End() is overriding density. Be considerate of this you change it. void ImGui::SetFontRasterizerDensity(float rasterizer_density) { ImGuiContext& g = *GImGui; @@ -15240,6 +15243,7 @@ static void ImGui::UpdateViewportsNewFrame() main_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp; main_viewport->Pos = ImVec2(0.0f, 0.0f); main_viewport->Size = g.IO.DisplaySize; + main_viewport->FramebufferScale = g.IO.DisplayFramebufferScale; for (ImGuiViewportP* viewport : g.Viewports) { diff --git a/imgui.h b/imgui.h index 61056bb6ffc2..0eb83cd9a9df 100644 --- a/imgui.h +++ b/imgui.h @@ -2322,7 +2322,8 @@ struct ImGuiIO ImGuiConfigFlags ConfigFlags; // = 0 // See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc. ImGuiBackendFlags BackendFlags; // = 0 // See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend. - ImVec2 DisplaySize; // // Main display size, in pixels (generally == GetMainViewport()->Size). May change every frame. + ImVec2 DisplaySize; // // Main display size, in pixels (== GetMainViewport()->Size). May change every frame. + ImVec2 DisplayFramebufferScale; // = (1, 1) // Main display density. For retina display where window coordinates are different from framebuffer coordinates. This will affect font density + will end up in ImDrawData::FramebufferScale. float DeltaTime; // = 1.0f/60.0f // Time elapsed since last frame, in seconds. May change every frame. float IniSavingRate; // = 5.0f // Minimum time between saving positions/sizes to .ini file, in seconds. const char* IniFilename; // = "imgui.ini" // Path to .ini file (important: default "imgui.ini" is relative to current working dir!). Set NULL to disable automatic .ini loading/saving or if you want to manually call LoadIniSettingsXXX() / SaveIniSettingsXXX() functions. @@ -2334,7 +2335,6 @@ struct ImGuiIO float FontGlobalScale; // = 1.0f // Global scale all fonts bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with CTRL+Wheel. ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. - ImVec2 DisplayFramebufferScale; // = (1, 1) // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale. // Keyboard/Gamepad Navigation options bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. @@ -3341,7 +3341,7 @@ struct ImDrawData ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. ImVec2 DisplayPos; // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications) ImVec2 DisplaySize; // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications) - ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. + ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Copied from viewport->FramebufferScale (== io.DisplayFramebufferScale for main viewport). Generally (1,1) on normal display, (2,2) on OSX with Retina display. ImGuiViewport* OwnerViewport; // Viewport carrying the ImDrawData instance, might be of use to the renderer (generally not). ImVector* Textures; // List of textures to update. Most of the times the list is shared by all ImDrawData, has only 1 texture and it doesn't need any update. This almost always points to ImGui::GetPlatformIO().Textures[]. May be overriden or set to NULL if you want to manually update textures. @@ -3734,8 +3734,8 @@ enum ImFontFlags_ ImFontFlags_None = 0, ImFontFlags_UseDefaultSize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use font->DefaultSize instead of current font size. ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. - ImFontFlags_NoLoadGlyphs = 1 << 2, // Disable loading new glyphs. - ImFontFlags_LockBakedSizes = 1 << 3, // Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. + ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. + ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display. }; // Font runtime data and rendering @@ -3766,7 +3766,7 @@ struct ImFont // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API ImFontBaked* GetFontBaked(float font_size); // Get or create baked data for given size + IMGUI_API ImFontBaked* GetFontBaked(float font_size, float density = -1.0f); // Get or create baked data for given size IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } const char* GetDebugName() const { return Sources.Size ? Sources[0]->Name : ""; } // Fill ImFontConfig::Name. @@ -3832,6 +3832,7 @@ struct ImGuiViewport ImGuiViewportFlags Flags; // See ImGuiViewportFlags_ ImVec2 Pos; // Main Area: Position of the viewport (Dear ImGui coordinates are the same as OS desktop/native coordinates) ImVec2 Size; // Main Area: Size of the viewport. + ImVec2 FramebufferScale; // Density of the viewport for Retina display (always 1,1 on Windows, may be 2,2 etc on macOS/iOS). This will affect font rasterizer density. ImVec2 WorkPos; // Work Area: Position of the viewport minus task bars, menus bars, status bars (>= Pos) ImVec2 WorkSize; // Work Area: Size of the viewport minus task bars, menu bars, status bars (<= Size) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 65485fb20681..6306e9c758dd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3786,25 +3786,28 @@ ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_si ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density) { ImFontAtlasBuilder* builder = atlas->Builder; - ImFontBaked* closest_larger_match = NULL; - ImFontBaked* closest_smaller_match = NULL; - for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + for (int step_n = 0; step_n < 2; step_n++) { - ImFontBaked* baked = &builder->BakedPool[baked_n]; - if (baked->ContainerFont != font || baked->WantDestroy) - continue; - if (baked->RasterizerDensity != font_rasterizer_density) - continue; - if (baked->Size > font_size && (closest_larger_match == NULL || baked->Size < closest_larger_match->Size)) - closest_larger_match = baked; - if (baked->Size < font_size && (closest_smaller_match == NULL || baked->Size > closest_smaller_match->Size)) - closest_smaller_match = baked; - } - if (closest_larger_match) - if (closest_smaller_match == NULL || (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f)) - return closest_larger_match; - if (closest_smaller_match) - return closest_smaller_match; + ImFontBaked* closest_larger_match = NULL; + ImFontBaked* closest_smaller_match = NULL; + for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) + { + ImFontBaked* baked = &builder->BakedPool[baked_n]; + if (baked->ContainerFont != font || baked->WantDestroy) + continue; + if (step_n == 0 && baked->RasterizerDensity != font_rasterizer_density) // First try with same density + continue; + if (baked->Size > font_size && (closest_larger_match == NULL || baked->Size < closest_larger_match->Size)) + closest_larger_match = baked; + if (baked->Size < font_size && (closest_smaller_match == NULL || baked->Size > closest_smaller_match->Size)) + closest_smaller_match = baked; + } + if (closest_larger_match) + if (closest_smaller_match == NULL || (closest_larger_match->Size >= font_size * 2.0f && closest_smaller_match->Size > font_size * 0.5f)) + return closest_larger_match; + if (closest_smaller_match) + return closest_smaller_match; + } return NULL; } @@ -5195,7 +5198,7 @@ ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterize } // ImFontBaked pointers are valid for the entire frame but shall never be kept between frames. -ImFontBaked* ImFont::GetFontBaked(float size) +ImFontBaked* ImFont::GetFontBaked(float size, float density) { ImFontBaked* baked = LastBaked; @@ -5203,12 +5206,14 @@ ImFontBaked* ImFont::GetFontBaked(float size) // - ImGui::PushFontSize() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges) size = ImGui::GetRoundedFontSize(size); - if (baked && baked->Size == size && baked->RasterizerDensity == CurrentRasterizerDensity) + if (density < 0.0f) + density = CurrentRasterizerDensity; + if (baked && baked->Size == size && baked->RasterizerDensity == density) return baked; ImFontAtlas* atlas = ContainerAtlas; ImFontAtlasBuilder* builder = atlas->Builder; - baked = ImFontAtlasBakedGetOrAdd(atlas, this, size, CurrentRasterizerDensity); + baked = ImFontAtlasBakedGetOrAdd(atlas, this, size, density); if (baked == NULL) return NULL; baked->LastUsedFrame = builder->FrameCount; From 822903e56debba39530ecc3bebfdf7709737c217 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 16 May 2025 16:55:29 +0200 Subject: [PATCH 577/716] Fonts: fixed ImFontAtlas::RemoveFont() with multiple sources. Thanks cyfewlp! --- imgui_draw.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6306e9c758dd..3d719820fde3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3205,10 +3205,10 @@ void ImFontAtlas::RemoveFont(ImFont* font) ImFontAtlasFontDestroyOutput(this, font); for (ImFontConfig* src : font->Sources) - { ImFontAtlasFontDestroySourceData(this, src); - Sources.erase(src); - } + for (int src_n = 0; src_n < Sources.Size; src_n++) + if (Sources[src_n].DstFont == font) + Sources.erase(&Sources[src_n--]); bool removed = Fonts.find_erase(font); IM_ASSERT(removed); From 3d848a886a4a071e4b3157b08f37254a4f0d9166 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 May 2025 13:43:16 +0200 Subject: [PATCH 578/716] Fonts: fixed support for IMGUI_STB_NAMESPACE. --- imgui_internal.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index 7c63057347f1..de68b9b3b19d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3746,13 +3746,21 @@ struct ImFontAtlasPostProcessData int Height; }; -// Internal storage for incrementally packing and building a ImFontAtlas -struct stbrp_context_opaque { char data[80]; }; +// We avoid dragging imstb_rectpack.h into public header (partly because binding generators are having issues with it) +#ifdef IMGUI_STB_NAMESPACE +namespace IMGUI_STB_NAMESPACE { struct stbrp_node; } +typedef IMGUI_STB_NAMESPACE::stbrp_node stbrp_node_im; +#else struct stbrp_node; +typedef stbrp_node stbrp_node_im; +#endif +struct stbrp_context_opaque { char data[80]; }; + +// Internal storage for incrementally packing and building a ImFontAtlas struct ImFontAtlasBuilder { stbrp_context_opaque PackContext; // Actually 'stbrp_context' but we don't want to define this in the header file. - ImVector PackNodes; + ImVector PackNodes; ImVector Rects; ImVector RectsIndex; // ImFontAtlasRectId -> index into Rects[] ImVector TempBuffer; // Misc scratch buffer From 92ff153763cc9f701d288a24957ffd552c172060 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 May 2025 14:03:45 +0200 Subject: [PATCH 579/716] Fonts: added notes/comments and dummy type about renaming ImFontBuilderIO::GetBuilderForFreeType() to ImFontLoader::GetFontLoader(). --- imgui_internal.h | 3 +++ misc/freetype/imgui_freetype.h | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index de68b9b3b19d..b1d8774ce38f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3699,6 +3699,9 @@ struct ImFontLoader #ifdef IMGUI_ENABLE_STB_TRUETYPE IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype(); #endif +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are not actually compatible but we provide this as a compile-time error report helper. +#endif //----------------------------------------------------------------------------- // [SECTION] ImFontAtlas internal API diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index b4e9ba1fdf70..2b4810e32e7b 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -6,7 +6,9 @@ #ifndef IMGUI_DISABLE // Usage: -// - Add '#define IMGUI_ENABLE_FREETYPE' in your imconfig to enable support for imgui_freetype in imgui. +// - Add '#define IMGUI_ENABLE_FREETYPE' in your imconfig to automatically enable support +// for imgui_freetype in imgui. It is equivalent to selecting the default loader with: +// io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader() // Optional support for OpenType SVG fonts: // - Add '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG' to use plutosvg (not provided). See #7927. @@ -52,8 +54,9 @@ namespace ImGuiFreeType // Display UI to edit FontBuilderFlags in ImFontAtlas (shared) or ImFontConfig (single source) IMGUI_API bool DebugEditFontBuilderFlags(unsigned int* p_font_loader_flags); - // Obsolete names (will be removed soon) + // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + //IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType(); // Renamed/changed in 1.92. Change 'io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()' to 'io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader()' if you need runtime selection. //static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE' #endif } From f3780c73544466ebe10c6c31749d57d605210b48 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 19 May 2025 18:14:12 +0200 Subject: [PATCH 580/716] Fonts: adding GetFontBaked() in public API. --- imgui.cpp | 5 +++++ imgui.h | 5 +++-- imgui_internal.h | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 58455df8d39b..13cb78f0b65e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8419,6 +8419,11 @@ ImFont* ImGui::GetFont() return GImGui->Font; } +ImFontBaked* ImGui::GetFontBaked() +{ + return GImGui->FontBaked; +} + float ImGui::GetFontSize() { return GImGui->FontSize; diff --git a/imgui.h b/imgui.h index 0eb83cd9a9df..916ad75471e6 100644 --- a/imgui.h +++ b/imgui.h @@ -495,7 +495,7 @@ namespace ImGui // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. // - Before 1.92: PushFont() always used font default size. // - Since 1.92: PushFont() preserve the current shared font size. - // - To use old behavior: use 'PushFont(font, font->DefaultSize)' in call site, or set 'ImFontConfig::Flags |= ImFontFlags_UseDefaultSize' before calling AddFont(). + // - To use old behavior (single size font): use 'PushFont(font, font->DefaultSize)' in call site, or set 'ImFontConfig::Flags |= ImFontFlags_UseDefaultSize' before calling AddFont(). IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. Use font->DefaultSize to revert to font default size. IMGUI_API void PopFont(); IMGUI_API void PushFontSize(float font_size); @@ -526,6 +526,7 @@ namespace ImGui IMGUI_API ImFont* GetFont(); // get current font IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API + IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList @@ -3754,7 +3755,7 @@ struct ImFont // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. ImGuiID FontId; // Unique identifier for the font - float DefaultSize; // 4 // in // Default font size + float DefaultSize; // 4 // in // Default font size passed to AddFont(). It's unlikely you should use this (use ImGui::GetFontBaked() to get font baked at current bound size). ImVector Sources; // 16 // in // List of sources. Pointers within ContainerAtlas->Sources[] ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') diff --git a/imgui_internal.h b/imgui_internal.h index b1d8774ce38f..b4ddf4175386 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2136,9 +2136,9 @@ struct ImGuiContext ImGuiPlatformIO PlatformIO; ImGuiStyle Style; ImVector FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas) - ImFont* Font; // == FontStack.back().Font - ImFontBaked* FontBaked; // == Font->GetFontBaked(FontSize) - float FontSize; // == FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale. Current text height. + ImFont* Font; // Currently bound font. (== FontStack.back().Font) + ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) + float FontSize; // Currently bound font size == line height (== FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale). float FontSizeBeforeScaling; // == value passed to PushFontSize() float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). From 83aad812798ff8a0cd7f583f07a4adc6d9b809a7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 May 2025 18:12:08 +0200 Subject: [PATCH 581/716] Fonts: comments + made IMGUI_DEBUG_LOG_FONT() work without an ImGui context. --- imgui.h | 5 ++++- imgui_internal.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 916ad75471e6..0e4c73915ac0 100644 --- a/imgui.h +++ b/imgui.h @@ -350,6 +350,8 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or // - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. // - Binding generators for languages such as C (which don't have constructors), should provide a helper: // inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } +// In 1.92 we changed most drawing functions using ImTextureID to use ImTextureRef. +// We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. IM_MSVC_RUNTIME_CHECKS_OFF struct ImTextureRef { @@ -358,7 +360,8 @@ struct ImTextureRef #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && !defined(ImTextureID) ImTextureRef(void* tex_id) { _TexData = NULL; _TexID = (ImTextureID)(size_t)tex_id; } // For legacy backends casting to ImTextureID #endif - inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. + + inline ImTextureID GetTexID() const; // == (_TexData ? _TexData->TexID : _TexID) // Implemented below in the file. // Members (either are set, never both!) ImTextureData* _TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded. diff --git a/imgui_internal.h b/imgui_internal.h index b4ddf4175386..55ca3ba897d4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -246,7 +246,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) -#define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext& g2 = *GImGui; if (g2.DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext* g2 = GImGui; if (g2 && g2->DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Called from ImFontAtlas function which may operate without a context. #define IMGUI_DEBUG_LOG_INPUTROUTING(...) do{if (g.DebugLogFlags & ImGuiDebugLogFlags_EventInputRouting)IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Static Asserts From b2343d62474e87b241c6cd2e27464142bb2dd2ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 20 May 2025 19:56:27 +0200 Subject: [PATCH 582/716] Fonts: fallback to default default rasterizer density + pick one from existing viewports at the time of calling AddUpdateViewport(). # Conflicts: # imgui.cpp --- imgui.cpp | 6 +++++- imgui_draw.cpp | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 13cb78f0b65e..d869da7fe9fc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4399,7 +4399,10 @@ static void SetCurrentWindow(ImGuiWindow* window) if (window) { if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) - g.FontRasterizerDensity = window->Viewport->FramebufferScale.x; // == SetFontRasterizerDensity() + { + ImGuiViewport* viewport = window->Viewport; + g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity() + } ImGui::UpdateCurrentFontSize(); ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } @@ -15249,6 +15252,7 @@ static void ImGui::UpdateViewportsNewFrame() main_viewport->Pos = ImVec2(0.0f, 0.0f); main_viewport->Size = g.IO.DisplaySize; main_viewport->FramebufferScale = g.IO.DisplayFramebufferScale; + IM_ASSERT(main_viewport->FramebufferScale.x > 0.0f && main_viewport->FramebufferScale.y > 0.0f); for (ImGuiViewportP* viewport : g.Viewports) { diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3d719820fde3..93f5fdf8d23f 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5225,6 +5225,7 @@ ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float fo { // FIXME-NEWATLAS: Design for picking a nearest size based on some criteria? // FIXME-NEWATLAS: Altering font density won't work right away. + IM_ASSERT(font_size > 0.0f && font_rasterizer_density > 0.0f); ImGuiID baked_id = ImFontAtlasBakedGetId(font->FontId, font_size, font_rasterizer_density); ImFontAtlasBuilder* builder = atlas->Builder; ImFontBaked** p_baked_in_map = (ImFontBaked**)builder->BakedMap.GetVoidPtrRef(baked_id); From 9f8b4bdaf1bc7565ebd9e0f762048d7754868ff3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 21 May 2025 20:35:04 +0200 Subject: [PATCH 583/716] Fonts: fixed edge case calling RenderText() without priming with CalcTextSize(). --- imgui_draw.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 93f5fdf8d23f..e84de2baaba2 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5502,6 +5502,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) { // Align to be pixel perfect +begin: float x = IM_TRUNC(pos.x); float y = IM_TRUNC(pos.y); if (y > clip_rect.w) @@ -5556,6 +5557,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im return; // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) + const int cmd_count = draw_list->CmdBuffer.Size; const int vtx_count_max = (int)(text_end - s) * 4; const int idx_count_max = (int)(text_end - s) * 6; const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; @@ -5678,6 +5680,18 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im x += char_width; } + // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: calls because CalcTextSize() is always used. + if (cmd_count != draw_list->CmdBuffer.Size) + { + IM_ASSERT(draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount == 0); + draw_list->CmdBuffer.pop_back(); + draw_list->PrimUnreserve(idx_count_max, vtx_count_max); + draw_list->AddDrawCmd(); + goto begin; + //RenderText(draw_list, size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip); // FIXME-OPT: Would a 'goto begin' be better for code-gen? + //return; + } + // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action. draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink() draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data); From 5926c877a115d626260f60fc4d80fdb46e92c3ec Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 May 2025 16:32:46 +0200 Subject: [PATCH 584/716] Fonts: detect if ImFontAtlasUpdateNewFrame() is not being called. --- imgui.cpp | 12 ++++++++++-- imgui_draw.cpp | 7 +++++-- imgui_internal.h | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d869da7fe9fc..f5c4330e8067 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5211,16 +5211,24 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } -// FIXME-NEWATLAS-V2: If we aim to support multiple atlases used by same context: how to reach/target all atlases? static void ImGui::UpdateTexturesNewFrame() { + // Cannot update every atlases based on atlas's FrameCount < g.FrameCount, because an atlas may be shared by multiple contexts with different frame count. ImGuiContext& g = *GImGui; + const bool has_textures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; for (ImFontAtlas* atlas : g.FontAtlases) + { if (atlas->OwnerContext == &g) { - atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; + atlas->RendererHasTextures = has_textures; ImFontAtlasUpdateNewFrame(atlas, g.FrameCount); } + else + { + IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1 && "If you manage font atlases yourself you need to call ImFontAtlasUpdateNewFrame() on it."); + IM_ASSERT(atlas->RendererHasTextures == has_textures && "If you manage font atlases yourself make sure atlas->RendererHasTextures is set consistently with all contexts using it."); + } + } } // Build a single texture list diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e84de2baaba2..e0d34c9776bd 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2715,11 +2715,14 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at } } -// Called by NewFrame(). When multiple context own the atlas, only the first one calls this. -// If you are calling this yourself, ensure atlas->RendererHasTextures is set. +// Called by NewFrame() for atlases owned by a context. +// If you manually manage font atlases, you'll need to call this yourself + ensure atlas->RendererHasTextures is set. // 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. +// 'frame_count' may not match those of imgui contexts using this atlas, as contexts may be updated as different frequencies. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) { + IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice? + // Check that font atlas was built or backend support texture reload in which case we can build now if (atlas->RendererHasTextures) { diff --git a/imgui_internal.h b/imgui_internal.h index 55ca3ba897d4..62b98f1f06e2 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3787,7 +3787,7 @@ struct ImFontAtlasBuilder ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure. ImFontAtlasRectId PackIdLinesTexData; - ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; } + ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); FrameCount = -1; RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; } }; IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); From 25f9c318e315e5275ca0993adf3b632574ee490c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 22 May 2025 17:45:22 +0200 Subject: [PATCH 585/716] Fonts: added "Input Glyphs Overlap Detection Tool". Added "Clear bakes", "Clear unused" buttons. Move code. --- imgui.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ imgui.h | 2 +- imgui_draw.cpp | 15 +++++++++----- imgui_internal.h | 2 +- 4 files changed, 64 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f5c4330e8067..9b9874a5a269 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -16699,6 +16699,21 @@ void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, co out_draw_list->Flags = backup_flags; } +// [DEBUG] Compute mask of inputs with the same codepoint. +static int CalcFontGlyphSrcOverlapMask(ImFontAtlas* atlas, ImFont* font, unsigned int codepoint) +{ + int mask = 0, count = 0; + for (int src_n = 0; src_n < font->Sources.Size; src_n++) + { + ImFontConfig* src = font->Sources[src_n]; + if (!(src->FontLoader ? src->FontLoader : atlas->FontLoader)->FontSrcContainsGlyph(atlas, src, (ImWchar)codepoint)) + continue; + mask |= (1 << src_n); + count++; + } + return count > 1 ? mask : 0; +} + // [DEBUG] Display details for a single font, called by ShowStyleEditor(). void ImGui::DebugNodeFont(ImFont* font) { @@ -16730,6 +16745,12 @@ void ImGui::DebugNodeFont(ImFont* font) if (SmallButton("Remove")) atlas->RemoveFont(font); EndDisabled(); + SameLine(); + if (SmallButton("Clear bakes")) + ImFontAtlasFontDiscardBakes(atlas, font, 0); + SameLine(); + if (SmallButton("Clear unused")) + ImFontAtlasFontDiscardBakes(atlas, font, 2); // Display details SetNextItemWidth(GetFontSize() * 8); @@ -16769,6 +16790,37 @@ void ImGui::DebugNodeFont(ImFont* font) TreePop(); } } + if (font->Sources.Size > 1 && TreeNode("Input Glyphs Overlap Detection Tool")) + { + TextWrapped("- First Input that contains the glyph is used.\n- Use ImFontConfig::GlyphExcludeRanges[] to specify ranges to ignore glyph in given Input.\n- This tool doesn't cache results and is slow, don't keep it open!"); + if (BeginTable("table", 2)) + { + for (unsigned int c = 0; c < 0x10000; c++) + if (int overlap_mask = CalcFontGlyphSrcOverlapMask(atlas, font, c)) + { + unsigned int c_end = c + 1; + while (c_end < 0x10000 && CalcFontGlyphSrcOverlapMask(atlas, font, c_end) == overlap_mask) + c_end++; + if (TableNextColumn() && TreeNode((void*)(intptr_t)c, "U+%04X-U+%04X: %d codepoints in %d inputs", c, c_end - 1, c_end - c, ImCountSetBits(overlap_mask))) + { + char utf8_buf[5]; + for (unsigned int n = c; n < c_end; n++) + BulletText("Codepoint U+%04X (%s)", n, ImTextCharToUtf8(utf8_buf, n)); + TreePop(); + } + TableNextColumn(); + for (int src_n = 0; src_n < font->Sources.Size; src_n++) + if (overlap_mask & (1 << src_n)) + { + Text("%d ", src_n); + SameLine(); + } + c = c_end - 1; + } + EndTable(); + } + TreePop(); + } // Display all glyphs of the fonts in separate pages of 256 characters for (int baked_n = 0; baked_n < atlas->Builder->BakedPool.Size; baked_n++) diff --git a/imgui.h b/imgui.h index 0e4c73915ac0..8ed8f2318bb5 100644 --- a/imgui.h +++ b/imgui.h @@ -3456,7 +3456,7 @@ struct ImFontConfig //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. + const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e0d34c9776bd..b2380dfc0638 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3843,14 +3843,18 @@ void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* bake font->LastBaked = NULL; } -void ImFontAtlasFontDiscardOutputBakes(ImFontAtlas* atlas, ImFont* font) +// use unused_frames==0 to discard everything. +void ImFontAtlasFontDiscardBakes(ImFontAtlas* atlas, ImFont* font, int unused_frames) { if (ImFontAtlasBuilder* builder = atlas->Builder) // This can be called from font destructor for (int baked_n = 0; baked_n < builder->BakedPool.Size; baked_n++) { ImFontBaked* baked = &builder->BakedPool[baked_n]; - if (baked->ContainerFont == font && !baked->WantDestroy) - ImFontAtlasBakedDiscard(atlas, font, baked); + if (baked->LastUsedFrame + unused_frames > atlas->Builder->FrameCount) + continue; + if (baked->ContainerFont != font || baked->WantDestroy) + continue; + ImFontAtlasBakedDiscard(atlas, font, baked); } } @@ -4364,7 +4368,8 @@ ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId return &builder->Rects[index_entry->TargetIndex]; } -// Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries) +// Important! This assume by ImFontConfig::GlyphExcludeRanges[] is a SMALL ARRAY (e.g. <10 entries) +// Use "Input Glyphs Overlap Detection Tool" to display a list of glyphs provided by multiple sources in order to set this array up. static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint) { if (const ImWchar* exclude_list = src->GlyphExcludeRanges) @@ -5024,7 +5029,7 @@ ImFont::~ImFont() void ImFont::ClearOutputData() { if (ImFontAtlas* atlas = ContainerAtlas) - ImFontAtlasFontDiscardOutputBakes(atlas, this); + ImFontAtlasFontDiscardBakes(atlas, this, 0); FallbackChar = EllipsisChar = 0; memset(Used8kPagesMap, 0, sizeof(Used8kPagesMap)); LastBaked = NULL; diff --git a/imgui_internal.h b/imgui_internal.h index 62b98f1f06e2..59666f3e5694 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3815,7 +3815,7 @@ IMGUI_API void ImFontAtlasFontSourceAddToFont(ImFontAtlas* atlas, I IMGUI_API void ImFontAtlasFontDestroySourceData(ImFontAtlas* atlas, ImFontConfig* src); IMGUI_API bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font); // Using FontDestroyOutput/FontInitOutput sequence useful notably if font loader params have changed IMGUI_API void ImFontAtlasFontDestroyOutput(ImFontAtlas* atlas, ImFont* font); -IMGUI_API void ImFontAtlasFontDiscardOutputBakes(ImFontAtlas* atlas, ImFont* font); +IMGUI_API void ImFontAtlasFontDiscardBakes(ImFontAtlas* atlas, ImFont* font, int unused_frames); IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_size, float rasterizer_density); IMGUI_API ImFontBaked* ImFontAtlasBakedGetOrAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density); From e3860aa6ac0be98df8df0aeaa194107a27f5f4d4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 13:52:20 +0200 Subject: [PATCH 586/716] (Breaking) Fonts: removing obsolete ImFont::Scale. --- imgui.cpp | 13 ++++++++++--- imgui.h | 4 +++- imgui_draw.cpp | 2 ++ imgui_internal.h | 2 +- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9b9874a5a269..79d36db59ff7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8683,7 +8683,9 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size) if (font != NULL) { IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IM_ASSERT(font->Scale > 0.0f); +#endif g.DrawListSharedData.Font = g.Font; ImFontAtlasUpdateDrawListsSharedData(g.Font->ContainerAtlas); if (g.CurrentWindow != NULL) @@ -8699,7 +8701,10 @@ void ImGui::UpdateCurrentFontSize() return; float final_size = g.FontSizeBeforeScaling * g.IO.FontGlobalScale; - final_size *= g.Font->Scale; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (g.Font != NULL) + final_size *= g.Font->Scale; +#endif if (window != NULL) final_size *= window->FontWindowScale; @@ -16753,14 +16758,16 @@ void ImGui::DebugNodeFont(ImFont* font) ImFontAtlasFontDiscardBakes(atlas, font, 2); // Display details +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS SetNextItemWidth(GetFontSize() * 8); DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f"); - SameLine(); MetricsHelpMarker( + /*SameLine(); MetricsHelpMarker( "Note that the default embedded font is NOT meant to be scaled.\n\n" "Font are currently rendered into bitmaps at a given size at the time of building the atlas. " "You may oversample them to get some flexibility with scaling. " "You can also render at multiple sizes and select which one to use at runtime.\n\n" - "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)"); + "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");*/ +#endif char c_str[5]; Text("Fallback character: '%s' (U+%04X)", ImTextCharToUtf8(c_str, font->FallbackChar), font->FallbackChar); diff --git a/imgui.h b/imgui.h index 8ed8f2318bb5..9a9473760692 100644 --- a/imgui.h +++ b/imgui.h @@ -3762,10 +3762,12 @@ struct ImFont ImVector Sources; // 16 // in // List of sources. Pointers within ContainerAtlas->Sources[] ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') - float Scale; // 4 // in // Base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() ImU8 Used8kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/8192/8]; // 1 bytes if ImWchar=ImWchar16, 16 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints. bool EllipsisAutoBake; // 1 // // Mark when the "..." glyph needs to be generated. ImGuiStorage RemapPairs; // 16 // // Remapping pairs when using AddRemapChar(), otherwise empty. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + float Scale; // 4 // in // Legacy base font scale (~1.0f), multiplied by the per-window font scale which you can adjust with SetWindowFontScale() +#endif // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b2380dfc0638..7e5b10f34062 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5018,7 +5018,9 @@ void ImFontBaked::ClearOutputData() ImFont::ImFont() { memset(this, 0, sizeof(*this)); +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS Scale = 1.0f; +#endif } ImFont::~ImFont() diff --git a/imgui_internal.h b/imgui_internal.h index 59666f3e5694..5dacf666e92a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2139,7 +2139,7 @@ struct ImGuiContext ImFont* Font; // Currently bound font. (== FontStack.back().Font) ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) float FontSize; // Currently bound font size == line height (== FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale). - float FontSizeBeforeScaling; // == value passed to PushFontSize() + float FontSizeBeforeScaling; // == value passed to PushFont() / PushFontSize() when specified. float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale From 69547bd4bdfb50841548b18574809d14dc83f05e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 14:54:26 +0200 Subject: [PATCH 587/716] Fonts: ImFont::DefaultSize -> ImFont::LegacySize. ImFontFlags_UseDefaultSize -> ImFontFlags_DefaultToLegacySize. --- imgui.cpp | 6 +++--- imgui.h | 10 +++++----- imgui_draw.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 79d36db59ff7..0a637be0ed9c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8620,7 +8620,7 @@ void ImGui::UpdateFontsNewFrame() atlas->Locked = true; // We do this really unusual thing of calling *push_front()*, the reason behind that we want to support the PushFont()/NewFrame()/PopFont() idiom. - ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->DefaultSize }; + ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->LegacySize }; g.FontStack.push_front(font_stack_data); if (g.FontStack.Size == 1) ImGui::SetCurrentFont(font_stack_data.Font, font_stack_data.FontSize); @@ -8741,8 +8741,8 @@ void ImGui::PushFont(ImFont* font, float font_size) font = GetDefaultFont(); if (font_size <= 0.0f) { - if (font->Flags & ImFontFlags_UseDefaultSize) - font_size = font->DefaultSize; // Legacy: use default font size. Same as doing PushFont(font, font->DefaultSize). // FIXME-NEWATLAS + if (font->Flags & ImFontFlags_DefaultToLegacySize) + font_size = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) else font_size = g.FontSizeBeforeScaling; // Keep current font size } diff --git a/imgui.h b/imgui.h index 9a9473760692..a10e8d1a38ae 100644 --- a/imgui.h +++ b/imgui.h @@ -498,8 +498,8 @@ namespace ImGui // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. // - Before 1.92: PushFont() always used font default size. // - Since 1.92: PushFont() preserve the current shared font size. - // - To use old behavior (single size font): use 'PushFont(font, font->DefaultSize)' in call site, or set 'ImFontConfig::Flags |= ImFontFlags_UseDefaultSize' before calling AddFont(). - IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. Use font->DefaultSize to revert to font default size. + // - To use old behavior (single size font): use 'PushFont(font, font->LegacySize)' in call site, or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(). + IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. Use font->LegacySize to revert to font size specified by AddFont(). IMGUI_API void PopFont(); IMGUI_API void PushFontSize(float font_size); IMGUI_API void PopFontSize(); @@ -3736,7 +3736,7 @@ struct ImFontBaked enum ImFontFlags_ { ImFontFlags_None = 0, - ImFontFlags_UseDefaultSize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use font->DefaultSize instead of current font size. + ImFontFlags_DefaultToLegacySize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use font->LegacySize instead of current font size. ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display. @@ -3758,7 +3758,7 @@ struct ImFont // [Internal] Members: Cold ~24-52 bytes // Conceptually Sources[] is the list of font sources merged to create this font. ImGuiID FontId; // Unique identifier for the font - float DefaultSize; // 4 // in // Default font size passed to AddFont(). It's unlikely you should use this (use ImGui::GetFontBaked() to get font baked at current bound size). + float LegacySize; // 4 // in // Font size passed to AddFont(). Use for old code calling PushFont() expecting to use that size. (use ImGui::GetFontBaked() to get font baked at current bound size). ImVector Sources; // 16 // in // List of sources. Pointers within ContainerAtlas->Sources[] ImWchar EllipsisChar; // 2-4 // out // Character used for ellipsis rendering ('...'). ImWchar FallbackChar; // 2-4 // out // Character used if a glyph isn't found (U+FFFD, '?') @@ -3785,7 +3785,7 @@ struct ImFont IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); IMGUI_API void RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(DefaultSize * scale, text, text_end, wrap_width); } + inline const char* CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) { return CalcWordWrapPosition(LegacySize * scale, text, text_end, wrap_width); } #endif // [Internal] Don't use! diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 7e5b10f34062..e067d57badc2 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3004,7 +3004,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) font = IM_NEW(ImFont)(); font->FontId = FontNextUniqueID++; font->Flags = font_cfg_in->Flags; - font->DefaultSize = font_cfg_in->SizePixels; + font->LegacySize = font_cfg_in->SizePixels; font->CurrentRasterizerDensity = font_cfg_in->RasterizerDensity; Fonts.push_back(font); } @@ -3266,7 +3266,7 @@ void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id) // myfont->Flags |= ImFontFlags_LockBakedSizes; ImFontAtlasRectId ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int width, int height, float advance_x, const ImVec2& offset) { - float font_size = font->DefaultSize; + float font_size = font->LegacySize; return AddCustomRectFontGlyphForSize(font, font_size, codepoint, width, height, advance_x, offset); } // FIXME: we automatically set glyph.Colored=true by default. From 033cdc41338e3b5947ac85ec57a997d964e31abb Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 15:08:54 +0200 Subject: [PATCH 588/716] Fonts: comments and slight packing of ImFontConfig fields. --- imgui.cpp | 7 ++----- imgui.h | 17 ++++++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0a637be0ed9c..38f0cf09625b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15914,11 +15914,8 @@ void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRe PopStyleVar(); char texid_desc[30]; - Text("Status = %s (%d)", ImTextureDataGetStatusName(tex->Status), tex->Status); - Text("Format = %s (%d)", ImTextureDataGetFormatName(tex->Format), tex->Format); - Text("TexID = %s", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID)); - Text("BackendUserData = %p", tex->BackendUserData); - Text("UseColors = %d", tex->UseColors); + Text("Status = %s (%d), Format = %s (%d), UseColors = %d", ImTextureDataGetStatusName(tex->Status), tex->Status, ImTextureDataGetFormatName(tex->Format), tex->Format, tex->UseColors); + Text("TexID = %s, BackendUserData = %p", FormatTextureIDForDebugDisplay(texid_desc, IM_ARRAYSIZE(texid_desc), tex->TexID), tex->BackendUserData); TreePop(); } PopID(); diff --git a/imgui.h b/imgui.h index a10e8d1a38ae..44aa078ae592 100644 --- a/imgui.h +++ b/imgui.h @@ -3443,20 +3443,24 @@ struct ImTextureData // A font input/source (we may rename this to ImFontSource in the future) struct ImFontConfig { + // Data Source + char Name[40]; // // Name (strictly to ease debugging, hence limited size buffer) void* FontData; // // TTF/OTF data int FontDataSize; // // TTF/OTF data size bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). + + // Options bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. bool PixelSnapV; // true // Align Scaled GlyphOffset.y to pixel boundaries. - int FontNo; // 0 // Index of font within TTF/OTF file - int OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - int OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. + ImS8 FontNo; // 0 // Index of font within TTF/OTF file + ImS8 OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + ImS8 OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). + const ImWchar* GlyphRanges; // NULL // *LEGACY* THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). + const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. - const ImWchar* GlyphRanges; // NULL // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. @@ -3466,8 +3470,7 @@ struct ImFontConfig ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] - char Name[40]; // Name (strictly to ease debugging) - ImFontFlags Flags; // Font flags (don't use just yet) + ImFontFlags Flags; // Font flags (don't use just yet, will be exposed in upcoming 1.92.X updates) ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) const ImFontLoader* FontLoader; // Custom font backend for this source (other use one stored in ImFontAtlas) void* FontLoaderData; // Font loader opaque storage (per font config) From b029be6b6c251e4bb647b9b5c60b239b38c93a9c Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 18:55:55 +0200 Subject: [PATCH 589/716] Fonts: avoid calling GetFontBaked() during SetFontSize(). Also fixes loading extraneous baked on atlas that will be locked e.g. PushFontSize() before NewFrame() on legacy backend. --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 38f0cf09625b..7b4fc863856a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8715,9 +8715,9 @@ void ImGui::UpdateCurrentFontSize() final_size = ImMax(1.0f, final_size); if (g.Font != NULL && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; - g.FontBaked = (g.Font != NULL) ? g.Font->GetFontBaked(final_size) : NULL; g.FontSize = final_size; - g.FontScale = (g.Font != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; + g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL; + g.FontScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; g.DrawListSharedData.FontSize = g.FontSize; g.DrawListSharedData.FontScale = g.FontScale; } From 1e118ab8911625bf49938dd5d29c2833af216096 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 20:24:06 +0200 Subject: [PATCH 590/716] Fonts: added ImGuiStyle::FontSizeBase. Ensuring PushFontSize() works before main loop and across NewFrame(). # Conflicts: # imgui.cpp --- imgui.cpp | 106 +++++++++++++++++++++++++++++++++-------------- imgui.h | 20 +++++++-- imgui_demo.cpp | 44 +++++++++++++------- imgui_draw.cpp | 2 +- imgui_internal.h | 9 ++-- 5 files changed, 125 insertions(+), 56 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7b4fc863856a..d18beab96aaf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1354,6 +1354,7 @@ static void* GImAllocatorUserData = NULL; ImGuiStyle::ImGuiStyle() { + FontSizeBase = 0.0f; // Will default to io.Fonts->Fonts[0] on first frame. Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. WindowPadding = ImVec2(8,8); // Padding within a window @@ -1415,6 +1416,10 @@ ImGuiStyle::ImGuiStyle() HoverFlagsForTooltipMouse = ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayShort | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. HoverFlagsForTooltipNav = ImGuiHoveredFlags_NoSharedDelay | ImGuiHoveredFlags_DelayNormal | ImGuiHoveredFlags_AllowWhenDisabled; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. + // [Internal] + _MainScale = 1.0f; + _NextFrameFontSizeBase = 0.0f; + // Default theme ImGui::StyleColorsDark(this); } @@ -1423,6 +1428,8 @@ ImGuiStyle::ImGuiStyle() // Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. void ImGuiStyle::ScaleAllSizes(float scale_factor) { + _MainScale *= scale_factor; + FontSizeBase = ImTrunc(FontSizeBase * scale_factor); WindowPadding = ImTrunc(WindowPadding * scale_factor); WindowRounding = ImTrunc(WindowRounding * scale_factor); WindowMinSize = ImTrunc(WindowMinSize * scale_factor); @@ -4403,7 +4410,7 @@ static void SetCurrentWindow(ImGuiWindow* window) ImGuiViewport* viewport = window->Viewport; g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity() } - ImGui::UpdateCurrentFontSize(); + ImGui::UpdateCurrentFontSize(0.0f); ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } } @@ -8450,7 +8457,7 @@ void ImGui::SetWindowFontScale(float scale) IM_ASSERT(scale > 0.0f); ImGuiWindow* window = GetCurrentWindow(); window->FontWindowScale = scale; - UpdateCurrentFontSize(); + UpdateCurrentFontSize(0.0f); } void ImGui::PushFocusScope(ImGuiID id) @@ -8619,12 +8626,24 @@ void ImGui::UpdateFontsNewFrame() for (ImFontAtlas* atlas : g.FontAtlases) atlas->Locked = true; - // We do this really unusual thing of calling *push_front()*, the reason behind that we want to support the PushFont()/NewFrame()/PopFont() idiom. - ImFontStackData font_stack_data = { ImGui::GetDefaultFont(), ImGui::GetDefaultFont()->LegacySize }; - g.FontStack.push_front(font_stack_data); - if (g.FontStack.Size == 1) - ImGui::SetCurrentFont(font_stack_data.Font, font_stack_data.FontSize); + if (g.Style._NextFrameFontSizeBase != 0.0f) + { + g.Style.FontSizeBase = g.Style._NextFrameFontSizeBase; + g.Style._NextFrameFontSizeBase = 0.0f; + } + + // Apply default font size the first time + ImFont* font = ImGui::GetDefaultFont(); + if (g.Style.FontSizeBase <= 0.0f) + g.Style.FontSizeBase = font->LegacySize * g.Style._MainScale; + // Set initial font + g.Font = font; + g.FontSizeBeforeScaling = g.Style.FontSizeBase; + g.FontSize = 0.0f; + ImFontStackData font_stack_data = { font, g.Style.FontSizeBase, g.Style.FontSizeBase }; // <--- Will restore FontSize + SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, 0.0f); // <--- but use 0.0f to enable scale + g.FontStack.push_back(font_stack_data); IM_ASSERT(g.Font->IsLoaded()); } @@ -8633,6 +8652,15 @@ void ImGui::UpdateFontsEndFrame() PopFont(); } +ImFont* ImGui::GetDefaultFont() +{ + ImGuiContext& g = *GImGui; + ImFontAtlas* atlas = g.IO.Fonts; + if (atlas->Builder == NULL) + ImFontAtlasBuildMain(atlas); + return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0]; +} + void ImGui::RegisterUserTexture(ImTextureData* tex) { ImGuiContext& g = *GImGui; @@ -8673,12 +8701,12 @@ void ImGui::UnregisterFontAtlas(ImFontAtlas* atlas) // the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem // because we have a concrete need and a test bed for multiple atlas textures. // FIXME-NEWATLAS-V2: perhaps we can now leverage ImFontAtlasUpdateDrawListsTextures() ? -void ImGui::SetCurrentFont(ImFont* font, float font_size) +void ImGui::SetCurrentFont(ImFont* font, float font_size_before_scaling, float font_size_after_scaling) { ImGuiContext& g = *GImGui; g.Font = font; - g.FontSizeBeforeScaling = font_size; - UpdateCurrentFontSize(); + g.FontSizeBeforeScaling = font_size_before_scaling; + UpdateCurrentFontSize(font_size_after_scaling); if (font != NULL) { @@ -8693,20 +8721,27 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size) } } -void ImGui::UpdateCurrentFontSize() +void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + + g.Style.FontSizeBase = g.FontSizeBeforeScaling; if (window != NULL && window->SkipItems) return; - float final_size = g.FontSizeBeforeScaling * g.IO.FontGlobalScale; + // Restoring is pretty much only used by PopFont()/PopFontSize() + float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; + if (final_size == 0.0f) + { + final_size = g.FontSizeBeforeScaling * g.IO.FontGlobalScale; #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (g.Font != NULL) - final_size *= g.Font->Scale; + if (g.Font != NULL) + final_size *= g.Font->Scale; #endif - if (window != NULL) - final_size *= window->FontWindowScale; + if (window != NULL) + final_size *= window->FontWindowScale; + } // Round font size // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. @@ -8731,12 +8766,16 @@ void ImGui::SetFontRasterizerDensity(float rasterizer_density) if (g.FontRasterizerDensity == rasterizer_density) return; g.FontRasterizerDensity = rasterizer_density; - UpdateCurrentFontSize(); + UpdateCurrentFontSize(0.0f); } +// If you want to scale an existing font size: +// - Use e.g. PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). +// - Do NOT use PushFontSize(GetFontSize() * factor) (= value after external scale factors applied). void ImGui::PushFont(ImFont* font, float font_size) { ImGuiContext& g = *GImGui; + g.FontStack.push_back({ g.Font, g.FontSizeBeforeScaling, g.FontSize }); if (font == NULL) font = GetDefaultFont(); if (font_size <= 0.0f) @@ -8746,23 +8785,20 @@ void ImGui::PushFont(ImFont* font, float font_size) else font_size = g.FontSizeBeforeScaling; // Keep current font size } - g.FontStack.push_back({ font, font_size }); - SetCurrentFont(font, font_size); + SetCurrentFont(font, font_size, 0.0f); } void ImGui::PopFont() { ImGuiContext& g = *GImGui; - if (g.FontStack.Size <= 1 && g.WithinFrameScope) + if (g.FontStack.Size <= 0 && g.WithinFrameScope) { IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); return; } + ImFontStackData* font_stack_data = &g.FontStack.back(); + SetCurrentFont(font_stack_data->Font, font_stack_data->FontSizeBeforeScaling, font_stack_data->FontSizeAfterScaling); g.FontStack.pop_back(); - if (ImFontStackData* font_stack_data = (g.FontStack.Size > 0) ? &g.FontStack.back() : NULL) - SetCurrentFont(font_stack_data->Font, font_stack_data->FontSize); - else - SetCurrentFont(NULL, 0.0f); } void ImGui::PushFontSize(float font_size) @@ -15751,10 +15787,11 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) { ImGuiContext& g = *GImGui; ImGuiIO& io = g.IO; + ImGuiStyle& style = g.Style; Text("Read "); SameLine(0, 0); TextLinkOpenURL("https://www.dearimgui.com/faq/"); SameLine(0, 0); - Text(" for details on font loading."); + Text(" for details."); SeparatorText("Backend Support for Dynamic Fonts"); BeginDisabled(); @@ -15762,11 +15799,16 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) EndDisabled(); BeginDisabled((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); - SetNextItemWidth(GetFontSize() * 5); - DragFloat("io.FontGlobalScale", &io.FontGlobalScale, 0.05f, 0.5f, 5.0f); - BulletText("This is scaling font only. General scaling will come later."); - BulletText("Load an actual font that's not the default for best result!"); - BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("https://github.com/ocornut/imgui/issues/8465"); + SetNextItemWidth(GetFontSize() * 10); + if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) + style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. + SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); + SameLine(); MetricsHelpMarker("- This is scaling font only. General scaling will come later."); + SetNextItemWidth(GetFontSize() * 10); + DragFloat("io.FontGlobalScale", &io.FontGlobalScale, 0.05f, 0.5f, 5.0f); // <-- This works, but no need to make it too visible. + BulletText("Load a nice font for better results!"); + BulletText("Please submit feedback:"); + SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); EndDisabled(); SeparatorText("Fonts"); @@ -15786,7 +15828,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) #else BeginDisabled(); RadioButton("stb_truetype", false); - SetItemTooltip("Requires IMGUI_ENABLE_STB_TRUETYPE"); + SetItemTooltip("Requires #define IMGUI_ENABLE_STB_TRUETYPE"); EndDisabled(); #endif SameLine(); @@ -15810,7 +15852,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) #else BeginDisabled(); RadioButton("FreeType", false); - SetItemTooltip("Requires IMGUI_ENABLE_FREETYPE + imgui_freetype.cpp."); + SetItemTooltip("Requires #define IMGUI_ENABLE_FREETYPE + imgui_freetype.cpp."); EndDisabled(); #endif EndDisabled(); diff --git a/imgui.h b/imgui.h index 44aa078ae592..d2bc7ce770f8 100644 --- a/imgui.h +++ b/imgui.h @@ -498,8 +498,13 @@ namespace ImGui // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. // - Before 1.92: PushFont() always used font default size. // - Since 1.92: PushFont() preserve the current shared font size. - // - To use old behavior (single size font): use 'PushFont(font, font->LegacySize)' in call site, or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(). - IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. Use font->LegacySize to revert to font size specified by AddFont(). + // - To use old behavior (single size font, size specified in AddFontXXX() call: + // - Use 'PushFont(font, font->LegacySize)' at call site + // - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then 'PushFont(font)' will use this size. + // *IMPORTANT* If you want to scale an existing font size: + // - OK: PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). + // - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale factors are io.FontGlobalScale and per-viewport scales.). + IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. IMGUI_API void PopFont(); IMGUI_API void PushFontSize(float font_size); IMGUI_API void PopFontSize(); @@ -2222,6 +2227,8 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { + float FontSizeBase; // Current base font size (scaling applied). Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. + float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. ImVec2 WindowPadding; // Padding within a window. @@ -2287,8 +2294,13 @@ struct ImGuiStyle ImGuiHoveredFlags HoverFlagsForTooltipMouse;// Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using mouse. ImGuiHoveredFlags HoverFlagsForTooltipNav; // Default flags when using IsItemHovered(ImGuiHoveredFlags_ForTooltip) or BeginItemTooltip()/SetItemTooltip() while using keyboard/gamepad. - IMGUI_API ImGuiStyle(); - IMGUI_API void ScaleAllSizes(float scale_factor); + // [Internal] + float _MainScale; // FIXME-WIP: Reference scale, as applied by ScaleAllSizes(). + float _NextFrameFontSizeBase; // FIXME: Temporary hack until we finish remaining work. + + // Functions + IMGUI_API ImGuiStyle(); + IMGUI_API void ScaleAllSizes(float scale_factor); // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_demo.cpp b/imgui_demo.cpp index dda817eb8924..fc1d16953d79 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -430,16 +430,25 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); - ImGui::SeparatorText("dynamic_fonts branch"); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 5); - ImGui::DragFloat("io.FontGlobalScale", &ImGui::GetIO().FontGlobalScale, 0.05f, 0.5f, 5.0f); - ImGui::BulletText("This is scaling font only. General scaling will come later."); - ImGui::BulletText("Load an actual font that's not the default for best result!"); - ImGui::BulletText("See 'Widgets->Fonts' below for more.."); - ImGui::BulletText("Current font loader: '%s'", ImGui::GetIO().Fonts->FontLoaderName); - ImGui::BulletText("Please submit feedback:"); ImGui::SameLine(); - ImGui::TextLinkOpenURL("https://github.com/ocornut/imgui/issues/8465"); - ImGui::Spacing(); + { + ImGui::SeparatorText("dynamic_fonts branch"); + ImGuiStyle& style = ImGui::GetStyle(); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); + ImGui::ShowFontSelector("Font"); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); + if (ImGui::DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) + style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. + ImGui::SameLine(0.0f, 0.0f); Text(" (out %.2f)", ImGui::GetFontSize()); + ImGui::SameLine(); HelpMarker("- This is scaling font only. General scaling will come later."); + //ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); + //ImGui::DragFloat("FontGlobalScale", &ImGui::GetIO().FontGlobalScale, 0.05f, 0.5f, 5.0f); + ImGui::BulletText("Load a nice font for better results!"); + ImGui::BulletText("See 'Widgets->Fonts' below for more."); + //ImGui::BulletText("Current font loader: '%s'", ImGui::GetIO().Fonts->FontLoaderName); + ImGui::BulletText("Please submit feedback:"); ImGui::SameLine(); + ImGui::TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); + ImGui::Spacing(); + } IMGUI_DEMO_MARKER("Help"); if (ImGui::CollapsingHeader("Help")) @@ -8207,11 +8216,16 @@ void ImGui::ShowFontSelector(const char* label) ImGui::EndCombo(); } ImGui::SameLine(); - HelpMarker( - "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" - "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" - "- Read FAQ and docs/FONTS.md for more details.\n" - "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) + HelpMarker( + "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n" + "- Read FAQ and docs/FONTS.md for more details."); + else + HelpMarker( + "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n" + "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" + "- Read FAQ and docs/FONTS.md for more details.\n" + "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); } // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e067d57badc2..69c207fd2e4b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3190,7 +3190,7 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, bool need_bind_ctx = ctx != curr_ctx; if (need_bind_ctx) ImGui::SetCurrentContext(ctx); - ImGui::SetCurrentFont(new_font, ctx->FontSize); + ImGui::SetCurrentFont(new_font, ctx->FontSizeBeforeScaling, ctx->FontSize); if (need_bind_ctx) ImGui::SetCurrentContext(curr_ctx); } diff --git a/imgui_internal.h b/imgui_internal.h index 5dacf666e92a..4c1d1f3921b8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -871,7 +871,8 @@ struct ImDrawDataBuilder struct ImFontStackData { ImFont* Font; - float FontSize; + float FontSizeBeforeScaling; + float FontSizeAfterScaling; }; //----------------------------------------------------------------------------- @@ -3116,12 +3117,12 @@ namespace ImGui IMGUI_API void UnregisterUserTexture(ImTextureData* tex); IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas); - IMGUI_API void SetCurrentFont(ImFont* font, float font_size); + IMGUI_API void SetCurrentFont(ImFont* font, float font_size_before_scaling, float font_size_after_scaling); + IMGUI_API void UpdateCurrentFontSize(float restore_font_size_after_scaling); IMGUI_API void SetFontRasterizerDensity(float rasterizer_density); inline float GetFontRasterizerDensity() { return GImGui->FontRasterizerDensity; } - IMGUI_API void UpdateCurrentFontSize(); inline float GetRoundedFontSize(float size) { return IM_ROUND(size); } - inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } + IMGUI_API ImFont* GetDefaultFont(); IMGUI_API void PushPasswordFont(); IMGUI_API void PopPasswordFont(); inline ImDrawList* GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); return GetForegroundDrawList(); } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches. From 402db2ef326735fe537f051980d569b668db4179 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Jun 2025 15:21:52 +0200 Subject: [PATCH 591/716] Fonts: fixed passing negative sizes to stb_truetype loader. --- imgui_draw.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 69c207fd2e4b..e74477dc6f08 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4530,10 +4530,10 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* } src->FontLoaderData = bd_font_data; - if (src->SizePixels > 0.0f) + if (src->SizePixels >= 0.0f) bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else - bd_font_data->ScaleFactor = -stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); + bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); if (src != src->DstFont->Sources[0]) bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit From 59a11363a52071b438043e35c0865f377b630d43 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 26 May 2025 23:13:34 +0200 Subject: [PATCH 592/716] Fonts: ground work for allowing SizePixels to be optional. --- imgui.cpp | 5 ++++- imgui.h | 4 ++-- imgui_draw.cpp | 11 ++++++++--- misc/freetype/imgui_freetype.cpp | 3 ++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d18beab96aaf..1ffa0652f34d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1204,6 +1204,9 @@ CODE #define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Hold CTRL to display for all candidates. CTRL+Arrow to change last direction. #define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window +// Default font size if unspecified in both style.FontSizeBase and AddFontXXX() calls. +static const float FONT_DEFAULT_SIZE = 20.0f; + // When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch. static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear @@ -8635,7 +8638,7 @@ void ImGui::UpdateFontsNewFrame() // Apply default font size the first time ImFont* font = ImGui::GetDefaultFont(); if (g.Style.FontSizeBase <= 0.0f) - g.Style.FontSizeBase = font->LegacySize * g.Style._MainScale; + g.Style.FontSizeBase = (font->LegacySize > 0.0f ? font->LegacySize : FONT_DEFAULT_SIZE) * g.Style._MainScale; // Set initial font g.Font = font; diff --git a/imgui.h b/imgui.h index d2bc7ce770f8..6e99b0be9c36 100644 --- a/imgui.h +++ b/imgui.h @@ -3475,10 +3475,10 @@ struct ImFontConfig ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs - float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. + float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. // FIXME-NEWATLAS: Intentionally unscaled unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. - float RasterizerDensity; // 1.0f // (Legacy: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported). DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. + float RasterizerDensity; // 1.0f // [LEGACY: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported] DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e74477dc6f08..6fabbac9e143 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2988,10 +2988,13 @@ bool ImFontAtlas::Build() ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) { + // Sanity Checks IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); IM_ASSERT((font_cfg_in->FontData != NULL && font_cfg_in->FontDataSize > 0) || (font_cfg_in->FontLoader != NULL)); - IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); + //IM_ASSERT(font_cfg_in->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?"); IM_ASSERT(font_cfg_in->RasterizerDensity > 0.0f && "Is ImFontConfig struct correctly initialized?"); + if (font_cfg_in->GlyphOffset.x != 0.0f || font_cfg_in->GlyphOffset.y != 0.0f || font_cfg_in->GlyphMinAdvanceX != 0.0f || font_cfg_in->GlyphMaxAdvanceX != FLT_MAX) + IM_ASSERT(font_cfg_in->SizePixels != 0.0f && "Specifying glyph offset/advances requires a reference size to base it on."); // Lazily create builder on the first call to AddFont if (Builder == NULL) @@ -4636,7 +4639,8 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC if (oversample_v > 1) stbtt__v_prefilter(bitmap_pixels, r->w, r->h, r->w, oversample_v); - const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; + const float ref_size = baked->ContainerFont->Sources[0]->SizePixels; + const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; float font_off_x = (src->GlyphOffset.x * offsets_scale); float font_off_y = (src->GlyphOffset.y * offsets_scale); if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. @@ -5075,7 +5079,8 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked if (src != NULL) { // Clamp & recenter if needed - const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; + const float ref_size = baked->ContainerFont->Sources[0]->SizePixels; + const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; float advance_x = ImClamp(glyph->AdvanceX, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); if (advance_x != glyph->AdvanceX) { diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index a0fc9692636b..4c10ff42dd70 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -527,7 +527,8 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data; ImGui_ImplFreeType_BlitGlyph(ft_bitmap, temp_buffer, w); - const float offsets_scale = baked->Size / baked->ContainerFont->Sources[0]->SizePixels; + const float ref_size = baked->ContainerFont->Sources[0]->SizePixels; + const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; float font_off_x = (src->GlyphOffset.x * offsets_scale); float font_off_y = (src->GlyphOffset.y * offsets_scale) + baked->Ascent; if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome. From 80c08f228667c5921a1b11a26fda05673059481a Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Jun 2025 14:58:30 +0200 Subject: [PATCH 593/716] (Breaking) Fonts: obsoleting SetWindowFontScale(). + Comments # Conflicts: # imgui.cpp --- imgui.cpp | 15 +++++++++++---- imgui.h | 5 +++-- imgui_demo.cpp | 6 +++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1ffa0652f34d..b4a4478b4c29 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8445,6 +8445,7 @@ ImFontBaked* ImGui::GetFontBaked() return GImGui->FontBaked; } +// Get current font size (= height in pixels) of current font, with external scale factors applied. Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. float ImGui::GetFontSize() { return GImGui->FontSize; @@ -8455,6 +8456,8 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() return GImGui->DrawListSharedData.TexUvWhitePixel; } +// Prefer using PushFontSize(style.FontSize * factor), or use io.FontGlobalScale to scale all windows. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS void ImGui::SetWindowFontScale(float scale) { IM_ASSERT(scale > 0.0f); @@ -8462,6 +8465,7 @@ void ImGui::SetWindowFontScale(float scale) window->FontWindowScale = scale; UpdateCurrentFontSize(0.0f); } +#endif void ImGui::PushFocusScope(ImGuiID id) { @@ -8737,13 +8741,16 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; if (final_size == 0.0f) { - final_size = g.FontSizeBeforeScaling * g.IO.FontGlobalScale; + final_size = g.FontSizeBeforeScaling; + + // External scale factors + final_size *= g.IO.FontGlobalScale; + if (window != NULL) + final_size *= window->FontWindowScale; #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (g.Font != NULL) - final_size *= g.Font->Scale; + final_size *= g.Font->Scale; #endif - if (window != NULL) - final_size *= window->FontWindowScale; } // Round font size diff --git a/imgui.h b/imgui.h index 6e99b0be9c36..e5a61be75ddc 100644 --- a/imgui.h +++ b/imgui.h @@ -474,7 +474,6 @@ namespace ImGui IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects. IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed(). IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus(). - IMGUI_API void SetWindowFontScale(float scale); // [OBSOLETE] set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes(). IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position. IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis. IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state @@ -532,7 +531,7 @@ namespace ImGui // Style read access // - Use the ShowStyleEditor() function to interactively see/edit the colors. IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with external scale factors applied. Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList @@ -3943,6 +3942,8 @@ struct ImGuiPlatformImeData #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.92.0 (from June 2025) + IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFontSize(style.FontSize * factor) or use io.FontGlobalScale to scale all windows. // OBSOLETED in 1.91.9 (from February 2025) IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. // OBSOLETED in 1.91.0 (from July 2024) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index fc1d16953d79..581a49eb0614 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8485,11 +8485,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, " "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n" "Using those settings here will give you poor quality results."); - static float window_scale = 1.0f; PushItemWidth(GetFontSize() * 8); - if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window - SetWindowFontScale(window_scale); DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything + //static float window_scale = 1.0f; + //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window + // SetWindowFontScale(window_scale); PopItemWidth(); EndTabItem(); From 8766efcba6a0c2e62afd5ec22260cd54dd82cc5c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 4 Jun 2025 18:16:14 +0200 Subject: [PATCH 594/716] (Breaking) Renamed io.FontGlobalScale to style.FontScaleMain. # Conflicts: # imgui.cpp --- imgui.cpp | 33 +++++++++++++++++++-------------- imgui.h | 12 +++++++----- imgui_demo.cpp | 18 +++++++++++++----- imgui_internal.h | 2 +- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b4a4478b4c29..527aae3f445f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1358,6 +1358,8 @@ static void* GImAllocatorUserData = NULL; ImGuiStyle::ImGuiStyle() { FontSizeBase = 0.0f; // Will default to io.Fonts->Fonts[0] on first frame. + FontScaleMain = 1.0f; // Main global scale factor. + Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. WindowPadding = ImVec2(8,8); // Padding within a window @@ -1481,9 +1483,11 @@ ImGuiIO::ImGuiIO() UserData = NULL; Fonts = NULL; - FontGlobalScale = 1.0f; FontDefault = NULL; FontAllowUserScaling = false; +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + FontGlobalScale = 1.0f; // Use style.FontScaleMain instead! +#endif DisplayFramebufferScale = ImVec2(1.0f, 1.0f); // Keyboard/Gamepad Navigation options @@ -8456,7 +8460,7 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() return GImGui->DrawListSharedData.TexUvWhitePixel; } -// Prefer using PushFontSize(style.FontSize * factor), or use io.FontGlobalScale to scale all windows. +// Prefer using PushFontSize(style.FontSizeBase * factor), or use style.FontScaleMain to scale all windows. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS void ImGui::SetWindowFontScale(float scale) { @@ -8744,12 +8748,15 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) final_size = g.FontSizeBeforeScaling; // External scale factors - final_size *= g.IO.FontGlobalScale; + final_size *= g.Style.FontScaleMain; if (window != NULL) final_size *= window->FontWindowScale; + + // Legacy scale factors #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + final_size *= g.IO.FontGlobalScale; // Use style.FontScaleMain instead! if (g.Font != NULL) - final_size *= g.Font->Scale; + final_size *= g.Font->Scale; // Was never really useful. #endif } @@ -10544,6 +10551,9 @@ static void ImGui::ErrorCheckNewFrameSanityChecks() IM_ASSERT(g.IO.ConfigErrorRecoveryEnableAssert || g.IO.ConfigErrorRecoveryEnableDebugLog || g.IO.ConfigErrorRecoveryEnableTooltip || g.ErrorCallback != NULL); #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (g.IO.FontGlobalScale > 1.0f) + IM_ASSERT(g.Style.FontScaleMain == 1.0f && "Since 1.92: use style.FontScaleMain instead of g.IO.FontGlobalScale!"); + // Remap legacy names if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) { @@ -15799,29 +15809,24 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) ImGuiIO& io = g.IO; ImGuiStyle& style = g.Style; - Text("Read "); SameLine(0, 0); - TextLinkOpenURL("https://www.dearimgui.com/faq/"); SameLine(0, 0); - Text(" for details."); - - SeparatorText("Backend Support for Dynamic Fonts"); BeginDisabled(); CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); EndDisabled(); - + ShowFontSelector("Font"); BeginDisabled((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); - SetNextItemWidth(GetFontSize() * 10); if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); SameLine(); MetricsHelpMarker("- This is scaling font only. General scaling will come later."); - SetNextItemWidth(GetFontSize() * 10); - DragFloat("io.FontGlobalScale", &io.FontGlobalScale, 0.05f, 0.5f, 5.0f); // <-- This works, but no need to make it too visible. + DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 5.0f); BulletText("Load a nice font for better results!"); BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); + BulletText("Read FAQ for more details:"); + SameLine(); TextLinkOpenURL("dearimgui.com/faq", "https://www.dearimgui.com/faq/"); EndDisabled(); - SeparatorText("Fonts"); + SeparatorText("Font List"); ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig; Checkbox("Show font preview", &cfg->ShowFontPreview); diff --git a/imgui.h b/imgui.h index e5a61be75ddc..8fa8c65e1a96 100644 --- a/imgui.h +++ b/imgui.h @@ -502,7 +502,7 @@ namespace ImGui // - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then 'PushFont(font)' will use this size. // *IMPORTANT* If you want to scale an existing font size: // - OK: PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). - // - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale factors are io.FontGlobalScale and per-viewport scales.). + // - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale factors are style.FontScaleMain + per-viewport scales.). IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. IMGUI_API void PopFont(); IMGUI_API void PushFontSize(float font_size); @@ -2227,6 +2227,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { float FontSizeBase; // Current base font size (scaling applied). Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. + float FontScaleMain; // Main global scale factor. Other scale factors may apply. float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. @@ -2347,9 +2348,8 @@ struct ImGuiIO // Font system ImFontAtlas*Fonts; // // Font atlas: load, rasterize and pack one or more fonts into a single texture. - float FontGlobalScale; // = 1.0f // Global scale all fonts - bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with CTRL+Wheel. ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0]. + bool FontAllowUserScaling; // = false // [OBSOLETE] Allow user scaling text of individual window with CTRL+Wheel. // Keyboard/Gamepad Navigation options bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout. @@ -2546,9 +2546,11 @@ struct ImGuiIO //float NavInputs[ImGuiNavInput_COUNT]; // [LEGACY] Since 1.88, NavInputs[] was removed. Backends from 1.60 to 1.86 won't build. Feed gamepad inputs via io.AddKeyEvent() and ImGuiKey_GamepadXXX enums. //void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + float FontGlobalScale; // Moved io.FontGlobalScale to style.FontScaleMain in 1.92 (June 2025) + // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO. // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete). -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS const char* (*GetClipboardTextFn)(void* user_data); void (*SetClipboardTextFn)(void* user_data, const char* text); void* ClipboardUserData; @@ -3943,7 +3945,7 @@ struct ImGuiPlatformImeData namespace ImGui { // OBSOLETED in 1.92.0 (from June 2025) - IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFontSize(style.FontSize * factor) or use io.FontGlobalScale to scale all windows. + IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFontSize(style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. // OBSOLETED in 1.91.9 (from February 2025) IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. // OBSOLETED in 1.91.0 (from July 2024) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 581a49eb0614..5aa9dc02b087 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -440,13 +440,13 @@ void ImGui::ShowDemoWindow(bool* p_open) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. ImGui::SameLine(0.0f, 0.0f); Text(" (out %.2f)", ImGui::GetFontSize()); ImGui::SameLine(); HelpMarker("- This is scaling font only. General scaling will come later."); - //ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); - //ImGui::DragFloat("FontGlobalScale", &ImGui::GetIO().FontGlobalScale, 0.05f, 0.5f, 5.0f); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); + ImGui::DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); ImGui::BulletText("Load a nice font for better results!"); - ImGui::BulletText("See 'Widgets->Fonts' below for more."); //ImGui::BulletText("Current font loader: '%s'", ImGui::GetIO().Fonts->FontLoaderName); ImGui::BulletText("Please submit feedback:"); ImGui::SameLine(); ImGui::TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); + ImGui::BulletText("See 'Widgets->Fonts' below for more."); ImGui::Spacing(); } @@ -8276,9 +8276,16 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { // General + SeparatorText("General"); if (ShowStyleSelector("Colors##Selector")) ref_saved_style = style; ShowFontSelector("Fonts##Selector"); + BeginDisabled((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); + if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) + style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. + SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); + DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); + EndDisabled(); // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) @@ -8301,8 +8308,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) "Save/Revert in local non-persistent storage. Default Colors definition are not affected. " "Use \"Export\" below to save them somewhere."); - Separator(); - + SeparatorText("Details"); if (BeginTabBar("##tabs", ImGuiTabBarFlags_None)) { if (BeginTabItem("Sizes")) @@ -8477,6 +8483,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below. // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds). + /* SeparatorText("Legacy Scaling"); const float MIN_SCALE = 0.3f; const float MAX_SCALE = 2.0f; @@ -8491,6 +8498,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) //if (DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window // SetWindowFontScale(window_scale); PopItemWidth(); + */ EndTabItem(); } diff --git a/imgui_internal.h b/imgui_internal.h index 4c1d1f3921b8..f4db19273a9a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2139,7 +2139,7 @@ struct ImGuiContext ImVector FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas) ImFont* Font; // Currently bound font. (== FontStack.back().Font) ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) - float FontSize; // Currently bound font size == line height (== FontSizeBeforeScaling * io.FontGlobalScale * font->Scale * g.CurrentWindow->FontWindowScale). + float FontSize; // Currently bound font size == line height (== FontSizeBeforeScaling + externals scales applied in the UpdateCurrentFontSize() function). float FontSizeBeforeScaling; // == value passed to PushFont() / PushFontSize() when specified. float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). From d85e22d205d347695944532fe1fcc6c23cacdc11 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Jun 2025 16:44:42 +0200 Subject: [PATCH 595/716] Added style.FontScaleDpi which is the field overwritten by ImGuiConfigFlags_DpiEnableScaleFonts. # Conflicts: # imgui.cpp # imgui.h # imgui_demo.cpp --- imgui.cpp | 16 ++++++++++++---- imgui.h | 3 ++- imgui_demo.cpp | 4 ++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 527aae3f445f..f6dd39c9dd61 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1359,6 +1359,7 @@ ImGuiStyle::ImGuiStyle() { FontSizeBase = 0.0f; // Will default to io.Fonts->Fonts[0] on first frame. FontScaleMain = 1.0f; // Main global scale factor. + FontScaleDpi = 1.0f; // Scale factor from viewport/monitor. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. @@ -1429,12 +1430,12 @@ ImGuiStyle::ImGuiStyle() ImGui::StyleColorsDark(this); } -// To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you. + +// Scale all spacing/padding/thickness values. Do not scale fonts. // Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times. void ImGuiStyle::ScaleAllSizes(float scale_factor) { _MainScale *= scale_factor; - FontSizeBase = ImTrunc(FontSizeBase * scale_factor); WindowPadding = ImTrunc(WindowPadding * scale_factor); WindowRounding = ImTrunc(WindowRounding * scale_factor); WindowMinSize = ImTrunc(WindowMinSize * scale_factor); @@ -8646,7 +8647,7 @@ void ImGui::UpdateFontsNewFrame() // Apply default font size the first time ImFont* font = ImGui::GetDefaultFont(); if (g.Style.FontSizeBase <= 0.0f) - g.Style.FontSizeBase = (font->LegacySize > 0.0f ? font->LegacySize : FONT_DEFAULT_SIZE) * g.Style._MainScale; + g.Style.FontSizeBase = (font->LegacySize > 0.0f ? font->LegacySize : FONT_DEFAULT_SIZE); // Set initial font g.Font = font; @@ -8748,7 +8749,10 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) final_size = g.FontSizeBeforeScaling; // External scale factors - final_size *= g.Style.FontScaleMain; + final_size *= g.Style.FontScaleMain; // Main global scale factor + final_size *= g.Style.FontScaleDpi; // Per-monitor/viewport DPI scale factor, automatically updated when io.ConfigDpiScaleFonts is enabled. + + // Window scale (mostly obsolete now) if (window != NULL) final_size *= window->FontWindowScale; @@ -15819,6 +15823,10 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); SameLine(); MetricsHelpMarker("- This is scaling font only. General scaling will come later."); DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 5.0f); + //BeginDisabled(io.ConfigDpiScaleFonts); + DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); + //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); + //EndDisabled(); BulletText("Load a nice font for better results!"); BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); diff --git a/imgui.h b/imgui.h index 8fa8c65e1a96..3b69ac1ff27d 100644 --- a/imgui.h +++ b/imgui.h @@ -2228,6 +2228,7 @@ struct ImGuiStyle { float FontSizeBase; // Current base font size (scaling applied). Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. float FontScaleMain; // Main global scale factor. Other scale factors may apply. + float FontScaleDpi; // Scale factor from viewport/monitor. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor. float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. @@ -2300,7 +2301,7 @@ struct ImGuiStyle // Functions IMGUI_API ImGuiStyle(); - IMGUI_API void ScaleAllSizes(float scale_factor); + IMGUI_API void ScaleAllSizes(float scale_factor); // Scale all spacing/padding/thickness values. Do not scale fonts. // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 5aa9dc02b087..985a490ea139 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8285,6 +8285,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); + //BeginDisabled(GetIO().ConfigDpiScaleFonts); + DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); + //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); + //EndDisabled(); EndDisabled(); // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) From 3c27c643a9c79f2248aee53336c754749b8622e5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Jun 2025 14:40:37 +0200 Subject: [PATCH 596/716] Fonts: internals: renamed g.FontScale to g.FontBakedScale for clarity. Comments. --- imgui.cpp | 20 ++++++++++---------- imgui.h | 11 ++++++----- imgui_internal.h | 8 ++++---- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 4 ++-- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f6dd39c9dd61..3fb75eb25581 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3979,7 +3979,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Initialized = false; Font = NULL; FontBaked = NULL; - FontSize = FontSizeBeforeScaling = FontScale = CurrentDpiScale = 0.0f; + FontSize = FontSizeBeforeScaling = FontBakedScale = CurrentDpiScale = 0.0f; FontRasterizerDensity = 1.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); if (shared_font_atlas == NULL) @@ -8773,9 +8773,9 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; g.FontSize = final_size; g.FontBaked = (g.Font != NULL && window != NULL) ? g.Font->GetFontBaked(final_size) : NULL; - g.FontScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; + g.FontBakedScale = (g.Font != NULL && window != NULL) ? (g.FontSize / g.FontBaked->Size) : 0.0f; g.DrawListSharedData.FontSize = g.FontSize; - g.DrawListSharedData.FontScale = g.FontScale; + g.DrawListSharedData.FontScale = g.FontBakedScale; } // Exposed in case user may want to override setting density. @@ -8793,20 +8793,20 @@ void ImGui::SetFontRasterizerDensity(float rasterizer_density) // If you want to scale an existing font size: // - Use e.g. PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). // - Do NOT use PushFontSize(GetFontSize() * factor) (= value after external scale factors applied). -void ImGui::PushFont(ImFont* font, float font_size) +void ImGui::PushFont(ImFont* font, float font_size_base) { ImGuiContext& g = *GImGui; g.FontStack.push_back({ g.Font, g.FontSizeBeforeScaling, g.FontSize }); if (font == NULL) font = GetDefaultFont(); - if (font_size <= 0.0f) + if (font_size_base <= 0.0f) { if (font->Flags & ImFontFlags_DefaultToLegacySize) - font_size = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) + font_size_base = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) else - font_size = g.FontSizeBeforeScaling; // Keep current font size + font_size_base = g.FontSizeBeforeScaling; // Keep current font size } - SetCurrentFont(font, font_size, 0.0f); + SetCurrentFont(font, font_size_base, 0.0f); } void ImGui::PopFont() @@ -8822,10 +8822,10 @@ void ImGui::PopFont() g.FontStack.pop_back(); } -void ImGui::PushFontSize(float font_size) +void ImGui::PushFontSize(float font_size_base) { ImGuiContext& g = *GImGui; - PushFont(g.Font, font_size); + PushFont(g.Font, font_size_base); } void ImGui::PopFontSize() diff --git a/imgui.h b/imgui.h index 3b69ac1ff27d..563d2eb92836 100644 --- a/imgui.h +++ b/imgui.h @@ -500,12 +500,13 @@ namespace ImGui // - To use old behavior (single size font, size specified in AddFontXXX() call: // - Use 'PushFont(font, font->LegacySize)' at call site // - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then 'PushFont(font)' will use this size. + // - External scale factors are applied over the provided value. // *IMPORTANT* If you want to scale an existing font size: // - OK: PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). // - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale factors are style.FontScaleMain + per-viewport scales.). - IMGUI_API void PushFont(ImFont* font, float font_size = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. + IMGUI_API void PushFont(ImFont* font, float font_size_base = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. IMGUI_API void PopFont(); - IMGUI_API void PushFontSize(float font_size); + IMGUI_API void PushFontSize(float font_size_base); IMGUI_API void PopFontSize(); // Parameters stacks (shared) @@ -2226,9 +2227,9 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { - float FontSizeBase; // Current base font size (scaling applied). Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. - float FontScaleMain; // Main global scale factor. Other scale factors may apply. - float FontScaleDpi; // Scale factor from viewport/monitor. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor. + float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. Final FontSize = FontSizeBase * (FontScaleBase * FontScaleDpi * other_factors) + float FontScaleMain; // Main scale factor. May be set by application once, or exposed to end-user. + float FontScaleDpi; // Scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor. float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. diff --git a/imgui_internal.h b/imgui_internal.h index f4db19273a9a..db308bc7a1e0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -871,8 +871,8 @@ struct ImDrawDataBuilder struct ImFontStackData { ImFont* Font; - float FontSizeBeforeScaling; - float FontSizeAfterScaling; + float FontSizeBeforeScaling; // ~~ style.FontSizeBase + float FontSizeAfterScaling; // ~~ g.FontSize }; //----------------------------------------------------------------------------- @@ -2140,8 +2140,8 @@ struct ImGuiContext ImFont* Font; // Currently bound font. (== FontStack.back().Font) ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) float FontSize; // Currently bound font size == line height (== FontSizeBeforeScaling + externals scales applied in the UpdateCurrentFontSize() function). - float FontSizeBeforeScaling; // == value passed to PushFont() / PushFontSize() when specified. - float FontScale; // == FontBaked->Size / Font->FontSize. Scale factor over baked size. + float FontSizeBeforeScaling; // Font size before scaling == style.FontSizeBase == value passed to PushFont() / PushFontSize() when specified. + float FontBakedScale; // == FontBaked->Size / FontSize. Scale factor over baked size. Rarely used nowadays, very often == 1.0f. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale ImDrawListSharedData DrawListSharedData; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e41041ce142d..61bc576caf99 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -3375,7 +3375,7 @@ void ImGui::TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label ButtonBehavior(row_r, row_id, NULL, NULL); KeepAliveID(row_id); - const float ascent_scaled = g.FontBaked->Ascent * g.FontScale; // FIXME: Standardize those scaling factors better + const float ascent_scaled = g.FontBaked->Ascent * g.FontBakedScale; // FIXME: Standardize those scaling factors better const float line_off_for_ascent_x = (ImMax((g.FontSize - ascent_scaled) * 0.5f, 0.0f) / -sin_a) * (flip_label ? -1.0f : 1.0f); const ImVec2 padding = g.Style.CellPadding; // We will always use swapped component const ImVec2 align = g.Style.TableAngledHeadersTextAlign; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 91d50933f2a2..cdca228c480f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1518,7 +1518,7 @@ bool ImGui::TextLink(const char* label) ColorConvertHSVtoRGB(h, s, v, line_colf.x, line_colf.y, line_colf.z); } - float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontScale * 0.20f); + float line_y = bb.Max.y + ImFloor(g.FontBaked->Descent * g.FontBakedScale * 0.20f); window->DrawList->AddLine(ImVec2(bb.Min.x, line_y), ImVec2(bb.Max.x, line_y), GetColorU32(line_colf)); // FIXME-TEXT: Underline mode // FIXME-DPI PushStyleColor(ImGuiCol_Text, GetColorU32(text_colf)); @@ -4012,7 +4012,7 @@ namespace ImStb { static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->TextLen; } static char STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { IM_ASSERT(idx <= obj->TextLen); return obj->TextSrc[idx]; } -static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.FontBaked->GetCharAdvance((ImWchar)c) * g.FontScale; } +static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { unsigned int c; ImTextCharFromUtf8(&c, obj->TextSrc + line_start_idx + char_idx, obj->TextSrc + obj->TextLen); if ((ImWchar)c == '\n') return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.FontBaked->GetCharAdvance((ImWchar)c) * g.FontBakedScale; } static char STB_TEXTEDIT_NEWLINE = '\n'; static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx) { From 2d2b1cee6b7c1e741375b09ddcda8a2d68602655 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Jun 2025 14:54:46 +0200 Subject: [PATCH 597/716] Fonts: internals: renamed g.FontSizeBeforeScaling to g.FontSizeBase for consistency. # Conflicts: # imgui_internal.h --- imgui.cpp | 18 +++++++++--------- imgui.h | 5 +++-- imgui_draw.cpp | 2 +- imgui_internal.h | 6 +++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3fb75eb25581..39a79a398c23 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1358,8 +1358,8 @@ static void* GImAllocatorUserData = NULL; ImGuiStyle::ImGuiStyle() { FontSizeBase = 0.0f; // Will default to io.Fonts->Fonts[0] on first frame. - FontScaleMain = 1.0f; // Main global scale factor. - FontScaleDpi = 1.0f; // Scale factor from viewport/monitor. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. + FontScaleMain = 1.0f; // Main scale factor. May be set by application once, or exposed to end-user. + FontScaleDpi = 1.0f; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. Alpha = 1.0f; // Global alpha applies to everything in Dear ImGui. DisabledAlpha = 0.60f; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. @@ -3979,7 +3979,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) Initialized = false; Font = NULL; FontBaked = NULL; - FontSize = FontSizeBeforeScaling = FontBakedScale = CurrentDpiScale = 0.0f; + FontSize = FontSizeBase = FontBakedScale = CurrentDpiScale = 0.0f; FontRasterizerDensity = 1.0f; IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); if (shared_font_atlas == NULL) @@ -8651,7 +8651,7 @@ void ImGui::UpdateFontsNewFrame() // Set initial font g.Font = font; - g.FontSizeBeforeScaling = g.Style.FontSizeBase; + g.FontSizeBase = g.Style.FontSizeBase; g.FontSize = 0.0f; ImFontStackData font_stack_data = { font, g.Style.FontSizeBase, g.Style.FontSizeBase }; // <--- Will restore FontSize SetCurrentFont(font_stack_data.Font, font_stack_data.FontSizeBeforeScaling, 0.0f); // <--- but use 0.0f to enable scale @@ -8717,7 +8717,7 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size_before_scaling, float f { ImGuiContext& g = *GImGui; g.Font = font; - g.FontSizeBeforeScaling = font_size_before_scaling; + g.FontSizeBase = font_size_before_scaling; UpdateCurrentFontSize(font_size_after_scaling); if (font != NULL) @@ -8738,7 +8738,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - g.Style.FontSizeBase = g.FontSizeBeforeScaling; + g.Style.FontSizeBase = g.FontSizeBase; if (window != NULL && window->SkipItems) return; @@ -8746,7 +8746,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; if (final_size == 0.0f) { - final_size = g.FontSizeBeforeScaling; + final_size = g.FontSizeBase; // External scale factors final_size *= g.Style.FontScaleMain; // Main global scale factor @@ -8796,7 +8796,7 @@ void ImGui::SetFontRasterizerDensity(float rasterizer_density) void ImGui::PushFont(ImFont* font, float font_size_base) { ImGuiContext& g = *GImGui; - g.FontStack.push_back({ g.Font, g.FontSizeBeforeScaling, g.FontSize }); + g.FontStack.push_back({ g.Font, g.FontSizeBase, g.FontSize }); if (font == NULL) font = GetDefaultFont(); if (font_size_base <= 0.0f) @@ -8804,7 +8804,7 @@ void ImGui::PushFont(ImFont* font, float font_size_base) if (font->Flags & ImFontFlags_DefaultToLegacySize) font_size_base = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) else - font_size_base = g.FontSizeBeforeScaling; // Keep current font size + font_size_base = g.FontSizeBase; // Keep current font size } SetCurrentFont(font, font_size_base, 0.0f); } diff --git a/imgui.h b/imgui.h index 563d2eb92836..cdcdae68b531 100644 --- a/imgui.h +++ b/imgui.h @@ -2227,9 +2227,10 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { - float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. Final FontSize = FontSizeBase * (FontScaleBase * FontScaleDpi * other_factors) + // ImGui::GetFontSize() == FontSizeBase * (FontScaleMain * FontScaleDpi * other_scaling_factors) + float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. float FontScaleMain; // Main scale factor. May be set by application once, or exposed to end-user. - float FontScaleDpi; // Scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor. + float FontScaleDpi; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6fabbac9e143..c4f342e540ff 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3193,7 +3193,7 @@ static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, bool need_bind_ctx = ctx != curr_ctx; if (need_bind_ctx) ImGui::SetCurrentContext(ctx); - ImGui::SetCurrentFont(new_font, ctx->FontSizeBeforeScaling, ctx->FontSize); + ImGui::SetCurrentFont(new_font, ctx->FontSizeBase, ctx->FontSize); if (need_bind_ctx) ImGui::SetCurrentContext(curr_ctx); } diff --git a/imgui_internal.h b/imgui_internal.h index db308bc7a1e0..e344cbccff40 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2139,8 +2139,8 @@ struct ImGuiContext ImVector FontAtlases; // List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas) ImFont* Font; // Currently bound font. (== FontStack.back().Font) ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) - float FontSize; // Currently bound font size == line height (== FontSizeBeforeScaling + externals scales applied in the UpdateCurrentFontSize() function). - float FontSizeBeforeScaling; // Font size before scaling == style.FontSizeBase == value passed to PushFont() / PushFontSize() when specified. + float FontSize; // Currently bound font size == line height (== FontSizeBase + externals scales applied in the UpdateCurrentFontSize() function). + float FontSizeBase; // Font size before scaling == style.FontSizeBase == value passed to PushFont() / PushFontSize() when specified. float FontBakedScale; // == FontBaked->Size / FontSize. Scale factor over baked size. Rarely used nowadays, very often == 1.0f. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale @@ -2690,7 +2690,7 @@ struct IMGUI_API ImGuiWindow ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight; return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight); } // [Obsolete] ImGuiWindow::CalcFontSize() was removed in 1.92.x because error-prone/misleading. You can use window->FontRefSize for a copy of g.FontSize at the time of the last Begin() call for this window. - //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontBaseSize * FontWindowScale * FontWindowScaleParents; } + //float CalcFontSize() const { ImGuiContext& g = *Ctx; return g.FontSizeBase * FontWindowScale * FontWindowScaleParents; }; //----------------------------------------------------------------------------- From d72e66cdee550cfa9735e8199dceac2a7ac27ab5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 5 Jun 2025 16:47:58 +0200 Subject: [PATCH 598/716] Examples: remove comments/references about baking and GetGlyphRangesJapanese(). --- examples/example_allegro5/main.cpp | 3 +-- examples/example_android_opengl3/main.cpp | 3 +-- examples/example_apple_metal/main.mm | 3 +-- examples/example_apple_opengl2/main.mm | 3 +-- examples/example_glfw_metal/main.mm | 3 +-- examples/example_glfw_opengl2/main.cpp | 3 +-- examples/example_glfw_opengl3/main.cpp | 3 +-- examples/example_glfw_vulkan/main.cpp | 3 +-- examples/example_glfw_wgpu/main.cpp | 3 +-- examples/example_glut_opengl2/main.cpp | 3 +-- examples/example_sdl2_directx11/main.cpp | 3 +-- examples/example_sdl2_metal/main.mm | 3 +-- examples/example_sdl2_opengl2/main.cpp | 3 +-- examples/example_sdl2_opengl3/main.cpp | 3 +-- examples/example_sdl2_sdlrenderer2/main.cpp | 3 +-- examples/example_sdl2_vulkan/main.cpp | 3 +-- examples/example_sdl3_opengl3/main.cpp | 3 +-- examples/example_sdl3_sdlgpu3/main.cpp | 3 +-- examples/example_sdl3_sdlrenderer3/main.cpp | 3 +-- examples/example_sdl3_vulkan/main.cpp | 3 +-- examples/example_win32_directx10/main.cpp | 3 +-- examples/example_win32_directx11/main.cpp | 3 +-- examples/example_win32_directx12/main.cpp | 3 +-- examples/example_win32_directx9/main.cpp | 3 +-- examples/example_win32_opengl3/main.cpp | 3 +-- examples/example_win32_vulkan/main.cpp | 3 +-- 26 files changed, 26 insertions(+), 52 deletions(-) diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp index 3ca061cc6971..67fc7ee65e22 100644 --- a/examples/example_allegro5/main.cpp +++ b/examples/example_allegro5/main.cpp @@ -52,7 +52,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -61,7 +60,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); bool show_demo_window = true; diff --git a/examples/example_android_opengl3/main.cpp b/examples/example_android_opengl3/main.cpp index 42aa622f762f..452cb77d9d16 100644 --- a/examples/example_android_opengl3/main.cpp +++ b/examples/example_android_opengl3/main.cpp @@ -154,7 +154,6 @@ void Init(struct android_app* app) // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Android: The TTF files have to be placed into the assets/ directory (android/app/src/main/assets), we use our GetAssetData() helper to retrieve them. @@ -181,7 +180,7 @@ void Init(struct android_app* app) //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 15.0f); //IM_ASSERT(font != nullptr); //font_data_size = GetAssetData("ArialUni.ttf", &font_data); - //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //font = io.Fonts->AddFontFromMemoryTTF(font_data, font_data_size, 18.0f); //IM_ASSERT(font != nullptr); // Arbitrary scale-up diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 3ad7cff4685a..9b9db8c6105c 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -72,7 +72,6 @@ -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullabl // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -81,7 +80,7 @@ -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullabl //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); return self; diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index 815c0f72e14b..5f1fd1e505d6 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -60,7 +60,6 @@ -(void)initialize // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -69,7 +68,7 @@ -(void)initialize //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); } diff --git a/examples/example_glfw_metal/main.mm b/examples/example_glfw_metal/main.mm index e9bc63acb1c0..c4380d5c31d9 100644 --- a/examples/example_glfw_metal/main.mm +++ b/examples/example_glfw_metal/main.mm @@ -42,7 +42,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -51,7 +50,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Setup window diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index 1fcec2b2a7bb..af4edbe2bfb0 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -65,7 +65,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -74,7 +73,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index e5f29d40578d..e133376bc457 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -99,7 +99,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -109,7 +108,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 3d2181e89302..10b9ab2ed1d9 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -417,7 +417,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -426,7 +425,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index f510987ed829..58c5b34f7dba 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -114,7 +114,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -126,7 +125,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); #endif diff --git a/examples/example_glut_opengl2/main.cpp b/examples/example_glut_opengl2/main.cpp index 58539ca5f91d..5720f85583fc 100644 --- a/examples/example_glut_opengl2/main.cpp +++ b/examples/example_glut_opengl2/main.cpp @@ -83,7 +83,6 @@ int main(int argc, char** argv) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -92,7 +91,7 @@ int main(int argc, char** argv) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Main loop diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index 47c852d273a2..fdb7ad458517 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -84,7 +84,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -93,7 +92,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_metal/main.mm b/examples/example_sdl2_metal/main.mm index d54812710c55..4dc4788a85b9 100644 --- a/examples/example_sdl2_metal/main.mm +++ b/examples/example_sdl2_metal/main.mm @@ -33,7 +33,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -42,7 +41,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Setup SDL diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index a70edd2258fa..feba216f0076 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -70,7 +70,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -79,7 +78,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 51add5c1ffaa..7b7b17ad2a69 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -110,7 +110,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -120,7 +119,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index 31fa3f9bf7b6..eee25c272748 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -72,7 +72,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -81,7 +80,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index c62222577b5b..6a8f68e8b157 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -417,7 +417,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -426,7 +425,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 46eeb59b59dd..ef25733240ba 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -106,7 +106,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -116,7 +115,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 4178f94b5e5b..4051edc3dea1 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -83,7 +83,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -92,7 +91,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 9a2732b45cab..2821f7b8094d 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -68,7 +68,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -78,7 +77,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 183965a84a0e..bdaf3aa02f92 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -422,7 +422,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -431,7 +430,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 21198da9ae5b..d6b23e63f5a2 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -67,7 +67,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -76,7 +75,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index 5285df10225f..838e5493bf41 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -67,7 +67,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -76,7 +75,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 2df2751c58c6..ce672f353473 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -161,7 +161,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -170,7 +169,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index 422248bcbf63..d13351b0a490 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -65,7 +65,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -74,7 +73,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index 8ecd27a20642..b516de7a7f4b 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -75,7 +75,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -84,7 +83,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 427a2494a43b..8699b61a93c8 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -408,7 +408,6 @@ int main(int, char**) // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! @@ -417,7 +416,7 @@ int main(int, char**) //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); //IM_ASSERT(font != nullptr); // Our state From 9da3e6696abce7f294d0d4f3bfb1db6ce80c6265 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Jun 2025 15:54:25 +0200 Subject: [PATCH 599/716] Backends: SDL2: added ImGui_ImplSDL2_GetDpiScaleForDisplay(), ImGui_ImplSDL2_GetContentScaleForWindow() helpers. --- backends/imgui_impl_sdl2.cpp | 21 +++++++++++++++++++++ backends/imgui_impl_sdl2.h | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index fa2714bb907b..3780b322bfc1 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps. // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) @@ -702,6 +703,26 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() } } +// - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend. +// - Apple platforms use FramebufferScale so we always return 1.0f. +// - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. +float ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) +{ + return ImGui_ImplSDL2_GetContentScaleForDisplay(SDL_GetWindowDisplayIndex(window)); +} + +float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) +{ +#if SDL_HAS_PER_MONITOR_DPI +#ifndef __APPLE__ + float dpi = 0.0f; + if (SDL_GetDisplayDPI(display_index, &dpi, nullptr, nullptr) == 0) + return dpi / 96.0f; +#endif +#endif + return 1.0f; +} + static void ImGui_ImplSDL2_CloseGamepads() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 9f7b551fc168..3c0a4a7e4e7d 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -38,6 +38,10 @@ IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); +// DPI-related helpers (optional) +IMGUI_IMPL_API float ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window); +IMGUI_IMPL_API float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index); + // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. // When using manual mode, caller is responsible for opening/closing gamepad. enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; From 8269924c33f3af562a83a5eada77b924bab5d7b1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Jun 2025 16:14:22 +0200 Subject: [PATCH 600/716] Backends: GLFW: added ImGui_ImplGlfw_GetContentScaleForMonitor(), ImGui_ImplGlfw_GetContentScaleForWindow() helpers. # Conflicts: # backends/imgui_impl_glfw.cpp --- backends/imgui_impl_glfw.cpp | 28 ++++++++++++++++++++++++++++ backends/imgui_impl_glfw.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index ba75699709b4..70369f38ba2e 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -28,6 +28,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. // 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. // 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: @@ -840,6 +841,33 @@ static void ImGui_ImplGlfw_UpdateGamepads() #undef MAP_ANALOG } +// - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend. +// - Apple platforms use FramebufferScale so we always return 1.0f. +// - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. +float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) +{ +#if GLFW_HAS_PER_MONITOR_DPI && !defined(__APPLE__) + float x_scale, y_scale; + glfwGetWindowContentScale(window, &x_scale, &y_scale); + return x_scale; +#else + IM_UNUSED(window); + return 1.0f; +#endif +} + +float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) +{ +#if GLFW_HAS_PER_MONITOR_DPI && !defined(__APPLE__) + float x_scale, y_scale; + glfwGetMonitorContentScale(monitor, &x_scale, &y_scale); + return x_scale; +#else + IM_UNUSED(monitor); + return 1.0f; +#endif +} + void ImGui_ImplGlfw_NewFrame() { ImGuiIO& io = ImGui::GetIO(); diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index e203b556fe95..1ef9ade17b42 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -62,5 +62,8 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int // GLFW helpers IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds); +IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window); +IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor); + #endif // #ifndef IMGUI_DISABLE From b98e92839c997fcab03f2be4453f42afb8676888 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 16:17:54 +0200 Subject: [PATCH 601/716] Backends: SDL2, SDL3, GLFW: Backport small part of c90ea13 from docking. --- backends/imgui_impl_glfw.cpp | 22 ++++++++++++-------- backends/imgui_impl_sdl2.cpp | 39 +++++++++++++++++++++--------------- backends/imgui_impl_sdl3.cpp | 26 +++++++++++++++--------- 3 files changed, 53 insertions(+), 34 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 70369f38ba2e..aac9eca2ece1 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -868,20 +868,26 @@ float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) #endif } +static void ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(GLFWwindow* window, ImVec2* out_size, ImVec2* out_framebuffer_scale) +{ + int w, h; + int display_w, display_h; + glfwGetWindowSize(window, &w, &h); + glfwGetFramebufferSize(window, &display_w, &display_h); + if (out_size != nullptr) + *out_size = ImVec2((float)w, (float)h); + if (out_framebuffer_scale != nullptr) + *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / (float)w, (float)display_h / (float)h) : ImVec2(1.0f, 1.0f); +} + void ImGui_ImplGlfw_NewFrame() { ImGuiIO& io = ImGui::GetIO(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?"); - // Setup display size (every frame to accommodate for window resizing) - int w, h; - int display_w, display_h; - glfwGetWindowSize(bd->Window, &w, &h); - glfwGetFramebufferSize(bd->Window, &display_w, &display_h); - io.DisplaySize = ImVec2((float)w, (float)h); - if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h); + // Setup main viewport size (every frame to accommodate for window resizing) + ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale); // Setup time step // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 3780b322bfc1..84ecc55e0863 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -720,6 +720,7 @@ float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) return dpi / 96.0f; #endif #endif + IM_UNUSED(display_index); return 1.0f; } @@ -825,29 +826,35 @@ static void ImGui_ImplSDL2_UpdateGamepads() ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767); } -void ImGui_ImplSDL2_NewFrame() +static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window, SDL_Renderer* renderer, ImVec2* out_size, ImVec2* out_framebuffer_scale) { - ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); - IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?"); - ImGuiIO& io = ImGui::GetIO(); - - // Setup display size (every frame to accommodate for window resizing) int w, h; int display_w, display_h; - SDL_GetWindowSize(bd->Window, &w, &h); - if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED) + SDL_GetWindowSize(window, &w, &h); + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) w = h = 0; - if (bd->Renderer != nullptr) - SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h); + if (renderer != nullptr) + SDL_GetRendererOutputSize(renderer, &display_w, &display_h); #if SDL_HAS_VULKAN - else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN) - SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h); + else if (SDL_GetWindowFlags(window) & SDL_WINDOW_VULKAN) + SDL_Vulkan_GetDrawableSize(window, &display_w, &display_h); #endif else - SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h); - io.DisplaySize = ImVec2((float)w, (float)h); - if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + SDL_GL_GetDrawableSize(window, &display_w, &display_h); + if (out_size != nullptr) + *out_size = ImVec2((float)w, (float)h); + if (out_framebuffer_scale != nullptr) + *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / w, (float)display_h / h) : ImVec2(1.0f, 1.0f); +} + +void ImGui_ImplSDL2_NewFrame() +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL2_Init()?"); + ImGuiIO& io = ImGui::GetIO(); + + // Setup main viewport size (every frame to accommodate for window resizing) + ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(bd->Window, bd->Renderer, &io.DisplaySize, &io.DisplayFramebufferScale); // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 58cc11c442b3..4f099595af84 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -771,22 +771,28 @@ static void ImGui_ImplSDL3_UpdateGamepads() ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767); } +static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(SDL_Window* window, ImVec2* out_size, ImVec2* out_framebuffer_scale) +{ + int w, h; + int display_w, display_h; + SDL_GetWindowSize(window, &w, &h); + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + w = h = 0; + SDL_GetWindowSizeInPixels(window, &display_w, &display_h); + if (out_size != nullptr) + *out_size = ImVec2((float)w, (float)h); + if (out_framebuffer_scale != nullptr) + *out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / w, (float)display_h / h) : ImVec2(1.0f, 1.0f); +} + void ImGui_ImplSDL3_NewFrame() { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDL3_Init()?"); ImGuiIO& io = ImGui::GetIO(); - // Setup display size (every frame to accommodate for window resizing) - int w, h; - int display_w, display_h; - SDL_GetWindowSize(bd->Window, &w, &h); - if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED) - w = h = 0; - SDL_GetWindowSizeInPixels(bd->Window, &display_w, &display_h); - io.DisplaySize = ImVec2((float)w, (float)h); - if (w > 0 && h > 0) - io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h); + // Setup main viewport size (every frame to accommodate for window resizing) + ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale); // Setup time step (we could also use SDL_GetTicksNS() available since SDL3) // (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644) From bc394410a2ad10bc36575eeaff1ec3918ddee830 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 2 Jun 2025 15:32:54 +0200 Subject: [PATCH 602/716] Examples: Win32+DX9/DX10/DX11/DX12, SDL2+DX11/OpenGL2/OpenGL3/SDLRenderer/Vulkan, SDL3+OpenGL/SDLGPU/SDLRenderer/Vulkan: made example DPI aware by default. (master + docking: partial support for multi-dpi by scaling fonts + viewports but not style) We don't bother with WIN32_LEAN_AND_MEAN. # Conflicts: # examples/example_glfw_opengl3/main.cpp # examples/example_sdl2_directx11/main.cpp # examples/example_sdl2_opengl2/main.cpp # examples/example_sdl2_opengl3/main.cpp # examples/example_sdl2_vulkan/main.cpp # examples/example_sdl3_opengl3/main.cpp # examples/example_sdl3_sdlgpu3/main.cpp # examples/example_sdl3_vulkan/main.cpp # examples/example_win32_directx10/main.cpp # examples/example_win32_directx11/main.cpp # examples/example_win32_directx12/main.cpp # examples/example_win32_directx9/main.cpp --- examples/example_glfw_opengl3/main.cpp | 8 +++++++- examples/example_sdl2_directx11/main.cpp | 11 ++++++++++- examples/example_sdl2_opengl2/main.cpp | 14 +++++++++++++- examples/example_sdl2_opengl3/main.cpp | 14 +++++++++++++- examples/example_sdl2_sdlrenderer2/main.cpp | 14 +++++++++++++- examples/example_sdl2_vulkan/main.cpp | 14 +++++++++++++- examples/example_sdl3_opengl3/main.cpp | 8 +++++++- examples/example_sdl3_sdlgpu3/main.cpp | 8 +++++++- examples/example_sdl3_sdlrenderer3/main.cpp | 8 +++++++- examples/example_sdl3_vulkan/main.cpp | 8 +++++++- examples/example_win32_directx10/main.cpp | 12 ++++++++++-- examples/example_win32_directx11/main.cpp | 12 ++++++++++-- examples/example_win32_directx12/main.cpp | 12 ++++++++++-- examples/example_win32_directx9/main.cpp | 12 ++++++++++-- 14 files changed, 137 insertions(+), 18 deletions(-) diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index e133376bc457..53dc69ce29bd 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -71,7 +71,8 @@ int main(int, char**) #endif // Create window with graphics context - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+OpenGL3 example", nullptr, nullptr); + float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only + GLFWwindow* window = glfwCreateWindow((int)(1280 * main_scale), (int)(800 * main_scale), "Dear ImGui GLFW+OpenGL3 example", nullptr, nullptr); if (window == nullptr) return 1; glfwMakeContextCurrent(window); @@ -88,6 +89,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); #ifdef __EMSCRIPTEN__ diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index fdb7ad458517..d2e151e54eed 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -33,6 +33,9 @@ int main(int, char**) // Setup SDL // (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems, // depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to the latest version of SDL is recommended!) +#ifdef _WIN32 + ::SetProcessDPIAware(); +#endif if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); @@ -45,8 +48,9 @@ int main(int, char**) #endif // Setup window + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+DirectX11 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+DirectX11 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -76,6 +80,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForD3D(window); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index feba216f0076..1fe0c58640a3 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -17,11 +17,17 @@ #include #include #include +#ifdef _WIN32 +#include // SetProcessDPIAware() +#endif // Main code int main(int, char**) { // Setup SDL +#ifdef _WIN32 + ::SetProcessDPIAware(); +#endif if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); @@ -39,8 +45,9 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -62,6 +69,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL2_Init(); diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 7b7b17ad2a69..63934cd884a3 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -17,6 +17,9 @@ #else #include #endif +#ifdef _WIN32 +#include // SetProcessDPIAware() +#endif // This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. #ifdef __EMSCRIPTEN__ @@ -27,6 +30,9 @@ int main(int, char**) { // Setup SDL +#ifdef _WIN32 + ::SetProcessDPIAware(); +#endif if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); @@ -73,8 +79,9 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -102,6 +109,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index eee25c272748..564729bad591 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -15,6 +15,9 @@ #include "imgui_impl_sdlrenderer2.h" #include #include +#ifdef _WIN32 +#include // SetProcessDPIAware() +#endif #if !SDL_VERSION_ATLEAST(2,0,17) #error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function @@ -24,6 +27,9 @@ int main(int, char**) { // Setup SDL +#ifdef _WIN32 + ::SetProcessDPIAware(); +#endif if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); @@ -36,8 +42,9 @@ int main(int, char**) #endif // Create window with SDL_Renderer graphics context + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -64,6 +71,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForSDLRenderer(window, renderer); ImGui_ImplSDLRenderer2_Init(renderer); diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 6a8f68e8b157..807751b01176 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -20,6 +20,9 @@ #include // abort #include #include +#ifdef _WIN32 +#include // SetProcessDPIAware() +#endif // Volk headers #ifdef IMGUI_IMPL_VULKAN_USE_VOLK @@ -340,6 +343,9 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) int main(int, char**) { // Setup SDL +#ifdef _WIN32 + ::SetProcessDPIAware(); +#endif if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0) { printf("Error: %s\n", SDL_GetError()); @@ -352,8 +358,9 @@ int main(int, char**) #endif // Create window with Vulkan graphics context + float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0); SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI); - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Vulkan example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -393,6 +400,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL2_InitForVulkan(window); ImGui_ImplVulkan_InitInfo init_info = {}; diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index ef25733240ba..4af533fa3de5 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -68,8 +68,9 @@ int main(int, char**) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+OpenGL3 example", 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+OpenGL3 example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -98,6 +99,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForOpenGL(window, gl_context); ImGui_ImplOpenGL3_Init(glsl_version); diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index 4051edc3dea1..e6678899b0a4 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -34,8 +34,9 @@ int main(int, char**) } // Create SDL window graphics context + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -71,6 +72,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForSDLGPU(window); ImGui_ImplSDLGPU3_InitInfo init_info = {}; diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 2821f7b8094d..0c8d67b538cd 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -32,8 +32,9 @@ int main(int, char**) } // Create window with SDL_Renderer graphics context + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -60,6 +61,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); ImGui_ImplSDLRenderer3_Init(renderer); diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index bdaf3aa02f92..895681544ea4 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -353,8 +353,9 @@ int main(int, char**) } // Create window with Vulkan graphics context + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Vulkan example", 1280, 720, window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Vulkan example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -398,6 +399,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplSDL3_InitForVulkan(window); ImGui_ImplVulkan_InitInfo init_info = {}; diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index d6b23e63f5a2..2b40e090b565 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -30,11 +30,14 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { + // Make process DPI aware and obtain main monitor scale + ImGui_ImplWin32_EnableDpiAwareness(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + // Create application window - //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX10 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX10 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); // Initialize Direct3D if (!CreateDeviceD3D(hwnd)) @@ -59,6 +62,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX10_Init(g_pd3dDevice); diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index 838e5493bf41..fbb6833fdc65 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -30,11 +30,14 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { + // Make process DPI aware and obtain main monitor scale + ImGui_ImplWin32_EnableDpiAwareness(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + // Create application window - //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); // Initialize Direct3D if (!CreateDeviceD3D(hwnd)) @@ -59,6 +62,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index ce672f353473..80aef78c53f6 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -109,11 +109,14 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { + // Make process DPI aware and obtain main monitor scale + ImGui_ImplWin32_EnableDpiAwareness(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + // Create application window - //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX12 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX12 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); // Initialize Direct3D if (!CreateDeviceD3D(hwnd)) @@ -138,6 +141,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index d13351b0a490..b7e905360948 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -28,11 +28,14 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Main code int main(int, char**) { + // Make process DPI aware and obtain main monitor scale + ImGui_ImplWin32_EnableDpiAwareness(); + float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); + // Create application window - //ImGui_ImplWin32_EnableDpiAwareness(); WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; ::RegisterClassExW(&wc); - HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); + HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr); // Initialize Direct3D if (!CreateDeviceD3D(hwnd)) @@ -57,6 +60,11 @@ int main(int, char**) ImGui::StyleColorsDark(); //ImGui::StyleColorsLight(); + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + // Setup Platform/Renderer backends ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX9_Init(g_pd3dDevice); From 02f58b3207b22c5b038f81bc0d2b6adbcebcafa1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Jun 2025 16:33:02 +0200 Subject: [PATCH 603/716] Fonts: AddFont() functions now allow size_pixels==0.0f (only required when using certain functions) Fonts: AddFont() funcitons allow size_pixels==0 for merged fonts. --- imgui.h | 8 ++++---- imgui_draw.cpp | 5 ++++- misc/freetype/imgui_freetype.cpp | 6 ++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index cdcdae68b531..2a07af8013ff 100644 --- a/imgui.h +++ b/imgui.h @@ -3577,10 +3577,10 @@ struct ImFontAtlas IMGUI_API ~ImFontAtlas(); IMGUI_API ImFont* AddFont(const ImFontConfig* font_cfg); IMGUI_API ImFont* AddFontDefault(const ImFontConfig* font_cfg = NULL); - IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); - IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. - IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. - IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. + IMGUI_API ImFont* AddFontFromFileTTF(const char* filename, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); + IMGUI_API ImFont* AddFontFromMemoryTTF(void* font_data, int font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed. + IMGUI_API ImFont* AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_data_size, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp. + IMGUI_API ImFont* AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels = 0.0f, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter. IMGUI_API void RemoveFont(ImFont* font); IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c4f342e540ff..4bde225d66dc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4533,11 +4533,14 @@ static bool ImGui_ImplStbTrueType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* } src->FontLoaderData = bd_font_data; + if (src->MergeMode && src->SizePixels == 0.0f) + src->SizePixels = src->DstFont->Sources[0]->SizePixels; + if (src->SizePixels >= 0.0f) bd_font_data->ScaleFactor = stbtt_ScaleForPixelHeight(&bd_font_data->FontInfo, 1.0f); else bd_font_data->ScaleFactor = stbtt_ScaleForMappingEmToPixels(&bd_font_data->FontInfo, 1.0f); - if (src != src->DstFont->Sources[0]) + if (src->MergeMode && src->SizePixels != 0.0f) bd_font_data->ScaleFactor *= src->SizePixels / src->DstFont->Sources[0]->SizePixels; // FIXME-NEWATLAS: Should tidy up that a bit return true; diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 4c10ff42dd70..a6cd13d0dea8 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -421,7 +421,9 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) { IM_UNUSED(atlas); - const float size = baked->Size * (src->SizePixels / baked->ContainerFont->Sources[0]->SizePixels); // FIXME-NEWATLAS: Should tidy up that a bit + float size = baked->Size; + if (src->MergeMode && src->SizePixels != 0.0f) + size *= (src->SizePixels / baked->ContainerFont->Sources[0]->SizePixels); ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; bd_font_data->BakedLastActivated = baked; @@ -637,7 +639,7 @@ static FT_Error ImGuiLunasvgPortRender(FT_GlyphSlot slot, FT_Pointer* _state) #else state->svg->setMatrix(state->svg->matrix().identity()); // Reset the svg matrix to the default value state->svg->render(bitmap, state->matrix); // state->matrix is already scaled and translated -#endif +#endif state->err = FT_Err_Ok; return state->err; } From c18301f356caea8ea47db3375b681cf934d90304 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Jun 2025 16:36:58 +0200 Subject: [PATCH 604/716] Examples: remove explicit font sizes from AddFontXXX() calls. Add commented out style.FontSizeBase assignment. --- examples/example_allegro5/main.cpp | 11 ++++++----- examples/example_apple_metal/main.mm | 11 ++++++----- examples/example_apple_opengl2/main.mm | 11 ++++++----- examples/example_glfw_metal/main.mm | 11 ++++++----- examples/example_glfw_opengl2/main.cpp | 11 ++++++----- examples/example_glfw_opengl3/main.cpp | 11 ++++++----- examples/example_glfw_vulkan/main.cpp | 11 ++++++----- examples/example_glfw_wgpu/main.cpp | 13 +++++++------ examples/example_glut_opengl2/main.cpp | 11 ++++++----- examples/example_sdl2_directx11/main.cpp | 11 ++++++----- examples/example_sdl2_metal/main.mm | 11 ++++++----- examples/example_sdl2_opengl2/main.cpp | 11 ++++++----- examples/example_sdl2_opengl3/main.cpp | 11 ++++++----- examples/example_sdl2_sdlrenderer2/main.cpp | 11 ++++++----- examples/example_sdl2_vulkan/main.cpp | 11 ++++++----- examples/example_sdl3_opengl3/main.cpp | 11 ++++++----- examples/example_sdl3_sdlgpu3/main.cpp | 11 ++++++----- examples/example_sdl3_sdlrenderer3/main.cpp | 11 ++++++----- examples/example_sdl3_vulkan/main.cpp | 11 ++++++----- examples/example_win32_directx10/main.cpp | 11 ++++++----- examples/example_win32_directx11/main.cpp | 11 ++++++----- examples/example_win32_directx12/main.cpp | 11 ++++++----- examples/example_win32_directx9/main.cpp | 11 ++++++----- examples/example_win32_opengl3/main.cpp | 11 ++++++----- examples/example_win32_vulkan/main.cpp | 11 ++++++----- 25 files changed, 151 insertions(+), 126 deletions(-) diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp index 67fc7ee65e22..02db84a48073 100644 --- a/examples/example_allegro5/main.cpp +++ b/examples/example_allegro5/main.cpp @@ -55,12 +55,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); bool show_demo_window = true; diff --git a/examples/example_apple_metal/main.mm b/examples/example_apple_metal/main.mm index 9b9db8c6105c..301a2b4add16 100644 --- a/examples/example_apple_metal/main.mm +++ b/examples/example_apple_metal/main.mm @@ -75,12 +75,13 @@ -(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullabl // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); return self; diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index 5f1fd1e505d6..c3f0c313b854 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -63,12 +63,13 @@ -(void)initialize // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); } diff --git a/examples/example_glfw_metal/main.mm b/examples/example_glfw_metal/main.mm index c4380d5c31d9..ef314702a78a 100644 --- a/examples/example_glfw_metal/main.mm +++ b/examples/example_glfw_metal/main.mm @@ -45,12 +45,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Setup window diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index af4edbe2bfb0..83fcab65fe68 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -68,12 +68,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 53dc69ce29bd..4bd7bc591831 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -109,12 +109,13 @@ int main(int, char**) // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 10b9ab2ed1d9..19766b9f3b67 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -420,12 +420,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp index 58c5b34f7dba..c150b59610ad 100644 --- a/examples/example_glfw_wgpu/main.cpp +++ b/examples/example_glfw_wgpu/main.cpp @@ -119,13 +119,14 @@ int main(int, char**) // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. //io.Fonts->AddFontDefault(); + //style.FontSizeBase = 20.0f; #ifndef IMGUI_DISABLE_FILE_FUNCTIONS - //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf"); + //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf"); //IM_ASSERT(font != nullptr); #endif diff --git a/examples/example_glut_opengl2/main.cpp b/examples/example_glut_opengl2/main.cpp index 5720f85583fc..69f85a2459dd 100644 --- a/examples/example_glut_opengl2/main.cpp +++ b/examples/example_glut_opengl2/main.cpp @@ -86,12 +86,13 @@ int main(int argc, char** argv) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Main loop diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index d2e151e54eed..194dd0e030e9 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -96,12 +96,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_metal/main.mm b/examples/example_sdl2_metal/main.mm index 4dc4788a85b9..c1750b16bd4c 100644 --- a/examples/example_sdl2_metal/main.mm +++ b/examples/example_sdl2_metal/main.mm @@ -36,12 +36,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Setup SDL diff --git a/examples/example_sdl2_opengl2/main.cpp b/examples/example_sdl2_opengl2/main.cpp index 1fe0c58640a3..c8363fecebec 100644 --- a/examples/example_sdl2_opengl2/main.cpp +++ b/examples/example_sdl2_opengl2/main.cpp @@ -85,12 +85,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_opengl3/main.cpp b/examples/example_sdl2_opengl3/main.cpp index 63934cd884a3..16a73deb688c 100644 --- a/examples/example_sdl2_opengl3/main.cpp +++ b/examples/example_sdl2_opengl3/main.cpp @@ -126,12 +126,13 @@ int main(int, char**) // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_sdlrenderer2/main.cpp b/examples/example_sdl2_sdlrenderer2/main.cpp index 564729bad591..e456b2e9e85e 100644 --- a/examples/example_sdl2_sdlrenderer2/main.cpp +++ b/examples/example_sdl2_sdlrenderer2/main.cpp @@ -87,12 +87,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl2_vulkan/main.cpp b/examples/example_sdl2_vulkan/main.cpp index 807751b01176..300543fbabb7 100644 --- a/examples/example_sdl2_vulkan/main.cpp +++ b/examples/example_sdl2_vulkan/main.cpp @@ -432,12 +432,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_opengl3/main.cpp b/examples/example_sdl3_opengl3/main.cpp index 4af533fa3de5..cfd6f6a1afef 100644 --- a/examples/example_sdl3_opengl3/main.cpp +++ b/examples/example_sdl3_opengl3/main.cpp @@ -116,12 +116,13 @@ int main(int, char**) // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_sdlgpu3/main.cpp b/examples/example_sdl3_sdlgpu3/main.cpp index e6678899b0a4..581b11c11169 100644 --- a/examples/example_sdl3_sdlgpu3/main.cpp +++ b/examples/example_sdl3_sdlgpu3/main.cpp @@ -92,12 +92,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 0c8d67b538cd..6e39429d2446 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -78,12 +78,13 @@ int main(int, char**) // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details. + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_sdl3_vulkan/main.cpp b/examples/example_sdl3_vulkan/main.cpp index 895681544ea4..df7f5efbdcd6 100644 --- a/examples/example_sdl3_vulkan/main.cpp +++ b/examples/example_sdl3_vulkan/main.cpp @@ -431,12 +431,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 2b40e090b565..23033d6c10c0 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -78,12 +78,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index fbb6833fdc65..c80114cfb2c0 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -78,12 +78,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 80aef78c53f6..3a9ba4fb408e 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -172,12 +172,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index b7e905360948..430a2b448c1e 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -76,12 +76,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index b516de7a7f4b..820248c6428b 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -78,12 +78,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index 8699b61a93c8..a98f16fe2b17 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -411,12 +411,13 @@ int main(int, char**) // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; //io.Fonts->AddFontDefault(); - //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); //IM_ASSERT(font != nullptr); // Our state From 2e67bd4de7a94a9f48a92bfcf487c92594f7cf5a Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 6 Jun 2025 18:07:27 +0200 Subject: [PATCH 605/716] Fonts: rename to ImFontAtlasBuildLegacyPreloadAllGlyphRanges(). --- imgui_draw.cpp | 6 +++--- imgui_internal.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 4bde225d66dc..b208b68369c7 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3368,7 +3368,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas) // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures - ImFontAtlasBuildPreloadAllGlyphRanges(atlas); + ImFontAtlasBuildLegacyPreloadAllGlyphRanges(atlas); atlas->TexIsBuilt = true; } @@ -3405,12 +3405,12 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon // Preload all glyph ranges for legacy backends. // This may lead to multiple texture creation which might be a little slower than before. -void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas) +void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas* atlas) { atlas->Builder->PreloadedAllGlyphsRanges = true; for (ImFont* font : atlas->Fonts) { - ImFontBaked* baked = font->GetFontBaked(font->Sources[0]->SizePixels); + ImFontBaked* baked = font->GetFontBaked(font->LegacySize); if (font->FallbackChar != 0) baked->FindGlyph(font->FallbackChar); if (font->EllipsisChar != 0) diff --git a/imgui_internal.h b/imgui_internal.h index e344cbccff40..b80bf50b65d3 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3807,7 +3807,7 @@ IMGUI_API void ImFontAtlasTextureCompact(ImFontAtlas* atlas); IMGUI_API ImVec2i ImFontAtlasTextureGetSizeEstimate(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFontSpecialGlyphs(ImFontAtlas* atlas, ImFont* font, ImFontConfig* src); -IMGUI_API void ImFontAtlasBuildPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy +IMGUI_API void ImFontAtlasBuildLegacyPreloadAllGlyphRanges(ImFontAtlas* atlas); // Legacy IMGUI_API void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v); IMGUI_API void ImFontAtlasBuildDiscardBakes(ImFontAtlas* atlas, int unused_frames); From 573f08135d8ce0d8cde6db2cd0156b2b602e137e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Jun 2025 17:47:30 +0200 Subject: [PATCH 606/716] Fonts: fixed PopFont() broken recovery. "misc_recover_1" test would assert in EndFrame() --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 39a79a398c23..faf8ae690cdd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8812,7 +8812,7 @@ void ImGui::PushFont(ImFont* font, float font_size_base) void ImGui::PopFont() { ImGuiContext& g = *GImGui; - if (g.FontStack.Size <= 0 && g.WithinFrameScope) + if (g.FontStack.Size <= 0) { IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!"); return; From 0e769c541835af126e344f9a4d0e3f19d6ba9163 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Jun 2025 17:56:09 +0200 Subject: [PATCH 607/716] Fonts: amend UpdateCurentFontSize() early out optimization. --- imgui.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index faf8ae690cdd..e97f5e6fb423 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8739,8 +8739,15 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) ImGuiWindow* window = g.CurrentWindow; g.Style.FontSizeBase = g.FontSizeBase; + + // Early out to avoid hidden window keeping bakes referenced and out of GC reach. + // However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching, so for now we null it. if (window != NULL && window->SkipItems) - return; + if (g.CurrentTable == NULL || g.CurrentTable->CurrentColumn != -1) // See 8465#issuecomment-2951509561. Ideally the SkipItems=true in tables would be amended with extra data. + { + g.FontBaked = NULL; + return; + } // Restoring is pretty much only used by PopFont()/PopFontSize() float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; From 29fbf3c1ec458e5765c40762e6cfda2cb2ed81e7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 10 Jun 2025 18:09:44 +0200 Subject: [PATCH 608/716] Fonts: demote ImFont::GetFontBaked() as slighty internal. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 2a07af8013ff..1c5dec57d7f4 100644 --- a/imgui.h +++ b/imgui.h @@ -3791,7 +3791,6 @@ struct ImFont // Methods IMGUI_API ImFont(); IMGUI_API ~ImFont(); - IMGUI_API ImFontBaked* GetFontBaked(float font_size, float density = -1.0f); // Get or create baked data for given size IMGUI_API bool IsGlyphInFont(ImWchar c); bool IsLoaded() const { return ContainerAtlas != NULL; } const char* GetDebugName() const { return Sources.Size ? Sources[0]->Name : ""; } // Fill ImFontConfig::Name. @@ -3799,6 +3798,7 @@ struct ImFont // [Internal] Don't use! // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable. // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable. + IMGUI_API ImFontBaked* GetFontBaked(float font_size, float density = -1.0f); // Get or create baked data for given size IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL); // utf8 IMGUI_API const char* CalcWordWrapPosition(float size, const char* text, const char* text_end, float wrap_width); IMGUI_API void RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, ImWchar c, const ImVec4* cpu_fine_clip = NULL); From e1481a731d0fd9f68157cdfbce0b6e7627456aae Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 13:20:17 +0200 Subject: [PATCH 609/716] Fonts: fixed NewFrame() when atlas builder has been created but fonts not added. Fixed GetCustomRect() after atlas clear. --- imgui.cpp | 2 +- imgui_draw.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index e97f5e6fb423..ff2d18a676a8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8668,7 +8668,7 @@ ImFont* ImGui::GetDefaultFont() { ImGuiContext& g = *GImGui; ImFontAtlas* atlas = g.IO.Fonts; - if (atlas->Builder == NULL) + if (atlas->Builder == NULL || atlas->Fonts.Size == 0) ImFontAtlasBuildMain(atlas); return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0]; } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b208b68369c7..195f5bece212 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -4362,6 +4362,8 @@ ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId if (id == ImFontAtlasRectId_Invalid) return NULL; int index_idx = ImFontAtlasRectId_GetIndex(id); + if (atlas->Builder == NULL) + ImFontAtlasBuildInit(atlas); ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder; if (index_idx >= builder->RectsIndex.Size) return NULL; From cc3d4cab21ac1d7f2ca42a4de9512134f663b419 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 14:38:45 +0200 Subject: [PATCH 610/716] (Breaking) renamed ImFontConfig::FontBuilderFlags -> FontLoaderFlags. ImFontAtlas::FontBuilderFlags -> FontLoaderFlags. ImGuiFreeTypeBuilderFlags -> ImGuiFreeTypeLoaderFlags. --- imgui.cpp | 14 ++++----- imgui.h | 14 +++++---- misc/freetype/imgui_freetype.cpp | 12 ++++---- misc/freetype/imgui_freetype.h | 51 ++++++++++++++++++++++---------- 4 files changed, 56 insertions(+), 35 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ff2d18a676a8..2909dfb8ea07 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15810,7 +15810,7 @@ static void MetricsHelpMarker(const char* desc) } #ifdef IMGUI_ENABLE_FREETYPE -namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); IMGUI_API bool DebugEditFontBuilderFlags(unsigned int* p_font_builder_flags); } +namespace ImGuiFreeType { IMGUI_API const ImFontLoader* GetFontLoader(); IMGUI_API bool DebugEditFontLoaderFlags(unsigned int* p_font_builder_flags); } #endif // [DEBUG] List fonts in a font atlas and display its texture @@ -15868,13 +15868,13 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); if (loader_current == loader_freetype) { - unsigned int loader_flags = atlas->FontBuilderFlags; + unsigned int loader_flags = atlas->FontLoaderFlags; Text("Shared FreeType Loader Flags: 0x%08", loader_flags); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) + if (ImGuiFreeType::DebugEditFontLoaderFlags(&loader_flags)) { for (ImFont* font : atlas->Fonts) ImFontAtlasFontDestroyOutput(atlas, font); - atlas->FontBuilderFlags = loader_flags; + atlas->FontLoaderFlags = loader_flags; for (ImFont* font : atlas->Fonts) ImFontAtlasFontInitOutput(atlas, font); } @@ -16853,12 +16853,12 @@ void ImGui::DebugNodeFont(ImFont* font) #ifdef IMGUI_ENABLE_FREETYPE if (loader->Name != NULL && strcmp(loader->Name, "FreeType") == 0) { - unsigned int loader_flags = src->FontBuilderFlags; + unsigned int loader_flags = src->FontLoaderFlags; Text("FreeType Loader Flags: 0x%08X", loader_flags); - if (ImGuiFreeType::DebugEditFontBuilderFlags(&loader_flags)) + if (ImGuiFreeType::DebugEditFontLoaderFlags(&loader_flags)) { ImFontAtlasFontDestroyOutput(atlas, font); - src->FontBuilderFlags = loader_flags; + src->FontLoaderFlags = loader_flags; ImFontAtlasFontInitOutput(atlas, font); } } diff --git a/imgui.h b/imgui.h index 1c5dec57d7f4..1d27953f2175 100644 --- a/imgui.h +++ b/imgui.h @@ -29,9 +29,9 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19197 -#define IMGUI_HAS_TABLE -#define IMGUI_HAS_TEXTURES // 1.92+ WIP branch with ImGuiBackendFlags_RendererHasTextures +#define IMGUI_VERSION_NUM 19198 +#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 +#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 /* @@ -3480,7 +3480,8 @@ struct ImFontConfig float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. // FIXME-NEWATLAS: Intentionally unscaled - unsigned int FontBuilderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. + unsigned int FontLoaderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. + //unsigned int FontBuilderFlags; // -- // [Renamed in 1.92] Ue FontLoaderFlags. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. float RasterizerDensity; // 1.0f // [LEGACY: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported] DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. @@ -3696,7 +3697,7 @@ struct ImFontAtlas const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name void* FontLoaderData; // Font backend opaque storage - unsigned int FontBuilderFlags; // [FIXME: Should be called FontLoaderFlags] Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. . Per-font override is also available in ImFontConfig. + unsigned int FontLoaderFlags; // Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. Per-font override is also available in ImFontConfig). int RefCount; // Number of contexts using this atlas ImGuiContext* OwnerContext; // Context which own the atlas will be in charge of updating and destroying it. @@ -3710,7 +3711,8 @@ struct ImFontAtlas IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyph(ImFont* font, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // OBSOLETED in 1.92.X: Use custom ImFontLoader in ImFontConfig IMGUI_API ImFontAtlasRectId AddCustomRectFontGlyphForSize(ImFont* font, float font_size, ImWchar codepoint, int w, int h, float advance_x, const ImVec2& offset = ImVec2(0, 0)); // ADDED AND OBSOLETED in 1.92.X #endif - //int TexDesiredWidth; // OBSOLETED in 1.92.X (force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) + //unsigned int FontBuilderFlags; // OBSOLETED in 1.92.X: Renamed to FontLoaderFlags. + //int TexDesiredWidth; // OBSOLETED in 1.92.X: Force texture width before calling Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height) //typedef ImFontAtlasRect ImFontAtlasCustomRect; // OBSOLETED in 1.92.X //typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+ //typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+ diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index a6cd13d0dea8..35a277f7c820 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -153,14 +153,14 @@ struct ImGui_ImplFreeType_Data struct ImGui_ImplFreeType_FontSrcData { // Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime. - bool InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_user_flags); + bool InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_user_flags); void CloseFont(); ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); } ~ImGui_ImplFreeType_FontSrcData() { CloseFont(); } // Members FT_Face FtFace; - ImGuiFreeTypeBuilderFlags UserFlags; // = ImFontConfig::FontBuilderFlags + ImGuiFreeTypeLoaderFlags UserFlags; // = ImFontConfig::FontLoaderFlags FT_Int32 LoadFlags; ImFontBaked* BakedLastActivated; }; @@ -172,7 +172,7 @@ struct ImGui_ImplFreeType_FontSrcBakedData ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); } }; -bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeBuilderFlags extra_font_builder_flags) +bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_font_loader_flags) { FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (uint32_t)src->FontDataSize, (uint32_t)src->FontNo, &FtFace); if (error != 0) @@ -182,7 +182,7 @@ bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfi return false; // Convert to FreeType flags (NB: Bold and Oblique are processed separately) - UserFlags = (ImGuiFreeTypeBuilderFlags)(src->FontBuilderFlags | extra_font_builder_flags); + UserFlags = (ImGuiFreeTypeLoaderFlags)(src->FontLoaderFlags | extra_font_loader_flags); LoadFlags = 0; if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) @@ -400,7 +400,7 @@ bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) IM_ASSERT(src->FontLoaderData == NULL); src->FontLoaderData = bd_font_data; - if (!bd_font_data->InitFont(bd->Library, src, (ImGuiFreeTypeBuilderFlags)atlas->FontBuilderFlags)) + if (!bd_font_data->InitFont(bd->Library, src, (ImGuiFreeTypeLoaderFlags)atlas->FontLoaderFlags)) { IM_DELETE(bd_font_data); src->FontLoaderData = NULL; @@ -587,7 +587,7 @@ void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* u GImGuiFreeTypeAllocatorUserData = user_data; } -bool ImGuiFreeType::DebugEditFontBuilderFlags(unsigned int* p_font_loader_flags) +bool ImGuiFreeType::DebugEditFontLoaderFlags(unsigned int* p_font_loader_flags) { bool edited = false; edited |= ImGui::CheckboxFlags("NoHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_NoHinting); diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 2b4810e32e7b..4f73067907fd 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -23,22 +23,41 @@ struct ImFontLoader; // - When disabled, FreeType generates blurrier glyphs, more or less matches the stb_truetype.h // - The Default hinting mode usually looks good, but may distort glyphs in an unusual way. // - The Light hinting mode generates fuzzier glyphs but better matches Microsoft's rasterizer. -// You can set those flags globally in ImFontAtlas::FontBuilderFlags -// You can set those flags on a per font basis in ImFontConfig::FontBuilderFlags -enum ImGuiFreeTypeBuilderFlags +// You can set those flags globally in ImFontAtlas::FontLoaderFlags +// You can set those flags on a per font basis in ImFontConfig::FontLoaderFlags +typedef unsigned int ImGuiFreeTypeLoaderFlags; +enum ImGuiFreeTypeLoaderFlags_ { - ImGuiFreeTypeBuilderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. - ImGuiFreeTypeBuilderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter. - ImGuiFreeTypeBuilderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter. - ImGuiFreeTypeBuilderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. - ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. - ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font? - ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? - ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results! - ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs - ImGuiFreeTypeBuilderFlags_Bitmap = 1 << 9 // Enable FreeType bitmap glyphs + ImGuiFreeTypeLoaderFlags_NoHinting = 1 << 0, // Disable hinting. This generally generates 'blurrier' bitmap glyphs when the glyph are rendered in any of the anti-aliased modes. + ImGuiFreeTypeLoaderFlags_NoAutoHint = 1 << 1, // Disable auto-hinter. + ImGuiFreeTypeLoaderFlags_ForceAutoHint = 1 << 2, // Indicates that the auto-hinter is preferred over the font's native hinter. + ImGuiFreeTypeLoaderFlags_LightHinting = 1 << 3, // A lighter hinting algorithm for gray-level modes. Many generated glyphs are fuzzier but better resemble their original shape. This is achieved by snapping glyphs to the pixel grid only vertically (Y-axis), as is done by Microsoft's ClearType and Adobe's proprietary font renderer. This preserves inter-glyph spacing in horizontal text. + ImGuiFreeTypeLoaderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. + ImGuiFreeTypeLoaderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font? + ImGuiFreeTypeLoaderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? + ImGuiFreeTypeLoaderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results! + ImGuiFreeTypeLoaderFlags_LoadColor = 1 << 8, // Enable FreeType color-layered glyphs + ImGuiFreeTypeLoaderFlags_Bitmap = 1 << 9, // Enable FreeType bitmap glyphs + +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + ImGuiFreeTypeBuilderFlags_NoHinting = ImGuiFreeTypeLoaderFlags_NoHinting, + ImGuiFreeTypeBuilderFlags_NoAutoHint = ImGuiFreeTypeLoaderFlags_NoAutoHint, + ImGuiFreeTypeBuilderFlags_ForceAutoHint = ImGuiFreeTypeLoaderFlags_ForceAutoHint, + ImGuiFreeTypeBuilderFlags_LightHinting = ImGuiFreeTypeLoaderFlags_LightHinting, + ImGuiFreeTypeBuilderFlags_MonoHinting = ImGuiFreeTypeLoaderFlags_MonoHinting, + ImGuiFreeTypeBuilderFlags_Bold = ImGuiFreeTypeLoaderFlags_Bold, + ImGuiFreeTypeBuilderFlags_Oblique = ImGuiFreeTypeLoaderFlags_Oblique, + ImGuiFreeTypeBuilderFlags_Monochrome = ImGuiFreeTypeLoaderFlags_Monochrome, + ImGuiFreeTypeBuilderFlags_LoadColor = ImGuiFreeTypeLoaderFlags_LoadColor, + ImGuiFreeTypeBuilderFlags_Bitmap = ImGuiFreeTypeLoaderFlags_Bitmap, +#endif }; +// Obsolete names (will be removed) +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +typedef ImGuiFreeTypeLoaderFlags_ ImGuiFreeTypeBuilderFlags_; +#endif + namespace ImGuiFreeType { // This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'. @@ -51,13 +70,13 @@ namespace ImGuiFreeType // However, as FreeType does lots of allocations we provide a way for the user to redirect it to a separate memory heap if desired. IMGUI_API void SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = nullptr); - // Display UI to edit FontBuilderFlags in ImFontAtlas (shared) or ImFontConfig (single source) - IMGUI_API bool DebugEditFontBuilderFlags(unsigned int* p_font_loader_flags); + // Display UI to edit ImFontAtlas::FontLoaderFlags (shared) or ImFontConfig::FontLoaderFlags (single source) + IMGUI_API bool DebugEditFontLoaderFlags(ImGuiFreeTypeLoaderFlags* p_font_loader_flags); // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS //IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType(); // Renamed/changed in 1.92. Change 'io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()' to 'io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader()' if you need runtime selection. - //static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE' + //static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontLoaderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE' #endif } From 4acce8565602ef30f29fa13e24da1991c6fe951e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 17:12:07 +0200 Subject: [PATCH 611/716] Fonts: tweaks demo and exposure to sliders, etc. --- imgui.cpp | 5 +++-- imgui_demo.cpp | 29 +++++------------------------ 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2909dfb8ea07..b9b5fbbc1836 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15824,7 +15824,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) CheckboxFlags("io.BackendFlags: RendererHasTextures", &io.BackendFlags, ImGuiBackendFlags_RendererHasTextures); EndDisabled(); ShowFontSelector("Font"); - BeginDisabled((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); + //BeginDisabled((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); @@ -15834,12 +15834,13 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); //EndDisabled(); + BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); BulletText("Load a nice font for better results!"); BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); BulletText("Read FAQ for more details:"); SameLine(); TextLinkOpenURL("dearimgui.com/faq", "https://www.dearimgui.com/faq/"); - EndDisabled(); + //EndDisabled(); SeparatorText("Font List"); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 985a490ea139..cd48ee0ff91b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -430,26 +430,6 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM); ImGui::Spacing(); - { - ImGui::SeparatorText("dynamic_fonts branch"); - ImGuiStyle& style = ImGui::GetStyle(); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); - ImGui::ShowFontSelector("Font"); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); - if (ImGui::DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) - style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. - ImGui::SameLine(0.0f, 0.0f); Text(" (out %.2f)", ImGui::GetFontSize()); - ImGui::SameLine(); HelpMarker("- This is scaling font only. General scaling will come later."); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20); - ImGui::DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); - ImGui::BulletText("Load a nice font for better results!"); - //ImGui::BulletText("Current font loader: '%s'", ImGui::GetIO().Fonts->FontLoaderName); - ImGui::BulletText("Please submit feedback:"); ImGui::SameLine(); - ImGui::TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); - ImGui::BulletText("See 'Widgets->Fonts' below for more."); - ImGui::Spacing(); - } - IMGUI_DEMO_MARKER("Help"); if (ImGui::CollapsingHeader("Help")) { @@ -603,8 +583,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Spacing(); } - IMGUI_DEMO_MARKER("Configuration/Style"); - if (ImGui::TreeNode("Style")) + IMGUI_DEMO_MARKER("Configuration/Style, Fonts"); + if (ImGui::TreeNode("Style, Fonts")) { ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor); ImGui::SameLine(); @@ -8277,10 +8257,12 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { // General SeparatorText("General"); + if ((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) + BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); + if (ShowStyleSelector("Colors##Selector")) ref_saved_style = style; ShowFontSelector("Fonts##Selector"); - BeginDisabled((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0); if (DragFloat("FontSizeBase", &style.FontSizeBase, 0.20f, 5.0f, 100.0f, "%.0f")) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); @@ -8289,7 +8271,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); //EndDisabled(); - EndDisabled(); // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f) if (SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f")) From 96be9573156549f6ebcda15c8783a582fe91c09f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 14:09:38 +0200 Subject: [PATCH 612/716] Docs: update Changelog, FAQ, Fonts docs. --- docs/CHANGELOG.txt | 329 +++++++++++++++++++++++++++++++++++++++------ docs/FAQ.md | 97 +++++++++---- docs/FONTS.md | 65 ++++++--- imgui.h | 23 ++-- 4 files changed, 419 insertions(+), 95 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 059daf5b5c0a..2a16008f6920 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -39,16 +39,161 @@ HOW TO UPDATE? VERSION 1.92.0 WIP (In Progress) ----------------------------------------------------------------------- +THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! +I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, +BUT INEVITABLY SOME USERS WILL BE AFFECTED. + +IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, +PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: + https://github.com/ocornut/imgui/issues/ + +As part of the plan to reduce impact of API breaking changes, several unfinished +changes/features/refactors related to font and text systems and scaling will be +part of subsequent releases (1.92.1+). + +If you are updating from an old version, and expecting a massive or difficult update, +consider first updating to 1.91.9 to reduce the amount of changes. + Breaking changes: -- TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent - for clarity. Kept inline redirection enum (will obsolete). (#1079, #8639) +- Fonts: **IMPORTANT**: if your app was solving the OSX/iOS Retina screen specific + logical vs display scale problem by setting io.DisplayFramebufferScale (e.g. to 2.0f) + + setting io.FontGlobalScale (e.g. to 1.0f/2.0f) + loading fonts at scaled sizes (e.g. size X * 2.0f): + This WILL NOT map correctly to the new system! Because font will rasterize as requested size. + - With a legacy backend (< 1.92): + - Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. + - This already worked before, but is now pretty much required. + - With a new backend (1.92+) + - FramebufferScale is automatically used to set current font RasterizerDensity. + - FramebufferScale is a per-viewport property provided by backend through the + Platform_GetWindowFramebufferScale() handler in 'docking' branch. + - So this should be all automatic. +- Fonts: **IMPORTANT** on Font Sizing: + - Before 1.92, fonts were of a single size. They can now be dynamically sized. + - PushFont() API now has an optional size parameter. PushFontSize() was also added. + void PushFont(ImFont* font) --> void PushFont(ImFont* font, float size = 0.0f); + - Before 1.92: ImGui::PushFont() always used font "default" size specified in AddFont() call. + - Since 1.92: ImGui::PushFont() preserve the current font size which is a shared value. + - To use old behavior: + - use 'ImGui::PushFont(font, font->LegacySize)' at call site. + - or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call + (not desirable as it requires e.g. third-party code to be aware of it). + - ImFont::FontSize was removed and does not make sense anymore. + ImFont::LegacySize is the size passed to AddFont(). + - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. + +- Textures: + - All API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef': + - ImTextureRef a small composite structure which may be constructed from a ImTextureID. + (or constructed from a ImTextureData* which represent a texture which will generally + be ready by the time of rendering). + - Affected functions are: + - ImGui::Image(), ImGui::ImageWithBg(), ImGui::ImageButton(), + - ImDrawList::AddImage(), ImDrawList::AddImageQuad(), ImDrawList::AddImageRounded(). + - We suggest that C users and any higher-level language bindings generators may + facilitate converting this in some way, aka emulating the trivial C++ constructor. +- Fonts: obsoleted ImFontAtlas::GetTexDataAsRGBA32(), GetTexDataAsAlpha8(), Build(), SetTexID() + and IsBuilt() functions. The new protocol for backends to handle textures doesn't need them. + Kept redirection functions (will obsolete). + - A majority of old backends should still work with new code (behaving like they did before). + - Calling ImFontAtlas::Build() before initializing new backends will erroneously trigger + preloading all glyphs. Will be detected with an assertion after the backend is initialized. +- Fonts: ImFontConfig::OversampleH/OversampleV default to automatic (== 0) + since v1.91.8. It is quite important you keep it automatic until we decide if we want + to provide a way to express finer policy, otherwise you will likely waste texture space + when using large glyphs. Note that the imgui_freetype backend doesn't use and does not + need oversampling. +- Fonts: specifying glyph ranges is now unnecessary. + - The value of ImFontConfig::GlyphRanges[] is only useful for legacy backends. + - All GetGlyphRangesXXXX() functions are now marked obsolete: + - GetGlyphRangesDefault(), GetGlyphRangesGreek(), GetGlyphRangesKorean(), + GetGlyphRangesJapanese(), GetGlyphRangesChineseSimplifiedCommon(), + GetGlyphRangesChineseFull(), GetGlyphRangesCyrillic(), + GetGlyphRangesThai(), GetGlyphRangesVietnamese(). +- Fonts: removed ImFontAtlas::TexDesiredWidth to enforce a texture width. (#327) + (it vaguely made sense with the old system as if unspecified textures width maxed up + to 4096 but that limit isn't necessary anymore, and Renderer_TextureMaxWidth covers this) + However you may set TexMinWidth = TexMaxWidth for the same effect. +- Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on + ImGuiContext to create one, you'll need to set the atlas->RendererHasTextures field + and call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. +- Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using + PushFontSize(style.FontSizeBase * factor) or to manipulate other scaling factors. +- Fonts: obsoleted ImFont::Scale which is not useful anymore. - Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition(): - - old: const char* CalcWordWrapPositionA(float scale, const char* text, ....); - - new: const char* CalcWordWrapPosition (float size, const char* text, ....); + - old: const char* CalcWordWrapPositionA(float scale, const char* text, ....); + - new: const char* CalcWordWrapPosition (float size, const char* text, ....); The leading 'float scale' parameters was changed to 'float size'. - This was necessary as 'scale' is assuming standard font size which is a concept we aim to - eliminate in an upcoming update. Kept inline redirection function. + This was necessary as 'scale' is assuming a unique font size. + Kept inline redirection function assuming using font->LegacySize. +- Fonts: generally reworked Internals of ImFontAtlas and ImFont. + While in theory a vast majority of users shouldn't be affected, some use cases or + extensions might be. Among other things: + - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef. + - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[] + - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. + - Each ImFont has a number of ImFontBaked instances corresponding to actively used + sizes. ImFont::GetFontBaked(size) retrieves the one for a given size. + - Things moved from ImFont to ImFontBaked: + - ImFont::IndexAdvanceX[] -> ImFontBaked::IndexAdvanceX[] + - ImFont::Glyphs[] -> ImFontBaked::Glyphs[] + - ImFont::Ascent, Descent -> ImFontBaked::Ascent, Descent + - ImFont::FindGlyph() -> ImFontBaked::FindGlyph() + - ImFont::FindGlyphNoFallback() -> ImFontBaked::FindGlyphNoFallback() + - ImFont::GetCharAdvance() -> ImFontBaked::GetCharAdvance() + - Widget code may use ImGui::GetFontBaked() instead of ImGui::GetFont() to + access font data for current font at current font size. + (and you may use font->GetFontBaked(size) to access it for any other size.) + g.Font == ImGui::GetFont() + g.FontSize == ImGui::GetFontSize() + g.FontBaked == ImGui::GetFontBaked() == ImGui::GetFont()->GetFontBaked(ImGui::GetFontSize()) + Please report if you are affected! +- Fonts: (users of imgui_freetype) + - renamed ImFontAtlas::FontBuilderFlags to ImFontAtlas::FontLoaderFlags. + - renamed ImFontConfig::FontBuilderFlags to ImFontConfig::FontLoaderFlags. + - renamed ImGuiFreeTypeBuilderFlags to ImGuiFreeTypeLoaderFlags. + - if you used runtime imgui_freetype selection rather than the default compile-time + option provided by IMGUI_ENABLE_FREETYPE: + - renamed/reworked ImFontBuilderIO into ImFontLoader, + - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader(). + - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() + - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader() +- DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). +- Fonts: (users of custom rectangles) + - Renamed AddCustomRectRegular() to AddCustomRect(). (#8466) + - Added GetCustomRect() as a replacement for GetCustomRectByIndex() + CalcCustomRectUV(). (#8466) + - The output type of GetCustomRect() is now ImFontAtlasRect, which include UV coordinates. + - ImFontAtlasCustomRect::X --> ImFontAtlasRect::x + - ImFontAtlasCustomRect::Y --> ImFontAtlasRect::y + - ImFontAtlasCustomRect::Width --> ImFontAtlasRect::w + - ImFontAtlasCustomRect::Height --> ImFontAtlasRect::h + Before: + const ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(custom_rect_id); + ImVec2 uv0, uv1; + atlas->GetCustomRectUV(r, &uv0, &uv1); + ImGui::Image(atlas->TexRef, ImVec2(r->w, r->h), uv0, uv1); + After: + ImFontAtlasRect r; + atlas->GetCustomRect(custom_rect_id, &r); + ImGui::Image(atlas->TexRef, ImVec2(r.w, r.h), r.uv0, r.uv1); + We added a redirecting typedef but haven't attempted to magically redirect + the field names, as this API is rarely used and the fix is simple. + - Obsoleted AddCustomRectFontGlyph() as the API does not make sense for scalable fonts: + - Kept existing function which uses the font "default size" (Sources[0]->LegacySize). + - Added a helper AddCustomRectFontGlyphForSize() which is immediately marked obsolete, + but can facilitate transitioning old code. + - Prefer adding a font source (ImFontConfig) using a custom/procedural loader. +- Backends: removed ImGui_ImplXXXX_CreateFontsTexture()/ImGui_ImplXXXX_DestroyFontsTexture() + for all backends that had them. They should not be necessary any more. + - removed ImGui_ImplMetal_CreateFontsTexture(), ImGui_ImplMetal_DestroyFontsTexture(). + - removed ImGui_ImplOpenGL2_CreateFontsTexture(), ImGui_ImplOpenGL2_DestroyFontsTexture(). + - removed ImGui_ImplOpenGL3_CreateFontsTexture(), ImGui_ImplOpenGL3_DestroyFontsTexture(). + - removed ImGui_ImplSDLGPU3_CreateFontsTexture(), ImGui_ImplSDLGPU3_DestroyFontsTexture(). + - removed ImGui_ImplSDLRenderer2_CreateFontsTexture(), ImGui_ImplSDLRenderer2_DestroyFontsTexture(). + - removed ImGui_ImplSDLRenderer3_CreateFontsTexture(), ImGui_ImplSDLRenderer3_DestroyFontsTexture(). + - removed ImGui_ImplVulkan_CreateFontsTexture(), ImGui_ImplVulkan_DestroyFontsTexture(). +- TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent + for clarity. Kept inline redirection enum (will obsolete). (#1079, #8639) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted in 1.89.4 (March 2023). (#3092) - PushAllowKeyboardFocus(bool tab_stop) --> PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); @@ -63,6 +208,89 @@ Breaking changes: Other changes: +- Textures: added partial texture update protocol. (#8465, #3761) + - The Renderer Backend needs to set io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures + and handle texture updates requests. + - New structs: ImTextureData, ImTextureRect. + - New enums: ImTextureStatus, ImTextureFormat. + - During its ImGui_ImplXXXX_RenderDrawData() call, the backend can now access a texture list + in ImDrawData::Textures[]. Textures may have four distinct states: + - ImTextureStatus_WantCreate: requesting backend to create a texture. + - ImTextureStatus_WantUpdates: requesting backend to copy given blocks from the CPU side + copy of the texture to your graphics pipeline. + A 'tex->Updates[]' list of update is provided as well as a single 'tex->UpdatesRect' bounding box. + - ImTextureStatus_WantDestroy: requesting backend to destroy the texture. + - A 'int UnusedFrames' value is provided to conveniently defer destroying. + - Backend is generally free to destroy textures whenever they like. + - ImTextureStatus_OK: nothing to do. + - Almost all standard backends have been updated to support this. + - Backends have allowed to destroy textures at any time if they desire so. + A list is available in platform_io.Textures[] for this purpose and for backend shutdown. + - Both stb_truetype and FreeType backends have been updated to work with the new + system, and they now share more code than before. + - Added '#define IMGUI_HAS_TEXTURES' to facilitate compile-time checks for third-party + extensions until this is merged with a definitive version number to check. +- Fonts: font backend/loader may easily be changed dynamically, allowing users to compare + rasterizers outputs and features. imgui_freetype is generally beneficial. +- Fonts: ImFontAtlas::AddFontXXX() functions may be called at any time during the frame. +- Fonts: ImFontAtlas::AddFontXXX() can fail more gracefully if error handling is configured + to not assert (this will be better exposed via future font flags). +- Fonts: added ImGui::PushFontSize()/PopFontSize() functions. +- Fonts: added style.FontScaleBase scaling factor (previously called io.FontGlobalScale). +- Fonts: added style.FontScaleDpi scaling factor. This is designed to be be changed on + per-monitor/per-viewport basis, which `io.ConfigDpiScaleFonts` does automatically. + (which is why it is separate from FontScaleBase). +- Fonts: added optional font_size parameter to ImGui::PushFont() function. +- Fonts: added ImFontAtlas::RemoveFont() function. +- Fonts: added ImFontAtlas::CompactCache() function. +- Fonts: added ImFontAtlas::TexDesiredFormat field (default to ImTextureFormat_RGBA32, + can be changed to ImTextureFormat_Alpha8). +- Fonts: added ImFontAtlas::TexMinWidth, TexMinHeight, TexMaxWidth, TexMaxHeight fields. +- Fonts: added ImFontConfig::PixelSnapV to align scaled GlyphOffset.y to pixel boundaries. +- Fonts: added ImFontConfig::GlyphExcludeRanges[], which behave similarly to + ImFontConfig::GlyphRanges[], but has the opposite meaning. It is tailored to situations + where merged fonts have overlapping characters. +- Fonts: added "Input Glyphs Overlap Detection Tool" which dumps a list of glyphs + provided by merged sources, which may help setting up a GlyphExcludeRanges[] filter. +- Fonts: added ImFontAtlas::FontBackendName (which is surfaced in the "About Dear ImGui" + window and other locations). +- Fonts: added ImFontFlags (currently needs to be passed through ImFontConfig until + we revamp font loading API): + - ImFontFlags_DefaultToLegacySize: for legacy compatibility: make PushFont() calls + without explicit size use font->LegacySize instead of current font size. + - ImFontFlags_NoLoadError: disable erroring/assert when calling AddFontXXX() + with missing file/data. Calling code is expected to check AddFontXXX() return value. + - ImFontFlags_NoLoadGlyphs: disable loading new glyphs. + - ImFontFlags_LockBakedSizes: disable loading new baked sizes, disable garbage + collecting current ones. e.g. if you want to lock a font to a single size. +- Fonts: the general design has changed toward meaning that a ImFont doesn't have + have a specific size: it may be bound and drawn with any size. + - We store ImFontBaked structures internally, which are a cache of information + for a given size being drawn. You should not need to deal with ImFontBaked directly. + - ImFontBaked structures may be cleaned up between frames when unused, pointers + to them are only valid for the current frame. + - Added ImFontBaked::IsGlyphLoaded() function. +- Fonts: custom rect packing has generally been reworked. (#8107, #7962, #1282) + - ImFontAtlas::AddCustomRect() (previously AddCustomRectRegular()/AddCustomRectFontGlyph()) + functions will immediately return a packed rectangle identifier, and you can write your + pixels immediately - previously had to wait for Build() to be called. + This is also the case when using a legacy backend. + - Custom packed rectangles may be moved during a texture change, aka practically anytime. + Always refer to latest uvs/position returned by GetCustomRect(). + - AddCustomRect() returns ImFontAtlasRectId_Invalid on failure. + - Added ImFontAtlas::RemoveCustomRect() function. + - GetCustomRect() can safely return false and not crash when passed an invalid or removed id. +- Fonts: texture is now stored in a single format CPU side (save ~25% when using RGBA). +- Fonts: changing current font to one from a different atlas is supported. (#8080) +- Fonts: automatic baking of an "..." ellipsis works better with monospace fonts. +- Fonts: each ImFontConfig font source may provide a custom backend/loader. +- Fonts: added platform_io.Renderer_TextureMaxWidth/Renderer_TextureMaxHeight fields + for Renderer Backend to specify if there is a maximum accepted texture size (not yet used). +- Fonts: added compile-time overridable '#define ImTextureID_Invalid 0' if you need 0 + to be a valid low-level texture identifier. +- Debug Tools: Fonts section: add font preview, add "Remove" button, add "Load all glyphs" + button, add selection to change font backend when both are compiled in. + - IO: variations in analog-only components of gamepad events do not interfere with trickling of mouse position events (#4921, #8508) - Windows: fixed SetNextWindowCollapsed()/SetWindowCollapsed() breaking @@ -132,39 +360,62 @@ Other changes: requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). -- Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) - would fail to claim it again the next subsequent click. (#8594) -- Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad - regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) -- Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't - call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use - the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] -- Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. -- Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() - memory ownership change. (#8530, #7801) [@Green-Sky] -- Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative - way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) -- Backends: SDLGPU3: Fixed creating atlas texture earlier than other backends, preventing - to load fonts between the Init and NewFrames calls. -- Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which - were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] -- Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) -- Backends: OpenGL3: made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor - GL_PRIMITIVE_RESTART. (#8664) [@DyXel] -- Backends: DirectX10, DirectX11, DirectX12: Honor FramebufferScale to allow for custom - platform backends and experiments using it (consistently with other renderer backends, - even though in normal condition it is not set under Windows). (#8412) [@WSSDude] -- Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's - pColorAttachmentFormats buffer when set, in order to reduce common user-error of - specifying a pointer to data that gets out of scope. (#8282) -- Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() - + try both non-KHR and KHR versions. (#8600, #8326, #8365) [@ChrisTom-94] -- Backends: Vulkan: fixed validation errors in window create/resize helpers used by examples - and by multi-viewports implementation, which would typically trigger errors while detaching - secondary viewports. (#8600, #8176) [@ChrisTom-94] -- Examples: Apple+Metal, Apple+OpenGL: add Makefile (CLion opens them nicely). (#8637) [@pthom] -- Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to - get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] +- Backends: + - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, Allegro5: + - Added ImGuiBackendFlags_RendererHasTextures support. (#8465, #3761, #3471) + [@ocornut, @ShironekoBen, @thedmd] + - Added ImGui_ImplXXXX_UpdateTexture(ImTextureData* tex) functions for all backend. + Available if you want to start uploading textures right after ImGui::Render() and without + waiting for the call to ImGui_ImplXXXX_RenderDrawData(). Also useful if you use a staged or + multi-threaded rendering schemes, where you might want to set ImDrawData::Textures = NULL. (#8597, #1860) + - Backends: GLFW: added ImGui_ImplGlfw_GetContentScaleForMonitor(), ImGui_ImplGlfw_GetContentScaleForWindow() + helpers. They are wrappers to glfwGetMonitorContentScale()/glfwGetWindowContentScale(), with compile-time + GLFW version checks + returning 1.0f on Apple platform. + - Backends: SDL2: added ImGui_ImplSDL2_GetDpiScaleForDisplay() and ImGui_ImplSDL2_GetContentScaleForWindow() + helpers. They are wrappers to SDL_GetDisplayDPI(), with compile-time SDL version checks + returning 1.0f + on Apple platforms. SDL3 already does this by default. + - Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) + would fail to claim it again the next subsequent click. (#8594) + - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad + regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) + - Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't + call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use + the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] + - Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. + - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() + memory ownership change. (#8530, #7801) [@Green-Sky] + - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative + way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) + - Backends: SDLGPU3: Fixed creating atlas texture earlier than other backends, preventing + to load fonts between the Init and NewFrames calls. + - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which + were unusually slow to recreate every frame. Much faster now. (#8534) [@ocornut, @TheMode] + - Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) + - Backends: OpenGL3: made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor + GL_PRIMITIVE_RESTART. (#8664) [@DyXel] + - Backends: DirectX10, DirectX11, DirectX12: Honor FramebufferScale to allow for custom + platform backends and experiments using it (consistently with other renderer backends, + even though in normal condition it is not set under Windows). (#8412) [@WSSDude] + - Backends: Vulkan: Deep-copy ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo's + pColorAttachmentFormats buffer when set, in order to reduce common user-error of + specifying a pointer to data that gets out of scope. (#8282) + - Backends: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + + try both non-KHR and KHR versions. (#8600, #8326, #8365) [@ChrisTom-94] + - Backends: Vulkan: fixed validation errors in window create/resize helpers used by examples + and by multi-viewports implementation, which would typically trigger errors while detaching + secondary viewports. (#8600, #8176) [@ChrisTom-94] +- Examples: + - Examples: Made many examples DPI aware by default. + The single-viewport is basically: + - Query monitor DPI scale. Helpers are provided in some backends. + - Call style.ScaleAllSizes() and set style.FontScaleDpi with this factor. + Multi-viewport applications may set both of those flags: + - io.ConfigDpiScaleFonts = true; + - io.ConfigDpiScaleViewports = true; + Which will scale fonts but NOT style padding/spacings/thicknesses yet. + - Examples: Apple+Metal, Apple+OpenGL: add Makefile (CLion opens them nicely). (#8637) [@pthom] + - Examples: DirectX12+Win32: also test for IsIconic() for sleeping since we don't seem to + get a DXGI_STATUS_OCCLUDED signal when minimized. (#8603) [@dooann] ----------------------------------------------------------------------- diff --git a/docs/FAQ.md b/docs/FAQ.md index 8c08b4dd7873..0e8ba5c774eb 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -24,7 +24,7 @@ or view this file with any Markdown viewer. | [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) | | **Q&A: Usage** | | **[About the ID Stack system..
Why is my widget not reacting when I click on it?
Why is the wrong widget reacting when I click on one?
How can I have widgets with an empty label?
How can I have multiple widgets with the same label?
How can I have multiple windows with the same label?](#q-about-the-id-stack-system)** | -| [How can I display an image? What is ImTextureID, how does it work?](#q-how-can-i-display-an-image-what-is-imtextureid-how-does-it-work)| +| [How can I display an image?](#q-how-can-i-display-an-image)
[What are ImTextureID/ImTextureRef?](#q-what-are-imtextureidimtextureref)| | [How can I use maths operators with ImVec2?](#q-how-can-i-use-maths-operators-with-imvec2) | | [How can I use my own maths types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-maths-types-instead-of-imvec2imvec4) | | [How can I interact with standard C++ types (such as std::string and std::vector)?](#q-how-can-i-interact-with-standard-c-types-such-as-stdstring-and-stdvector) | @@ -161,7 +161,8 @@ Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-lik ### Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... Your renderer backend is not using the font texture correctly or it hasn't been uploaded to the GPU. -- If this happens using the standard backends: A) have you modified the font atlas after `ImGui_ImplXXX_NewFrame()`? B) maybe the texture failed to upload, which **can if your texture atlas is too big**. Also see [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). +- If this happens using standard backends (before 1.92): A) have you modified the font atlas after `ImGui_ImplXXX_NewFrame()`? B) maybe the texture failed to upload, which **can if your texture atlas is too big**. Also see [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). +- If this happens using standard backends (after 1.92): please report. - If this happens with a custom backend: make sure you have uploaded the font texture to the GPU, that all shaders are rendering states are setup properly (e.g. texture is bound). Compare your code to existing backends and use a graphics debugger such as [RenderDoc](https://renderdoc.org) to debug your rendering states. ##### [Return to Index](#index) @@ -375,23 +376,49 @@ node open/closed state differently. See what makes more sense in your situation! --- -### Q: How can I display an image? What is ImTextureID, how does it work? +### Q: How can I display an image? +### Q: What are ImTextureID/ImTextureRef? -Short explanation: +**Short explanation:** - Refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki). - You may use functions such as `ImGui::Image()`, `ImGui::ImageButton()` or lower-level `ImDrawList::AddImage()` to emit draw calls that will use your own textures. - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as an opaque ImTextureID value. - By default ImTextureID can store up to 64-bits. You may `#define` it to a custom type/structure if you need. - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason), but the examples linked above may be useful references. +**Details:** + +1.92 introduced `ImTextureRef` in June 2025. +- Most drawing functions using ImTextureID were changed to use ImTextureRef. +- We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. + +**ImTextureID = backend specific, low-level identifier for a texture uploaded in GPU/graphics system.** +- When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). +- User may submit their own textures to e.g. ImGui::Image() function by passing the same type. +- During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a ImTextureRef, which is stored inside ImDrawCmd. +- Compile-time type configuration: + - To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file. + - This can be whatever to you want it to be! read the FAQ entry about textures for details. + - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various constructors if you like. You will need to implement ==/!= operators. + +**ImTextureRef = higher-level identifier for a texture.** +- The identifier is valid even before the texture has been uploaded to the GPU/graphics system. +- This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. +- This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. + - When a texture is created by user code (e.g. custom images), we directly stores the low-level `ImTextureID`. + - When a texture is created by the backend, we stores a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. + - There is no constructor to create a `ImTextureID` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. + - If you want to bind the current atlas when using custom rectangle, you can use `io.Fonts->TexRef`. + - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }` + **Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.** Long explanation: - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices. At the end of the frame, those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code to render them is generally fairly short (a few dozen lines). In the examples/ folder, we provide functions for popular graphics APIs (OpenGL, DirectX, etc.). - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API. - We carry the information to identify a "texture" in the ImTextureID type. +We carry the information to identify a "texture" in the ImTextureID type, which itself tends to be stored inside a ImTextureRef. ImTextureID default to ImU64 aka 8 bytes worth of data: just enough to store one pointer or integer of your choice. -Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely passes ImTextureID values until they reach your rendering function. +Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely passes values until they reach your rendering function. - In the [examples/](https://github.com/ocornut/imgui/tree/master/examples) backends, for each graphics API we decided on a type that is likely to be a good representation for specifying an image from the end-user perspective. This is what the _examples_ rendering functions are using: ```cpp OpenGL: @@ -539,30 +566,49 @@ ImGui::End(); ### Q: How should I handle DPI in my application? -The short answer is: obtain the desired DPI scale, load your fonts resized with that scale (always round down fonts size to the nearest integer), and scale your Style structure accordingly using `style.ScaleAllSizes()`. +Since 1.92 (June 2025) fonts may be dynamically used at any size. -Your application may want to detect DPI change and reload the fonts and reset style between frames. +**Scaling fonts** -Your UI code should avoid using hardcoded constants for size and positioning. Prefer to express values as multiple of reference values such as `ImGui::GetFontSize()` or `ImGui::GetFrameHeight()`. So e.g. instead of seeing a hardcoded height of 500 for a given item/window, you may want to use `30*ImGui::GetFontSize()` instead. +To change font size: +```cpp +ImGui::PushFontSize(42.0f); +``` +To change font and font size: +```cpp +ImGui::PushFont(new_font, 42.0f); +``` +To scale all fonts: +```cpp +style.FontScaleDpi = 2.0f; +``` +In `docking` branch or with multi-viewports: +```cpp +io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. +io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. +``` -Down the line Dear ImGui will provide a variety of standardized reference values to facilitate using this. +**Scaling style** (paddings, spacings, thicknesses) -Applications in the `examples/` folder are not DPI aware partly because they are unable to load a custom font from the file-system (may change that in the future). +This is still massively work in progress, expect turbulence. +Style values are currently not easily scalable dynamically. +For single viewport application you can call once: +```cpp +style.ScaleAllSizes(factor); // call once! +``` +If you need to change the scaling factor, it is currently most practical to reset the style and call this again with a new value. -The reason DPI is not auto-magically solved in stock examples is that we don't yet have a satisfying solution for the "multi-dpi" problem (using the `docking` branch: when multiple viewport windows are over multiple monitors using different DPI scales). The current way to handle this on the application side is: -- Create and maintain one font atlas per active DPI scale (e.g. by iterating `platform_io.Monitors[]` before `NewFrame()`). -- Hook `platform_io.OnChangedViewport()` to detect when a `Begin()` call makes a Dear ImGui window change monitor (and therefore DPI). -- In the hook: swap atlas, swap style with correctly sized one, and remap the current font from one atlas to the other (you may need to maintain a remapping table of your fonts at varying DPI scales). +Your UI code should avoid using hardcoded constants for size and positioning. Prefer to express values as multiple of reference values such as `ImGui::GetFontSize()` or `ImGui::GetFrameHeight()`. So e.g. instead of seeing a hardcoded height of 500 for a given item/window, you may want to use `30*ImGui::GetFontSize()` instead. -This approach is relatively easy and functional but comes with two issues: -- It's not possibly to reliably size or position a window ahead of `Begin()` without knowing on which monitor it'll land. -- Style override may be lost during the `Begin()` call crossing monitor boundaries. You may need to do some custom scaling mumbo-jumbo if you want your `OnChangedViewport()` handler to preserve style overrides. +Down the line Dear ImGui will provide a variety of standardized reference values to facilitate using this. This is expected to happen during subsequent 1.92.x releases. -Please note that if you are not using multi-viewports with multi-monitors using different DPI scales, you can ignore that and use the simpler technique recommended at the top. +Applications in the `examples/` folder are partly DPI aware but they are unable to load a custom font from the file-system, so they look ugly (may change that in the future). -On Windows, in addition to scaling the font size (make sure to round to an integer) and using `style.ScaleAllSizes()`, you will need to inform Windows that your application is DPI aware. If this is not done, Windows will scale the application window and the UI text will be blurry. Potential solutions to indicate DPI awareness on Windows are: +The reason DPI is not auto-magically solved in stock examples is that we don't yet have a satisfying solution for the "multi-dpi" problem (using the `docking` branch: when multiple viewport windows are over multiple monitors using different DPI scales) specifically for the `ImGuiStyle` structure. Fonts are however now perfectly scalable. -- For SDL2: the flag `SDL_WINDOW_ALLOW_HIGHDPI` needs to be passed to `SDL_CreateWindow()`. +**On Windows, you need to inform Windows that your application is DPI aware!** +If this is not done, Windows will scale the application window and the UI text will be blurry. Potential solutions to indicate DPI awareness on Windows are: +- For SDL2: the flag `SDL_WINDOW_ALLOW_HIGHDPI` needs to be passed to `SDL_CreateWindow()` + call `::SetProcessDPIAware()`. - For SDL3: the flag `SDL_WINDOW_HIGH_PIXEL_DENSITY` needs to be passed to `SDL_CreateWindow()`. - For GLFW: this is done automatically. - For other Windows projects with other backends, or wrapper projects: @@ -615,9 +661,12 @@ Use the font atlas to pack them into a single texture. Read [docs/FONTS.md](http --- ### Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? -When loading a font, pass custom Unicode ranges to specify the glyphs to load. +Since 1.92 (June 2025) and with an updated backend, it is not necessary to specify glyph ranges at all. + +Before 1.92, when loading a font, pass custom Unicode ranges to specify the glyphs to load. ```cpp +// [BEFORE 1.92] // Add default Japanese ranges io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, nullptr, io.Fonts->GetGlyphRangesJapanese()); @@ -641,8 +690,8 @@ Text input: it is up to your application to pass the right character code by cal The applications in examples/ are doing that. Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode). You may also use `MultiByteToWideChar()` or `ToUnicode()` to retrieve Unicode codepoints from MultiByte characters or keyboard state. -Windows: if your language is relying on an Input Method Editor (IME), you can write your HWND to ImGui::GetMainViewport()->PlatformHandleRaw -for the default implementation of GetPlatformIO().Platform_SetImeDataFn() to set your Microsoft IME position correctly. +Windows: if your language is relying on an Input Method Editor (IME), you can write your HWND to `ImGui::GetMainViewport()->PlatformHandleRaw` +for the default implementation of `GetPlatformIO().Platform_SetImeDataFn()` to set your Microsoft IME position correctly. ##### [Return to Index](#index) diff --git a/docs/FONTS.md b/docs/FONTS.md index baa53adde641..7ed8fe026b9f 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -12,7 +12,7 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo ## Index - [Troubleshooting](#troubleshooting) -- [New! Dynamic Fonts system in 1.92 (March 2025)](#new-dynamic-fonts-system-in-192-march-2025) +- [New! Dynamic Fonts system in 1.92 (June 2025)](#new-dynamic-fonts-system-in-192-june-2025) - [How should I handle DPI in my application?](#how-should-i-handle-dpi-in-my-application) - [Fonts Loading Instructions](#fonts-loading-instructions) - [Loading Font Data from Memory](#loading-font-data-from-memory) @@ -72,11 +72,11 @@ Future versions of Dear ImGui should solve this problem. --------------------------------------- -## New! Dynamic Fonts system in 1.92 (March 2025+) +## New! Dynamic Fonts system in 1.92 (June 2025) -v1.92 will introduce a newer, dynamic font system. It requires backend to support the `ImGuiBackendFlags_HasTextures` feature: +v1.92 introduces a newer, dynamic font system. It requires backend to support the `ImGuiBackendFlags_HasTextures` feature: - Users of icons, Asian and non-English languages do not need to pre-build all glyphs ahead of time. Saving on loading time, memory, and also reducing issues with missing glyphs. Specifying glyph ranges is not needed anymore. -- PushFontSize() may be used anytime to change font size. +- `PushFontSize()` may be used anytime to change font size. - Packing custom rectangles is more convenient as pixels may be written to immediately. - Any update to fonts previously required backend specific calls to re-upload the texture, and said calls were not portable across backends. It is now possible to scale fonts etc. in a way that doesn't require you to make backend-specific calls. - It is possible to plug a custom loader/backend to any font source. @@ -105,6 +105,12 @@ io.Fonts->AddFontDefault(); ``` **Load .TTF/.OTF file with:** +🆕 **Since 1.92, with an up to date backend: passing a size is not necessary** +```cpp +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontFromFileTTF("font.ttf"); +``` +**Before 1.92, or without an up to date backend:** ```cpp ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); @@ -115,8 +121,8 @@ If you get an assert stating "Could not load font file!", your font filename is ```cpp // Init ImGuiIO& io = ImGui::GetIO(); -ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); -ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); +ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf",); +ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf"); ``` In your application loop, select which font to use: @@ -135,6 +141,18 @@ ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); ``` **Combine multiple fonts into one:** + +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is unnecessary.** +```cpp +// Load a first font +ImFont* font = io.Fonts->AddFontDefault(); +ImFontConfig config; +config.MergeMode = true; +io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 0.0f, &config); // Merge into first font to add e.g. Asian characters +io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 0.0f, &config); // Merge into first font to add Icons +io.Fonts->Build(); +``` +**Before 1.92, or without an up to date backend:** ```cpp // Load a first font ImFont* font = io.Fonts->AddFontDefault(); @@ -152,8 +170,7 @@ io.Fonts->Build(); **Add a fourth parameter to bake specific font ranges only:** -🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary. All the GetGlyphRangesXXX() functions are marked obsolete.** - +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is unnecessary. All the GetGlyphRangesXXX() functions are marked obsolete.** ```cpp // Basic Latin, Extended Latin io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, nullptr, io.Fonts->GetGlyphRangesDefault()); @@ -169,14 +186,12 @@ See [Using Custom Glyph Ranges](#using-custom-glyph-ranges) section to create yo **Example loading and using a Japanese font:** 🆕 **Since 1.92, with an up to date backend:** - ```cpp ImGuiIO& io = ImGui::GetIO(); -io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f); +io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf"); ``` **Before 1.92, or without an up to date backend:** - ```cpp ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); @@ -248,14 +263,24 @@ To refer to the icon UTF-8 codepoints from your C++ code, you may use those head So you can use `ICON_FA_SEARCH` as a string that will render as a "Search" icon. -🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary. You can omit this parameter.** - +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is unnecessary. You can omit this parameter.** Example Setup: ```cpp // Merge icons into default tool font #include "IconsFontAwesome.h" ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontDefault(); +ImFontConfig config; +config.MergeMode = true; +config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced +io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config); +``` +**Before 1.92:** +```cpp +// Merge icons into default tool font +#include "IconsFontAwesome.h" +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontDefault(); ImFontConfig config; config.MergeMode = true; @@ -275,7 +300,8 @@ See Links below for other icons fonts and related tools. **Monospace Icons?** -To make your icon look more monospace and facilitate alignment, you may want to set the ImFontConfig::GlyphMinAdvanceX value when loading an icon font. +To make your icon look more monospace and facilitate alignment, you may want to set the `ImFontConfig::GlyphMinAdvanceX` value when loading an icon font. +If you `GlyphMinAdvanceX` you need to pass a `font_size` to `AddFontXXX()` calls, as the MinAdvanceX value will be specified for the given size and scaled otherwise. **Screenshot** @@ -288,8 +314,8 @@ Here's an application using icons ("Avoyd", https://www.avoyd.com): ## Using FreeType Rasterizer (imgui_freetype) -- Dear ImGui uses imstb\_truetype.h to rasterize fonts (with optional oversampling). This technique and its implementation are not ideal for fonts rendered at small sizes, which may appear a little blurry or hard to read. -- There is an implementation of the ImFontAtlas builder using FreeType that you can use in the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. +- Dear ImGui uses [stb_truetype.h](https://github.com/nothings/stb/) to rasterize fonts (with optional oversampling). This technique and its implementation are not ideal for fonts rendered at small sizes, which may appear a little blurry or hard to read. +- You can however use `imgui_freetype.cpp` from the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. - FreeType supports auto-hinting which tends to improve the readability of small fonts. - Read documentation in the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. - Correct sRGB space blending will have an important effect on your font rendering quality. @@ -312,10 +338,9 @@ Here's an application using icons ("Avoyd", https://www.avoyd.com): io.Fonts->AddFontFromFileTTF("../../../imgui_dev/data/fonts/NotoSans-Regular.ttf", 16.0f); static ImWchar ranges[] = { 0x1, 0x1FFFF, 0 }; static ImFontConfig cfg; -cfg.OversampleH = cfg.OversampleV = 1; cfg.MergeMode = true; -cfg.FontBuilderFlags |= ImGuiFreeTypeBuilderFlags_LoadColor; -io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\seguiemj.ttf", 16.0f, &cfg, ranges); +cfg.FontLoaderFlags |= ImGuiFreeTypeLoaderFlags_LoadColor; +io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\seguiemj.ttf", 16.0f, &cfg); ``` ##### [Return to Index](#index) @@ -348,7 +373,7 @@ io.Fonts->Build(); // Build the atlas while 🆕 **Since 1.92, with an up to date backend: this system has been revamped.** TL;DR; With the new system, it is recommended that you create a custom `ImFontLoader` and register your fonts with it. -`AddCustomRectFontGlyph()` has been obsolete because its API does not make much sense with resizable fonts. +`AddCustomRectFontGlyph()` has been obsoleted because its API does not make much sense with resizable fonts. You can ask questions in [#8466](https://github.com/ocornut/imgui/issues/8466). diff --git a/imgui.h b/imgui.h index 1d27953f2175..de0d06645271 100644 --- a/imgui.h +++ b/imgui.h @@ -314,18 +314,17 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // ImTextureID = backend specific, low-level identifier for a texture uploaded in GPU/graphics system. // [Compile-time configurable type] -// Overview: // - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value. -// (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint'; +// (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; // Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). // - User may submit their own textures to e.g. ImGui::Image() function by passing the same type. -// - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside -// ImTextureRef, which is stored inside ImDrawCmd. -// Configuring the type: -// - To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file. -// - This can be whatever to you want it to be! read the FAQ entry about textures for details. -// - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various -// constructors if you like. You will need to implement ==/!= operators. +// - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a +// ImTextureRef, which is stored inside a ImDrawCmd. +// - Compile-time type configuration: +// - To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file. +// - This can be whatever to you want it to be! read the FAQ entry about textures for details. +// - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various +// constructors if you like. You will need to implement ==/!= operators. // History: // - In v1.91.4 (2024/10/08): the default type for ImTextureID was changed from 'void*' to 'ImU64'. This allowed backends requirig 64-bit worth of data to build on 32-bit architectures. Use intermediary intptr_t cast and read FAQ if you have casting warnings. // - In v1.92.0 (2025/XX/XX): added ImTextureRef which carry either a ImTextureID either a pointer to internal texture atlas. All user facing functions taking ImTextureID changed to ImTextureRef @@ -340,15 +339,15 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or // ImTextureRef = higher-level identifier for a texture. // The identifier is valid even before the texture has been uploaded to the GPU/graphics system. -// This is what gets passed to functions such as ImGui::Image(), ImDrawList::AddImage(). -// This is what gets stored in draw commands (ImDrawCmd) to identify a texture during rendering. +// This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. +// This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. // - When a texture is created by user code (e.g. custom images), we directly stores the low-level ImTextureID. // - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection // to extract the ImTextureID value during rendering, after texture upload has happened. // - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this // to be useful to the end-user, and it would be erroneously called by many legacy code. // - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. -// - Binding generators for languages such as C (which don't have constructors), should provide a helper: +// - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. // inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } // In 1.92 we changed most drawing functions using ImTextureID to use ImTextureRef. // We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. From df068ce11eeee0566090fcdf3fbfab807cf95808 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 18:30:18 +0200 Subject: [PATCH 613/716] Various/misc fixes following back-and-forth dynamic_fonts->master->docking merges. Added missing API BREAKING CHANGES section. --- backends/imgui_impl_dx12.cpp | 9 ----- backends/imgui_impl_opengl2.cpp | 2 +- backends/imgui_impl_sdlgpu3.cpp | 2 +- backends/imgui_impl_sdlgpu3.h | 2 +- backends/imgui_impl_sdlrenderer2.cpp | 2 +- backends/imgui_impl_sdlrenderer2.h | 2 +- backends/imgui_impl_sdlrenderer3.cpp | 2 +- backends/imgui_impl_sdlrenderer3.h | 2 +- backends/imgui_impl_wgpu.cpp | 4 ++- backends/imgui_impl_wgpu.h | 4 ++- docs/CHANGELOG.txt | 14 ++++---- imgui.cpp | 51 ++++++++++++++++++++++++++++ 12 files changed, 71 insertions(+), 25 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index ea7e3b8813bc..e3bcda195a62 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -820,15 +820,6 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. - if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - ImGui_ImplDX12_InitPlatformInterface(); - - // Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport, - // Since this is created and managed by the application, we will only use the ->Resources[] fields. - ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight); ->>>>>>> dda12fbd9a (Backends: DirectX12: added ImGuiBackendFlags_RendererHasTextures support.) - #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (init_info->SrvDescriptorAllocFn == nullptr) { diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 5e9df17153d3..afcafe82606d 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -3,7 +3,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // Missing features or Issues: // [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 92515602b108..0ad9e2c301f8 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -4,7 +4,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index 380855b297fc..826767ac5369 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -4,7 +4,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use simply cast a reference to your SDL_GPUTextureSamplerBinding to ImTextureID. // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification. // IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/ diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index dbdeb5c114c8..bcc4404ff7a2 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -12,7 +12,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index cf127c1f7917..a62e60927831 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -12,7 +12,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index ef6f0441c8c0..77b5bc059600 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -12,7 +12,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 170560fdc038..618cc2430089 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -12,7 +12,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). -// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 3187be29a39f..3a182ccd2156 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -3,9 +3,11 @@ // (Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break.) // Implemented features: -// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// Missing features or Issues: +// [ ] Renderer: Missing texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 7efb02afe109..1da208f0090b 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -10,9 +10,11 @@ //#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU // Implemented features: -// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! +// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. +// Missing features or Issues: +// [ ] Renderer: Missing texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2a16008f6920..8a49b9a04e47 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,11 +63,11 @@ Breaking changes: - With a legacy backend (< 1.92): - Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. - This already worked before, but is now pretty much required. - - With a new backend (1.92+) + - With a new backend (1.92+), + - This should be all automatic. - FramebufferScale is automatically used to set current font RasterizerDensity. - FramebufferScale is a per-viewport property provided by backend through the Platform_GetWindowFramebufferScale() handler in 'docking' branch. - - So this should be all automatic. - Fonts: **IMPORTANT** on Font Sizing: - Before 1.92, fonts were of a single size. They can now be dynamically sized. - PushFont() API now has an optional size parameter. PushFontSize() was also added. @@ -75,9 +75,9 @@ Breaking changes: - Before 1.92: ImGui::PushFont() always used font "default" size specified in AddFont() call. - Since 1.92: ImGui::PushFont() preserve the current font size which is a shared value. - To use old behavior: - - use 'ImGui::PushFont(font, font->LegacySize)' at call site. + - use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). - or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call - (not desirable as it requires e.g. third-party code to be aware of it). + (not desirable as it requires e.g. all third-party code to be aware of it). - ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. @@ -134,7 +134,7 @@ Breaking changes: - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. - Each ImFont has a number of ImFontBaked instances corresponding to actively used sizes. ImFont::GetFontBaked(size) retrieves the one for a given size. - - Things moved from ImFont to ImFontBaked: + - Fields moved from ImFont to ImFontBaked: - ImFont::IndexAdvanceX[] -> ImFontBaked::IndexAdvanceX[] - ImFont::Glyphs[] -> ImFontBaked::Glyphs[] - ImFont::Ascent, Descent -> ImFontBaked::Ascent, Descent @@ -155,9 +155,9 @@ Breaking changes: - if you used runtime imgui_freetype selection rather than the default compile-time option provided by IMGUI_ENABLE_FREETYPE: - renamed/reworked ImFontBuilderIO into ImFontLoader, - - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader(). + - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader() - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() - - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader() + - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader(); - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). - Fonts: (users of custom rectangles) - Renamed AddCustomRectRegular() to AddCustomRect(). (#8466) diff --git a/imgui.cpp b/imgui.cpp index b9b5fbbc1836..74c135ddffba 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -449,6 +449,57 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/06/11 (1.92.0) - THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, BUT INEVITABLY SOME USERS WILL BE AFFECTED. + IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: https://github.com/ocornut/imgui/issues/ + As part of the plan to reduce impact of API breaking changes, several unfinished changes/features/refactors related to font and text systems and scaling will be part of subsequent releases (1.92.1+). + If you are updating from an old version, and expecting a massive or difficult update, consider first updating to 1.91.9 to reduce the amount of changes. + - Hard to read? Refer to 'docs/Changelog.txt' for a less compact and more complete version of this! + - Fonts: **IMPORTANT**: if your app was solving the OSX/iOS Retina screen specific logical vs display scale problem by setting io.DisplayFramebufferScale (e.g. to 2.0f) + setting io.FontGlobalScale (e.g. to 1.0f/2.0f) + loading fonts at scaled sizes (e.g. size X * 2.0f): + This WILL NOT map correctly to the new system! Because font will rasterize as requested size. + - With a legacy backend (< 1.92): Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. This already worked before, but is now pretty much required. + - With a new backend (1.92+): This should be all automatic. FramebufferScale is automatically used to set current font RasterizerDensity. FramebufferScale is a per-viewport property provided by backend through the Platform_GetWindowFramebufferScale() handler in 'docking' branch. + - Fonts: **IMPORTANT** on Font Sizing: Before 1.92, fonts were of a single size. They can now be dynamically sized. + - PushFont() API now has an optional size parameter. PushFontSize() was also added. + - Before 1.92: ImGui::PushFont() always used font "default" size specified in AddFont() call. + - Since 1.92: ImGui::PushFont() preserve the current font size which is a shared value. + - To use old behavior: (A) use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). (B) Set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call (not desirable as it requires e.g. third-party code to be aware of it). + - Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). + - Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. + - Textures: all API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef'. Affected functions are: ImGui::Image(), ImGui::ImageWithBg(), ImGui::ImageButton(), ImDrawList::AddImage(), ImDrawList::AddImageQuad(), ImDrawList::AddImageRounded(). + - Fonts: obsoleted ImFontAtlas::GetTexDataAsRGBA32(), GetTexDataAsAlpha8(), Build(), SetTexID(), IsBuilt() functions. The new protocol for backends to handle textures doesn't need them. Kept redirection functions (will obsolete). + - Fonts: ImFontConfig::OversampleH/OversampleV default to automatic (== 0) since v1.91.8. It is quite important you keep it automatic until we decide if we want to provide a way to express finer policy, otherwise you will likely waste texture space when using large glyphs. Note that the imgui_freetype backend doesn't use and does not need oversampling. + - Fonts: specifying glyph ranges is now unnecessary. The value of ImFontConfig::GlyphRanges[] is only useful for legacy backends. All GetGlyphRangesXXXX() functions are now marked obsolete: GetGlyphRangesDefault(), GetGlyphRangesGreek(), GetGlyphRangesKorean(), GetGlyphRangesJapanese(), GetGlyphRangesChineseSimplifiedCommon(), GetGlyphRangesChineseFull(), GetGlyphRangesCyrillic(), GetGlyphRangesThai(), GetGlyphRangesVietnamese(). + - Fonts: removed ImFontAtlas::TexDesiredWidth to enforce a texture width. (#327) + - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to set the atlas->RendererHasTextures field and call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. + - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using 'PushFontSize(style.FontSizeBase * factor)' or to manipulate other scaling factors. + - Fonts: obsoleted ImFont::Scale which is not useful anymore. + - Fonts: generally reworked Internals of ImFontAtlas and ImFont. While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things: + - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef. + - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[] + - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. + - Each ImFont has a number of ImFontBaked instances corresponding to actively used sizes. ImFont::GetFontBaked(size) retrieves the one for a given size. + - Fields moved from ImFont to ImFontBaked: IndexAdvanceX[], Glyphs[], Ascent, Descent, FindGlyph(), FindGlyphNoFallback(), GetCharAdvance(). + - Widget code may use ImGui::GetFontBaked() instead of ImGui::GetFont() to access font data for current font at current font size (and you may use font->GetFontBaked(size) to access it for any other size.) + - Fonts: (users of imgui_freetype): renamed ImFontAtlas::FontBuilderFlags to ImFontAtlas::FontLoaderFlags. Renamed ImFontConfig::FontBuilderFlags to ImFontConfig::FontLoaderFlags. Renamed ImGuiFreeTypeBuilderFlags to ImGuiFreeTypeLoaderFlags. + If you used runtime imgui_freetype selection rather than the default IMGUI_ENABLE_FREETYPE compile-time option: Renamed/reworked ImFontBuilderIO into ImFontLoader. Renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader(). + - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() + - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader() + - Fonts: (users of custom rectangles, see #8466): Renamed AddCustomRectRegular() to AddCustomRect(). Added GetCustomRect() as a replacement for GetCustomRectByIndex() + CalcCustomRectUV(). + - The output type of GetCustomRect() is now ImFontAtlasRect, which include UV coordinates. X->x, Y->y, Width->w, Height->h. + - old: + const ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(custom_rect_id); + ImVec2 uv0, uv1; + atlas->GetCustomRectUV(r, &uv0, &uv1); + ImGui::Image(atlas->TexRef, ImVec2(r->w, r->h), uv0, uv1); + - new; + ImFontAtlasRect r; + atlas->GetCustomRect(custom_rect_id, &r); + ImGui::Image(atlas->TexRef, ImVec2(r.w, r.h), r.uv0, r.uv1); + - We added a redirecting typedef but haven't attempted to magically redirect the field names, as this API is rarely used and the fix is simple. + - Obsoleted AddCustomRectFontGlyph() as the API does not make sense for scalable fonts. Kept existing function which uses the font "default size" (Sources[0]->LegacySize). Added a helper AddCustomRectFontGlyphForSize() which is immediately marked obsolete, but can facilitate transitioning old code. + - Prefer adding a font source (ImFontConfig) using a custom/procedural loader. + - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). + - Backends: removed ImGui_ImplXXXX_CreateFontsTexture()/ImGui_ImplXXXX_DestroyFontsTexture() for all backends that had them. They should not be necessary any more. - 2025/05/23 (1.92.0) - Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition() - old: const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, ....); - new: const char* ImFont::CalcWordWrapPosition (float size, const char* text, ....); From 895bff6524549ccb3fb1136aa23ad130b68d0a3e Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 19:16:50 +0200 Subject: [PATCH 614/716] Removed unneeded check in RenderText() loop + disable static analyzer false-positive warnings. --- imgui_draw.cpp | 6 +++--- imstb_truetype.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 195f5bece212..2e9a0b6456f5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2874,7 +2874,7 @@ void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data } } } - else if (data->Format == ImTextureFormat_RGBA32) + else if (data->Format == ImTextureFormat_RGBA32) //-V547 { for (int ny = data->Height; ny > 0; ny--, pixels += pitch) { @@ -5631,8 +5631,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im } const ImFontGlyph* glyph = baked->FindGlyph((ImWchar)c); - if (glyph == NULL) - continue; + //if (glyph == NULL) + // continue; float char_width = glyph->AdvanceX * scale; if (glyph->Visible) diff --git a/imstb_truetype.h b/imstb_truetype.h index 976f09cb9278..cf33289f6184 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -4516,8 +4516,8 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex q2[0] = (float)x2; q2[1] = (float)y2; if (equal(q0,q1) || equal(q1,q2)) { - x0 = (int)verts[i-1].x; - y0 = (int)verts[i-1].y; + x0 = (int)verts[i-1].x; //-V1048 + y0 = (int)verts[i-1].y; //-V1048 x1 = (int)verts[i ].x; y1 = (int)verts[i ].y; if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { From 7a42233d43dfab63de340e8b187d24c3c55e2ce7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 11 Jun 2025 20:47:17 +0200 Subject: [PATCH 615/716] imgui_freetype: fixed using legacy names. --- misc/freetype/imgui_freetype.cpp | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 35a277f7c820..ae87f63f9ba2 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -7,7 +7,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025/XX/XX: refactored for the new ImFontLoader architecture, and ImGuiBackendFlags_RendererHasTextures support. +// 2025/06/11: refactored for the new ImFontLoader architecture, and ImGuiBackendFlags_RendererHasTextures support. // 2024/10/17: added plutosvg support for SVG Fonts (seems faster/better than lunasvg). Enable by using '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG'. (#7927) // 2023/11/13: added support for ImFontConfig::RasterizationDensity field for scaling render density without scaling metrics. // 2023/08/01: added support for SVG fonts, enable by using '#define IMGUI_ENABLE_FREETYPE_LUNASVG'. (#6591) @@ -185,26 +185,26 @@ bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfi UserFlags = (ImGuiFreeTypeLoaderFlags)(src->FontLoaderFlags | extra_font_loader_flags); LoadFlags = 0; - if ((UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) == 0) + if ((UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) == 0) LoadFlags |= FT_LOAD_NO_BITMAP; - if (UserFlags & ImGuiFreeTypeBuilderFlags_NoHinting) + if (UserFlags & ImGuiFreeTypeLoaderFlags_NoHinting) LoadFlags |= FT_LOAD_NO_HINTING; else src->PixelSnapH = true; // FIXME: A bit weird to do this this way. - if (UserFlags & ImGuiFreeTypeBuilderFlags_NoAutoHint) + if (UserFlags & ImGuiFreeTypeLoaderFlags_NoAutoHint) LoadFlags |= FT_LOAD_NO_AUTOHINT; - if (UserFlags & ImGuiFreeTypeBuilderFlags_ForceAutoHint) + if (UserFlags & ImGuiFreeTypeLoaderFlags_ForceAutoHint) LoadFlags |= FT_LOAD_FORCE_AUTOHINT; - if (UserFlags & ImGuiFreeTypeBuilderFlags_LightHinting) + if (UserFlags & ImGuiFreeTypeLoaderFlags_LightHinting) LoadFlags |= FT_LOAD_TARGET_LIGHT; - else if (UserFlags & ImGuiFreeTypeBuilderFlags_MonoHinting) + else if (UserFlags & ImGuiFreeTypeLoaderFlags_MonoHinting) LoadFlags |= FT_LOAD_TARGET_MONO; else LoadFlags |= FT_LOAD_TARGET_NORMAL; - if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) + if (UserFlags & ImGuiFreeTypeLoaderFlags_LoadColor) LoadFlags |= FT_LOAD_COLOR; return true; @@ -246,9 +246,9 @@ static const FT_Glyph_Metrics* ImGui_ImplFreeType_LoadGlyph(ImGui_ImplFreeType_F #endif // IMGUI_ENABLE_FREETYPE_LUNASVG // Apply convenience transform (this is not picking from real "Bold"/"Italic" fonts! Merely applying FreeType helper transform. Oblique == Slanting) - if (src_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bold) + if (src_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bold) FT_GlyphSlot_Embolden(slot); - if (src_data->UserFlags & ImGuiFreeTypeBuilderFlags_Oblique) + if (src_data->UserFlags & ImGuiFreeTypeLoaderFlags_Oblique) { FT_GlyphSlot_Oblique(slot); //FT_BBox bbox; @@ -442,7 +442,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF // (FT_Set_Pixel_Sizes() essentially calls FT_Request_Size() with FT_SIZE_REQUEST_TYPE_NOMINAL) const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; FT_Size_RequestRec req; - req.type = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; + req.type = (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) ? FT_SIZE_REQUEST_TYPE_NOMINAL : FT_SIZE_REQUEST_TYPE_REAL_DIM; req.width = 0; req.height = (uint32_t)(size * 64 * rasterizer_density); req.horiResolution = 0; @@ -497,7 +497,7 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src // Render glyph into a bitmap (currently held by FreeType) FT_Face face = bd_font_data->FtFace; FT_GlyphSlot slot = face->glyph; - FT_Render_Mode render_mode = (bd_font_data->UserFlags & ImGuiFreeTypeBuilderFlags_Monochrome) ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL; + FT_Render_Mode render_mode = (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Monochrome) ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL; FT_Error error = FT_Render_Glyph(slot, render_mode); const FT_Bitmap* ft_bitmap = &slot->bitmap; if (error != 0 || ft_bitmap == nullptr) @@ -590,16 +590,16 @@ void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* u bool ImGuiFreeType::DebugEditFontLoaderFlags(unsigned int* p_font_loader_flags) { bool edited = false; - edited |= ImGui::CheckboxFlags("NoHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_NoHinting); - edited |= ImGui::CheckboxFlags("NoAutoHint", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_NoAutoHint); - edited |= ImGui::CheckboxFlags("ForceAutoHint",p_font_loader_flags, ImGuiFreeTypeBuilderFlags_ForceAutoHint); - edited |= ImGui::CheckboxFlags("LightHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_LightHinting); - edited |= ImGui::CheckboxFlags("MonoHinting", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_MonoHinting); - edited |= ImGui::CheckboxFlags("Bold", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Bold); - edited |= ImGui::CheckboxFlags("Oblique", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Oblique); - edited |= ImGui::CheckboxFlags("Monochrome", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Monochrome); - edited |= ImGui::CheckboxFlags("LoadColor", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_LoadColor); - edited |= ImGui::CheckboxFlags("Bitmap", p_font_loader_flags, ImGuiFreeTypeBuilderFlags_Bitmap); + edited |= ImGui::CheckboxFlags("NoHinting", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_NoHinting); + edited |= ImGui::CheckboxFlags("NoAutoHint", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_NoAutoHint); + edited |= ImGui::CheckboxFlags("ForceAutoHint",p_font_loader_flags, ImGuiFreeTypeLoaderFlags_ForceAutoHint); + edited |= ImGui::CheckboxFlags("LightHinting", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_LightHinting); + edited |= ImGui::CheckboxFlags("MonoHinting", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_MonoHinting); + edited |= ImGui::CheckboxFlags("Bold", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_Bold); + edited |= ImGui::CheckboxFlags("Oblique", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_Oblique); + edited |= ImGui::CheckboxFlags("Monochrome", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_Monochrome); + edited |= ImGui::CheckboxFlags("LoadColor", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_LoadColor); + edited |= ImGui::CheckboxFlags("Bitmap", p_font_loader_flags, ImGuiFreeTypeLoaderFlags_Bitmap); return edited; } From a0b3eceec7854be4a32e19ff21397738c06517fe Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 11:02:32 +0200 Subject: [PATCH 616/716] Fixed using IMGUI_DISABLE_DEMO_WINDOWS without IMGUI_DISABLE_DEBUG_TOOLS and without linking with imgui_demo.cpp --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 36 +++++++++++++++++++++++++++++++++++- imgui_demo.cpp | 39 +++------------------------------------ 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8a49b9a04e47..7cda2db6c2f6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -290,6 +290,8 @@ Other changes: to be a valid low-level texture identifier. - Debug Tools: Fonts section: add font preview, add "Remove" button, add "Load all glyphs" button, add selection to change font backend when both are compiled in. +- Special thanks for fonts/texture related feedback to: @thedmd, @ShironekoBen, @rodrigorc, + @pathogendavid, @itamago, @rokups, @DucaRii, @Aarkham, @cyfewlp. - IO: variations in analog-only components of gamepad events do not interfere with trickling of mouse position events (#4921, #8508) diff --git a/imgui.cpp b/imgui.cpp index 74c135ddffba..90f9ecd2de0b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15921,7 +15921,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) if (loader_current == loader_freetype) { unsigned int loader_flags = atlas->FontLoaderFlags; - Text("Shared FreeType Loader Flags: 0x%08", loader_flags); + Text("Shared FreeType Loader Flags: 0x%08X", loader_flags); if (ImGuiFreeType::DebugEditFontLoaderFlags(&loader_flags)) { for (ImFont* font : atlas->Fonts) @@ -17726,6 +17726,40 @@ void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {} #endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS +#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS) +// Demo helper function to select among loaded fonts. +// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one. +void ImGui::ShowFontSelector(const char* label) +{ + ImGuiIO& io = GetIO(); + ImFont* font_current = GetFont(); + if (BeginCombo(label, font_current->GetDebugName())) + { + for (ImFont* font : io.Fonts->Fonts) + { + PushID((void*)font); + if (Selectable(font->GetDebugName(), font == font_current)) + io.FontDefault = font; + if (font == font_current) + SetItemDefaultFocus(); + PopID(); + } + EndCombo(); + } + SameLine(); + if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) + MetricsHelpMarker( + "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n" + "- Read FAQ and docs/FONTS.md for more details."); + else + MetricsHelpMarker( + "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n" + "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" + "- Read FAQ and docs/FONTS.md for more details.\n" + "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); +} +#endif // #if !defined(IMGUI_DISABLE_DEMO_WINDOWS) || !defined(IMGUI_DISABLE_DEBUG_TOOLS) + //----------------------------------------------------------------------------- // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index cd48ee0ff91b..0b7c45aca724 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8171,43 +8171,10 @@ void ImGui::ShowAboutWindow(bool* p_open) //----------------------------------------------------------------------------- // [SECTION] Style Editor / ShowStyleEditor() //----------------------------------------------------------------------------- -// - ShowFontSelector() // - ShowStyleSelector() // - ShowStyleEditor() //----------------------------------------------------------------------------- -// Demo helper function to select among loaded fonts. -// Here we use the regular BeginCombo()/EndCombo() api which is the more flexible one. -void ImGui::ShowFontSelector(const char* label) -{ - ImGuiIO& io = ImGui::GetIO(); - ImFont* font_current = ImGui::GetFont(); - if (ImGui::BeginCombo(label, font_current->GetDebugName())) - { - for (ImFont* font : io.Fonts->Fonts) - { - ImGui::PushID((void*)font); - if (ImGui::Selectable(font->GetDebugName(), font == font_current)) - io.FontDefault = font; - if (font == font_current) - ImGui::SetItemDefaultFocus(); - ImGui::PopID(); - } - ImGui::EndCombo(); - } - ImGui::SameLine(); - if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) - HelpMarker( - "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n" - "- Read FAQ and docs/FONTS.md for more details."); - else - HelpMarker( - "- Load additional fonts with io.Fonts->AddFontXXX() functions.\n" - "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" - "- Read FAQ and docs/FONTS.md for more details.\n" - "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); -} - // Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options. // Here we use the simplified Combo() api that packs items into a single literal string. // Useful for quick combo boxes where the choices are known locally. @@ -10808,9 +10775,9 @@ void ImGui::ShowAboutWindow(bool*) {} void ImGui::ShowDemoWindow(bool*) {} void ImGui::ShowUserGuide() {} void ImGui::ShowStyleEditor(ImGuiStyle*) {} -bool ImGui::ShowStyleSelector(const char* label) { return false; } -void ImGui::ShowFontSelector(const char* label) {} +bool ImGui::ShowStyleSelector(const char*) { return false; } +void ImGui::ShowFontSelector(const char*) {} -#endif +#endif // #ifndef IMGUI_DISABLE_DEMO_WINDOWS #endif // #ifndef IMGUI_DISABLE From f6fc166584783b8a886f102ea8623a24115ca5c4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 11:07:08 +0200 Subject: [PATCH 617/716] TreeNode: fixed runtime asan warning (#2920) imgui_widgets.cpp:6923:52: runtime error: shift exponent -1 is negative --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index cdca228c480f..ba35e531ba39 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6914,7 +6914,7 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - if ((window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1))) == 0) + if (window->DC.TreeDepth == 0 || (window->DC.TreeHasStackDataDepthMask & (1 << (window->DC.TreeDepth - 1))) == 0) return; ImGuiTreeNodeStackData* parent_data = &g.TreeNodeStack.Data[g.TreeNodeStack.Size - 1]; From 1ce75e2bcad6f85efc3a91a795837ed3489ed9dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 11:25:15 +0200 Subject: [PATCH 618/716] Fixed duplicate symbols in some compile-time configurations. --- imgui_demo.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0b7c45aca724..8999320666e7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -10776,7 +10776,6 @@ void ImGui::ShowDemoWindow(bool*) {} void ImGui::ShowUserGuide() {} void ImGui::ShowStyleEditor(ImGuiStyle*) {} bool ImGui::ShowStyleSelector(const char*) { return false; } -void ImGui::ShowFontSelector(const char*) {} #endif // #ifndef IMGUI_DISABLE_DEMO_WINDOWS From 41f4acfb4ff259d97eecdf031b44c4853e54e8fc Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 11:44:11 +0200 Subject: [PATCH 619/716] Fonts: add has_textures parameters to ImFontAtlasUpdateNewFrame(). --- docs/CHANGELOG.txt | 4 ++-- imgui.cpp | 7 +++---- imgui_draw.cpp | 11 ++++++----- imgui_internal.h | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7cda2db6c2f6..20377e2aabf7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -115,8 +115,8 @@ Breaking changes: to 4096 but that limit isn't necessary anymore, and Renderer_TextureMaxWidth covers this) However you may set TexMinWidth = TexMaxWidth for the same effect. - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on - ImGuiContext to create one, you'll need to set the atlas->RendererHasTextures field - and call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. + ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. + An assert will trigger if you don't. - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using PushFontSize(style.FontSizeBase * factor) or to manipulate other scaling factors. - Fonts: obsoleted ImFont::Scale which is not useful anymore. diff --git a/imgui.cpp b/imgui.cpp index 90f9ecd2de0b..f57c305b4899 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -470,7 +470,7 @@ CODE - Fonts: ImFontConfig::OversampleH/OversampleV default to automatic (== 0) since v1.91.8. It is quite important you keep it automatic until we decide if we want to provide a way to express finer policy, otherwise you will likely waste texture space when using large glyphs. Note that the imgui_freetype backend doesn't use and does not need oversampling. - Fonts: specifying glyph ranges is now unnecessary. The value of ImFontConfig::GlyphRanges[] is only useful for legacy backends. All GetGlyphRangesXXXX() functions are now marked obsolete: GetGlyphRangesDefault(), GetGlyphRangesGreek(), GetGlyphRangesKorean(), GetGlyphRangesJapanese(), GetGlyphRangesChineseSimplifiedCommon(), GetGlyphRangesChineseFull(), GetGlyphRangesCyrillic(), GetGlyphRangesThai(), GetGlyphRangesVietnamese(). - Fonts: removed ImFontAtlas::TexDesiredWidth to enforce a texture width. (#327) - - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to set the atlas->RendererHasTextures field and call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. + - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using 'PushFontSize(style.FontSizeBase * factor)' or to manipulate other scaling factors. - Fonts: obsoleted ImFont::Scale which is not useful anymore. - Fonts: generally reworked Internals of ImFontAtlas and ImFont. While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things: @@ -5286,13 +5286,12 @@ static void ImGui::UpdateTexturesNewFrame() { if (atlas->OwnerContext == &g) { - atlas->RendererHasTextures = has_textures; - ImFontAtlasUpdateNewFrame(atlas, g.FrameCount); + ImFontAtlasUpdateNewFrame(atlas, g.FrameCount, has_textures); } else { IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1 && "If you manage font atlases yourself you need to call ImFontAtlasUpdateNewFrame() on it."); - IM_ASSERT(atlas->RendererHasTextures == has_textures && "If you manage font atlases yourself make sure atlas->RendererHasTextures is set consistently with all contexts using it."); + IM_ASSERT(atlas->RendererHasTextures == has_textures && "If you manage font atlases yourself make sure ImGuiBackendFlags_RendererHasTextures is set consistently with atlas->RendererHasTextures as specified in the ImFontAtlasUpdateNewFrame() call."); } } } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 2e9a0b6456f5..cd3d22ef92e0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2716,12 +2716,13 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at } // Called by NewFrame() for atlases owned by a context. -// If you manually manage font atlases, you'll need to call this yourself + ensure atlas->RendererHasTextures is set. -// 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. -// 'frame_count' may not match those of imgui contexts using this atlas, as contexts may be updated as different frequencies. -void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count) +// If you manually manage font atlases, you'll need to call this yourself. +// - 'frame_count' needs to be provided because we can gc/prioritize baked fonts based on their age. +// - 'frame_count' may not match those of all imgui contexts using this atlas, as contexts may be updated as different frequencies. But generally you can use ImGui::GetFrameCount() on one of your context. +void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool renderer_has_textures) { - IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice? + IM_ASSERT(atlas->Builder == NULL || atlas->Builder->FrameCount < frame_count); // Protection against being called twice. + atlas->RendererHasTextures = renderer_has_textures; // Check that font atlas was built or backend support texture reload in which case we can build now if (atlas->RendererHasTextures) diff --git a/imgui_internal.h b/imgui_internal.h index b80bf50b65d3..1d572d5a6151 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3833,7 +3833,7 @@ IMGUI_API ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtl IMGUI_API ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id); IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id); -IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count); +IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool renderer_has_textures); IMGUI_API void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); IMGUI_API void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data); IMGUI_API void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex); From 115a8e74c2478d372d09b6ecc2170818fbced396 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 14:18:23 +0200 Subject: [PATCH 620/716] Fonts: update misc comments, docs. --- .github/ISSUE_TEMPLATE/issue_template.yml | 2 +- docs/FONTS.md | 3 +- imgui.cpp | 35 +++++++++++++++-------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/issue_template.yml b/.github/ISSUE_TEMPLATE/issue_template.yml index 46ed826d520a..6ed62493a43b 100644 --- a/.github/ISSUE_TEMPLATE/issue_template.yml +++ b/.github/ISSUE_TEMPLATE/issue_template.yml @@ -4,7 +4,7 @@ body: - type: markdown attributes: value: | - FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions) + FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions) For anything else: **we are happy to use 'GitHub Issues' for many types of open-ended questions**. We are encouraging 'Issues' becoming a large, centralized, tagged, cross-referenced database of Dear ImGui contents. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users. diff --git a/docs/FONTS.md b/docs/FONTS.md index 7ed8fe026b9f..95538f97d0ae 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -105,6 +105,7 @@ io.Fonts->AddFontDefault(); ``` **Load .TTF/.OTF file with:** + 🆕 **Since 1.92, with an up to date backend: passing a size is not necessary** ```cpp ImGuiIO& io = ImGui::GetIO(); @@ -377,7 +378,7 @@ TL;DR; With the new system, it is recommended that you create a custom `ImFontLo You can ask questions in [#8466](https://github.com/ocornut/imgui/issues/8466). -🆕 **Before 1.92:** +**Before 1.92:** As an alternative to rendering colorful glyphs using imgui_freetype with `ImGuiFreeTypeBuilderFlags_LoadColor`, you may allocate your own space in the texture atlas and write yourself into it. **(This is a BETA api, use if you are familiar with dear imgui and with your rendering backend)** diff --git a/imgui.cpp b/imgui.cpp index f57c305b4899..f7d2e7441237 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -21,9 +21,10 @@ // - Issues & support ........... https://github.com/ocornut/imgui/issues // - Test Engine & Automation ... https://github.com/ocornut/imgui_test_engine (test suite, test engine to automate your apps) -// For first-time users having issues compiling/linking/running/loading fonts: +// For first-time users having issues compiling/linking/running: // please post in https://github.com/ocornut/imgui/discussions if you cannot find a solution in resources above. // Everything else should be asked in 'Issues'! We are building a database of cross-linked knowledge there. +// Since 1.92, we encourage font loading question to also be posted in 'Issues'. // Copyright (c) 2014-2025 Omar Cornut // Developed by Omar Cornut and every direct or indirect contributors to the GitHub. @@ -347,12 +348,12 @@ CODE ImGui::Render(); // Update textures - for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + ImDrawData* draw_data = ImGui::GetDrawData(); + for (ImTextureData* tex : *draw_data->Textures) if (tex->Status != ImTextureStatus_OK) MyImGuiBackend_UpdateTexture(tex); // Render dear imgui contents, swap buffers - ImDrawData* draw_data = ImGui::GetDrawData(); MyImGuiBackend_RenderDrawData(draw_data); SwapBuffers(); } @@ -372,25 +373,32 @@ CODE { if (tex->Status == ImTextureStatus_WantCreate) { - // create texture based on tex->Width/Height/Pixels - // call tex->SetTexID() to specify backend-specific identifiers - // tex->Status = ImTextureStatus_OK; + // Width/Height/Pixels> + tex->SetTexID(xxxx); // specify backend-specific ImTextureID identifier + tex->SetStatus(ImTextureStatus_OK); + tex->BackendUserData = xxxx; // store more backend data } if (tex->Status == ImTextureStatus_WantUpdates) { - // update texture blocks based on tex->UpdateRect - // tex->Status = ImTextureStatus_OK; + // UpdateRect> + tex->SetStatus(ImTextureStatus_OK); } if (tex->Status == ImTextureStatus_WantDestroy) { - // destroy texture - // call tex->SetTexID(ImTextureID_Invalid) - // tex->Status = ImTextureStatus_Destroyed; + // + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); } } void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) { + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + MyImGuiBackend_UpdateTexture(tex); + + // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize @@ -407,7 +415,10 @@ CODE const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) { - pcmd->UserCallback(cmd_list, pcmd); + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + MyEngineResetRenderState(); + else + pcmd->UserCallback(cmd_list, pcmd); } else { From b178fd42862f4314370a32c252c8fbd54eee1127 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 14:55:46 +0200 Subject: [PATCH 621/716] Backends: WebGPU: moved sampler creation out of ImGui_ImplWGPU_CreateFontsTexture(). --- backends/imgui_impl_wgpu.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 3a182ccd2156..d5ac95d502d5 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -597,20 +597,6 @@ static void ImGui_ImplWGPU_CreateFontsTexture() wgpuQueueWriteTexture(bd->defaultQueue, &dst_view, pixels, (uint32_t)(width * size_pp * height), &layout, &size); } - // Create the associated sampler - // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) - { - WGPUSamplerDescriptor sampler_desc = {}; - sampler_desc.minFilter = WGPUFilterMode_Linear; - sampler_desc.magFilter = WGPUFilterMode_Linear; - sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; - sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; - sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; - sampler_desc.maxAnisotropy = 1; - bd->renderResources.Sampler = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); - } - // Store our identifier static_assert(sizeof(ImTextureID) >= sizeof(bd->renderResources.FontTexture), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); io.Fonts->SetTexID((ImTextureID)bd->renderResources.FontTextureView); @@ -760,13 +746,24 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() ImGui_ImplWGPU_CreateFontsTexture(); ImGui_ImplWGPU_CreateUniformBuffer(); + // Create sampler + // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) + WGPUSamplerDescriptor sampler_desc = {}; + sampler_desc.minFilter = WGPUFilterMode_Linear; + sampler_desc.magFilter = WGPUFilterMode_Linear; + sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; + sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge; + sampler_desc.maxAnisotropy = 1; + bd->renderResources.Sampler = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc); + // Create resource bind group WGPUBindGroupEntry common_bg_entries[] = { { nullptr, 0, bd->renderResources.Uniforms, 0, MEMALIGN(sizeof(Uniforms), 16), 0, 0 }, { nullptr, 1, 0, 0, 0, bd->renderResources.Sampler, 0 }, }; - WGPUBindGroupDescriptor common_bg_descriptor = {}; common_bg_descriptor.layout = bg_layouts[0]; common_bg_descriptor.entryCount = sizeof(common_bg_entries) / sizeof(WGPUBindGroupEntry); From 571dae9664ee842d88b3139476f1cb85fdc7b48a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 15:12:07 +0200 Subject: [PATCH 622/716] Backends: WGPU: added ImGuiBackendFlags_RendererHasTextures support. (#8465) --- backends/imgui_impl_wgpu.cpp | 132 +++++++++++++++++++++-------------- backends/imgui_impl_wgpu.h | 6 +- docs/CHANGELOG.txt | 2 +- 3 files changed, 86 insertions(+), 54 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index d5ac95d502d5..09bd30ca8499 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -6,8 +6,7 @@ // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// Missing features or Issues: -// [ ] Renderer: Missing texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -19,6 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. (#8465) // 2025-02-26: Recreate image bind groups during render. (#8426, #8046, #7765, #8027) + Update for latest webgpu-native changes. // 2024-10-14: Update Dawn support for change of string usages. (#8082, #8083) // 2024-10-07: Expose selected render state in ImGui_ImplWGPU_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -73,11 +73,15 @@ extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed); #define MEMALIGN(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align (copied from IM_ALIGN() macro). // WebGPU data +struct ImGui_ImplWGPU_Texture +{ + WGPUTexture Texture = nullptr; + WGPUTextureView TextureView = nullptr; +}; + struct RenderResources { - WGPUTexture FontTexture = nullptr; // Font texture - WGPUTextureView FontTextureView = nullptr; // Texture view for font texture - WGPUSampler Sampler = nullptr; // Sampler for the font texture + WGPUSampler Sampler = nullptr; // Sampler for textures WGPUBuffer Uniforms = nullptr; // Shader uniforms WGPUBindGroup CommonBindGroup = nullptr; // Resources bind-group to bind the common resources to pipeline ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map) @@ -234,23 +238,8 @@ static void SafeRelease(WGPUShaderModule& res) wgpuShaderModuleRelease(res); res = nullptr; } -static void SafeRelease(WGPUTextureView& res) -{ - if (res) - wgpuTextureViewRelease(res); - res = nullptr; -} -static void SafeRelease(WGPUTexture& res) -{ - if (res) - wgpuTextureRelease(res); - res = nullptr; -} - static void SafeRelease(RenderResources& res) { - SafeRelease(res.FontTexture); - SafeRelease(res.FontTextureView); SafeRelease(res.Sampler); SafeRelease(res.Uniforms); SafeRelease(res.CommonBindGroup); @@ -381,6 +370,13 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) return; + // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates). + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + ImGui_ImplWGPU_UpdateTexture(tex); + // FIXME: Assuming that this only gets called once per frame! // If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator. ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); @@ -536,33 +532,52 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder platform_io.Renderer_RenderState = nullptr; } -static void ImGui_ImplWGPU_CreateFontsTexture() +static void ImGui_ImplWGPU_DestroyTexture(ImTextureData* tex) { - // Build texture atlas - ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels; - int width, height, size_pp; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &size_pp); + ImGui_ImplWGPU_Texture* backend_tex = (ImGui_ImplWGPU_Texture*)tex->BackendUserData; + if (backend_tex == nullptr) + return; - // Upload texture to graphics system + IM_ASSERT(backend_tex->TextureView == (WGPUTextureView)(intptr_t)tex->TexID); + wgpuTextureViewRelease(backend_tex->TextureView); + wgpuTextureRelease(backend_tex->Texture); + IM_DELETE(backend_tex); + + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + tex->BackendUserData = nullptr; +} + +void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex) +{ + ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); + if (tex->Status == ImTextureStatus_WantCreate) { + // Create and upload new texture to graphics system + //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height); + IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr); + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + ImGui_ImplWGPU_Texture* backend_tex = IM_NEW(ImGui_ImplWGPU_Texture)(); + + // Create texture WGPUTextureDescriptor tex_desc = {}; #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) - tex_desc.label = { "Dear ImGui Font Texture", WGPU_STRLEN }; + tex_desc.label = { "Dear ImGui Texture", WGPU_STRLEN }; #else - tex_desc.label = "Dear ImGui Font Texture"; + tex_desc.label = "Dear ImGui Texture"; #endif tex_desc.dimension = WGPUTextureDimension_2D; - tex_desc.size.width = width; - tex_desc.size.height = height; + tex_desc.size.width = tex->Width; + tex_desc.size.height = tex->Height; tex_desc.size.depthOrArrayLayers = 1; tex_desc.sampleCount = 1; tex_desc.format = WGPUTextureFormat_RGBA8Unorm; tex_desc.mipLevelCount = 1; tex_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding; - bd->renderResources.FontTexture = wgpuDeviceCreateTexture(bd->wgpuDevice, &tex_desc); + backend_tex->Texture = wgpuDeviceCreateTexture(bd->wgpuDevice, &tex_desc); + // Create texture view WGPUTextureViewDescriptor tex_view_desc = {}; tex_view_desc.format = WGPUTextureFormat_RGBA8Unorm; tex_view_desc.dimension = WGPUTextureViewDimension_2D; @@ -571,19 +586,35 @@ static void ImGui_ImplWGPU_CreateFontsTexture() tex_view_desc.baseArrayLayer = 0; tex_view_desc.arrayLayerCount = 1; tex_view_desc.aspect = WGPUTextureAspect_All; - bd->renderResources.FontTextureView = wgpuTextureCreateView(bd->renderResources.FontTexture, &tex_view_desc); + backend_tex->TextureView = wgpuTextureCreateView(backend_tex->Texture, &tex_view_desc); + + // Store identifiers + tex->SetTexID((ImTextureID)(intptr_t)backend_tex->TextureView); + tex->BackendUserData = backend_tex; + // We don't set tex->Status to ImTextureStatus_OK to let the code fallthrough below. } - // Upload texture data + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) { + ImGui_ImplWGPU_Texture* backend_tex = (ImGui_ImplWGPU_Texture*)tex->BackendUserData; + IM_ASSERT(tex->Format == ImTextureFormat_RGBA32); + + // We could use the smaller rect on _WantCreate but using the full rect allows us to clear the texture. + const int upload_x = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.x; + const int upload_y = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.y; + const int upload_w = (tex->Status == ImTextureStatus_WantCreate) ? tex->Width : tex->UpdateRect.w; + const int upload_h = (tex->Status == ImTextureStatus_WantCreate) ? tex->Height : tex->UpdateRect.h; + + // Update full texture or selected blocks. We only ever write to textures regions which have never been used before! + // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions. #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUTexelCopyTextureInfo dst_view = {}; #else WGPUImageCopyTexture dst_view = {}; #endif - dst_view.texture = bd->renderResources.FontTexture; + dst_view.texture = backend_tex->Texture; dst_view.mipLevel = 0; - dst_view.origin = { 0, 0, 0 }; + dst_view.origin = { (uint32_t)upload_x, (uint32_t)upload_y, 0 }; dst_view.aspect = WGPUTextureAspect_All; #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) WGPUTexelCopyBufferLayout layout = {}; @@ -591,15 +622,14 @@ static void ImGui_ImplWGPU_CreateFontsTexture() WGPUTextureDataLayout layout = {}; #endif layout.offset = 0; - layout.bytesPerRow = width * size_pp; - layout.rowsPerImage = height; - WGPUExtent3D size = { (uint32_t)width, (uint32_t)height, 1 }; - wgpuQueueWriteTexture(bd->defaultQueue, &dst_view, pixels, (uint32_t)(width * size_pp * height), &layout, &size); + layout.bytesPerRow = tex->Width * tex->BytesPerPixel; + layout.rowsPerImage = upload_h; + WGPUExtent3D write_size = { (uint32_t)upload_w, (uint32_t)upload_h, 1 }; + wgpuQueueWriteTexture(bd->defaultQueue, &dst_view, tex->GetPixelsAt(upload_x, upload_y), (uint32_t)(tex->Width * upload_h * tex->BytesPerPixel), &layout, &write_size); + tex->SetStatus(ImTextureStatus_OK); } - - // Store our identifier - static_assert(sizeof(ImTextureID) >= sizeof(bd->renderResources.FontTexture), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); - io.Fonts->SetTexID((ImTextureID)bd->renderResources.FontTextureView); + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + ImGui_ImplWGPU_DestroyTexture(tex); } static void ImGui_ImplWGPU_CreateUniformBuffer() @@ -743,7 +773,6 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() bd->pipelineState = wgpuDeviceCreateRenderPipeline(bd->wgpuDevice, &graphics_pipeline_desc); - ImGui_ImplWGPU_CreateFontsTexture(); ImGui_ImplWGPU_CreateUniformBuffer(); // Create sampler @@ -788,8 +817,10 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects() SafeRelease(bd->pipelineState); SafeRelease(bd->renderResources); - ImGuiIO& io = ImGui::GetIO(); - io.Fonts->SetTexID(0); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + // Destroy all textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->RefCount == 1) + ImGui_ImplWGPU_DestroyTexture(tex); for (unsigned int i = 0; i < bd->numFramesInFlight; i++) SafeRelease(bd->pFrameResources[i]); @@ -814,6 +845,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) io.BackendRendererName = "imgui_impl_webgpu"; #endif io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render. bd->initInfo = *init_info; bd->wgpuDevice = init_info->Device; @@ -823,8 +855,6 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) bd->numFramesInFlight = init_info->NumFramesInFlight; bd->frameIndex = UINT_MAX; - bd->renderResources.FontTexture = nullptr; - bd->renderResources.FontTextureView = nullptr; bd->renderResources.Sampler = nullptr; bd->renderResources.Uniforms = nullptr; bd->renderResources.CommonBindGroup = nullptr; @@ -863,7 +893,7 @@ void ImGui_ImplWGPU_Shutdown() io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; + io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); IM_DELETE(bd); } diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 1da208f0090b..61d2d23c0157 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -13,8 +13,7 @@ // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef! // [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset). // [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'. -// Missing features or Issues: -// [ ] Renderer: Missing texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures). +// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures). // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -57,6 +56,9 @@ IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURen IMGUI_IMPL_API bool ImGui_ImplWGPU_CreateDeviceObjects(); IMGUI_IMPL_API void ImGui_ImplWGPU_InvalidateDeviceObjects(); +// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually. +IMGUI_IMPL_API void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex); + // [BETA] Selected render state data shared with callbacks. // This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplWGPU_RenderDrawData() call. // (Please open an issue if you feel you need access to more data) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 20377e2aabf7..9a24bd72f9b5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -363,7 +363,7 @@ Other changes: - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). - Backends: - - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, Allegro5: + - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: - Added ImGuiBackendFlags_RendererHasTextures support. (#8465, #3761, #3471) [@ocornut, @ShironekoBen, @thedmd] - Added ImGui_ImplXXXX_UpdateTexture(ImTextureData* tex) functions for all backend. From b7f13df130354c1cb7eba3d83aa697b8f489fa32 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 15:42:51 +0200 Subject: [PATCH 623/716] Docs: reformat Changelog. --- docs/CHANGELOG.txt | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9a24bd72f9b5..1cb16ad61f6d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -362,7 +362,7 @@ Other changes: requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). -- Backends: +- Renderer Backends: - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: - Added ImGuiBackendFlags_RendererHasTextures support. (#8465, #3761, #3471) [@ocornut, @ShironekoBen, @thedmd] @@ -370,24 +370,6 @@ Other changes: Available if you want to start uploading textures right after ImGui::Render() and without waiting for the call to ImGui_ImplXXXX_RenderDrawData(). Also useful if you use a staged or multi-threaded rendering schemes, where you might want to set ImDrawData::Textures = NULL. (#8597, #1860) - - Backends: GLFW: added ImGui_ImplGlfw_GetContentScaleForMonitor(), ImGui_ImplGlfw_GetContentScaleForWindow() - helpers. They are wrappers to glfwGetMonitorContentScale()/glfwGetWindowContentScale(), with compile-time - GLFW version checks + returning 1.0f on Apple platform. - - Backends: SDL2: added ImGui_ImplSDL2_GetDpiScaleForDisplay() and ImGui_ImplSDL2_GetContentScaleForWindow() - helpers. They are wrappers to SDL_GetDisplayDPI(), with compile-time SDL version checks + returning 1.0f - on Apple platforms. SDL3 already does this by default. - - Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) - would fail to claim it again the next subsequent click. (#8594) - - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad - regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) - - Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't - call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use - the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] - - Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. - - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() - memory ownership change. (#8530, #7801) [@Green-Sky] - - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative - way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) - Backends: SDLGPU3: Fixed creating atlas texture earlier than other backends, preventing to load fonts between the Init and NewFrames calls. - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which @@ -406,6 +388,25 @@ Other changes: - Backends: Vulkan: fixed validation errors in window create/resize helpers used by examples and by multi-viewports implementation, which would typically trigger errors while detaching secondary viewports. (#8600, #8176) [@ChrisTom-94] +- Platform Backends: + - Backends: GLFW: added ImGui_ImplGlfw_GetContentScaleForMonitor(), ImGui_ImplGlfw_GetContentScaleForWindow() + helpers. They are wrappers to glfwGetMonitorContentScale()/glfwGetWindowContentScale(), with compile-time + GLFW version checks + returning 1.0f on Apple platform. + - Backends: SDL2: added ImGui_ImplSDL2_GetDpiScaleForDisplay() and ImGui_ImplSDL2_GetContentScaleForWindow() + helpers. They are wrappers to SDL_GetDisplayDPI(), with compile-time SDL version checks + returning 1.0f + on Apple platforms. SDL3 already does this by default. + - Backends: Win32: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) + would fail to claim it again the next subsequent click. (#8594) + - Backends: SDL2, SDL3, OSX: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad + regardless of ImGuiConfigFlags_NavEnableGamepad being set. (#8508) + - Backends: SDL2, SDL3: don't attempt to call SDL_CaptureMouse() on drivers where we don't + call SDL_GetGlobalMouseState(). This is specifically for Wayland but we currently use + the same white-list as SDL_GetGlobalMouseState(). (#8561) [@vs49688] + - Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. + - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() + memory ownership change. (#8530, #7801) [@Green-Sky] + - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative + way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) - Examples: - Examples: Made many examples DPI aware by default. The single-viewport is basically: From 7ac99a43662b9dd011610fca500665279af1fbe3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 15:43:12 +0200 Subject: [PATCH 624/716] Backends: OSX: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644) --- backends/imgui_impl_osx.mm | 4 ++++ docs/CHANGELOG.txt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 32e562472dd5..27567fb196fa 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -31,6 +31,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-01-20: Removed notification observer when shutting down. (#8331) // 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO: @@ -663,6 +664,9 @@ static ImGuiMouseSource GetMouseSource(NSEvent* event) static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view) { + // Only process events from the window containing ImGui view + if (event.window != view.window) + return false; ImGuiIO& io = ImGui::GetIO(); if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1cb16ad61f6d..4d73a2aa2776 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -407,6 +407,8 @@ Other changes: memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) + - Backends: OSX: ImGui_ImplOSX_HandleEvent() only process event for window containing + our view. (#8644) [@BingoXuan] - Examples: - Examples: Made many examples DPI aware by default. The single-viewport is basically: From 1ec1510ef7ac64cae4a1876fe25736d05bda02ba Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 12 Jun 2025 16:35:51 +0200 Subject: [PATCH 625/716] Fonts: clarify assert. (#8680) --- docs/CHANGELOG.txt | 5 ++++- imgui.cpp | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4d73a2aa2776..87dfe567205e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -41,11 +41,14 @@ HOW TO UPDATE? THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, -BUT INEVITABLY SOME USERS WILL BE AFFECTED. +BUT INEVITABLY SOME USERS OR THIRD-PARTY EXTENSIONS WILL BE AFFECTED. IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: https://github.com/ocornut/imgui/issues/ +If you are using custom widgets, internals or third-party extension that are somehow +breaking and aren't obvious how to solve, please post in Issues so we can gather +data and share solutions that may help others. As part of the plan to reduce impact of API breaking changes, several unfinished changes/features/refactors related to font and text systems and scaling will be diff --git a/imgui.cpp b/imgui.cpp index f7d2e7441237..67e29e228ee4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5301,8 +5301,12 @@ static void ImGui::UpdateTexturesNewFrame() } else { - IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1 && "If you manage font atlases yourself you need to call ImFontAtlasUpdateNewFrame() on it."); - IM_ASSERT(atlas->RendererHasTextures == has_textures && "If you manage font atlases yourself make sure ImGuiBackendFlags_RendererHasTextures is set consistently with atlas->RendererHasTextures as specified in the ImFontAtlasUpdateNewFrame() call."); + // (1) If you manage font atlases yourself, e.g. create a ImFontAtlas yourself you need to call ImFontAtlasUpdateNewFrame() on it. + // Otherwise, calling ImGui::CreateContext() without parameter will create an atlas owned by the context. + // (2) If you have multiple font atlases, make sure the 'atlas->RendererHasTextures' as specified in the ImFontAtlasUpdateNewFrame() call matches for that. + // (3) If you have multiple imgui contexts, they also need to have a matching value for ImGuiBackendFlags_RendererHasTextures. + IM_ASSERT(atlas->Builder != NULL && atlas->Builder->FrameCount != -1); + IM_ASSERT(atlas->RendererHasTextures == has_textures); } } } @@ -16967,7 +16971,7 @@ void ImGui::DebugNodeFont(ImFont* font) if (baked->ContainerFont != font) continue; PushID(baked_n); - if (TreeNode("Glyphs", "Baked at { %.2fpx, d.%.1f }: %d glyphs%s", baked->Size, baked->RasterizerDensity, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) + if (TreeNode("Glyphs", "Baked at { %.2fpx, d.%.2f }: %d glyphs%s", baked->Size, baked->RasterizerDensity, baked->Glyphs.Size, (baked->LastUsedFrame < atlas->Builder->FrameCount - 1) ? " *Unused*" : "")) { if (SmallButton("Load all")) for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base++) From ca3169310ea3e2e8c4a140fd7eaa872edcc2245e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Jun 2025 16:43:58 +0200 Subject: [PATCH 626/716] Fonts: fixed FontBaked=NULL in initial call to SetCurrentWindow() in Begin() using previous frame value of SkipItems. (#8465) ref 0e769c5 --- imgui.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 67e29e228ee4..3618384fbd4c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4475,12 +4475,15 @@ static void SetCurrentWindow(ImGuiWindow* window) g.CurrentDpiScale = 1.0f; // FIXME-DPI: WIP this is modified in docking if (window) { + bool backup_skip_items = window->SkipItems; + window->SkipItems = false; if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) { ImGuiViewport* viewport = window->Viewport; g.FontRasterizerDensity = (viewport->FramebufferScale.x != 0.0f) ? viewport->FramebufferScale.x : g.IO.DisplayFramebufferScale.x; // == SetFontRasterizerDensity() } ImGui::UpdateCurrentFontSize(0.0f); + window->SkipItems = backup_skip_items; ImGui::NavUpdateCurrentWindowIsScrollPushableX(); } } @@ -8695,6 +8698,21 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // Most of the relevant font logic is in imgui_draw.cpp. // Those are high-level support functions. //----------------------------------------------------------------------------- +// - UpdateFontsNewFrame() [Internal] +// - UpdateFontsEndFrame() [Internal] +// - GetDefaultFont() [Internal] +// - RegisterUserTexture() [Internal] +// - UnregisterUserTexture() [Internal] +// - RegisterFontAtlas() [Internal] +// - UnregisterFontAtlas() [Internal] +// - SetCurrentFont() [Internal] +// - UpdateCurrentFontSize() [Internal] +// - SetFontRasterizerDensity() [Internal] +// - PushFont() +// - PopFont() +// - PushFontSize() +// - PopFontSize() +//----------------------------------------------------------------------------- void ImGui::UpdateFontsNewFrame() { From d8da97f756d8e69ed3ebd858c109edf608cebccc Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Jun 2025 16:47:23 +0200 Subject: [PATCH 627/716] Fonts: UpdateCurrentFontSize() early out doesn't need to clear FontBaked. This was meant when the code would be lower in the function (after updating e.g. g.FontSize) Amend 0e769c5. --- imgui.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3618384fbd4c..2bd7cebc5fe7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8825,12 +8825,10 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) // Early out to avoid hidden window keeping bakes referenced and out of GC reach. // However this would leave a pretty subtle and damning error surface area if g.FontBaked was mismatching, so for now we null it. + // FIXME: perhaps g.FontSize should be updated? if (window != NULL && window->SkipItems) if (g.CurrentTable == NULL || g.CurrentTable->CurrentColumn != -1) // See 8465#issuecomment-2951509561. Ideally the SkipItems=true in tables would be amended with extra data. - { - g.FontBaked = NULL; return; - } // Restoring is pretty much only used by PopFont()/PopFontSize() float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; From cfa43e721aa1300b17d633f7590516587ff23617 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 13 Jun 2025 17:40:17 +0200 Subject: [PATCH 628/716] Windows: clicking on a window close button doesn't claim focus and bring to front. (#8683) Added ImGuiItemFlags_NoFocus, ImGuiButtonFlags_NoFocus. Neither are well specified so marking as experimental. --- docs/CHANGELOG.txt | 1 + imgui.cpp | 4 ++++ imgui_internal.h | 2 ++ imgui_widgets.cpp | 6 ++++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 87dfe567205e..c23a2b7e22b2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -302,6 +302,7 @@ Other changes: codepath that preserve last contents size when collapsed, resulting in programmatically uncollapsing auto-sizing windows having them flicker size for a frame. (#7691) [@achabense] +- Windows: clicking on a window close button doesn't claim focus and bring to front. (#8683) - Windows: loosened code to allow hovering of resize grips, borders, and table borders while hovering a sibling child window, so that the code in master matches one in docking (they accidentally diverged). (#8554) diff --git a/imgui.cpp b/imgui.cpp index 2bd7cebc5fe7..9ed61ba5d660 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7126,8 +7126,12 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl // Close button if (has_close_button) + { + g.CurrentItemFlags |= ImGuiItemFlags_NoFocus; if (CloseButton(window->GetID("#CLOSE"), close_button_pos)) *p_open = false; + g.CurrentItemFlags &= ~ImGuiItemFlags_NoFocus; + } window->DC.NavLayerCurrent = ImGuiNavLayer_Main; g.CurrentItemFlags = item_flags_backup; diff --git a/imgui_internal.h b/imgui_internal.h index 1d572d5a6151..fe71e49b0c43 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -946,6 +946,7 @@ enum ImGuiItemFlagsPrivate_ ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. ImGuiItemFlags_NoNavDisableMouseHover = 1 << 15, // false // Nav keyboard/gamepad mode doesn't disable hover highlight (behave as if NavHighlightItemUnderNav==false). ImGuiItemFlags_NoMarkEdited = 1 << 16, // false // Skip calling MarkItemEdited() + ImGuiItemFlags_NoFocus = 1 << 17, // false // [EXPERIMENTAL: Not very well specced] Clicking doesn't take focus. Automatically sets ImGuiButtonFlags_NoFocus + ImGuiButtonFlags_NoNavFocus in ButtonBehavior(). // Controlled by widget code ImGuiItemFlags_Inputable = 1 << 20, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. @@ -1023,6 +1024,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_NoHoveredOnFocus = 1 << 19, // don't report as hovered when nav focus is on this item ImGuiButtonFlags_NoSetKeyOwner = 1 << 20, // don't set key/input owner on the initial click (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) ImGuiButtonFlags_NoTestKeyOwner = 1 << 21, // don't test key/input owner when polling the key (note: mouse buttons are keys! often, the key in question will be ImGuiKey_MouseLeft!) + ImGuiButtonFlags_NoFocus = 1 << 22, // [EXPERIMENTAL: Not very well specced]. Don't focus parent window when clicking. ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease, }; diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ba35e531ba39..2e80564eae44 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -548,6 +548,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.ItemFlags : g.CurrentItemFlags); if (flags & ImGuiButtonFlags_AllowOverlap) item_flags |= ImGuiItemFlags_AllowOverlap; + if (item_flags & ImGuiItemFlags_NoFocus) + flags |= ImGuiButtonFlags_NoFocus | ImGuiButtonFlags_NoNavFocus; // Default only reacts to left mouse button if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0) @@ -623,7 +625,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetFocusID(id, window); FocusWindow(window); } - else + else if (!(flags & ImGuiButtonFlags_NoFocus)) { FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child } @@ -641,7 +643,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool SetFocusID(id, window); FocusWindow(window); } - else + else if (!(flags & ImGuiButtonFlags_NoFocus)) { FocusWindow(window, ImGuiFocusRequestFlags_RestoreFocusedChild); // Still need to focus and bring to front, but try to avoid losing NavId when navigating a child } From 6b3cbb10a2e73b2ce93b1f402667c7b50ddd4a60 Mon Sep 17 00:00:00 2001 From: Shawn Hatori <5499686+shawnhatori@users.noreply.github.com> Date: Mon, 16 Jun 2025 05:59:26 -0400 Subject: [PATCH 629/716] Backends: Vulkan: correct minimum pool size assertion (#8691) --- backends/imgui_impl_vulkan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 74c7d791b9f4..3e2c043dedbc 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1043,7 +1043,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() if (v->DescriptorPoolSize != 0) { - IM_ASSERT(v->DescriptorPoolSize > IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE); + IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE); VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize }; VkDescriptorPoolCreateInfo pool_info = {}; pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; From 842837e35b421a4c85ca30f6840321f0a3c5a029 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Mon, 16 Jun 2025 18:36:33 +0200 Subject: [PATCH 630/716] imgui_freetype: fix conversion null -> bool in FontBakedLoadGlyph (#8696) --- misc/freetype/imgui_freetype.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index ae87f63f9ba2..d7d50db392bf 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -501,7 +501,7 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src FT_Error error = FT_Render_Glyph(slot, render_mode); const FT_Bitmap* ft_bitmap = &slot->bitmap; if (error != 0 || ft_bitmap == nullptr) - return NULL; + return false; const int w = (int)ft_bitmap->width; const int h = (int)ft_bitmap->rows; @@ -520,7 +520,7 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src { // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?) IM_ASSERT(pack_id != ImFontAtlasRectId_Invalid && "Out of texture memory."); - return NULL; + return false; } ImTextureRect* r = ImFontAtlasPackGetRect(atlas, pack_id); From 24f7328e5f7939c0fa9d9dd8c6cf9fd06c38540a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 11:55:40 +0200 Subject: [PATCH 631/716] DrawList, Fonts: fixed ImFontAtlasTextureRepack() overwriting draw list shared data UV's etc. even when not bound. (#8694, #8465) ImFontAtlasUpdateDrawListsSharedData() call from ImFontAtlasTextureRepack() would trigger this. For simplicity we also track current atlas in ImDrawListSharedData, but we could probably use Font->ContainerAtlas. --- imgui.cpp | 10 ++++++---- imgui_draw.cpp | 18 ++++++++++-------- imgui_internal.h | 7 ++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9ed61ba5d660..4ace6433dad6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3932,7 +3932,7 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso ImGuiContext& g = *GImGui; if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values. mouse_cursor = ImGuiMouseCursor_Arrow; - ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; + ImFontAtlas* font_atlas = g.DrawListSharedData.FontAtlas; for (ImGuiViewportP* viewport : g.Viewports) { // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. @@ -8813,10 +8813,12 @@ void ImGui::SetCurrentFont(ImFont* font, float font_size_before_scaling, float f #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS IM_ASSERT(font->Scale > 0.0f); #endif - g.DrawListSharedData.Font = g.Font; - ImFontAtlasUpdateDrawListsSharedData(g.Font->ContainerAtlas); + ImFontAtlas* atlas = font->ContainerAtlas; + g.DrawListSharedData.FontAtlas = atlas; + g.DrawListSharedData.Font = font; + ImFontAtlasUpdateDrawListsSharedData(atlas); if (g.CurrentWindow != NULL) - g.CurrentWindow->DrawList->_SetTexture(font->ContainerAtlas->TexRef); + g.CurrentWindow->DrawList->_SetTexture(atlas->TexRef); } } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index cd3d22ef92e0..3621deb466f3 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2694,10 +2694,11 @@ void ImFontAtlas::ClearFonts() Fonts.clear_delete(); TexIsBuilt = false; for (ImDrawListSharedData* shared_data : DrawListSharedDatas) - { - shared_data->Font = NULL; - shared_data->FontScale = shared_data->FontSize = 0.0f; - } + if (shared_data->FontAtlas == this) + { + shared_data->Font = NULL; + shared_data->FontScale = shared_data->FontSize = 0.0f; + } } static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* atlas) @@ -3914,10 +3915,11 @@ void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) { for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas) - { - shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; - shared_data->TexUvLines = atlas->TexUvLines; - } + if (shared_data->FontAtlas == atlas) + { + shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; + shared_data->TexUvLines = atlas->TexUvLines; + } } // Set current texture. This is mostly called from AddTexture() + to handle a failed resize. diff --git a/imgui_internal.h b/imgui_internal.h index fe71e49b0c43..b3a950c7ad9a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -838,9 +838,10 @@ struct IMGUI_API ImDrawListSharedData { ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel) const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas (== FontAtlas->TexUvLines) - ImFont* Font; // Current/default font (optional, for simplified AddText overload) - float FontSize; // Current/default font size (optional, for simplified AddText overload) - float FontScale; // Current/default font scale (== FontSize / Font->FontSize) + ImFontAtlas* FontAtlas; // Current font atlas + ImFont* Font; // Current font (used for simplified AddText overload) + float FontSize; // Current font size (used for for simplified AddText overload) + float FontScale; // Current font scale (== FontSize / Font->FontSize) float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo() float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc float InitialFringeScale; // Initial scale to apply to AA fringe From fe048efeab2fe21f397579f49ea1011be6d2be4a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 11:56:43 +0200 Subject: [PATCH 632/716] DrawList, Fonts: fixed PushFont()/AddImage() not restoring correct atlas texture id when using multiple atlas (#8694) This also needs 24f7328. --- docs/CHANGELOG.txt | 3 +++ imgui_draw.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c23a2b7e22b2..c895a0532f7a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -161,6 +161,9 @@ Breaking changes: - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader() - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader(); +- DrawList: Fixed a regression from 1.91.1 where a Begin()/PushFont()/AddImage() sequence + would not restore the correct atlas Texture Identifier when the PushFont() call used + a font from a different atlas. (#8694, caused by #3224, #3875, #6398, #7903) - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). - Fonts: (users of custom rectangles) - Renamed AddCustomRectRegular() to AddCustomRect(). (#8466) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3621deb466f3..6ac94649176b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -695,6 +695,7 @@ void ImDrawList::_SetTexture(ImTextureRef tex_ref) if (_CmdHeader.TexRef == tex_ref) return; _CmdHeader.TexRef = tex_ref; + _TextureStack.back() = tex_ref; _OnChangedTexture(); } From f2e4e8039154515b43b89b6e236504b140850c5e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 14:01:01 +0200 Subject: [PATCH 633/716] Windows: BeginChild(): fixed being unable to combine manual resize on one axis and automatic resize on the other axis. (#8690) + removed obsolete TODO entries. --- docs/CHANGELOG.txt | 4 ++++ docs/TODO.txt | 3 --- imgui.cpp | 8 +++++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c895a0532f7a..dd9daeba15fe 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -309,6 +309,10 @@ Other changes: - Windows: loosened code to allow hovering of resize grips, borders, and table borders while hovering a sibling child window, so that the code in master matches one in docking (they accidentally diverged). (#8554) +- Windows: BeginChild(): fixed being unable to combine manual resize on one axis + and automatic resize on the other axis. (#8690) + e.g. neither ImGuiChildFlags_ResizeX | ImGuiChildFlags_AutoResizeY + or ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX worked before. - TreeNode: added experimental flags to draw tree hierarchy outlines linking parent and tree nodes: (#2920) - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn (default value in style.TreeLinesFlags). diff --git a/docs/TODO.txt b/docs/TODO.txt index aeef17592575..8866d04fbef9 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -26,9 +26,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - window/size: manually triggered auto-fit (double-click on grip) shouldn't resize window down to viewport size? - window/size: how to allow to e.g. auto-size vertically to fit contents, but be horizontally resizable? Assuming SetNextWindowSize() is modified to treat -1.0f on each axis as "keep as-is" (would be good but might break erroneous code): Problem is UpdateWindowManualResize() and lots of code treat (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) together. - window/opt: freeze window flag: if not focused/hovered, return false, render with previous ImDrawList. and/or reduce refresh rate. -> this may require enforcing that it is illegal to submit contents if Begin returns false. - - window/child: background options for child windows, border option (disable rounding). - - window/child: allow resizing of child windows (possibly given min/max for each axis?.) - - window/child: allow SetNextWindowContentSize() to work on child windows. - window/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero. - window/tabbing: add a way to signify that a window or docked window requires attention (e.g. blinking title bar, trying to click behind a modal). - window/id_stack: add e.g. window->GetIDFromPath() with support for leading / and ../ (#1390, #331) -> model from test engine. diff --git a/imgui.cpp b/imgui.cpp index 4ace6433dad6..af22c37fada2 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6612,9 +6612,9 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont // FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars, // we may need to compute/store three variants of size_auto_fit, for x/y/xy. // Here we implement a workaround for child windows only, but a full solution would apply to normal windows as well: - if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && !(window->ChildFlags & ImGuiChildFlags_ResizeY)) + if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && !(window->ChildFlags & (ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeY))) size_auto_fit.y = window->SizeFull.y; - else if (!(window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->ChildFlags & ImGuiChildFlags_ResizeY)) + else if ((window->ChildFlags & ImGuiChildFlags_ResizeY) && !(window->ChildFlags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_AutoResizeX))) size_auto_fit.x = window->SizeFull.x; // When the window cannot fit all contents (either because of constraints, either because screen is too small), @@ -6734,7 +6734,9 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ImGuiContext& g = *GImGui; ImGuiWindowFlags flags = window->Flags; - if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + if ((flags & ImGuiWindowFlags_NoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) + return false; + if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && (window->ChildFlags & (ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY)) == 0) return false; if (window->WasActive == false) // Early out to avoid running this code for e.g. a hidden implicit/fallback Debug window. return false; From 39a90ac4d63867bb9bbd3ee4012b0981c4329eaf Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 14:52:34 +0200 Subject: [PATCH 634/716] Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) [@radjkarl] --- docs/CHANGELOG.txt | 1 + imgui.h | 48 +++++++++++++++++++++++----------------------- imgui_internal.h | 4 ++-- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dd9daeba15fe..245462463e1c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -372,6 +372,7 @@ Other changes: of WantVisible. This is set in the same structure because activating text input generally requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] +- Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) [@johmani] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). - Renderer Backends: - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: diff --git a/imgui.h b/imgui.h index de0d06645271..195a4ea5a1fa 100644 --- a/imgui.h +++ b/imgui.h @@ -2827,31 +2827,31 @@ struct ImGuiListClipper #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF // ImVec2 operators -static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } -static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } -static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } -static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } -static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } -static inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -static inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } +inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } +inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } +inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } // ImVec4 operators -static inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } -static inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } -static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } -static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } -static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } -static inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } -static inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } -static inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } -static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } +inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } +inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } +inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } +inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } +inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } +inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } IM_MSVC_RUNTIME_CHECKS_RESTORE #endif diff --git a/imgui_internal.h b/imgui_internal.h index b3a950c7ad9a..7ff24d889a5a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3713,8 +3713,8 @@ typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are // Helpers: ImTextureRef ==/!= operators provided as convenience // (note that _TexID and _TexData are never set simultaneously) -static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } -static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } +inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } +inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } // Refer to ImFontAtlasPackGetRect() to better understand how this works. #define ImFontAtlasRectId_IndexMask_ (0x000FFFFF) // 20-bits: index to access builder->RectsIndex[]. From 041abe85224c38d4629dd1e9f9e9ab6f20837a99 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 14:57:39 +0200 Subject: [PATCH 635/716] Revert "Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) [@radjkarl]" This reverts commit 39a90ac4d63867bb9bbd3ee4012b0981c4329eaf. --- docs/CHANGELOG.txt | 1 - imgui.h | 48 +++++++++++++++++++++++----------------------- imgui_internal.h | 4 ++-- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 245462463e1c..dd9daeba15fe 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -372,7 +372,6 @@ Other changes: of WantVisible. This is set in the same structure because activating text input generally requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] -- Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) [@johmani] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). - Renderer Backends: - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: diff --git a/imgui.h b/imgui.h index 195a4ea5a1fa..de0d06645271 100644 --- a/imgui.h +++ b/imgui.h @@ -2827,31 +2827,31 @@ struct ImGuiListClipper #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF // ImVec2 operators -inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } -inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } -inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } -inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } -inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } -inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } -inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } -inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } +static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } +static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +static inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } +static inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } // ImVec4 operators -inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } -inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } -inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } -inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } -inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } -inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } -inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } -inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } -inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } +static inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } +static inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } +static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +static inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } +static inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } +static inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } +static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } IM_MSVC_RUNTIME_CHECKS_RESTORE #endif diff --git a/imgui_internal.h b/imgui_internal.h index 7ff24d889a5a..b3a950c7ad9a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3713,8 +3713,8 @@ typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are // Helpers: ImTextureRef ==/!= operators provided as convenience // (note that _TexID and _TexData are never set simultaneously) -inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } -inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } +static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } +static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } // Refer to ImFontAtlasPackGetRect() to better understand how this works. #define ImFontAtlasRectId_IndexMask_ (0x000FFFFF) // 20-bits: index to access builder->RectsIndex[]. From 08bb348142386feca796cbbe51e030875a2216a0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 14:52:34 +0200 Subject: [PATCH 636/716] Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) --- docs/CHANGELOG.txt | 1 + imgui.h | 48 +++++++++++++++++++++++----------------------- imgui_internal.h | 4 ++-- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index dd9daeba15fe..245462463e1c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -372,6 +372,7 @@ Other changes: of WantVisible. This is set in the same structure because activating text input generally requires providing a window to the backend. (#8584, #6341) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] +- Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) [@johmani] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). - Renderer Backends: - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: diff --git a/imgui.h b/imgui.h index de0d06645271..195a4ea5a1fa 100644 --- a/imgui.h +++ b/imgui.h @@ -2827,31 +2827,31 @@ struct ImGuiListClipper #define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED IM_MSVC_RUNTIME_CHECKS_OFF // ImVec2 operators -static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } -static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } -static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } -static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } -static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } -static inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } -static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } -static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } -static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } -static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } -static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } -static inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } -static inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } +inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x * rhs, lhs.y * rhs); } +inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); } +inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); } +inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); } +inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); } +inline ImVec2 operator-(const ImVec2& lhs) { return ImVec2(-lhs.x, -lhs.y); } +inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } +inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } +inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; } +inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } +inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs) { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; } +inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs) { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; } +inline bool operator==(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } +inline bool operator!=(const ImVec2& lhs, const ImVec2& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } // ImVec4 operators -static inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } -static inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } -static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } -static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } -static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } -static inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } -static inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } -static inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } -static inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } +inline ImVec4 operator*(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs); } +inline ImVec4 operator/(const ImVec4& lhs, const float rhs) { return ImVec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs); } +inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); } +inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); } +inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); } +inline ImVec4 operator/(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w); } +inline ImVec4 operator-(const ImVec4& lhs) { return ImVec4(-lhs.x, -lhs.y, -lhs.z, -lhs.w); } +inline bool operator==(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.w == rhs.w; } +inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y || lhs.z != rhs.z || lhs.w != rhs.w; } IM_MSVC_RUNTIME_CHECKS_RESTORE #endif diff --git a/imgui_internal.h b/imgui_internal.h index b3a950c7ad9a..7ff24d889a5a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3713,8 +3713,8 @@ typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are // Helpers: ImTextureRef ==/!= operators provided as convenience // (note that _TexID and _TexData are never set simultaneously) -static inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } -static inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } +inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } +inline bool operator!=(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID != rhs._TexID || lhs._TexData != rhs._TexData; } // Refer to ImFontAtlasPackGetRect() to better understand how this works. #define ImFontAtlasRectId_IndexMask_ (0x000FFFFF) // 20-bits: index to access builder->RectsIndex[]. From 12626b85c496b6d8f5995f0f77ba9a9516d0beaa Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 19:24:10 +0200 Subject: [PATCH 637/716] InputText: minor changes to match for both insert chars paths to look more similar. --- imgui_widgets.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2e80564eae44..22f8b4ecafb1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4282,6 +4282,10 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (new_text == new_text_end) return; + ImGuiContext& g = *Ctx; + ImGuiInputTextState* obj = &g.InputTextState; + IM_ASSERT(obj->ID != 0 && g.ActiveId == obj->ID); + // Grow internal buffer if needed const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text); @@ -4290,15 +4294,12 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons if (!is_resizable) return; - ImGuiContext& g = *Ctx; - ImGuiInputTextState* edit_state = &g.InputTextState; - IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID); - IM_ASSERT(Buf == edit_state->TextA.Data); + IM_ASSERT(Buf == obj->TextA.Data); int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1; - edit_state->TextA.resize(new_buf_size + 1); - edit_state->TextSrc = edit_state->TextA.Data; - Buf = edit_state->TextA.Data; - BufSize = edit_state->BufCapacity = new_buf_size; + obj->TextA.resize(new_buf_size + 1); + obj->TextSrc = obj->TextA.Data; + Buf = obj->TextA.Data; + BufSize = obj->BufCapacity = new_buf_size; } if (BufTextLen != pos) @@ -5483,7 +5484,7 @@ void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state) Text("ID: 0x%08X, ActiveID: 0x%08X", state->ID, g.ActiveId); DebugLocateItemOnHover(state->ID); Text("CurLenA: %d, Cursor: %d, Selection: %d..%d", state->TextLen, stb_state->cursor, stb_state->select_start, stb_state->select_end); - Text("BufCapacityA: %d", state->BufCapacity); + Text("BufCapacity: %d", state->BufCapacity); Text("(Internal Buffer: TextA Size: %d, Capacity: %d)", state->TextA.Size, state->TextA.Capacity); Text("has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x); Text("undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point); From b2c73596aeaf63b46b66a615ec02fce1b87f4248 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 17 Jun 2025 20:11:22 +0200 Subject: [PATCH 638/716] InputText: fixed a buffer overrun that could happen when using dynamically resizing buffers. (#8689) --- docs/CHANGELOG.txt | 3 +++ imgui.h | 2 +- imgui_widgets.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 245462463e1c..2104b9c9c1fe 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -336,6 +336,9 @@ Other changes: - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. - InputText: fixed cursor positioning issue using up/down keys near end of lines while editing non-ASCII text. (Regression from 1.91.2) (#8635, #7925) +- InputText: fixed a buffer overrun that could happen when using dynamically resizing + buffers (e.g. imgui_stdlib.cpp for std::string, or ImGuiInputTextFlags_CallbackRezize) + and programmatically making an insertion. (#8689) [@ocornut, @m9710797] - Tables: fixed TableHeader() eager vertical clipping of text which may be noticeable with FramePadding.y was too small. (#6236) - Tables: fixed an assert when combining Tables, Frozen Rows, Clipper and BeginMultiSelect() diff --git a/imgui.h b/imgui.h index 195a4ea5a1fa..ae0b90e8c872 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19198 +#define IMGUI_VERSION_NUM 19199 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 22f8b4ecafb1..43d98bb88dd0 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4289,7 +4289,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons // Grow internal buffer if needed const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text); - if (new_text_len + BufTextLen >= BufSize) + if (new_text_len + BufTextLen + 1 > obj->TextA.Size) { if (!is_resizable) return; From c56e8b496467aa573ca0f65a295b4b1235718d43 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Jun 2025 15:31:00 +0200 Subject: [PATCH 639/716] imgui_freetype: fixed NULL that creeped in instead of nullptr. --- misc/freetype/imgui_freetype.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index d7d50db392bf..e5f2818dba06 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -346,7 +346,7 @@ static void* FreeType_Realloc(FT_Memory /*memory*/, long cur_size, long new_size bool ImGui_ImplFreeType_LoaderInit(ImFontAtlas* atlas) { - IM_ASSERT(atlas->FontLoaderData == NULL); + IM_ASSERT(atlas->FontLoaderData == nullptr); ImGui_ImplFreeType_Data* bd = IM_NEW(ImGui_ImplFreeType_Data)(); // FreeType memory management: https://www.freetype.org/freetype2/docs/design/design-4.html @@ -387,23 +387,23 @@ bool ImGui_ImplFreeType_LoaderInit(ImFontAtlas* atlas) void ImGui_ImplFreeType_LoaderShutdown(ImFontAtlas* atlas) { ImGui_ImplFreeType_Data* bd = (ImGui_ImplFreeType_Data*)atlas->FontLoaderData; - IM_ASSERT(bd != NULL); + IM_ASSERT(bd != nullptr); FT_Done_Library(bd->Library); IM_DELETE(bd); - atlas->FontLoaderData = NULL; + atlas->FontLoaderData = nullptr; } bool ImGui_ImplFreeType_FontSrcInit(ImFontAtlas* atlas, ImFontConfig* src) { ImGui_ImplFreeType_Data* bd = (ImGui_ImplFreeType_Data*)atlas->FontLoaderData; ImGui_ImplFreeType_FontSrcData* bd_font_data = IM_NEW(ImGui_ImplFreeType_FontSrcData); - IM_ASSERT(src->FontLoaderData == NULL); + IM_ASSERT(src->FontLoaderData == nullptr); src->FontLoaderData = bd_font_data; if (!bd_font_data->InitFont(bd->Library, src, (ImGuiFreeTypeLoaderFlags)atlas->FontLoaderFlags)) { IM_DELETE(bd_font_data); - src->FontLoaderData = NULL; + src->FontLoaderData = nullptr; return false; } @@ -415,7 +415,7 @@ void ImGui_ImplFreeType_FontSrcDestroy(ImFontAtlas* atlas, ImFontConfig* src) IM_UNUSED(atlas); ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; IM_DELETE(bd_font_data); - src->FontLoaderData = NULL; + src->FontLoaderData = nullptr; } bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src) @@ -430,7 +430,7 @@ bool ImGui_ImplFreeType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig* src, ImF // We use one FT_Size per (source + baked) combination. ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; - IM_ASSERT(bd_baked_data != NULL); + IM_ASSERT(bd_baked_data != nullptr); IM_PLACEMENT_NEW(bd_baked_data) ImGui_ImplFreeType_FontSrcBakedData(); FT_New_Size(bd_font_data->FtFace, &bd_baked_data->FtSize); @@ -470,7 +470,7 @@ void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, IM_UNUSED(baked); IM_UNUSED(src); ImGui_ImplFreeType_FontSrcBakedData* bd_baked_data = (ImGui_ImplFreeType_FontSrcBakedData*)loader_data_for_baked_src; - IM_ASSERT(bd_baked_data != NULL); + IM_ASSERT(bd_baked_data != nullptr); FT_Done_Size(bd_baked_data->FtSize); bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE() } @@ -491,7 +491,7 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src } const FT_Glyph_Metrics* metrics = ImGui_ImplFreeType_LoadGlyph(bd_font_data, codepoint); - if (metrics == NULL) + if (metrics == nullptr) return false; // Render glyph into a bitmap (currently held by FreeType) From d290e583c54dcb020cc96cfcab2f629441c7dad5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Jun 2025 15:50:49 +0200 Subject: [PATCH 640/716] Backends: GLFW: fixed WndProc relying on current context. (#8676, #8239, #8069) This makes the backend closer to support multi-context. --- backends/imgui_impl_glfw.cpp | 16 +++++++++++++--- docs/CHANGELOG.txt | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index aac9eca2ece1..fb8df3e556e6 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -191,6 +191,10 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } +static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(ImGuiIO& io) +{ + return (ImGui_ImplGlfw_Data*)io.BackendPlatformUserData; +} // Functions @@ -501,6 +505,7 @@ static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEven #ifdef _WIN32 // GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen. // Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently. +namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); } static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() { LPARAM extra_info = ::GetMessageExtraInfo(); @@ -512,7 +517,10 @@ static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() } static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGuiContext* ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT"); + ImGuiIO& io = ImGui::GetIO(ctx); + + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(io); switch (msg) { case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: @@ -520,7 +528,7 @@ static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wPara case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP: case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP: - ImGui::GetIO().AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); + io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); break; } return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam); @@ -661,6 +669,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw // Windows: register a WndProc hook so we can intercept some messages. #ifdef _WIN32 + ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_CONTEXT", ImGui::GetCurrentContext()); bd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC); IM_ASSERT(bd->PrevWndProc != nullptr); ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); @@ -672,7 +681,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw #if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817 if (emscripten::glfw3::IsRuntimePlatformApple()) { - ImGui::GetIO().ConfigMacOSXBehaviors = true; + io.ConfigMacOSXBehaviors = true; // Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used. // This means that Meta + V only registers a single key-press, even if the keys are held. @@ -721,6 +730,7 @@ void ImGui_ImplGlfw_Shutdown() // Windows: restore our WndProc hook #ifdef _WIN32 ImGuiViewport* main_viewport = ImGui::GetMainViewport(); + ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_CONTEXT", nullptr); ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc); bd->PrevWndProc = nullptr; #endif diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2104b9c9c1fe..72edad331ac1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -407,6 +407,7 @@ Other changes: - Backends: GLFW: added ImGui_ImplGlfw_GetContentScaleForMonitor(), ImGui_ImplGlfw_GetContentScaleForWindow() helpers. They are wrappers to glfwGetMonitorContentScale()/glfwGetWindowContentScale(), with compile-time GLFW version checks + returning 1.0f on Apple platform. + - Backends: GLFW: fixed Win32 specific WndProc handler relying on current context. (#8676, #8239, #8069) - Backends: SDL2: added ImGui_ImplSDL2_GetDpiScaleForDisplay() and ImGui_ImplSDL2_GetContentScaleForWindow() helpers. They are wrappers to SDL_GetDisplayDPI(), with compile-time SDL version checks + returning 1.0f on Apple platforms. SDL3 already does this by default. From f633a60581bc7573f76c9913f66695aa02caf5d0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 18 Jun 2025 16:40:35 +0200 Subject: [PATCH 641/716] Backends: GLFW: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) --- backends/imgui_impl_glfw.cpp | 102 ++++++++++++++++++++--------------- backends/imgui_impl_glfw.h | 1 + docs/CHANGELOG.txt | 2 +- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index fb8df3e556e6..5518a823e37e 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -9,6 +9,7 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Multiple Dear ImGui contexts support. // Missing features or Issues: // [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. // [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. @@ -28,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. // 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. // 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled. @@ -141,6 +143,16 @@ #define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName() #define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError() +// Map GLFWWindow* to ImGuiContext*. +// - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource. +// - Would be simpler if we could use e.g. std::map<> as well. But we don't. +// - This is not particularly optimized as we expect size to be small and queries to be rare. +struct ImGui_ImplGlfw_WindowToContext { GLFWwindow* Window; ImGuiContext* Context; }; +static ImVector g_ContextMap; +static void ImGui_ImplGlfw_ContextMap_Add(GLFWwindow* window, ImGuiContext* ctx) { g_ContextMap.push_back(ImGui_ImplGlfw_WindowToContext{ window, ctx }); } +static void ImGui_ImplGlfw_ContextMap_Remove(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) { g_ContextMap.erase_unsorted(&entry); return; } } +static ImGuiContext* ImGui_ImplGlfw_ContextMap_Get(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) return entry.Context; return nullptr; } + // GLFW data enum GlfwClientApi { @@ -151,6 +163,7 @@ enum GlfwClientApi struct ImGui_ImplGlfw_Data { + ImGuiContext* Context; GLFWwindow* Window; GlfwClientApi ClientApi; double Time; @@ -187,13 +200,17 @@ struct ImGui_ImplGlfw_Data // (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks. // - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it. // FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context. +namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); } static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() { + // Get data for current context return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; } -static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(ImGuiIO& io) +static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(GLFWwindow* window) { - return (ImGui_ImplGlfw_Data*)io.BackendPlatformUserData; + // Get data for a given GLFW window, regardless of current context (since GLFW events are sent together) + ImGuiContext* ctx = ImGui_ImplGlfw_ContextMap_Get(window); + return (ImGui_ImplGlfw_Data*)ImGui::GetIO(ctx).BackendPlatformUserData; } // Functions @@ -330,38 +347,36 @@ ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode) // X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW // See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630 -static void ImGui_ImplGlfw_UpdateKeyModifiers(GLFWwindow* window) +static void ImGui_ImplGlfw_UpdateKeyModifiers(ImGuiIO& io, GLFWwindow* window) { - ImGuiIO& io = ImGui::GetIO(); io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS)); io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS)); io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS)); io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS)); } -static bool ImGui_ImplGlfw_ShouldChainCallback(GLFWwindow* window) +static bool ImGui_ImplGlfw_ShouldChainCallback(ImGui_ImplGlfw_Data* bd, GLFWwindow* window) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); return bd->CallbacksChainForAllWindows ? true : (window == bd->Window); } void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) - bd->PrevUserCallbackMousebutton(window, button, action, mods); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); - ImGui_ImplGlfw_UpdateKeyModifiers(window); + if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) + bd->PrevUserCallbackMousebutton(window, button, action, mods); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); + ImGui_ImplGlfw_UpdateKeyModifiers(io, window); if (button >= 0 && button < ImGuiMouseButton_COUNT) io.AddMouseButtonEvent(button, action == GLFW_PRESS); } void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackScroll(window, xoffset, yoffset); #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 @@ -369,7 +384,7 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo return; #endif - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); io.AddMouseWheelEvent((float)xoffset, (float)yoffset); } @@ -409,18 +424,18 @@ static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode) void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackKey(window, keycode, scancode, action, mods); if (action != GLFW_PRESS && action != GLFW_RELEASE) return; - ImGui_ImplGlfw_UpdateKeyModifiers(window); + ImGuiIO& io = ImGui::GetIO(bd->Context); + ImGui_ImplGlfw_UpdateKeyModifiers(io, window); keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode); - ImGuiIO& io = ImGui::GetIO(); ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode); io.AddKeyEvent(imgui_key, (action == GLFW_PRESS)); io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code) @@ -428,21 +443,21 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackWindowFocus(window, focused); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); io.AddFocusEvent(focused != 0); } void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackCursorPos(window, x, y); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); io.AddMousePosEvent((float)x, (float)y); bd->LastValidMousePos = ImVec2((float)x, (float)y); } @@ -451,11 +466,11 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) // so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984) void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackCursorEnter(window, entered); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); if (entered) { bd->MouseWindow = window; @@ -471,11 +486,11 @@ void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered) void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); - if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(window)) + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); + if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window)) bd->PrevUserCallbackChar(window, c); - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); io.AddInputCharacter(c); } @@ -485,17 +500,18 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int) } #ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3 -static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void*) +static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void* user_data) { // Mimic Emscripten_HandleWheel() in SDL. // Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096 + ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; float multiplier = 0.0f; if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step. else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step. else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps. float wheel_x = ev->deltaX * -multiplier; float wheel_y = ev->deltaY * -multiplier; - ImGuiIO& io = ImGui::GetIO(); + ImGuiIO& io = ImGui::GetIO(bd->Context); io.AddMouseWheelEvent(wheel_x, wheel_y); //IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y); return EM_TRUE; @@ -505,7 +521,6 @@ static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEven #ifdef _WIN32 // GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen. // Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently. -namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); } static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() { LPARAM extra_info = ::GetMessageExtraInfo(); @@ -517,10 +532,9 @@ static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() } static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - ImGuiContext* ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT"); - ImGuiIO& io = ImGui::GetIO(ctx); + ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA"); + ImGuiIO& io = ImGui::GetIO(bd->Context); - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(io); switch (msg) { case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: @@ -537,7 +551,7 @@ static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wPara void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!"); IM_ASSERT(bd->Window == window); @@ -554,7 +568,7 @@ void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window) void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window) { - ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window); IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!"); IM_ASSERT(bd->Window == window); @@ -610,8 +624,10 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + bd->Context = ImGui::GetCurrentContext(); bd->Window = window; bd->Time = 0.0; + ImGui_ImplGlfw_ContextMap_Add(window, bd->Context); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); #if GLFW_VERSION_COMBINED < 3300 @@ -669,8 +685,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw // Windows: register a WndProc hook so we can intercept some messages. #ifdef _WIN32 - ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_CONTEXT", ImGui::GetCurrentContext()); - bd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC); + HWND hwnd = (HWND)main_viewport->PlatformHandleRaw; + ::SetPropA(hwnd, "IMGUI_BACKEND_DATA", bd); + bd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC); IM_ASSERT(bd->PrevWndProc != nullptr); ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); #endif @@ -730,7 +747,7 @@ void ImGui_ImplGlfw_Shutdown() // Windows: restore our WndProc hook #ifdef _WIN32 ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_CONTEXT", nullptr); + ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_BACKEND_DATA", nullptr); ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc); bd->PrevWndProc = nullptr; #endif @@ -738,6 +755,7 @@ void ImGui_ImplGlfw_Shutdown() io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + ImGui_ImplGlfw_ContextMap_Remove(bd->Window); IM_DELETE(bd); } @@ -961,7 +979,7 @@ void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow*, const char* canvas_s // Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096) // We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves. // FIXME: May break chaining in case user registered their own Emscripten callback? - emscripten_set_wheel_callback(bd->CanvasSelector, nullptr, false, ImGui_ImplEmscripten_WheelCallback); + emscripten_set_wheel_callback(bd->CanvasSelector, bd, false, ImGui_ImplEmscripten_WheelCallback); } #elif defined(EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3) // When using --use-port=contrib.glfw3 for the GLFW implementation, you can override the behavior of this call diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 1ef9ade17b42..80e2b55efa38 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -8,6 +8,7 @@ // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. +// [X] Multiple Dear ImGui contexts support. // Missing features or Issues: // [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround. // [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 72edad331ac1..b6f5c9e6e68a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -407,7 +407,7 @@ Other changes: - Backends: GLFW: added ImGui_ImplGlfw_GetContentScaleForMonitor(), ImGui_ImplGlfw_GetContentScaleForWindow() helpers. They are wrappers to glfwGetMonitorContentScale()/glfwGetWindowContentScale(), with compile-time GLFW version checks + returning 1.0f on Apple platform. - - Backends: GLFW: fixed Win32 specific WndProc handler relying on current context. (#8676, #8239, #8069) + - Backends: GLFW: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) - Backends: SDL2: added ImGui_ImplSDL2_GetDpiScaleForDisplay() and ImGui_ImplSDL2_GetContentScaleForWindow() helpers. They are wrappers to SDL_GetDisplayDPI(), with compile-time SDL version checks + returning 1.0f on Apple platforms. SDL3 already does this by default. From 725d185a31f860b74014aba167aa69003d12c01a Mon Sep 17 00:00:00 2001 From: PlayDay <18056374+playday3008@users.noreply.github.com> Date: Thu, 19 Jun 2025 05:54:54 +0200 Subject: [PATCH 642/716] Backends: DirectX12: fixed build on MinGW. (#8702, #4594) --- backends/imgui_impl_dx12.cpp | 6 +++++- docs/CHANGELOG.txt | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index e3bcda195a62..5f7eec0635f6 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-19: Fixed build on MinGW. (#8702, #4594) // 2025-06-11: DirectX12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-02-24: DirectX12: Fixed an issue where ImGui_ImplDX12_Init() signature change from 2024-11-15 combined with change from 2025-01-15 made legacy ImGui_ImplDX12_Init() crash. (#8429) @@ -61,6 +62,9 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif +// MinGW workaround, see #4594 +typedef decltype(D3D12SerializeRootSignature) *_PFN_D3D12_SERIALIZE_ROOT_SIGNATURE; + // DirectX12 data struct ImGui_ImplDX12_RenderBuffers; @@ -618,7 +622,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() return false; } - PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)(void*)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature"); + _PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (_PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)(void*)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature"); if (D3D12SerializeRootSignatureFn == nullptr) return false; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b6f5c9e6e68a..71549deb53f7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -392,6 +392,7 @@ Other changes: - Backends: SDLGPU3: added support for ImDrawCallback_ResetRenderState. (#8599) - Backends: OpenGL3: made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) [@DyXel] + - Backends: DirectX12: Fixed build on MinGW. (#8702, #4594) [@playday3008] - Backends: DirectX10, DirectX11, DirectX12: Honor FramebufferScale to allow for custom platform backends and experiments using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). (#8412) [@WSSDude] From f7dabede8b1bd3e439c5bff048a22c8d00cd9fcf Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 09:45:26 +0200 Subject: [PATCH 643/716] Backends: Allegro5: Fixed missing invisible mouse cursor, broken by ee8941e0d. --- backends/imgui_impl_allegro5.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index b5f8ca00a718..bd7f10c64296 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -647,6 +647,9 @@ void ImGui_ImplAllegro5_NewFrame() ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplAllegro5_Init()?"); + if (!bd->MouseCursorInvisible) + ImGui_ImplAllegro5_CreateDeviceObjects(); + // Setup display size (every frame to accommodate for window resizing) ImGuiIO& io = ImGui::GetIO(); int w, h; From 8d6e66d38cfcf7e2057a378c14b5de64a04eaac8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 09:49:06 +0200 Subject: [PATCH 644/716] Backends: DX10, DX11, DX12, OpenGL3, Vulkan, WGPU: Assert when CreateDeviceObjects() calls return false. --- backends/imgui_impl_dx10.cpp | 3 ++- backends/imgui_impl_dx11.cpp | 3 ++- backends/imgui_impl_dx12.cpp | 3 ++- backends/imgui_impl_opengl3.cpp | 12 ++++++++---- backends/imgui_impl_vulkan.cpp | 3 ++- backends/imgui_impl_wgpu.cpp | 3 ++- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 4dc5f884ebb6..b7be791c7eb9 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -642,7 +642,8 @@ void ImGui_ImplDX10_NewFrame() IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX10_Init()?"); if (!bd->pVertexShader) - ImGui_ImplDX10_CreateDeviceObjects(); + if (!ImGui_ImplDX10_CreateDeviceObjects()) + IM_ASSERT(0 && "ImGui_ImplDX10_CreateDeviceObjects() failed!"); } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 14e74e9b245e..1917f6c0f43d 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -662,7 +662,8 @@ void ImGui_ImplDX11_NewFrame() IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX11_Init()?"); if (!bd->pVertexShader) - ImGui_ImplDX11_CreateDeviceObjects(); + if (!ImGui_ImplDX11_CreateDeviceObjects()) + IM_ASSERT(0 && "ImGui_ImplDX11_CreateDeviceObjects() failed!"); } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 5f7eec0635f6..1baa3c4e8e06 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -914,7 +914,8 @@ void ImGui_ImplDX12_NewFrame() IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX12_Init()?"); if (!bd->pPipelineState) - ImGui_ImplDX12_CreateDeviceObjects(); + if (!ImGui_ImplDX12_CreateDeviceObjects()) + IM_ASSERT(0 && "ImGui_ImplDX12_CreateDeviceObjects() failed!"); } //----------------------------------------------------------------------------- diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 3f6c087567b1..40b3be68b2df 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -431,7 +431,8 @@ void ImGui_ImplOpenGL3_NewFrame() ImGui_ImplOpenGL3_InitLoader(); // Lazily init loader if not already done for e.g. DLL boundaries. if (!bd->ShaderHandle) - ImGui_ImplOpenGL3_CreateDeviceObjects(); + if (!ImGui_ImplOpenGL3_CreateDeviceObjects()) + IM_ASSERT(0 && "ImGui_ImplOpenGL3_CreateDeviceObjects() failed!"); } static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) @@ -965,21 +966,24 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() GL_CALL(vert_handle = glCreateShader(GL_VERTEX_SHADER)); glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr); glCompileShader(vert_handle); - CheckShader(vert_handle, "vertex shader"); + if (!CheckShader(vert_handle, "vertex shader")) + return false; const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader }; GLuint frag_handle; GL_CALL(frag_handle = glCreateShader(GL_FRAGMENT_SHADER)); glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr); glCompileShader(frag_handle); - CheckShader(frag_handle, "fragment shader"); + if (!CheckShader(frag_handle, "fragment shader")) + return false; // Link bd->ShaderHandle = glCreateProgram(); glAttachShader(bd->ShaderHandle, vert_handle); glAttachShader(bd->ShaderHandle, frag_handle); glLinkProgram(bd->ShaderHandle); - CheckProgram(bd->ShaderHandle, "shader program"); + if (!CheckProgram(bd->ShaderHandle, "shader program")) + return false; glDetachShader(bd->ShaderHandle, vert_handle); glDetachShader(bd->ShaderHandle, frag_handle); diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 3e2c043dedbc..a0f787e8a504 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1236,7 +1236,8 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) } #endif - ImGui_ImplVulkan_CreateDeviceObjects(); + if (!ImGui_ImplVulkan_CreateDeviceObjects()) + IM_ASSERT(0 && "ImGui_ImplVulkan_CreateDeviceObjects() failed!"); // <- Can't be hit yet. return true; } diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 09bd30ca8499..c0ec2e3f9f42 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -901,7 +901,8 @@ void ImGui_ImplWGPU_NewFrame() { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); if (!bd->pipelineState) - ImGui_ImplWGPU_CreateDeviceObjects(); + if (!ImGui_ImplWGPU_CreateDeviceObjects()) + IM_ASSERT(0 && "ImGui_ImplWGPU_CreateDeviceObjects() failed!"); } //----------------------------------------------------------------------------- From 3a964d18e0e336b626a4b2e09536e087a81d382e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 10:11:07 +0200 Subject: [PATCH 645/716] Comments on ImGuiMod_XXXX and ImGuiKey_GamepadXXXX values. --- imgui.h | 69 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/imgui.h b/imgui.h index ae0b90e8c872..10eac63c9a78 100644 --- a/imgui.h +++ b/imgui.h @@ -1530,7 +1530,7 @@ enum ImGuiKey : int ImGuiKey_Space, ImGuiKey_Enter, ImGuiKey_Escape, - ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, + ImGuiKey_LeftCtrl, ImGuiKey_LeftShift, ImGuiKey_LeftAlt, ImGuiKey_LeftSuper, // Also see ImGuiMod_Ctrl, ImGuiMod_Shift, ImGuiMod_Alt, ImGuiMod_Super below! ImGuiKey_RightCtrl, ImGuiKey_RightShift, ImGuiKey_RightAlt, ImGuiKey_RightSuper, ImGuiKey_Menu, ImGuiKey_0, ImGuiKey_1, ImGuiKey_2, ImGuiKey_3, ImGuiKey_4, ImGuiKey_5, ImGuiKey_6, ImGuiKey_7, ImGuiKey_8, ImGuiKey_9, @@ -1570,32 +1570,34 @@ enum ImGuiKey : int ImGuiKey_AppForward, ImGuiKey_Oem102, // Non-US backslash. - // Gamepad (some of those are analog values, 0.0f to 1.0f) // NAVIGATION ACTION + // Gamepad + // (analog values are 0.0f to 1.0f) // (download controller mapping PNG/PSD at http://dearimgui.com/controls_sheets) - ImGuiKey_GamepadStart, // Menu (Xbox) + (Switch) Start/Options (PS) - ImGuiKey_GamepadBack, // View (Xbox) - (Switch) Share (PS) - ImGuiKey_GamepadFaceLeft, // X (Xbox) Y (Switch) Square (PS) // Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) - ImGuiKey_GamepadFaceRight, // B (Xbox) A (Switch) Circle (PS) // Cancel / Close / Exit - ImGuiKey_GamepadFaceUp, // Y (Xbox) X (Switch) Triangle (PS) // Text Input / On-screen Keyboard - ImGuiKey_GamepadFaceDown, // A (Xbox) B (Switch) Cross (PS) // Activate / Open / Toggle / Tweak - ImGuiKey_GamepadDpadLeft, // D-pad Left // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadDpadRight, // D-pad Right // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadDpadUp, // D-pad Up // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadDpadDown, // D-pad Down // Move / Tweak / Resize Window (in Windowing mode) - ImGuiKey_GamepadL1, // L Bumper (Xbox) L (Switch) L1 (PS) // Tweak Slower / Focus Previous (in Windowing mode) - ImGuiKey_GamepadR1, // R Bumper (Xbox) R (Switch) R1 (PS) // Tweak Faster / Focus Next (in Windowing mode) - ImGuiKey_GamepadL2, // L Trig. (Xbox) ZL (Switch) L2 (PS) [Analog] - ImGuiKey_GamepadR2, // R Trig. (Xbox) ZR (Switch) R2 (PS) [Analog] - ImGuiKey_GamepadL3, // L Stick (Xbox) L3 (Switch) L3 (PS) - ImGuiKey_GamepadR3, // R Stick (Xbox) R3 (Switch) R3 (PS) - ImGuiKey_GamepadLStickLeft, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadLStickRight, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadLStickUp, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadLStickDown, // [Analog] // Move Window (in Windowing mode) - ImGuiKey_GamepadRStickLeft, // [Analog] - ImGuiKey_GamepadRStickRight, // [Analog] - ImGuiKey_GamepadRStickUp, // [Analog] - ImGuiKey_GamepadRStickDown, // [Analog] + // // XBOX | SWITCH | PLAYSTA. | -> ACTION + ImGuiKey_GamepadStart, // Menu | + | Options | + ImGuiKey_GamepadBack, // View | - | Share | + ImGuiKey_GamepadFaceLeft, // X | Y | Square | Tap: Toggle Menu. Hold: Windowing mode (Focus/Move/Resize windows) + ImGuiKey_GamepadFaceRight, // B | A | Circle | Cancel / Close / Exit + ImGuiKey_GamepadFaceUp, // Y | X | Triangle | Text Input / On-screen Keyboard + ImGuiKey_GamepadFaceDown, // A | B | Cross | Activate / Open / Toggle / Tweak + ImGuiKey_GamepadDpadLeft, // D-pad Left | " | " | Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadRight, // D-pad Right | " | " | Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadUp, // D-pad Up | " | " | Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadDpadDown, // D-pad Down | " | " | Move / Tweak / Resize Window (in Windowing mode) + ImGuiKey_GamepadL1, // L Bumper | L | L1 | Tweak Slower / Focus Previous (in Windowing mode) + ImGuiKey_GamepadR1, // R Bumper | R | R1 | Tweak Faster / Focus Next (in Windowing mode) + ImGuiKey_GamepadL2, // L Trigger | ZL | L2 | [Analog] + ImGuiKey_GamepadR2, // R Trigger | ZR | R2 | [Analog] + ImGuiKey_GamepadL3, // L Stick | L3 | L3 | + ImGuiKey_GamepadR3, // R Stick | R3 | R3 | + ImGuiKey_GamepadLStickLeft, // | | | [Analog] Move Window (in Windowing mode) + ImGuiKey_GamepadLStickRight, // | | | [Analog] Move Window (in Windowing mode) + ImGuiKey_GamepadLStickUp, // | | | [Analog] Move Window (in Windowing mode) + ImGuiKey_GamepadLStickDown, // | | | [Analog] Move Window (in Windowing mode) + ImGuiKey_GamepadRStickLeft, // | | | [Analog] + ImGuiKey_GamepadRStickRight, // | | | [Analog] + ImGuiKey_GamepadRStickUp, // | | | [Analog] + ImGuiKey_GamepadRStickDown, // | | | [Analog] // Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls) // - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API. @@ -1603,11 +1605,15 @@ enum ImGuiKey : int // [Internal] Reserved for mod storage ImGuiKey_ReservedForModCtrl, ImGuiKey_ReservedForModShift, ImGuiKey_ReservedForModAlt, ImGuiKey_ReservedForModSuper, + + // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. ImGuiKey_NamedKey_END, + ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, // Keyboard Modifiers (explicitly submitted by backend via AddKeyEvent() calls) - // - This is mirroring the data also written to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper, in a format allowing - // them to be accessed via standard key API, allowing calls such as IsKeyPressed(), IsKeyReleased(), querying duration etc. + // - Any functions taking a ImGuiKeyChord parameter can binary-or those with regular keys, e.g. Shortcut(ImGuiMod_Ctrl | ImGuiKey_S). + // - Those are written back into io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper for convenience, + // but may be accessed via standard key API such as IsKeyPressed(), IsKeyReleased(), querying duration etc. // - Code polling every key (e.g. an interface to detect a key press for input mapping) might want to ignore those // and prefer using the real keys (e.g. ImGuiKey_LeftCtrl, ImGuiKey_RightCtrl instead of ImGuiMod_Ctrl). // - In theory the value of keyboard modifiers should be roughly equivalent to a logical or of the equivalent left/right keys. @@ -1621,11 +1627,6 @@ enum ImGuiKey : int ImGuiMod_Super = 1 << 15, // Windows/Super (non-macOS), Ctrl (macOS) ImGuiMod_Mask_ = 0xF000, // 4-bits - // [Internal] If you need to iterate all keys (for e.g. an input mapper) you may use ImGuiKey_NamedKey_BEGIN..ImGuiKey_NamedKey_END. - ImGuiKey_NamedKey_COUNT = ImGuiKey_NamedKey_END - ImGuiKey_NamedKey_BEGIN, - //ImGuiKey_KeysData_SIZE = ImGuiKey_NamedKey_COUNT, // Size of KeysData[]: only hold named keys - //ImGuiKey_KeysData_OFFSET = ImGuiKey_NamedKey_BEGIN, // Accesses to io.KeysData[] must use (key - ImGuiKey_NamedKey_BEGIN) index. - #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS ImGuiKey_COUNT = ImGuiKey_NamedKey_END, // Obsoleted in 1.91.5 because it was extremely misleading (since named keys don't start at 0 anymore) ImGuiMod_Shortcut = ImGuiMod_Ctrl, // Removed in 1.90.7, you can now simply use ImGuiMod_Ctrl @@ -2514,7 +2515,7 @@ struct ImGuiIO // Other state maintained from data above + IO function calls ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. Read-only, updated by NewFrame() - ImGuiKeyData KeysData[ImGuiKey_NamedKey_COUNT];// Key state for all known keys. Use IsKeyXXX() functions to access this. + ImGuiKeyData KeysData[ImGuiKey_NamedKey_COUNT];// Key state for all known keys. MUST use 'key - ImGuiKey_NamedKey_BEGIN' as index. Use IsKeyXXX() functions to access this. bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup. ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid) ImVec2 MouseClickedPos[5]; // Position at time of clicking From 9a50c091722bdc57355325d4b40dea1dcdfd0075 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 14:30:33 +0200 Subject: [PATCH 646/716] Bsckends: SDL2, GLFW: fixed ImGui_ImplXXXX_GetContentScaleXXX functions never using SDL 2.0.4 & GLFW 3.3 path in master. Amend 9da3e6696a, 8269924c (was broken for master) --- backends/imgui_impl_glfw.cpp | 1 + backends/imgui_impl_sdl2.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 5518a823e37e..a20759747dd9 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -134,6 +134,7 @@ // We gather version tests as define in order to easily see which features are version-dependent. #define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION) +#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale #ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released? #define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR #else diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 84ecc55e0863..9fa8f296b026 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -123,6 +123,7 @@ #else #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0 #endif +#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) #define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14) #if SDL_HAS_VULKAN From 2f9c518ca89f80fccb96d5d3d335546b4ede78ef Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 15:15:27 +0200 Subject: [PATCH 647/716] Textures: ImTextureData::GetPixels() returns void* for clarity. --- imgui.h | 4 ++-- imgui_draw.cpp | 8 ++++---- imgui_internal.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.h b/imgui.h index 10eac63c9a78..061e6a9eb367 100644 --- a/imgui.h +++ b/imgui.h @@ -3440,8 +3440,8 @@ struct ImTextureData ~ImTextureData() { DestroyPixels(); } IMGUI_API void Create(ImTextureFormat format, int w, int h); IMGUI_API void DestroyPixels(); - unsigned char* GetPixels() { IM_ASSERT(Pixels != NULL); return Pixels; } - unsigned char* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } + void* GetPixels() { IM_ASSERT(Pixels != NULL); return Pixels; } + void* GetPixelsAt(int x, int y) { IM_ASSERT(Pixels != NULL); return Pixels + (x + y * Width) * BytesPerPixel; } int GetSizeInBytes() const { return Width * Height * BytesPerPixel; } int GetPitch() const { return Width * BytesPerPixel; } ImTextureRef GetTexRef() { ImTextureRef tex_ref; tex_ref._TexData = this; tex_ref._TexID = ImTextureID_Invalid; return tex_ref; } diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6ac94649176b..5a67b239abd0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2863,7 +2863,7 @@ void ImFontAtlasTextureBlockPostProcess(ImFontAtlasPostProcessData* data) void ImFontAtlasTextureBlockPostProcessMultiply(ImFontAtlasPostProcessData* data, float multiply_factor) { - unsigned char* pixels = data->Pixels; + unsigned char* pixels = (unsigned char*)data->Pixels; int pitch = data->Pitch; if (data->Format == ImTextureFormat_Alpha8) { @@ -3448,7 +3448,7 @@ void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, in { case ImTextureFormat_Alpha8: { - ImU8* out_p = tex->GetPixelsAt(x, y); + ImU8* out_p = (ImU8*)tex->GetPixelsAt(x, y); for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w) for (int off_x = 0; off_x < w; off_x++) out_p[off_x] = (in_str[off_x] == in_marker_char) ? 0xFF : 0x00; @@ -3456,7 +3456,7 @@ void ImFontAtlasBuildRenderBitmapFromString(ImFontAtlas* atlas, int x, int y, in } case ImTextureFormat_RGBA32: { - ImU32* out_p = (ImU32*)(void*)tex->GetPixelsAt(x, y); + ImU32* out_p = (ImU32*)tex->GetPixelsAt(x, y); for (int off_y = 0; off_y < h; off_y++, out_p += tex->Width, in_str += w) for (int off_x = 0; off_x < w; off_x++) out_p[off_x] = (in_str[off_x] == in_marker_char) ? IM_COL32_WHITE : IM_COL32_BLACK_TRANS; @@ -5124,7 +5124,7 @@ void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, { ImTextureData* tex = atlas->TexData; IM_ASSERT(r->x + r->w <= tex->Width && r->y + r->h <= tex->Height); - ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h); + ImFontAtlasTextureBlockConvert(src_pixels, src_fmt, src_pitch, (unsigned char*)tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h); ImFontAtlasPostProcessData pp_data = { atlas, baked->ContainerFont, src, baked, glyph, tex->GetPixelsAt(r->x, r->y), tex->Format, tex->GetPitch(), r->w, r->h }; ImFontAtlasTextureBlockPostProcess(&pp_data); ImFontAtlasTextureBlockQueueUpload(atlas, tex, r->x, r->y, r->w, r->h); diff --git a/imgui_internal.h b/imgui_internal.h index 7ff24d889a5a..b2656a7345d0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3746,7 +3746,7 @@ struct ImFontAtlasPostProcessData ImFontGlyph* Glyph; // Pixel data - unsigned char* Pixels; + void* Pixels; ImTextureFormat Format; int Pitch; int Width; From e97e55adbc025325e16a48f5970fd1e1d85d588e Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 14:46:32 +0200 Subject: [PATCH 648/716] Backends: Fixed various warnings discovered when using MinGW GCC 15/Clang on latest backends. dx12: 'ImGui_ImplDX12_Data* bd' shadowed local in spite of being in lambda. --- backends/imgui_impl_dx10.cpp | 6 ++++ backends/imgui_impl_dx11.cpp | 6 ++++ backends/imgui_impl_dx12.cpp | 47 +++++++++++++++++----------- backends/imgui_impl_dx9.cpp | 10 ++++-- backends/imgui_impl_glfw.cpp | 1 + backends/imgui_impl_sdl2.cpp | 5 ++- backends/imgui_impl_sdl3.cpp | 7 +++-- backends/imgui_impl_sdlrenderer2.cpp | 2 ++ backends/imgui_impl_sdlrenderer3.cpp | 2 ++ backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_win32.cpp | 1 + imgui_demo.cpp | 2 +- 12 files changed, 66 insertions(+), 25 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index b7be791c7eb9..6bc52156ff82 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -50,6 +50,12 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + // DirectX10 data struct ImGui_ImplDX10_Texture { diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 1917f6c0f43d..1b28745a38d0 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -52,6 +52,12 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + // DirectX11 data struct ImGui_ImplDX11_Texture { diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 1baa3c4e8e06..55785097932c 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -62,6 +62,12 @@ #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + // MinGW workaround, see #4594 typedef decltype(D3D12SerializeRootSignature) *_PFN_D3D12_SERIALIZE_ROOT_SIGNATURE; @@ -800,6 +806,28 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() } } +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +static void ImGui_ImplDX12_InitLegacySingleDescriptorMode(ImGui_ImplDX12_InitInfo* init_info) +{ + // Wrap legacy behavior of passing space for a single descriptor + IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); + init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) + { + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + IM_ASSERT(bd->LegacySingleDescriptorUsed == false && "Only 1 simultaneous texture allowed with legacy ImGui_ImplDX12_Init() signature!"); + *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor; + *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor; + bd->LegacySingleDescriptorUsed = true; + }; + init_info->SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE) + { + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + IM_ASSERT(bd->LegacySingleDescriptorUsed == true); + bd->LegacySingleDescriptorUsed = false; + }; +} +#endif + bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) { ImGuiIO& io = ImGui::GetIO(); @@ -826,24 +854,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (init_info->SrvDescriptorAllocFn == nullptr) - { - // Wrap legacy behavior of passing space for a single descriptor - IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0); - init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle) - { - ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - IM_ASSERT(bd->LegacySingleDescriptorUsed == false && "Only 1 simultaneous texture allowed with legacy ImGui_ImplDX12_Init() signature!"); - *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor; - *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor; - bd->LegacySingleDescriptorUsed = true; - }; - init_info->SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE) - { - ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - IM_ASSERT(bd->LegacySingleDescriptorUsed == true); - bd->LegacySingleDescriptorUsed = false; - }; - } + ImGui_ImplDX12_InitLegacySingleDescriptorMode(init_info); #endif IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr); diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 2617988e7ca7..5f3f3bd1c3be 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -46,6 +46,12 @@ // DirectX #include +// Clang/GCC warnings with -Weverything +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse. +#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#endif + // DirectX data struct ImGui_ImplDX9_Data { @@ -368,8 +374,8 @@ static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* sr #endif for (int y = 0; y < h; y++) { - ImU32* src_p = (ImU32*)((unsigned char*)src + src_pitch * y); - ImU32* dst_p = (ImU32*)((unsigned char*)dst + dst_pitch * y); + const ImU32* src_p = (const ImU32*)(void*)((const unsigned char*)src + src_pitch * y); + ImU32* dst_p = (ImU32*)(void*)((unsigned char*)dst + dst_pitch * y); if (convert_rgba_to_bgra) for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy *dst_p = IMGUI_COL_TO_DX9_ARGB(*src_p); diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index a20759747dd9..d0a75ac78438 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -545,6 +545,7 @@ static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wPara case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP: io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo()); break; + default: break; } return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam); } diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 9fa8f296b026..9f5e0374aaee 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -104,6 +104,7 @@ // Clang warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #endif @@ -434,7 +435,7 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) // (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod); ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode); io.AddKeyEvent(key, (event->type == SDL_KEYDOWN)); - io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. + io.SetKeyEventNativeData(key, (int)event->key.keysym.sym, (int)event->key.keysym.scancode, (int)event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. return true; } case SDL_WINDOWEVENT: @@ -466,6 +467,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) bd->WantUpdateGamepadsList = true; return true; } + default: + break; } return false; } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 4f099595af84..68fc4d746c47 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -64,6 +64,7 @@ // Clang warnings with -Weverything #if defined(__clang__) #pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision #endif @@ -409,7 +410,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod); ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode); io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN)); - io.SetKeyEventNativeData(key, event->key.key, event->key.scancode, event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. + io.SetKeyEventNativeData(key, (int)event->key.key, (int)event->key.scancode, (int)event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions. return true; } case SDL_EVENT_WINDOW_MOUSE_ENTER: @@ -445,6 +446,8 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) bd->WantUpdateGamepadsList = true; return true; } + default: + break; } return false; } @@ -471,7 +474,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void // Setup backend capabilities flags ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)(); - snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl3 (%u.%u.%u; %u.%u.%u)", + snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl3 (%d.%d.%d; %d.%d.%d)", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, SDL_VERSIONNUM_MAJOR(ver_linked), SDL_VERSIONNUM_MINOR(ver_linked), SDL_VERSIONNUM_MICRO(ver_linked)); io.BackendPlatformUserData = (void*)bd; io.BackendPlatformName = bd->BackendPlatformName; diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index bcc4404ff7a2..a39360f5cf8f 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -44,6 +44,8 @@ #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #endif // SDL diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 77b5bc059600..f62949150bde 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -41,6 +41,8 @@ #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness +#elif defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe #endif // SDL diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index a0f787e8a504..5546a59ff03a 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1250,7 +1250,7 @@ void ImGui_ImplVulkan_Shutdown() ImGui_ImplVulkan_DestroyDeviceObjects(); #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - IM_FREE((void*)bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats); + IM_FREE((void*)const_cast(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats)); #endif io.BackendRendererName = nullptr; diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index cd5e2dbf20b1..d7206b97051d 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -571,6 +571,7 @@ ImGuiKey ImGui_ImplWin32_KeyEventToImGuiKey(WPARAM wParam, LPARAM lParam) case 51: return ImGuiKey_Comma; case 52: return ImGuiKey_Period; case 53: return ImGuiKey_Slash; + default: break; } return ImGuiKey_None; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8999320666e7..a979b9e920d0 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8146,7 +8146,7 @@ void ImGui::ShowAboutWindow(bool* p_open) if (io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) ImGui::Text(" RendererHasTextures"); ImGui::Separator(); ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexData->Width, io.Fonts->TexData->Height); - ImGui::Text("io.Fonts->FontLoaderName: \"%s\"", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL"); + ImGui::Text("io.Fonts->FontLoaderName: %s", io.Fonts->FontLoaderName ? io.Fonts->FontLoaderName : "NULL"); ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y); ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y); ImGui::Separator(); From afe20dc9b608e29b2e75964327287cf5588c1d2d Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 20 Jun 2025 15:23:52 +0200 Subject: [PATCH 649/716] Backends: warning fix. --- backends/imgui_impl_dx9.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 5f3f3bd1c3be..b0159bf371af 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -374,7 +374,7 @@ static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* sr #endif for (int y = 0; y < h; y++) { - const ImU32* src_p = (const ImU32*)(void*)((const unsigned char*)src + src_pitch * y); + const ImU32* src_p = (const ImU32*)(const void*)((const unsigned char*)src + src_pitch * y); ImU32* dst_p = (ImU32*)(void*)((unsigned char*)dst + dst_pitch * y); if (convert_rgba_to_bgra) for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy From 0dc2885f3e0890585a0fa61a1ea041df9609b0ab Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Jun 2025 13:04:06 +0200 Subject: [PATCH 650/716] InputText: fix for InsertChars() to work on read-only buffer. (#8714, #8689, #8242) Ill defined feature but memory editor use InsertChars etc on a read-only buffer. `if (init_state)` block of InputTextEx() intentionally does not resize TextA, as unneeded. Amend b2c73596aeaf63b46b66a615ec02fce1b87f4248 Amend e900571 --- imgui_widgets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 43d98bb88dd0..d7214b6c237a 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4289,7 +4289,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons // Grow internal buffer if needed const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)ImStrlen(new_text); - if (new_text_len + BufTextLen + 1 > obj->TextA.Size) + if (new_text_len + BufTextLen + 1 > obj->TextA.Size && (Flags & ImGuiInputTextFlags_ReadOnly) == 0) { if (!is_resizable) return; From 613a6a964c9183c1fcdffde792ae96bc9fdfb944 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 10:27:24 +0200 Subject: [PATCH 651/716] Fonts: AddFontDefault() adds to GlyphOffset.y instead of overriding it. --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 5a67b239abd0..0b41751265dc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3102,7 +3102,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template) if (font_cfg.Name[0] == '\0') ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf"); font_cfg.EllipsisChar = (ImWchar)0x0085; - font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units + font_cfg.GlyphOffset.y += 1.0f * IM_TRUNC(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units int ttf_compressed_size = 0; const char* ttf_compressed = GetDefaultCompressedFontDataTTF(&ttf_compressed_size); From a49ddaac897538aee7b8dffe4f7cc537ac9e8e9a Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 10:50:30 +0200 Subject: [PATCH 652/716] Fonts: add comments and examples for GlyphExcludeRanges[]. --- docs/CHANGELOG.txt | 22 +++++++++++++++++++++- docs/FONTS.md | 39 +++++++++++++++++++++++++++++++++++++++ imgui.cpp | 19 +++++++++++++++++-- imgui.h | 2 +- 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 71549deb53f7..4b879a6cb0be 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,7 +62,7 @@ Breaking changes: - Fonts: **IMPORTANT**: if your app was solving the OSX/iOS Retina screen specific logical vs display scale problem by setting io.DisplayFramebufferScale (e.g. to 2.0f) + setting io.FontGlobalScale (e.g. to 1.0f/2.0f) + loading fonts at scaled sizes (e.g. size X * 2.0f): - This WILL NOT map correctly to the new system! Because font will rasterize as requested size. + - This WILL NOT map correctly to the new system! Because font will rasterize as requested size. - With a legacy backend (< 1.92): - Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. - This already worked before, but is now pretty much required. @@ -84,6 +84,26 @@ Breaking changes: - ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. +- Fonts: **IMPORTANT** on Font Merging: + - When searching for a glyph in multiple merged fonts: font inputs are now scanned in order + for the first font input which the desired glyph. This is technically a different behavior + than before! + - e.g. If you are merging fonts you may have glyphs that you expected to load from + Font Source 2 which exists in Font Source 1. After the update and when using a new backend, + those glyphs may now loaded from Font Source 1! + - You can use `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to ignore in given Input: + // Add Font Source 1 but ignore ICON_MIN_FA..ICON_MAX_FA range + static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + ImFontConfig cfg1; + cfg1.GlyphExcludeRanges = exclude_ranges; + io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1); + // Add Font Source 2, which expects to use the range above + ImFontConfig cfg2; + cfg2.MergeMode = true; + io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2); + - You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to + see list of glyphs available in multiple font sources. This can facilitate understanding + which font input is providing which glyph. - Textures: - All API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef': diff --git a/docs/FONTS.md b/docs/FONTS.md index 95538f97d0ae..8edfbd33ba89 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -18,6 +18,7 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo - [Loading Font Data from Memory](#loading-font-data-from-memory) - [Loading Font Data Embedded In Source Code](#loading-font-data-embedded-in-source-code) - [Using Icon Fonts](#using-icon-fonts) + - [Excluding Overlapping Ranges](#excluding-overlapping-ranges) - [Using FreeType Rasterizer (imgui_freetype)](#using-freetype-rasterizer-imgui_freetype) - [Using Colorful Glyphs/Emojis](#using-colorful-glyphsemojis) - [Using Custom Glyph Ranges](#using-custom-glyph-ranges) @@ -313,6 +314,44 @@ Here's an application using icons ("Avoyd", https://www.avoyd.com): --------------------------------------- +### Excluding Overlapping Ranges + +🆕 **Since 1.92, with an up to date backend: glyphs ranges are ignored**: when loading a glyph, input fonts in the merge list are queried in order. The first font which has the glyph loads it. +
‼️ **If you are merging several fonts, you may have undesirable overlapping ranges.** You can use `ImFontConfig::GlyphExcludeRanges[] `to specify ranges to ignore in a given Input. + +```cpp +// Add Font Source 1 but ignore ICON_MIN_FA..ICON_MAX_FA range +static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; +ImFontConfig cfg1; +cfg1.GlyphExcludeRanges = exclude_ranges; +io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1); + +// Add Font Source 2, which expects to use the range above +ImFontConfig cfg2; +cfg2.MergeMode = true; +io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2); +``` +Another (silly) example: +```cpp +// Remove 'A'-'Z' from first font +static ImWchar exclude_ranges[] = { 'A', 'Z', 0 }; +ImFontConfig cfg1; +cfg1.GlyphExcludeRanges = exclude_ranges; +io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1); + +// Load another font to fill the gaps +ImFontConfig cfg2; +cfg2.MergeMode = true; +io.Fonts->AddFontFromFileTTF("Roboto-Medium.ttf", 0.0f, &cfg2); +``` +![image](https://github.com/user-attachments/assets/f3d751d3-1aee-4698-bd9b-f511902f56bb) + +You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate understanding which font input is providing which glyph. + +##### [Return to Index](#index) + +--------------------------------------- + ## Using FreeType Rasterizer (imgui_freetype) - Dear ImGui uses [stb_truetype.h](https://github.com/nothings/stb/) to rasterize fonts (with optional oversampling). This technique and its implementation are not ideal for fonts rendered at small sizes, which may appear a little blurry or hard to read. diff --git a/imgui.cpp b/imgui.cpp index af22c37fada2..2b4a98802972 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -474,6 +474,20 @@ CODE - Before 1.92: ImGui::PushFont() always used font "default" size specified in AddFont() call. - Since 1.92: ImGui::PushFont() preserve the current font size which is a shared value. - To use old behavior: (A) use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). (B) Set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call (not desirable as it requires e.g. third-party code to be aware of it). + - Fonts: **IMPORTANT** on Font Merging: + - When searching for a glyph in multiple merged fonts: font inputs are now scanned in orderfor the first font input which the desired glyph. This is technically a different behavior than before! + - e.g. If you are merging fonts you may have glyphs that you expected to load from Font Source 2 which exists in Font Source 1. After the update and when using a new backend, those glyphs may now loaded from Font Source 1! + - You can use `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to ignore in given Input: + // Add Font Source 1 but ignore ICON_MIN_FA..ICON_MAX_FA range + static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + ImFontConfig cfg1; + cfg1.GlyphExcludeRanges = exclude_ranges; + io.Fonts->AddFontFromFileTTF("segoeui.ttf", 0.0f, &cfg1); + // Add Font Source 2, which expects to use the range above + ImFontConfig cfg2; + cfg2.MergeMode = true; + io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2); + - You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate unde - Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. - Textures: all API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef'. Affected functions are: ImGui::Image(), ImGui::ImageWithBg(), ImGui::ImageButton(), ImDrawList::AddImage(), ImDrawList::AddImageQuad(), ImDrawList::AddImageRounded(). @@ -3932,7 +3946,7 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso ImGuiContext& g = *GImGui; if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values. mouse_cursor = ImGuiMouseCursor_Arrow; - ImFontAtlas* font_atlas = g.DrawListSharedData.FontAtlas; + ImFontAtlas* font_atlas = g.DrawListSharedData.FontAtlas; for (ImGuiViewportP* viewport : g.Viewports) { // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. @@ -16958,7 +16972,8 @@ void ImGui::DebugNodeFont(ImFont* font) } if (font->Sources.Size > 1 && TreeNode("Input Glyphs Overlap Detection Tool")) { - TextWrapped("- First Input that contains the glyph is used.\n- Use ImFontConfig::GlyphExcludeRanges[] to specify ranges to ignore glyph in given Input.\n- This tool doesn't cache results and is slow, don't keep it open!"); + TextWrapped("- First Input that contains the glyph is used.\n" + "- Use ImFontConfig::GlyphExcludeRanges[] to specify ranges to ignore glyph in given Input.\n- Prefer using a small number of ranges as the list is scanned every time a new glyph is loaded,\n - e.g. GlyphExcludeRanges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };\n- This tool doesn't cache results and is slow, don't keep it open!"); if (BeginTable("table", 2)) { for (unsigned int c = 0; c < 0x10000; c++) diff --git a/imgui.h b/imgui.h index 061e6a9eb367..ba8001d877cb 100644 --- a/imgui.h +++ b/imgui.h @@ -3474,7 +3474,7 @@ struct ImFontConfig ImS8 OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). const ImWchar* GlyphRanges; // NULL // *LEGACY* THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). - const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a VERY SHORT user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. + const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a small user-provided list of Unicode ranges (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. //ImVec2 GlyphExtraSpacing; // 0, 0 // (REMOVED AT IT SEEMS LARGELY OBSOLETE. PLEASE REPORT IF YOU WERE USING THIS). Extra spacing (in pixels) between glyphs when rendered: essentially add to glyph->AdvanceX. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset (in pixels) all glyphs from this font input. Absolute value for default size, other sizes will scale this value. float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. From 608dd96de654b9831c9d2c7d31fd0806df4b358e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 12:21:07 +0200 Subject: [PATCH 653/716] Fonts: fixed RenderText() asserting when crossing VtxOffset change boundaries. (#8720, #8465) --- imgui_draw.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0b41751265dc..8d56c01780eb 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5581,7 +5581,6 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im return; // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized) - const int cmd_count = draw_list->CmdBuffer.Size; const int vtx_count_max = (int)(text_end - s) * 4; const int idx_count_max = (int)(text_end - s) * 6; const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max; @@ -5589,6 +5588,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im ImDrawVert* vtx_write = draw_list->_VtxWritePtr; ImDrawIdx* idx_write = draw_list->_IdxWritePtr; unsigned int vtx_index = draw_list->_VtxCurrentIdx; + const int cmd_count = draw_list->CmdBuffer.Size; const ImU32 col_untinted = col | ~IM_COL32_A_MASK; const char* word_wrap_eol = NULL; @@ -5711,6 +5711,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im draw_list->CmdBuffer.pop_back(); draw_list->PrimUnreserve(idx_count_max, vtx_count_max); draw_list->AddDrawCmd(); + //IMGUI_DEBUG_LOG("RenderText: cancel and retry to missing glyphs.\n"); // [DEBUG] + //draw_list->AddRectFilled(pos, pos + ImVec2(10, 10), IM_COL32(255, 0, 0, 255)); // [DEBUG] goto begin; //RenderText(draw_list, size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip); // FIXME-OPT: Would a 'goto begin' be better for code-gen? //return; From 6e846c56b4823110269eb6530468eaf5b106019c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 12:25:04 +0200 Subject: [PATCH 654/716] Demo: fixed ID conflicts. (#8723) --- imgui_demo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index a979b9e920d0..8a4c4584e864 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -4444,11 +4444,11 @@ static void DemoWindowLayout() ImGui::Text("SetNextItemWidth/PushItemWidth(-Min(GetContentRegionAvail().x * 0.40f, GetFontSize() * 12))"); ImGui::PushItemWidth(-IM_MIN(ImGui::GetFontSize() * 12, ImGui::GetContentRegionAvail().x * 0.40f)); - ImGui::DragFloat("float##4a", &f); + ImGui::DragFloat("float##5a", &f); if (show_indented_items) { ImGui::Indent(); - ImGui::DragFloat("float (indented)##4b", &f); + ImGui::DragFloat("float (indented)##5b", &f); ImGui::Unindent(); } ImGui::PopItemWidth(); @@ -4458,11 +4458,11 @@ static void DemoWindowLayout() ImGui::Text("SetNextItemWidth/PushItemWidth(-FLT_MIN)"); ImGui::SameLine(); HelpMarker("Align to right edge"); ImGui::PushItemWidth(-FLT_MIN); - ImGui::DragFloat("##float5a", &f); + ImGui::DragFloat("##float6a", &f); if (show_indented_items) { ImGui::Indent(); - ImGui::DragFloat("float (indented)##5b", &f); + ImGui::DragFloat("float (indented)##6b", &f); ImGui::Unindent(); } ImGui::PopItemWidth(); From 6722d789e91b78f8c1565dbeabfbacd8a1ce87a7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 14:44:38 +0200 Subject: [PATCH 655/716] (Breaking) Fonts: Removed support for PushFont(NULL) which was a shortcut for "default font". --- docs/CHANGELOG.txt | 1 + imgui.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4b879a6cb0be..1f166b629728 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -83,6 +83,7 @@ Breaking changes: (not desirable as it requires e.g. all third-party code to be aware of it). - ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). + - Removed support for PushFont(NULL) which was a shortcut for "default font". - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. - Fonts: **IMPORTANT** on Font Merging: - When searching for a glyph in multiple merged fonts: font inputs are now scanned in order diff --git a/imgui.cpp b/imgui.cpp index 2b4a98802972..1234bce4d62d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -489,6 +489,7 @@ CODE io.Fonts->AddFontFromFileTTF("FontAwesome4.ttf", 0.0f, &cfg2); - You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` to see list of glyphs available in multiple font sources. This can facilitate unde - Fonts: ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). + - Fonts: Removed support for PushFont(NULL) which was a shortcut for "default font". - Fonts: Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. - Textures: all API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef'. Affected functions are: ImGui::Image(), ImGui::ImageWithBg(), ImGui::ImageButton(), ImDrawList::AddImage(), ImDrawList::AddImageQuad(), ImDrawList::AddImageRounded(). - Fonts: obsoleted ImFontAtlas::GetTexDataAsRGBA32(), GetTexDataAsAlpha8(), Build(), SetTexID(), IsBuilt() functions. The new protocol for backends to handle textures doesn't need them. Kept redirection functions (will obsolete). @@ -8906,9 +8907,11 @@ void ImGui::SetFontRasterizerDensity(float rasterizer_density) void ImGui::PushFont(ImFont* font, float font_size_base) { ImGuiContext& g = *GImGui; + //if (font == NULL) // Before 1.92 (June 2025), PushFont(NULL) == PushFont(GetDefaultFont()) + // font = g.Font; + IM_ASSERT(font != NULL); + g.FontStack.push_back({ g.Font, g.FontSizeBase, g.FontSize }); - if (font == NULL) - font = GetDefaultFont(); if (font_size_base <= 0.0f) { if (font->Flags & ImFontFlags_DefaultToLegacySize) From 0218ddd5753f0b028ad65a5a1a6b4ce0fdc41168 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 15:00:42 +0200 Subject: [PATCH 656/716] Fonts: moved GetFont(), GetFontSize(), GetFontBaked() to higher section. --- imgui.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index ba8001d877cb..b73089d661e6 100644 --- a/imgui.h +++ b/imgui.h @@ -499,14 +499,16 @@ namespace ImGui // - To use old behavior (single size font, size specified in AddFontXXX() call: // - Use 'PushFont(font, font->LegacySize)' at call site // - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then 'PushFont(font)' will use this size. - // - External scale factors are applied over the provided value. - // *IMPORTANT* If you want to scale an existing font size: - // - OK: PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). - // - KO: PushFontSize(GetFontSize() * factor) (= value after external scale factors applied. external scale factors are style.FontScaleMain + per-viewport scales.). + // *IMPORTANT* External scale factors are applied over the provided value. If you want to scale an existing font size: + // - OK: PushFontSize(style.FontSizeBase * 2.0f) (= value before external scale factors applied). + // - NOT OK: PushFontSize(GetFontSize() * 2.0f) (= value after external scale factors applied. External scale factors are: 'style.FontScaleMain * style.FontScaleDpi * maybe more'). IMGUI_API void PushFont(ImFont* font, float font_size_base = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. IMGUI_API void PopFont(); - IMGUI_API void PushFontSize(float font_size_base); + IMGUI_API void PushFontSize(float font_size_base); // keep current font, change its size. Final 'font size = font_size_base * external scale factors'. IMGUI_API void PopFontSize(); + IMGUI_API ImFont* GetFont(); // get current font + IMGUI_API float GetFontSize(); // get current font size (= height in pixels) AFTER external scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()/PushFontSize()! Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. + IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) // Parameters stacks (shared) IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame(). @@ -530,10 +532,7 @@ namespace ImGui // Style read access // - Use the ShowStyleEditor() function to interactively see/edit the colors. - IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with external scale factors applied. Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API - IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList From 776897d3c9ae721dcb1dfa935162a67dbac7a69d Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 15:24:09 +0200 Subject: [PATCH 657/716] Fonts: fixed PVS Studio false positive "expression 'cmd_count != draw_list->CmdBuffer.Size' is always false." (#8720, #8465) Amend 608dd96 --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 8d56c01780eb..50b486cada5c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5705,7 +5705,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im } // Edge case: calling RenderText() with unloaded glyphs triggering texture change. It doesn't happen via ImGui:: calls because CalcTextSize() is always used. - if (cmd_count != draw_list->CmdBuffer.Size) + if (cmd_count != draw_list->CmdBuffer.Size) //-V547 { IM_ASSERT(draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount == 0); draw_list->CmdBuffer.pop_back(); From 04a5b9c2cf58c78b116e4dbcfe90f8cb1eec2a07 Mon Sep 17 00:00:00 2001 From: Geert Bleyen Date: Tue, 24 Jun 2025 16:13:44 +0200 Subject: [PATCH 658/716] Backends: SDL3: fixed pulling SDL_PROP_WINDOW_COCOA_WINDOW_POINTER into viewport->PlatformHandleRaw. (#8725, #8726) SDL_VIDEO_DRIVER_COCOA does not exist on SDL3. --- backends/imgui_impl_sdl3.cpp | 2 +- docs/CHANGELOG.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 68fc4d746c47..9c0d6581cea0 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -458,7 +458,7 @@ static void ImGui_ImplSDL3_SetupPlatformHandles(ImGuiViewport* viewport, SDL_Win viewport->PlatformHandleRaw = nullptr; #if defined(_WIN32) && !defined(__WINRT__) viewport->PlatformHandleRaw = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); -#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA) +#elif defined(__APPLE__) viewport->PlatformHandleRaw = SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); #endif } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1f166b629728..948b3d326bf9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -445,6 +445,8 @@ Other changes: memory ownership change. (#8530, #7801) [@Green-Sky] - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) + - Backends: SDL3: fixed pulling SDL_PROP_WINDOW_COCOA_WINDOW_POINTER into + viewport->PlatformHandleRaw. (#8725, #8726) [@eertbleyen] - Backends: OSX: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644) [@BingoXuan] - Examples: From ca72eb059648efdba4617170005206d7d44539dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 18:53:40 +0200 Subject: [PATCH 659/716] (Breaking) Fonts: obsolete PushFont() default parameter. --- docs/CHANGELOG.txt | 26 +++++++++++++++++--------- imgui.cpp | 20 ++++++++++---------- imgui.h | 30 ++++++++++++++++++------------ 3 files changed, 45 insertions(+), 31 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 948b3d326bf9..d468b60ae21d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -73,17 +73,25 @@ Breaking changes: Platform_GetWindowFramebufferScale() handler in 'docking' branch. - Fonts: **IMPORTANT** on Font Sizing: - Before 1.92, fonts were of a single size. They can now be dynamically sized. - - PushFont() API now has an optional size parameter. PushFontSize() was also added. - void PushFont(ImFont* font) --> void PushFont(ImFont* font, float size = 0.0f); - - Before 1.92: ImGui::PushFont() always used font "default" size specified in AddFont() call. - - Since 1.92: ImGui::PushFont() preserve the current font size which is a shared value. + - PushFont() API now has a REQUIRED size parameter. + void PushFont(ImFont* font) --> void PushFont(ImFont* font, float size); + - PushFont(font, 0.0f) // Change font and keep current size + - PushFont(NULL, 20.0f) // Keep font and change current size + - PushFont(font, 20.0f) // Change font and set size to 20.0f + - PushFont(font, style.FontSizeBase * 2.0f) // Change font and set size to be twice bigger than current size. + - PushFont(font, font->LegacySize) // Change font and set size to size passed to AddFontXXX() function. Same as pre-1.92 behavor, for fixed size fonts. - To use old behavior: - use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). - or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call (not desirable as it requires e.g. all third-party code to be aware of it). + We intentionally didn't add a default parameter because it would make the long-term + transition more difficult. + - Kept inline redirection font. Will obsolete. + - External scale factors may be applied over the provided size. + This is why it is called 'FontSizeBase' in the style structure. - ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - - Removed support for PushFont(NULL) which was a shortcut for "default font". + - Removed support for old PushFont(NULL) which was a shortcut for "revert to default font". - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. - Fonts: **IMPORTANT** on Font Merging: - When searching for a glyph in multiple merged fonts: font inputs are now scanned in order @@ -182,8 +190,8 @@ Breaking changes: - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader() - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader(); -- DrawList: Fixed a regression from 1.91.1 where a Begin()/PushFont()/AddImage() sequence - would not restore the correct atlas Texture Identifier when the PushFont() call used +- DrawList: Fixed a regression from 1.91.1 where a Begin()/PushFont()/AddImage() sequence + would not restore the correct atlas Texture Identifier when the PushFont() call used a font from a different atlas. (#8694, caused by #3224, #3875, #6398, #7903) - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). - Fonts: (users of custom rectangles) @@ -332,7 +340,7 @@ Other changes: one in docking (they accidentally diverged). (#8554) - Windows: BeginChild(): fixed being unable to combine manual resize on one axis and automatic resize on the other axis. (#8690) - e.g. neither ImGuiChildFlags_ResizeX | ImGuiChildFlags_AutoResizeY + e.g. neither ImGuiChildFlags_ResizeX | ImGuiChildFlags_AutoResizeY or ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX worked before. - TreeNode: added experimental flags to draw tree hierarchy outlines linking parent and tree nodes: (#2920) @@ -357,7 +365,7 @@ Other changes: - TreeNode: fixed incorrect clipping of arrow/bullet when using ImGuiTreeNodeFlags_SpanAllColumns. - InputText: fixed cursor positioning issue using up/down keys near end of lines while editing non-ASCII text. (Regression from 1.91.2) (#8635, #7925) -- InputText: fixed a buffer overrun that could happen when using dynamically resizing +- InputText: fixed a buffer overrun that could happen when using dynamically resizing buffers (e.g. imgui_stdlib.cpp for std::string, or ImGuiInputTextFlags_CallbackRezize) and programmatically making an insertion. (#8689) [@ocornut, @m9710797] - Tables: fixed TableHeader() eager vertical clipping of text which may be noticeable diff --git a/imgui.cpp b/imgui.cpp index 1234bce4d62d..44a613ac9c86 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -470,10 +470,11 @@ CODE - With a legacy backend (< 1.92): Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. This already worked before, but is now pretty much required. - With a new backend (1.92+): This should be all automatic. FramebufferScale is automatically used to set current font RasterizerDensity. FramebufferScale is a per-viewport property provided by backend through the Platform_GetWindowFramebufferScale() handler in 'docking' branch. - Fonts: **IMPORTANT** on Font Sizing: Before 1.92, fonts were of a single size. They can now be dynamically sized. - - PushFont() API now has an optional size parameter. PushFontSize() was also added. - - Before 1.92: ImGui::PushFont() always used font "default" size specified in AddFont() call. - - Since 1.92: ImGui::PushFont() preserve the current font size which is a shared value. + - PushFont() API now has a REQUIRED size parameter. PushFontSize() was also added. + - Before 1.92: PushFont() always used font "default" size specified in AddFont() call. It is equivalent to calling PushFont(font, font->LegacySize). + - Since 1.92: PushFont(font, 0.0f) preserve the current font size which is a shared value. - To use old behavior: (A) use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). (B) Set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call (not desirable as it requires e.g. third-party code to be aware of it). + - Kept inline single parameter function. Will obsolete. - Fonts: **IMPORTANT** on Font Merging: - When searching for a glyph in multiple merged fonts: font inputs are now scanned in orderfor the first font input which the desired glyph. This is technically a different behavior than before! - e.g. If you are merging fonts you may have glyphs that you expected to load from Font Source 2 which exists in Font Source 1. After the update and when using a new backend, those glyphs may now loaded from Font Source 1! @@ -8901,23 +8902,22 @@ void ImGui::SetFontRasterizerDensity(float rasterizer_density) UpdateCurrentFontSize(0.0f); } -// If you want to scale an existing font size: -// - Use e.g. PushFontSize(style.FontSizeBase * factor) (= value before external scale factors applied). -// - Do NOT use PushFontSize(GetFontSize() * factor) (= value after external scale factors applied). +// If you want to scale an existing font size! Read comments in imgui.h! void ImGui::PushFont(ImFont* font, float font_size_base) { ImGuiContext& g = *GImGui; //if (font == NULL) // Before 1.92 (June 2025), PushFont(NULL) == PushFont(GetDefaultFont()) // font = g.Font; IM_ASSERT(font != NULL); + IM_ASSERT(font_size_base >= 0.0f); g.FontStack.push_back({ g.Font, g.FontSizeBase, g.FontSize }); - if (font_size_base <= 0.0f) + if (font_size_base == 0.0f) { if (font->Flags & ImFontFlags_DefaultToLegacySize) - font_size_base = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) + font_size_base = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) else - font_size_base = g.FontSizeBase; // Keep current font size + font_size_base = g.FontSizeBase; // Keep current font size } SetCurrentFont(font, font_size_base, 0.0f); } @@ -16909,7 +16909,7 @@ void ImGui::DebugNodeFont(ImFont* font) Indent(); if (cfg->ShowFontPreview) { - PushFont(font); + PushFont(font, 0.0f); Text("The quick brown fox jumps over the lazy dog"); PopFont(); } diff --git a/imgui.h b/imgui.h index b73089d661e6..2c361c4cf1d9 100644 --- a/imgui.h +++ b/imgui.h @@ -493,21 +493,26 @@ namespace ImGui IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position. // Parameters stacks (font) + // - PushFont(font, 0.0f) // Change font and keep current size + // - PushFont(NULL, 20.0f) // Keep font and change current size + // - PushFont(font, 20.0f) // Change font and set size to 20.0f + // - PushFont(font, style.FontSizeBase * 2.0f) // Change font and set size to be twice bigger than current size. + // - PushFont(font, font->LegacySize) // Change font and set size to size passed to AddFontXXX() function. Same as pre-1.92 behavior. // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. - // - Before 1.92: PushFont() always used font default size. - // - Since 1.92: PushFont() preserve the current shared font size. - // - To use old behavior (single size font, size specified in AddFontXXX() call: - // - Use 'PushFont(font, font->LegacySize)' at call site - // - Or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' before calling AddFont(), and then 'PushFont(font)' will use this size. - // *IMPORTANT* External scale factors are applied over the provided value. If you want to scale an existing font size: - // - OK: PushFontSize(style.FontSizeBase * 2.0f) (= value before external scale factors applied). - // - NOT OK: PushFontSize(GetFontSize() * 2.0f) (= value after external scale factors applied. External scale factors are: 'style.FontScaleMain * style.FontScaleDpi * maybe more'). - IMGUI_API void PushFont(ImFont* font, float font_size_base = -1); // use NULL as a shortcut to push default font. Use <0.0f to keep current font size. + // - In 1.92 we have REMOVED the single parameter version of PushFont() because it seems like the easiest way to provide an error-proof transition. + // - PushFont(font) before 1.92 = PushFont(font, font->LegacySize) after 1.92 // Use default font size as passed to AddFontXXX() function. + // *IMPORTANT* external scale factors are applied over the provided size. If you want to scale an *existing* font size: + // - External scale factors are: 'style.FontScaleMain * style.FontScaleDpi' and maybe more. + // - CORRECT: PushFont(NULL, style.FontSizeBase) // use current unscaled size == does nothing + // - CORRECT: PushFont(NULL, style.FontSizeBase * 2.0f) // use current unscaled size x2 == make text twice bigger + // - INCORRECT: PushFont(NULL, GetFontSize()) // INCORRECT! use size after external factors applied == EXTERNAL SCALING FACTORS WILL APPLY TWICE! + // - INCORRECT: PushFont(NULL, GetFontSize() * 2.0f) // INCORRECT! use size after external factors applied == EXTERNAL SCALING FACTORS WILL APPLY TWICE! + IMGUI_API void PushFont(ImFont* font, float font_size_base_unscaled); // Use NULL as a shortcut to keep current font. Use 0.0f to keep current size. IMGUI_API void PopFont(); IMGUI_API void PushFontSize(float font_size_base); // keep current font, change its size. Final 'font size = font_size_base * external scale factors'. IMGUI_API void PopFontSize(); IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current font size (= height in pixels) AFTER external scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()/PushFontSize()! Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. + IMGUI_API float GetFontSize(); // get current scaled font size (= height in pixels). AFTER external scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()/PushFontSize()! Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) // Parameters stacks (shared) @@ -3756,7 +3761,7 @@ struct ImFontBaked enum ImFontFlags_ { ImFontFlags_None = 0, - ImFontFlags_DefaultToLegacySize = 1 << 0, // Legacy compatibility: make PushFont() calls without explicit size use font->LegacySize instead of current font size. + ImFontFlags_DefaultToLegacySize = 1 << 0, // Legacy compatibility: make `PushFont(font)` == `PushFont(font, font->LegacySize)`. Otherwise by default/shared current font size is used. ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display. @@ -3949,7 +3954,8 @@ struct ImGuiPlatformImeData namespace ImGui { // OBSOLETED in 1.92.0 (from June 2025) - IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFontSize(style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. + static inline void PushFont(ImFont* font) { IM_ASSERT(font != NULL); PushFont(font, font->LegacySize); } + IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFont(NULL, style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. // OBSOLETED in 1.91.9 (from February 2025) IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. // OBSOLETED in 1.91.0 (from July 2024) From 97e0d59619f0796f64be2a4b35383e422c93b5d6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 19:01:59 +0200 Subject: [PATCH 660/716] (Breaking) Fonts: removed PushFontSize(), PopFontSize(). --- docs/CHANGELOG.txt | 3 +-- docs/FAQ.md | 2 +- docs/FONTS.md | 2 +- docs/TODO.txt | 1 - imgui.cpp | 21 ++++----------------- imgui.h | 6 ++---- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- 8 files changed, 11 insertions(+), 28 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d468b60ae21d..7c7daf79d472 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -150,7 +150,7 @@ Breaking changes: ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using - PushFontSize(style.FontSizeBase * factor) or to manipulate other scaling factors. + PushFont(NULL, style.FontSizeBase * factor) or to manipulate other scaling factors. - Fonts: obsoleted ImFont::Scale which is not useful anymore. - Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition(): - old: const char* CalcWordWrapPositionA(float scale, const char* text, ....); @@ -270,7 +270,6 @@ Other changes: - Fonts: ImFontAtlas::AddFontXXX() functions may be called at any time during the frame. - Fonts: ImFontAtlas::AddFontXXX() can fail more gracefully if error handling is configured to not assert (this will be better exposed via future font flags). -- Fonts: added ImGui::PushFontSize()/PopFontSize() functions. - Fonts: added style.FontScaleBase scaling factor (previously called io.FontGlobalScale). - Fonts: added style.FontScaleDpi scaling factor. This is designed to be be changed on per-monitor/per-viewport basis, which `io.ConfigDpiScaleFonts` does automatically. diff --git a/docs/FAQ.md b/docs/FAQ.md index 0e8ba5c774eb..ad35d5451b0d 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -572,7 +572,7 @@ Since 1.92 (June 2025) fonts may be dynamically used at any size. To change font size: ```cpp -ImGui::PushFontSize(42.0f); +ImGui::PushFont(NULL, 42.0f); ``` To change font and font size: ```cpp diff --git a/docs/FONTS.md b/docs/FONTS.md index 8edfbd33ba89..5a43b4403e47 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -77,7 +77,7 @@ Future versions of Dear ImGui should solve this problem. v1.92 introduces a newer, dynamic font system. It requires backend to support the `ImGuiBackendFlags_HasTextures` feature: - Users of icons, Asian and non-English languages do not need to pre-build all glyphs ahead of time. Saving on loading time, memory, and also reducing issues with missing glyphs. Specifying glyph ranges is not needed anymore. -- `PushFontSize()` may be used anytime to change font size. +- `PushFont(NULL, new_size)` may be used anytime to change font size. - Packing custom rectangles is more convenient as pixels may be written to immediately. - Any update to fonts previously required backend specific calls to re-upload the texture, and said calls were not portable across backends. It is now possible to scale fonts etc. in a way that doesn't require you to make backend-specific calls. - It is possible to plug a custom loader/backend to any font source. diff --git a/docs/TODO.txt b/docs/TODO.txt index 8866d04fbef9..03deffb2dc70 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -249,7 +249,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data - font: remove ID from CustomRect registration, it seems unnecessary! - font: make it easier to submit own bitmap font (same texture, another texture?). (#2127, #2575) - - font: PushFontSize API (#1018) - font: MemoryTTF taking ownership confusing/not obvious, maybe default should be opposite? - font: storing MinAdvanceX per font would allow us to skip calculating line width (under a threshold of character count) in loops looking for block width - font/demo: add tools to show glyphs used by a text blob, display U16 value, list missing glyphs. diff --git a/imgui.cpp b/imgui.cpp index 44a613ac9c86..eceda68f1e94 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -470,7 +470,7 @@ CODE - With a legacy backend (< 1.92): Instead of setting io.FontGlobalScale = 1.0f/N -> set ImFontCfg::RasterizerDensity = N. This already worked before, but is now pretty much required. - With a new backend (1.92+): This should be all automatic. FramebufferScale is automatically used to set current font RasterizerDensity. FramebufferScale is a per-viewport property provided by backend through the Platform_GetWindowFramebufferScale() handler in 'docking' branch. - Fonts: **IMPORTANT** on Font Sizing: Before 1.92, fonts were of a single size. They can now be dynamically sized. - - PushFont() API now has a REQUIRED size parameter. PushFontSize() was also added. + - PushFont() API now has a REQUIRED size parameter. - Before 1.92: PushFont() always used font "default" size specified in AddFont() call. It is equivalent to calling PushFont(font, font->LegacySize). - Since 1.92: PushFont(font, 0.0f) preserve the current font size which is a shared value. - To use old behavior: (A) use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). (B) Set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call (not desirable as it requires e.g. third-party code to be aware of it). @@ -498,7 +498,7 @@ CODE - Fonts: specifying glyph ranges is now unnecessary. The value of ImFontConfig::GlyphRanges[] is only useful for legacy backends. All GetGlyphRangesXXXX() functions are now marked obsolete: GetGlyphRangesDefault(), GetGlyphRangesGreek(), GetGlyphRangesKorean(), GetGlyphRangesJapanese(), GetGlyphRangesChineseSimplifiedCommon(), GetGlyphRangesChineseFull(), GetGlyphRangesCyrillic(), GetGlyphRangesThai(), GetGlyphRangesVietnamese(). - Fonts: removed ImFontAtlas::TexDesiredWidth to enforce a texture width. (#327) - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. - - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using 'PushFontSize(style.FontSizeBase * factor)' or to manipulate other scaling factors. + - Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using 'PushFont(NULL, style.FontSizeBase * factor)' or to manipulate other scaling factors. - Fonts: obsoleted ImFont::Scale which is not useful anymore. - Fonts: generally reworked Internals of ImFontAtlas and ImFont. While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things: - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef. @@ -8551,7 +8551,7 @@ ImVec2 ImGui::GetFontTexUvWhitePixel() return GImGui->DrawListSharedData.TexUvWhitePixel; } -// Prefer using PushFontSize(style.FontSizeBase * factor), or use style.FontScaleMain to scale all windows. +// Prefer using PushFont(NULL, style.FontSizeBase * factor), or use style.FontScaleMain to scale all windows. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS void ImGui::SetWindowFontScale(float scale) { @@ -8732,8 +8732,6 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) // - SetFontRasterizerDensity() [Internal] // - PushFont() // - PopFont() -// - PushFontSize() -// - PopFontSize() //----------------------------------------------------------------------------- void ImGui::UpdateFontsNewFrame() @@ -8854,7 +8852,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) if (g.CurrentTable == NULL || g.CurrentTable->CurrentColumn != -1) // See 8465#issuecomment-2951509561. Ideally the SkipItems=true in tables would be amended with extra data. return; - // Restoring is pretty much only used by PopFont()/PopFontSize() + // Restoring is pretty much only used by PopFont() float final_size = (restore_font_size_after_scaling > 0.0f) ? restore_font_size_after_scaling : 0.0f; if (final_size == 0.0f) { @@ -8935,17 +8933,6 @@ void ImGui::PopFont() g.FontStack.pop_back(); } -void ImGui::PushFontSize(float font_size_base) -{ - ImGuiContext& g = *GImGui; - PushFont(g.Font, font_size_base); -} - -void ImGui::PopFontSize() -{ - PopFont(); -} - //----------------------------------------------------------------------------- // [SECTION] ID STACK //----------------------------------------------------------------------------- diff --git a/imgui.h b/imgui.h index 2c361c4cf1d9..1022ea3fa3f5 100644 --- a/imgui.h +++ b/imgui.h @@ -509,10 +509,8 @@ namespace ImGui // - INCORRECT: PushFont(NULL, GetFontSize() * 2.0f) // INCORRECT! use size after external factors applied == EXTERNAL SCALING FACTORS WILL APPLY TWICE! IMGUI_API void PushFont(ImFont* font, float font_size_base_unscaled); // Use NULL as a shortcut to keep current font. Use 0.0f to keep current size. IMGUI_API void PopFont(); - IMGUI_API void PushFontSize(float font_size_base); // keep current font, change its size. Final 'font size = font_size_base * external scale factors'. - IMGUI_API void PopFontSize(); IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current scaled font size (= height in pixels). AFTER external scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()/PushFontSize()! Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. + IMGUI_API float GetFontSize(); // get current scaled font size (= height in pixels). AFTER external scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()! Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) // Parameters stacks (shared) @@ -2232,7 +2230,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { // ImGui::GetFontSize() == FontSizeBase * (FontScaleMain * FontScaleDpi * other_scaling_factors) - float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont()/PushFontSize() to modify. Use ImGui::GetFontSize() to obtain scaled value. + float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont(NULL, size) to modify. Use ImGui::GetFontSize() to obtain scaled value. float FontScaleMain; // Main scale factor. May be set by application once, or exposed to end-user. float FontScaleDpi; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 50b486cada5c..e540f9e6a428 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5227,7 +5227,7 @@ ImFontBaked* ImFont::GetFontBaked(float size, float density) ImFontBaked* baked = LastBaked; // Round font size - // - ImGui::PushFontSize() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges) + // - ImGui::PushFont() will already round, but other paths calling GetFontBaked() directly also needs it (e.g. ImFontAtlasBuildPreloadAllGlyphRanges) size = ImGui::GetRoundedFontSize(size); if (density < 0.0f) diff --git a/imgui_internal.h b/imgui_internal.h index b2656a7345d0..a01a974f5e93 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2143,7 +2143,7 @@ struct ImGuiContext ImFont* Font; // Currently bound font. (== FontStack.back().Font) ImFontBaked* FontBaked; // Currently bound font at currently bound size. (== Font->GetFontBaked(FontSize)) float FontSize; // Currently bound font size == line height (== FontSizeBase + externals scales applied in the UpdateCurrentFontSize() function). - float FontSizeBase; // Font size before scaling == style.FontSizeBase == value passed to PushFont() / PushFontSize() when specified. + float FontSizeBase; // Font size before scaling == style.FontSizeBase == value passed to PushFont() when specified. float FontBakedScale; // == FontBaked->Size / FontSize. Scale factor over baked size. Rarely used nowadays, very often == 1.0f. float FontRasterizerDensity; // Current font density. Used by all calls to GetFontBaked(). float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale From 89b5a2c3d50e4ca6a0a88378f096d7d05ff1c962 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 24 Jun 2025 19:06:46 +0200 Subject: [PATCH 661/716] (Breaking) Fonts: removed ImFontFlags_DefaultToLegacySize. --- docs/CHANGELOG.txt | 7 +------ imgui.cpp | 9 ++------- imgui.h | 1 - 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7c7daf79d472..01694d50a6cc 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -80,10 +80,7 @@ Breaking changes: - PushFont(font, 20.0f) // Change font and set size to 20.0f - PushFont(font, style.FontSizeBase * 2.0f) // Change font and set size to be twice bigger than current size. - PushFont(font, font->LegacySize) // Change font and set size to size passed to AddFontXXX() function. Same as pre-1.92 behavor, for fixed size fonts. - - To use old behavior: - - use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). - - or set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call - (not desirable as it requires e.g. all third-party code to be aware of it). + - To use old behavior use 'ImGui::PushFont(font, font->LegacySize)' at call site. We intentionally didn't add a default parameter because it would make the long-term transition more difficult. - Kept inline redirection font. Will obsolete. @@ -290,8 +287,6 @@ Other changes: window and other locations). - Fonts: added ImFontFlags (currently needs to be passed through ImFontConfig until we revamp font loading API): - - ImFontFlags_DefaultToLegacySize: for legacy compatibility: make PushFont() calls - without explicit size use font->LegacySize instead of current font size. - ImFontFlags_NoLoadError: disable erroring/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. - ImFontFlags_NoLoadGlyphs: disable loading new glyphs. diff --git a/imgui.cpp b/imgui.cpp index eceda68f1e94..e36d0a9e256f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -473,7 +473,7 @@ CODE - PushFont() API now has a REQUIRED size parameter. - Before 1.92: PushFont() always used font "default" size specified in AddFont() call. It is equivalent to calling PushFont(font, font->LegacySize). - Since 1.92: PushFont(font, 0.0f) preserve the current font size which is a shared value. - - To use old behavior: (A) use 'ImGui::PushFont(font, font->LegacySize)' at call site (preferred). (B) Set 'ImFontConfig::Flags |= ImFontFlags_DefaultToLegacySize' in AddFont() call (not desirable as it requires e.g. third-party code to be aware of it). + - To use old behavior: use 'ImGui::PushFont(font, font->LegacySize)' at call site. - Kept inline single parameter function. Will obsolete. - Fonts: **IMPORTANT** on Font Merging: - When searching for a glyph in multiple merged fonts: font inputs are now scanned in orderfor the first font input which the desired glyph. This is technically a different behavior than before! @@ -8911,12 +8911,7 @@ void ImGui::PushFont(ImFont* font, float font_size_base) g.FontStack.push_back({ g.Font, g.FontSizeBase, g.FontSize }); if (font_size_base == 0.0f) - { - if (font->Flags & ImFontFlags_DefaultToLegacySize) - font_size_base = font->LegacySize; // Legacy: use AddFont() specified font size. Same as doing PushFont(font, font->LegacySize) - else - font_size_base = g.FontSizeBase; // Keep current font size - } + font_size_base = g.FontSizeBase; // Keep current font size SetCurrentFont(font, font_size_base, 0.0f); } diff --git a/imgui.h b/imgui.h index 1022ea3fa3f5..44ab90869bf9 100644 --- a/imgui.h +++ b/imgui.h @@ -3759,7 +3759,6 @@ struct ImFontBaked enum ImFontFlags_ { ImFontFlags_None = 0, - ImFontFlags_DefaultToLegacySize = 1 << 0, // Legacy compatibility: make `PushFont(font)` == `PushFont(font, font->LegacySize)`. Otherwise by default/shared current font size is used. ImFontFlags_NoLoadError = 1 << 1, // Disable throwing an error/assert when calling AddFontXXX() with missing file/data. Calling code is expected to check AddFontXXX() return value. ImFontFlags_NoLoadGlyphs = 1 << 2, // [Internal] Disable loading new glyphs. ImFontFlags_LockBakedSizes = 1 << 3, // [Internal] Disable loading new baked sizes, disable garbage collecting current ones. e.g. if you want to lock a font to a single size. Important: if you use this to preload given sizes, consider the possibility of multiple font density used on Retina display. From d8c69537103fef8c14304d003e6db9859e31b5a3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 12:08:00 +0200 Subject: [PATCH 662/716] Fonts: comments. --- docs/BACKENDS.md | 2 +- docs/CHANGELOG.txt | 5 +++-- docs/FONTS.md | 32 +++++++++++++++----------------- docs/TODO.txt | 10 +--------- imgui.cpp | 6 ++++-- imgui.h | 20 +++++++++++--------- 6 files changed, 35 insertions(+), 40 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index de5cd6697bad..fcdd703f4578 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -12,7 +12,7 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKE Dear ImGui is highly portable and only requires a few things to run and render, typically: - Required: providing mouse/keyboard inputs (fed into the `ImGuiIO` structure). - - Required: uploading the font atlas texture into graphics memory. + - Required: creating, updating and destroying textures. - Required: rendering indexed textured triangles with a clipping rectangle. Extra features are opt-in, our backends try to support as many as possible: diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 01694d50a6cc..4a753127a801 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -79,13 +79,14 @@ Breaking changes: - PushFont(NULL, 20.0f) // Keep font and change current size - PushFont(font, 20.0f) // Change font and set size to 20.0f - PushFont(font, style.FontSizeBase * 2.0f) // Change font and set size to be twice bigger than current size. - - PushFont(font, font->LegacySize) // Change font and set size to size passed to AddFontXXX() function. Same as pre-1.92 behavor, for fixed size fonts. + - PushFont(font, font->LegacySize) // Change font and set size to size passed to AddFontXXX() function. Same as pre-1.92 behavior, for fixed size fonts. - To use old behavior use 'ImGui::PushFont(font, font->LegacySize)' at call site. We intentionally didn't add a default parameter because it would make the long-term transition more difficult. - Kept inline redirection font. Will obsolete. - - External scale factors may be applied over the provided size. + - Global scale factors may be applied over the provided size. This is why it is called 'FontSizeBase' in the style structure. + - Global scale factors are: 'style.FontScaleMain', 'style.FontScaleDpi' and maybe more. - ImFont::FontSize was removed and does not make sense anymore. ImFont::LegacySize is the size passed to AddFont(). - Removed support for old PushFont(NULL) which was a shortcut for "revert to default font". diff --git a/docs/FONTS.md b/docs/FONTS.md index 5a43b4403e47..f8431507cf50 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -2,7 +2,7 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/FONTS ## Dear ImGui: Using Fonts -The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' (by Tristan Grimmer), +The code in imgui.cpp embeds a copy of [ProggyClean.ttf](http://proggyfonts.net) (by Tristan Grimmer), a 13 pixels high, pixel-perfect font used by default. We embed it in the source code so you can use Dear ImGui without any file system access. ProggyClean does not scale smoothly, therefore it is recommended that you load your own file when using Dear ImGui in an application aiming to look nice and wanting to support multiple resolutions. You may also load external .TTF/.OTF files. @@ -37,7 +37,7 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo ### (1) Invalid filename due to use of `\` or unexpected working directory. -See [About Filenames](#about-filenames). AddFontXXX functions should assert if the filename is incorrect. +See [About Filenames](#about-filenames). AddFontXXX() functions should assert if the filename is incorrect. ### (2) Invalid UTF-8 encoding of your non-ASCII strings. @@ -45,18 +45,18 @@ See [About UTF-8 Encoding](#about-utf-8-encoding). Use the encoding viewer to co ### (3) Missing glyph ranges. -🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary.** +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is unnecessary.** -You need to load a font with explicit glyph ranges if you want to use non-ASCII characters. See [Fonts Loading Instructions](#fonts-loading-instructions). Use [Debug Tools](#debug-tools) confirm loaded fonts and loaded glyph ranges. +⏪ Before 1.92: you need to load a font with explicit glyph ranges if you want to use non-ASCII characters. See [Fonts Loading Instructions](#fonts-loading-instructions). Use [Debug Tools](#debug-tools) confirm loaded fonts and loaded glyph ranges. -This is a current constraint of Dear ImGui (which we will lift in the future): when loading a font you need to specify which characters glyphs to load. +This was a previous constraint of Dear ImGui (lifted in 1.92): when loading a font you need to specify which characters glyphs to load. All loaded fonts glyphs are rendered into a single texture atlas ahead of time. Calling either of `io.Fonts->GetTexDataAsAlpha8()`, `io.Fonts->GetTexDataAsRGBA32()` or `io.Fonts->Build()` will build the atlas. This is generally called by the Renderer backend, e.g. `ImGui_ImplDX11_NewFrame()` calls it. **If you use custom glyphs ranges, make sure the array is persistent** and available during the calls to `GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build()`. ### (4) Font atlas texture fails to upload to GPU. 🆕 **Since 1.92, with an up to date backend: atlas is built incrementally and dynamically resized, this is less likely to happen** -This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty white rectangles.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. +:rewind: This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty white rectangles.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. ![empty squares](https://github.com/user-attachments/assets/68b50fb5-8b9d-4c38-baec-6ac384f06d26) @@ -67,8 +67,6 @@ Some solutions: You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! - Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. -Future versions of Dear ImGui should solve this problem. - ##### [Return to Index](#index) --------------------------------------- @@ -112,7 +110,7 @@ io.Fonts->AddFontDefault(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("font.ttf"); ``` -**Before 1.92, or without an up to date backend:** +:rewind: **Before 1.92, or without an up to date backend:** ```cpp ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); @@ -130,7 +128,7 @@ ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf"); In your application loop, select which font to use: ```cpp ImGui::Text("Hello"); // use the default font (which is the first loaded font) -ImGui::PushFont(font2); +ImGui::PushFont(font2, 0.0f); // change font, keep current size ImGui::Text("Hello with another font"); ImGui::PopFont(); ``` @@ -154,7 +152,7 @@ io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 0.0f, &config); // Merge io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 0.0f, &config); // Merge into first font to add Icons io.Fonts->Build(); ``` -**Before 1.92, or without an up to date backend:** +:rewind: **Before 1.92, or without an up to date backend:** ```cpp // Load a first font ImFont* font = io.Fonts->AddFontDefault(); @@ -193,7 +191,7 @@ ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf"); ``` -**Before 1.92, or without an up to date backend:** +:rewind: **Before 1.92, or without an up to date backend:** ```cpp ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); @@ -277,7 +275,7 @@ config.MergeMode = true; config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config); ``` -**Before 1.92:** +:rewind: **Before 1.92:** ```cpp // Merge icons into default tool font #include "IconsFontAwesome.h" @@ -355,8 +353,8 @@ You can use `Metrics/Debugger->Fonts->Font->Input Glyphs Overlap Detection Tool` ## Using FreeType Rasterizer (imgui_freetype) - Dear ImGui uses [stb_truetype.h](https://github.com/nothings/stb/) to rasterize fonts (with optional oversampling). This technique and its implementation are not ideal for fonts rendered at small sizes, which may appear a little blurry or hard to read. -- You can however use `imgui_freetype.cpp` from the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. -- FreeType supports auto-hinting which tends to improve the readability of small fonts. +- You can however use `imgui_freetype.cpp` from the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. Compile with this file and add `#define IMGUI_ENABLE_FREETYPE` to your imconfig.h file or build system to automatically activate it. +- FreeType supports auto-hinting which tends to improve the readability of small fonts. It makes a big difference especially at smaller resolutions. - Read documentation in the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. - Correct sRGB space blending will have an important effect on your font rendering quality. @@ -391,7 +389,7 @@ io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\seguiemj.ttf", 16.0f, &cfg); 🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary, so this is not needed.** -You can use the `ImFontGlyphRangesBuilder` helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. +:rewind: You can use the `ImFontGlyphRangesBuilder` helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. ```cpp ImVector ranges; ImFontGlyphRangesBuilder builder; @@ -417,7 +415,7 @@ TL;DR; With the new system, it is recommended that you create a custom `ImFontLo You can ask questions in [#8466](https://github.com/ocornut/imgui/issues/8466). -**Before 1.92:** +:rewind: **Before 1.92:** As an alternative to rendering colorful glyphs using imgui_freetype with `ImGuiFreeTypeBuilderFlags_LoadColor`, you may allocate your own space in the texture atlas and write yourself into it. **(This is a BETA api, use if you are familiar with dear imgui and with your rendering backend)** diff --git a/docs/TODO.txt b/docs/TODO.txt index 03deffb2dc70..90d2b35db400 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -241,21 +241,14 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: arbitrary line spacing. (#2945) - font: MergeMode: flags to select overwriting or not (this is now very easy with refactored ImFontAtlasBuildWithStbTruetype) - - font: free the Alpha buffer if user only requested RGBA. -!- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions). + - font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions). - font: for the purpose of RenderTextEllipsis(), it might be useful that CalcTextSizeA() can ignore the trailing padding? - font: a CalcTextHeight() helper could run faster than CalcTextSize().y - font: enforce monospace through ImFontConfig (for icons?) + create dual ImFont output from same input, reusing rasterized data but with different glyphs/AdvanceX - - font: finish CustomRectRegister() to allow mapping Unicode codepoint to custom texture data - - font: remove ID from CustomRect registration, it seems unnecessary! - font: make it easier to submit own bitmap font (same texture, another texture?). (#2127, #2575) - font: MemoryTTF taking ownership confusing/not obvious, maybe default should be opposite? - font: storing MinAdvanceX per font would allow us to skip calculating line width (under a threshold of character count) in loops looking for block width - - font/demo: add tools to show glyphs used by a text blob, display U16 value, list missing glyphs. - font/demo: demonstrate use of ImFontGlyphRangesBuilder. - - font/atlas: add a missing Glyphs.reserve() - - font/atlas: incremental updates - - font/atlas: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier. - font/draw: vertical and/or rotated text renderer (#705) - vertical is easier clipping wise - font/draw: need to be able to specify wrap start position. - font/draw: better reserve policy for large horizontal block of text (shouldn't reserve for all clipped lines). also see #3349. @@ -264,7 +257,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - font: optimization: for monospace font (like the default one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance (need to make sure TAB is still correct), would save on cache line. - font: add support for kerning, probably optional. A) perhaps default to (32..128)^2 matrix ~ 9K entries = 36KB, then hash for non-ascii?. B) or sparse lookup into per-char list? - font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize) - - font: fix AddRemapChar() to work before atlas has been built. - font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF. - font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer? - font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8? diff --git a/imgui.cpp b/imgui.cpp index e36d0a9e256f..bed833764707 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8540,7 +8540,9 @@ ImFontBaked* ImGui::GetFontBaked() return GImGui->FontBaked; } -// Get current font size (= height in pixels) of current font, with external scale factors applied. Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. +// Get current font size (= height in pixels) of current font, with global scale factors applied. +// - Use style.FontSizeBase to get value before global scale factors. +// - recap: ImGui::GetFontSize() == style.FontSizeBase * (style.FontScaleMain * style.FontScaleDpi * other_scaling_factors) float ImGui::GetFontSize() { return GImGui->FontSize; @@ -8858,7 +8860,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) { final_size = g.FontSizeBase; - // External scale factors + // Global scale factors final_size *= g.Style.FontScaleMain; // Main global scale factor final_size *= g.Style.FontScaleDpi; // Per-monitor/viewport DPI scale factor, automatically updated when io.ConfigDpiScaleFonts is enabled. diff --git a/imgui.h b/imgui.h index 44ab90869bf9..e7f74e7dad1e 100644 --- a/imgui.h +++ b/imgui.h @@ -501,16 +501,17 @@ namespace ImGui // *IMPORTANT* before 1.92, fonts had a single size. They can now be dynamically be adjusted. // - In 1.92 we have REMOVED the single parameter version of PushFont() because it seems like the easiest way to provide an error-proof transition. // - PushFont(font) before 1.92 = PushFont(font, font->LegacySize) after 1.92 // Use default font size as passed to AddFontXXX() function. - // *IMPORTANT* external scale factors are applied over the provided size. If you want to scale an *existing* font size: - // - External scale factors are: 'style.FontScaleMain * style.FontScaleDpi' and maybe more. + // *IMPORTANT* global scale factors are applied over the provided size. + // - Global scale factors are: 'style.FontScaleMain', 'style.FontScaleDpi' and maybe more. + // - If you want to apply a factor to the _current_ font size: // - CORRECT: PushFont(NULL, style.FontSizeBase) // use current unscaled size == does nothing // - CORRECT: PushFont(NULL, style.FontSizeBase * 2.0f) // use current unscaled size x2 == make text twice bigger - // - INCORRECT: PushFont(NULL, GetFontSize()) // INCORRECT! use size after external factors applied == EXTERNAL SCALING FACTORS WILL APPLY TWICE! - // - INCORRECT: PushFont(NULL, GetFontSize() * 2.0f) // INCORRECT! use size after external factors applied == EXTERNAL SCALING FACTORS WILL APPLY TWICE! + // - INCORRECT: PushFont(NULL, GetFontSize()) // INCORRECT! using size after global factors already applied == GLOBAL SCALING FACTORS WILL APPLY TWICE! + // - INCORRECT: PushFont(NULL, GetFontSize() * 2.0f) // INCORRECT! using size after global factors already applied == GLOBAL SCALING FACTORS WILL APPLY TWICE! IMGUI_API void PushFont(ImFont* font, float font_size_base_unscaled); // Use NULL as a shortcut to keep current font. Use 0.0f to keep current size. IMGUI_API void PopFont(); IMGUI_API ImFont* GetFont(); // get current font - IMGUI_API float GetFontSize(); // get current scaled font size (= height in pixels). AFTER external scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()! Use ImGui::GetStyle().FontSizeBase to get value before external scale factors. + IMGUI_API float GetFontSize(); // get current scaled font size (= height in pixels). AFTER global scale factors applied. *IMPORTANT* DO NOT PASS THIS VALUE TO PushFont()! Use ImGui::GetStyle().FontSizeBase to get value before global scale factors. IMGUI_API ImFontBaked* GetFontBaked(); // get current font bound at current size // == GetFont()->GetFontBaked(GetFontSize()) // Parameters stacks (shared) @@ -2229,10 +2230,11 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE struct ImGuiStyle { - // ImGui::GetFontSize() == FontSizeBase * (FontScaleMain * FontScaleDpi * other_scaling_factors) - float FontSizeBase; // Current base font size before external scaling factors are applied. Use PushFont(NULL, size) to modify. Use ImGui::GetFontSize() to obtain scaled value. - float FontScaleMain; // Main scale factor. May be set by application once, or exposed to end-user. - float FontScaleDpi; // Additional scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. + // Font scaling + // - recap: ImGui::GetFontSize() == FontSizeBase * (FontScaleMain * FontScaleDpi * other_scaling_factors) + float FontSizeBase; // Current base font size before external global factors are applied. Use PushFont(NULL, size) to modify. Use ImGui::GetFontSize() to obtain scaled value. + float FontScaleMain; // Main global scale factor. May be set by application once, or exposed to end-user. + float FontScaleDpi; // Additional global scale factor from viewport/monitor contents scale. When io.ConfigDpiScaleFonts is enabled, this is automatically overwritten when changing monitor DPI. float Alpha; // Global alpha applies to everything in Dear ImGui. float DisabledAlpha; // Additional alpha multiplier applied by BeginDisabled(). Multiply over current value of Alpha. From dcf14505e27f16f6cf1933d4834705ed76302637 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 15:46:25 +0200 Subject: [PATCH 663/716] Backends: SDLGPU: fixes call to SDL_MapGPUTransferBuffer(). Fixes artifacts on OSX/Metal. (#8465, #8703) --- backends/imgui_impl_sdlgpu3.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 0ad9e2c301f8..927e511cb8d8 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -22,6 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2025-06-25: Mapping transfer buffer for texture update use cycle=true. Fixes artifacts e.g. on Metal backend. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture(). // 2025-04-28: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2025-03-30: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which were unusually slow to recreate every frame. Much faster now. @@ -373,7 +374,7 @@ void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex) // Copy to transfer buffer { - void* texture_ptr = SDL_MapGPUTransferBuffer(v->Device, bd->TexTransferBuffer, false); + void* texture_ptr = SDL_MapGPUTransferBuffer(v->Device, bd->TexTransferBuffer, true); for (int y = 0; y < upload_h; y++) memcpy((void*)((uintptr_t)texture_ptr + y * upload_pitch), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch); SDL_UnmapGPUTransferBuffer(v->Device, bd->TexTransferBuffer); From 5bc70c68e2dff11ad55036ddf9e5f86f7a0a1a9f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 15:55:25 +0200 Subject: [PATCH 664/716] Fonts: fix PushFont(NULL) to work as advertised. Didn't properly finish ca72eb0. --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index bed833764707..343862b30e1e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8906,8 +8906,8 @@ void ImGui::SetFontRasterizerDensity(float rasterizer_density) void ImGui::PushFont(ImFont* font, float font_size_base) { ImGuiContext& g = *GImGui; - //if (font == NULL) // Before 1.92 (June 2025), PushFont(NULL) == PushFont(GetDefaultFont()) - // font = g.Font; + if (font == NULL) // Before 1.92 (June 2025), PushFont(NULL) == PushFont(GetDefaultFont()) + font = g.Font; IM_ASSERT(font != NULL); IM_ASSERT(font_size_base >= 0.0f); From 719a3fe98eb692cd35aba1d792fd6702669275f5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 16:04:51 +0200 Subject: [PATCH 665/716] Additional comments on ErrorCheckUsingSetCursorPosToExtendParentBoundaries(). (#5548) --- imgui.cpp | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 343862b30e1e..aa73294fedfe 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10581,21 +10581,30 @@ bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si return !error; } -// Until 1.89 (IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos() to extend the boundary of a parent (e.g. window or table cell) -// This is causing issues and ambiguity and we need to retire that. -// See https://github.com/ocornut/imgui/issues/5548 for more details. -// [Scenario 1] +// Until 1.89 (August 2022, IMGUI_VERSION_NUM < 18814) it was legal to use SetCursorPos()/SetCursorScreenPos() +// to extend contents size of our parent container (e.g. window contents size, which is used for auto-resizing +// windows, table column contents size used for auto-resizing columns, group size). +// This was causing issues and ambiguities and we needed to retire that. +// From 1.89, extending contents size boundaries REQUIRES AN ITEM TO BE SUBMITTED. +// // Previously this would make the window content size ~200x200: -// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK +// Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); // NOT OK ANYMORE // Instead, please submit an item: // Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); // OK // Alternative: // Begin(...) + Dummy(ImVec2(200,200)) + End(); // OK -// [Scenario 2] -// For reference this is one of the issue what we aim to fix with this change: -// BeginGroup() + SomeItem("foobar") + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup() -// The previous logic made SetCursorScreenPos(GetCursorScreenPos()) have a side-effect! It would erroneously incorporate ItemSpacing.y after the item into content size, making the group taller! -// While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect. Using vertical alignment patterns could trigger this issue. +// +// The assert below detects when the _last_ call in a window was a SetCursorPos() not followed by an Item, +// and with a position that would grow the parent contents size. +// +// Advanced: +// - For reference, old logic was causing issues because it meant that SetCursorScreenPos(GetCursorScreenPos()) +// had a side-effect on layout! In particular this caused problem to compute group boundaries. +// e.g. BeginGroup() + SomeItem() + SetCursorScreenPos(GetCursorScreenPos()) + EndGroup() would cause the +// group to be taller because auto-sizing generally adds padding on bottom and right side. +// - While this code is a little twisted, no-one would expect SetXXX(GetXXX()) to have a side-effect. +// Using vertical alignment patterns would frequently trigger this sorts of issue. +// - See https://github.com/ocornut/imgui/issues/5548 for more details. void ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries() { ImGuiContext& g = *GImGui; From 6f21bed66d678dc4207113ba874e1b5b96e34f92 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 16:23:06 +0200 Subject: [PATCH 666/716] Fonts: removing assert from legacy PushFont() to mirror new PushFont(). for consistency. --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index e7f74e7dad1e..15acc8c0e530 100644 --- a/imgui.h +++ b/imgui.h @@ -3953,7 +3953,7 @@ struct ImGuiPlatformImeData namespace ImGui { // OBSOLETED in 1.92.0 (from June 2025) - static inline void PushFont(ImFont* font) { IM_ASSERT(font != NULL); PushFont(font, font->LegacySize); } + static inline void PushFont(ImFont* font) { PushFont(font, font ? font->LegacySize : 0.0f); } IMGUI_API void SetWindowFontScale(float scale); // Set font scale factor for current window. Prefer using PushFont(NULL, style.FontSizeBase * factor) or use style.FontScaleMain to scale all windows. // OBSOLETED in 1.91.9 (from February 2025) IMGUI_API void Image(ImTextureRef tex_ref, const ImVec2& image_size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col); // <-- 'border_col' was removed in favor of ImGuiCol_ImageBorder. If you use 'tint_col', use ImageWithBg() instead. From 2819ab32f85b97d8c99a6cb0ec0f39b42bec4c92 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 16:39:23 +0200 Subject: [PATCH 667/716] Layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback. (#5548, #4510, #3355, #1760, #1490, #4152, #150) --- docs/CHANGELOG.txt | 10 ++++++++++ imgui.cpp | 17 ++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4a753127a801..8ef51cc23f72 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -225,6 +225,16 @@ Breaking changes: - removed ImGui_ImplSDLRenderer2_CreateFontsTexture(), ImGui_ImplSDLRenderer2_DestroyFontsTexture(). - removed ImGui_ImplSDLRenderer3_CreateFontsTexture(), ImGui_ImplSDLRenderer3_DestroyFontsTexture(). - removed ImGui_ImplVulkan_CreateFontsTexture(), ImGui_ImplVulkan_DestroyFontsTexture(). +- Layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback + obsoleted in 1.89 (August 2022) which allowed a SetCursorPos()/SetCursorScreenPos() call WITHOUT AN ITEM + to extend parent window/cell boundaries. Replaced with assert/tooltip that would already happens if + previously using IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#5548, #4510, #3355, #1760, #1490, #4152, #150) + - Incorrect way to make a window content size 200x200: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); + - Correct ways to make a window content size 200x200: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); + Begin(...) + Dummy(ImVec2(200,200)) + End(); + - TL;DR; if the assert triggers, you can add a Dummy({0,0}) call to validate extending parent boundaries. - TreeNode: renamed ImGuiTreeNodeFlags_NavLeftJumpsBackHere to ImGuiTreeNodeFlags_NavLeftJumpsToParent for clarity. Kept inline redirection enum (will obsolete). (#1079, #8639) - Commented out PushAllowKeyboardFocus()/PopAllowKeyboardFocus() which was obsoleted diff --git a/imgui.cpp b/imgui.cpp index aa73294fedfe..660e9da9b462 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -460,6 +460,14 @@ CODE When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2025/06/25 (1.92.0) - layout: commented out legacy ErrorCheckUsingSetCursorPosToExtendParentBoundaries() fallback obsoleted in 1.89 (August 2022) which allowed a SetCursorPos()/SetCursorScreenPos() call WITHOUT AN ITEM + to extend parent window/cell boundaries. Replaced with assert/tooltip that would already happens if previously using IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#5548, #4510, #3355, #1760, #1490, #4152, #150) + - Incorrect way to make a window content size 200x200: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + End(); + - Correct ways to make a window content size 200x200: + Begin(...) + SetCursorScreenPos(GetCursorScreenPos() + ImVec2(200,200)) + Dummy(ImVec2(0,0)) + End(); + Begin(...) + Dummy(ImVec2(200,200)) + End(); + - TL;DR; if the assert triggers, you can add a Dummy({0,0}) call to validate extending parent boundaries. - 2025/06/11 (1.92.0) - THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, BUT INEVITABLY SOME USERS WILL BE AFFECTED. IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: https://github.com/ocornut/imgui/issues/ As part of the plan to reduce impact of API breaking changes, several unfinished changes/features/refactors related to font and text systems and scaling will be part of subsequent releases (1.92.1+). @@ -10611,15 +10619,14 @@ void ImGui::ErrorCheckUsingSetCursorPosToExtendParentBoundaries() ImGuiWindow* window = g.CurrentWindow; IM_ASSERT(window->DC.IsSetPos); window->DC.IsSetPos = false; -#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (window->DC.CursorPos.x <= window->DC.CursorMaxPos.x && window->DC.CursorPos.y <= window->DC.CursorMaxPos.y) return; if (window->SkipItems) return; - IM_ASSERT(0 && "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries. Please submit an item e.g. Dummy() to validate extent."); -#else - window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); -#endif + IM_ASSERT_USER_ERROR(0, "Code uses SetCursorPos()/SetCursorScreenPos() to extend window/parent boundaries.\nPlease submit an item e.g. Dummy() afterwards in order to grow window/parent boundaries."); + + // For reference, the old behavior was essentially: + //window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos); } static void ImGui::ErrorCheckNewFrameSanityChecks() From da3c86925ab90c3a998bf8d7a6084decdbe23d6a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 18:19:48 +0200 Subject: [PATCH 668/716] Demo: added TextLinkOpenURL() call in Widgets section. --- imgui_demo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8a4c4584e864..ccd6a11f59c5 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -842,6 +842,9 @@ static void DemoWindowWidgetsBasic() ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); ImGui::RadioButton("radio c", &e, 2); + ImGui::AlignTextToFramePadding(); + ImGui::TextLinkOpenURL("Hyperlink", "https://github.com/ocornut/imgui/wiki/Error-Handling"); + // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Colored)"); for (int i = 0; i < 7; i++) @@ -8024,6 +8027,8 @@ void ImGui::ShowAboutWindow(bool* p_open) ImGui::SameLine(); ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki"); ImGui::SameLine(); + ImGui::TextLinkOpenURL("Extensions", "https://github.com/ocornut/imgui/wiki/Useful-Extensions"); + ImGui::SameLine(); ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases"); ImGui::SameLine(); ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding"); From 673eb7de9678459ccd2c340a75786d8b1434848f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 18:13:10 +0200 Subject: [PATCH 669/716] Version 1.92.0 --- docs/CHANGELOG.txt | 60 +++++++++++++++++++++++++--------------------- imgui.cpp | 2 +- imgui.h | 6 ++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 42 insertions(+), 36 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8ef51cc23f72..473c389f93d5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,11 +36,13 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.92.0 WIP (In Progress) + VERSION 1.92.0 (Released 2025-06-25) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92 + THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! -I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCES, +I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCE, BUT INEVITABLY SOME USERS OR THIRD-PARTY EXTENSIONS WILL BE AFFECTED. IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, @@ -88,8 +90,9 @@ Breaking changes: This is why it is called 'FontSizeBase' in the style structure. - Global scale factors are: 'style.FontScaleMain', 'style.FontScaleDpi' and maybe more. - ImFont::FontSize was removed and does not make sense anymore. - ImFont::LegacySize is the size passed to AddFont(). + - ImFont::LegacySize is the size passed to AddFont(). - Removed support for old PushFont(NULL) which was a shortcut for "revert to default font". + `PushFont(NULL, some_size)` now keeps current change and changes size. - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. - Fonts: **IMPORTANT** on Font Merging: - When searching for a glyph in multiple merged fonts: font inputs are now scanned in order @@ -114,7 +117,7 @@ Breaking changes: - Textures: - All API functions taking a 'ImTextureID' parameter are now taking a 'ImTextureRef': - - ImTextureRef a small composite structure which may be constructed from a ImTextureID. + - ImTextureRef ais small composite structure which may be constructed from a ImTextureID. (or constructed from a ImTextureData* which represent a texture which will generally be ready by the time of rendering). - Affected functions are: @@ -147,7 +150,7 @@ Breaking changes: - Fonts: if you create and manage ImFontAtlas instances yourself (instead of relying on ImGuiContext to create one, you'll need to call ImFontAtlasUpdateNewFrame() yourself. An assert will trigger if you don't. -- Fonts: obsolete ImGui::SetWindowFontScale() which is not useful anymore. Prefer using +- Fonts: obsoleted ImGui::SetWindowFontScale() which is not useful anymore. Prefer using PushFont(NULL, style.FontSizeBase * factor) or to manipulate other scaling factors. - Fonts: obsoleted ImFont::Scale which is not useful anymore. - Fonts: changed ImFont::CalcWordWrapPositionA() to ImFont::CalcWordWrapPosition(): @@ -160,7 +163,7 @@ Breaking changes: While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things: - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef. - - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[] + - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]. - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. - Each ImFont has a number of ImFontBaked instances corresponding to actively used sizes. ImFont::GetFontBaked(size) retrieves the one for a given size. @@ -188,9 +191,6 @@ Breaking changes: - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader() - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader(); -- DrawList: Fixed a regression from 1.91.1 where a Begin()/PushFont()/AddImage() sequence - would not restore the correct atlas Texture Identifier when the PushFont() call used - a font from a different atlas. (#8694, caused by #3224, #3875, #6398, #7903) - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). - Fonts: (users of custom rectangles) - Renamed AddCustomRectRegular() to AddCustomRect(). (#8466) @@ -249,7 +249,7 @@ Breaking changes: - Internals: RenderTextEllipsis() function removed the 'float clip_max_x' parameter directly preceding 'float ellipsis_max_x'. Values were identical for a vast majority of users. (#8387) -Other changes: +Non-breaking Fonts/Textures related changes: - Textures: added partial texture update protocol. (#8465, #3761) - The Renderer Backend needs to set io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures @@ -310,7 +310,7 @@ Other changes: - ImFontBaked structures may be cleaned up between frames when unused, pointers to them are only valid for the current frame. - Added ImFontBaked::IsGlyphLoaded() function. -- Fonts: custom rect packing has generally been reworked. (#8107, #7962, #1282) +- Fonts: Custom Rect packing has generally been reworked. (#8107, #7962, #1282) - ImFontAtlas::AddCustomRect() (previously AddCustomRectRegular()/AddCustomRectFontGlyph()) functions will immediately return a packed rectangle identifier, and you can write your pixels immediately - previously had to wait for Build() to be called. @@ -328,14 +328,29 @@ Other changes: for Renderer Backend to specify if there is a maximum accepted texture size (not yet used). - Fonts: added compile-time overridable '#define ImTextureID_Invalid 0' if you need 0 to be a valid low-level texture identifier. +- Fonts: reworked text ellipsis logic to ensure a "..." is always displayed instead + of a single character. (#7024) +- Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) +- Fonts: fixed CalcWordWrapPosition() fallback when width is too small to wrap: + would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) - Debug Tools: Fonts section: add font preview, add "Remove" button, add "Load all glyphs" button, add selection to change font backend when both are compiled in. +- Renderer Backends: + - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: + - Added ImGuiBackendFlags_RendererHasTextures support for all backends. (#8465, #3761, #3471) + [@ocornut, @ShironekoBen, @thedmd] + - Added ImGui_ImplXXXX_UpdateTexture(ImTextureData* tex) functions for all backends. + Available if you want to start uploading textures right after ImGui::Render() and without + waiting for the call to ImGui_ImplXXXX_RenderDrawData(). Also useful if you use a staged or + multi-threaded rendering schemes, where you might want to set ImDrawData::Textures = NULL. (#8597, #1860) - Special thanks for fonts/texture related feedback to: @thedmd, @ShironekoBen, @rodrigorc, @pathogendavid, @itamago, @rokups, @DucaRii, @Aarkham, @cyfewlp. +Other Changes: + - IO: variations in analog-only components of gamepad events do not interfere with trickling of mouse position events (#4921, #8508) -- Windows: fixed SetNextWindowCollapsed()/SetWindowCollapsed() breaking +- Windows: fixed SetNextWindowCollapsed()/SetWindowCollapsed() bypassing the codepath that preserve last contents size when collapsed, resulting in programmatically uncollapsing auto-sizing windows having them flicker size for a frame. (#7691) [@achabense] @@ -353,10 +368,10 @@ Other changes: - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. - Added style.TreeLinesFlags which stores the default setting, - which may be overriden in individual TreeNode() calls. + which may be overridden in individual TreeNode() calls. - Added style.TreeLinesSize (default to 1.0f). - Added style.TreeLinesRadius (default to 0.0f). - - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). + - Added ImGuiCol_TreeLines (in default styles this is the same as ImGuiCol_Border). - Caveats: - Tree nodes may be used in many creative ways (manually positioning openable nodes in unusual ways, using indent to create tree-looking structures, etc.) @@ -397,28 +412,19 @@ Other changes: EndPopup() call. (#1651, #8499) - Error Handling: added better error report and recovery when calling EndFrame() or Render() without NewFrame(). Was previously only an assert. -- Fonts: reworked text ellipsis logic to ensure a "..." is always displayed instead - of a single character. (#7024) -- Fonts: word-wrapping code handle ideographic comma & full stop (U+3001, U+3002). (#8540) -- Fonts: fixed CalcWordWrapPosition() fallback when width is too small to wrap: - would use a +1 offset instead of advancing to the next UTF-8 codepoint. (#8540) - Style, InputText: added ImGuiCol_InputTextCursor to configure color of the InputText cursor/caret. (#7031) - Platform IME: added ImGuiPlatformImeData::ViewportId info (backported from Docking branch). - Platform IME: added ImGuiPlatformImeData::WantTextInput which might set independently of WantVisible. This is set in the same structure because activating text input generally requires providing a window to the backend. (#8584, #6341) +- DrawList: Fixed a regression from 1.91.1 where a Begin()/PushFont()/AddImage() sequence + would not restore the correct atlas Texture Identifier when the PushFont() call used + a font from a different atlas. (#8694, caused by #3224, #3875, #6398, #7903) - Misc: added extra operators to ImVec4 in IMGUI_DEFINE_MATH_OPERATORS block. (#8510) [@gan74] - Misc: removed static linkage from operators to facilitate using in C++ modules. (#8682, #8358) [@johmani] - Demo: changed default framed item width to use Min(GetFontSize() * 12, GetContentRegionAvail().x * 0.40f). - Renderer Backends: - - Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, WebGPU, Allegro5: - - Added ImGuiBackendFlags_RendererHasTextures support. (#8465, #3761, #3471) - [@ocornut, @ShironekoBen, @thedmd] - - Added ImGui_ImplXXXX_UpdateTexture(ImTextureData* tex) functions for all backend. - Available if you want to start uploading textures right after ImGui::Render() and without - waiting for the call to ImGui_ImplXXXX_RenderDrawData(). Also useful if you use a staged or - multi-threaded rendering schemes, where you might want to set ImDrawData::Textures = NULL. (#8597, #1860) - Backends: SDLGPU3: Fixed creating atlas texture earlier than other backends, preventing to load fonts between the Init and NewFrames calls. - Backends: SDLGPU3: Made ImGui_ImplSDLGPU3_PrepareDrawData() reuse GPU Transfer Buffers which @@ -456,7 +462,7 @@ Other changes: - Backends: GLFW, SDL2, SDL3: include GLFW/SDL version number in io.BackendPlatformName. - Backends: SDL3: Update for SDL3 api changes: revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) [@Green-Sky] - - Backends: SDL3: honor ImGuiPlatformImeData->WantTextInput as an alternative + - Backends: SDL3: honor ImGuiPlatformImeData::WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. (#8584) - Backends: SDL3: fixed pulling SDL_PROP_WINDOW_COCOA_WINDOW_POINTER into viewport->PlatformHandleRaw. (#8725, #8726) [@eertbleyen] diff --git a/imgui.cpp b/imgui.cpp index 660e9da9b462..21df133271ff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 15acc8c0e530..78baa1b7bb10 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.0 WIP" -#define IMGUI_VERSION_NUM 19199 +#define IMGUI_VERSION "1.92.0" +#define IMGUI_VERSION_NUM 19200 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ccd6a11f59c5..9b71ceae48b1 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e540f9e6a428..dc0944506cf9 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index a01a974f5e93..40fe681f8c0c 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 61bc576caf99..88b99d0a7913 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index d7214b6c237a..49bee8436513 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 WIP +// dear imgui, v1.92.0 // (widgets code) /* From 85b2fe8486190fa9326565a2fb5fccb6caea4396 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 25 Jun 2025 18:46:41 +0200 Subject: [PATCH 670/716] Docs: update binaries. --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 701016a6a31d..7c62950d8fae 100644 --- a/docs/README.md +++ b/docs/README.md @@ -110,7 +110,7 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. [Here's how the demo looks](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: -- [imgui-demo-binaries-20241211.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20241211.zip) (Windows, 1.91.6, built 2024/11/11, master) or [older binaries](https://www.dearimgui.com/binaries). +- [imgui-demo-binaries-20250625.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20250625.zip) (Windows, 1.92.0, built 2025/06/25, master) or [older binaries](https://www.dearimgui.com/binaries). The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). From 4f4bc7cc8fa6ba821298221a80fc6a8092a08f13 Mon Sep 17 00:00:00 2001 From: Aidan Sun Date: Thu, 26 Jun 2025 03:46:54 -0400 Subject: [PATCH 671/716] Replace IMGUI_API with inline for PushTextureID() and PopTextureID() (#8729) --- imgui.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 78baa1b7bb10..6b7dd2b64b5c 100644 --- a/imgui.h +++ b/imgui.h @@ -3329,8 +3329,8 @@ struct ImDrawList // Obsolete names #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - IMGUI_API void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.x - IMGUI_API void PopTextureID() { PopTexture(); } // RENAMED in 1.92.x + inline void PushTextureID(ImTextureRef tex_ref) { PushTexture(tex_ref); } // RENAMED in 1.92.x + inline void PopTextureID() { PopTexture(); } // RENAMED in 1.92.x #endif //inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024) //inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024) From 5ee9c2ad1ffcc105910b8f059f7d6c86b0ef30b7 Mon Sep 17 00:00:00 2001 From: Ves Georgiev <1884844+VesCodes@users.noreply.github.com> Date: Fri, 27 Jun 2025 00:06:42 +0100 Subject: [PATCH 672/716] Demo: Fixed font scaling warning if ImGuiBackendFlags_RendererHasTextures is set (#8736) --- imgui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 21df133271ff..fe9e8686a24e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15940,7 +15940,8 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); //EndDisabled(); - BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); + if ((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) + BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); BulletText("Load a nice font for better results!"); BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); From f18aea52460a3cd5ad25ef07c60100b71d603c61 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Jun 2025 20:35:35 +0200 Subject: [PATCH 673/716] Version 1.92.1 WIP --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 2 +- imgui.h | 8 ++++---- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 473c389f93d5..ea760cd109e9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.92.1 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + + ----------------------------------------------------------------------- VERSION 1.92.0 (Released 2025-06-25) ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index fe9e8686a24e..b5c534c57b78 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 6b7dd2b64b5c..ab23774d19d8 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.0" -#define IMGUI_VERSION_NUM 19200 +#define IMGUI_VERSION "1.92.1 WIP" +#define IMGUI_VERSION_NUM 19201 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 @@ -327,7 +327,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // constructors if you like. You will need to implement ==/!= operators. // History: // - In v1.91.4 (2024/10/08): the default type for ImTextureID was changed from 'void*' to 'ImU64'. This allowed backends requirig 64-bit worth of data to build on 32-bit architectures. Use intermediary intptr_t cast and read FAQ if you have casting warnings. -// - In v1.92.0 (2025/XX/XX): added ImTextureRef which carry either a ImTextureID either a pointer to internal texture atlas. All user facing functions taking ImTextureID changed to ImTextureRef +// - In v1.92.0 (2025/06/11): added ImTextureRef which carry either a ImTextureID either a pointer to internal texture atlas. All user facing functions taking ImTextureID changed to ImTextureRef #ifndef ImTextureID typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. #endif diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 9b71ceae48b1..94d39587f2f7 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dc0944506cf9..e835dcd75ee5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 40fe681f8c0c..eeee93778f5e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 88b99d0a7913..f6d51652145e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 49bee8436513..afad7b6ecffb 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.0 +// dear imgui, v1.92.1 WIP // (widgets code) /* From 22ad62c90ca47474f7328548a7818e9955a73958 Mon Sep 17 00:00:00 2001 From: Christian Fillion Date: Thu, 26 Jun 2025 22:43:41 -0400 Subject: [PATCH 674/716] Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) Yet another undocumented standard cursor. Amend 8a35386. --- backends/imgui_impl_osx.h | 2 -- backends/imgui_impl_osx.mm | 5 +++-- docs/CHANGELOG.txt | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index b4d7bf8d7d61..ea2b4f492e8c 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -10,8 +10,6 @@ // [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. -// Missing features or Issues: -// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 27567fb196fa..06a6aff8b9c8 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -10,8 +10,6 @@ // [X] Platform: Gamepad support. // [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: IME support. -// Missing features or Issues: -// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -31,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-27: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. // 2025-01-20: Removed notification observer when shutting down. (#8331) @@ -110,6 +109,7 @@ + (id)_windowResizeNorthWestSouthEastCursor; + (id)_windowResizeNorthEastSouthWestCursor; + (id)_windowResizeNorthSouthCursor; + (id)_windowResizeEastWestCursor; ++ (id)busyButClickableCursor; @end /** @@ -431,6 +431,7 @@ bool ImGui_ImplOSX_Init(NSView* view) bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = [NSCursor respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)] ? [NSCursor _windowResizeNorthEastSouthWestCursor] : [NSCursor closedHandCursor]; bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = [NSCursor respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)] ? [NSCursor _windowResizeNorthWestSouthEastCursor] : [NSCursor closedHandCursor]; bd->MouseCursors[ImGuiMouseCursor_Hand] = [NSCursor pointingHandCursor]; + bd->MouseCursors[ImGuiMouseCursor_Wait] = bd->MouseCursors[ImGuiMouseCursor_Progress] = [NSCursor respondsToSelector:@selector(busyButClickableCursor)] ? [NSCursor busyButClickableCursor] : [NSCursor arrowCursor]; bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = [NSCursor operationNotAllowedCursor]; // Note that imgui.cpp also include default OSX clipboard handlers which can be enabled diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ea760cd109e9..1b93505d1126 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress + mouse cursor support. (#8739) [@cfillion] + ----------------------------------------------------------------------- VERSION 1.92.0 (Released 2025-06-25) From ec13fa436b2219bbffcf7f30c5a51fc4e227bb5b Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 27 Jun 2025 13:59:51 +0200 Subject: [PATCH 675/716] Docs: tidying up Backends.md, add index, prepare for adding more docs. --- docs/BACKENDS.md | 88 ++++++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index fcdd703f4578..0c5f71bc84da 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -1,8 +1,19 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md or view this file with any Markdown viewer)_ -## Dear ImGui: Backends +# Dear ImGui: Backends -### Integrating backends +## Index + +- [Introduction](#introduction) +- [Using standard backends](#using-standard-backends) +- [List of third-party backends](#list-of-third-party-backends) +- [Writing your own backend](#writing-your-own-backend) + - [Using a custom engine?](#using-a-custom-engine) + - [Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+)](#adding-support-for-imguibackendflags_rendererhastextures-192) + +## Introduction + +### Getting Started 💡 The **[Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) wiki guide** has examples of how to integrate Dear ImGui into an existing application.
The [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) documentation may also be worth a read. @@ -34,13 +45,13 @@ and the backends which we are describing here (backends/ folder). - You should be able to write backends for pretty much any platform and any 3D graphics API. e.g. you can get creative and use software rendering or render remotely on a different machine. -### Standard backends +## Using standard backends **The [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder contains backends for popular platforms/graphics API, which you can use in your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. - The 'Platform' backends are in charge of: mouse/keyboard/gamepad inputs, cursor shape, timing, and windowing.
- e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl2.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl2.cpp)), etc. + e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), SDL3 ([imgui_impl_sdl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl3.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), etc. - The 'Renderer' backends are in charge of: creating atlas texture, and rendering imgui draw data.
e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc. @@ -53,44 +64,41 @@ For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree **Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** -### List of backends +### List of standard backends In the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder: List of Platforms Backends: - imgui_impl_android.cpp ; Android native app API - imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/ - imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends) - imgui_impl_sdl2.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org - imgui_impl_sdl3.cpp ; SDL3 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org (*EXPERIMENTAL UNTIL SDL3 IS RELEASED*) - imgui_impl_win32.cpp ; Win32 native API (Windows) - imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!) + imgui_impl_android.cpp ; Android native app API + imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/ + imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends) + imgui_impl_sdl2.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org + imgui_impl_sdl3.cpp ; SDL3 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org + imgui_impl_win32.cpp ; Win32 native API (Windows) + imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!) List of Renderer Backends: - imgui_impl_dx9.cpp ; DirectX9 - imgui_impl_dx10.cpp ; DirectX10 - imgui_impl_dx11.cpp ; DirectX11 - imgui_impl_dx12.cpp ; DirectX12 - imgui_impl_metal.mm ; Metal (with ObjC) - imgui_impl_opengl2.cpp ; OpenGL 2 (legacy, fixed pipeline <- don't use with modern OpenGL context) - imgui_impl_opengl3.cpp ; OpenGL 3/4, OpenGL ES 2, OpenGL ES 3 (modern programmable pipeline) + imgui_impl_dx9.cpp ; DirectX9 + imgui_impl_dx10.cpp ; DirectX10 + imgui_impl_dx11.cpp ; DirectX11 + imgui_impl_dx12.cpp ; DirectX12 + imgui_impl_metal.mm ; Metal (ObjC or C++) + imgui_impl_opengl2.cpp ; OpenGL 2 (legacy fixed pipeline. Don't use with modern OpenGL code!) + imgui_impl_opengl3.cpp ; OpenGL 3/4, OpenGL ES 2/3, WebGL + imgui_impl_sdlgpu3.cpp ; SDL_GPU (portable 3D graphics API of SDL3) imgui_impl_sdlrenderer2.cpp ; SDL_Renderer (optional component of SDL2 available from SDL 2.0.18+) - imgui_impl_sdlrenderer3.cpp ; SDL_Renderer (optional component of SDL3 available from SDL 3.0.0+) - imgui_impl_vulkan.cpp ; Vulkan - imgui_impl_wgpu.cpp ; WebGPU (web and desktop) + imgui_impl_sdlrenderer3.cpp ; SDL_Renderer (optional component of SDL3. Prefer using SDL_GPU!). + imgui_impl_vulkan.cpp ; Vulkan + imgui_impl_wgpu.cpp ; WebGPU (web + desktop) List of high-level Frameworks Backends (combining Platform + Renderer): imgui_impl_allegro5.cpp Emscripten is also supported! -The SDL+GL, GLFW+GL and GLFW+WebGPU examples are all ready to build and run with Emscripten. - -### Backends for third-party frameworks, graphics API or other languages - -See https://github.com/ocornut/imgui/wiki/Bindings for the full list (e.g. Adventure Game Studio, Cinder, Cocos2d-x, Game Maker Studio2, Godot, LÖVE+LUA, Magnum, Monogame, Ogre, openFrameworks, OpenSceneGraph, SFML, Sokol, Unity, Unreal Engine and many others). +The SDL2+GL, SDL3+GL, GLFW+GL and GLFW+WebGPU examples are all ready to build and run with Emscripten. ### Recommended Backends @@ -98,18 +106,27 @@ If you are not sure which backend to use, the recommended platform/frameworks fo |Library |Website |Backend |Note | |--------|--------|--------|-----| -| GLFW | https://github.com/glfw/glfw | imgui_impl_glfw.cpp | | +| SDL3 | https://www.libsdl.org | imgui_impl_sdl3.cpp | Recommended | | SDL2 | https://www.libsdl.org | imgui_impl_sdl2.cpp | | +| GLFW | https://github.com/glfw/glfw | imgui_impl_glfw.cpp | | | Sokol | https://github.com/floooh/sokol | [util/sokol_imgui.h](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h) | Lower-level than GLFW/SDL | +If your application runs on Windows or if you are using multi-viewport, the win32 backend handles some details a little better than other backends. + +## List of third-party backends + +See https://github.com/ocornut/imgui/wiki/Bindings for the full list (e.g. Adventure Game Studio, Cinder, Cocos2d-x, Game Maker Studio2, Godot, LÖVE+LUA, Magnum, Monogame, Ogre, openFrameworks, OpenSceneGraph, SFML, Sokol, Unity, Unreal Engine and many others). + +## Writing your own backend ### Using a custom engine? You will likely be tempted to start by rewrite your own backend using your own custom/high-level facilities...
Think twice! -If you are new to Dear ImGui, first try using the existing backends as-is. -You will save lots of time integrating the library. +**Consider using the existing backends as-is**. +You will save lots of time integrating the library. +Standard backends are battle-tested and handle subtleties that you are likely to implement incorrectly. You can LATER decide to rewrite yourself a custom backend if you really need to. In most situations, custom backends have fewer features and more bugs than the standard backends we provide. If you want portability, you can use multiple backends and choose between them either at compile time @@ -131,8 +148,10 @@ Suggestion: try using a non-portable backend first (e.g. win32 + underlying grap your desktop builds working first. This will get you running faster and get your acquainted with how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API... -Generally: -It is unlikely you will add value to your project by creating your own backend. +TL;DR; +- **It is unlikely you will add value to your project by creating your own backend.** +- Writing your own Renderer Backend is easier. +- Writing your own Platform Backend is harder and you are more likely to introduce bugs. Also: The [multi-viewports feature](https://github.com/ocornut/imgui/wiki/Multi-Viewports) of the 'docking' branch allows @@ -144,3 +163,8 @@ Supporting the multi-viewports feature correctly using 100% of your own abstract than supporting single-viewport. If you decide to use unmodified imgui_impl_XXXX.cpp files, you can automatically benefit from improvements and fixes related to viewports and platform windows without extra work on your side. + +### Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+) + +Version [1.92.0](https://github.com/ocornut/imgui/releases/tag/v1.92.0), released June 2025, added texture support in Rendering Backends, which is the backbone for supporting dynamic font scaling among other things. +
**In order to move forward and take advantage of all new features, support for `ImGuiBackendFlags_RendererHasTextures` will likely be REQUIRED for all backends before June 2026.** From 47570d045db3749a97f7a632694e78ef80999f19 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 27 Jun 2025 14:51:13 +0200 Subject: [PATCH 676/716] Docs: update Backends with direction for implementing RenderDrawData function and supporting ImGuiBackendFlags_RendererHasTextures. (#8735, #8465) --- docs/BACKENDS.md | 191 +++++++++++++++++++++++++++++++++++++++++---- docs/CHANGELOG.txt | 3 + docs/EXAMPLES.md | 2 +- docs/FAQ.md | 13 ++- imgui.cpp | 123 +++++++---------------------- imgui.h | 2 +- imgui_demo.cpp | 5 ++ 7 files changed, 228 insertions(+), 111 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 0c5f71bc84da..aae663078bd8 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -7,9 +7,10 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKE - [Introduction](#introduction) - [Using standard backends](#using-standard-backends) - [List of third-party backends](#list-of-third-party-backends) -- [Writing your own backend](#writing-your-own-backend) +- [Writing your own Backend](#writing-your-own-backend) - [Using a custom engine?](#using-a-custom-engine) - - [Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+)](#adding-support-for-imguibackendflags_rendererhastextures-192) + - [Rendering: Implementing your RenderDrawData function](#rendering-implementing-your-renderdrawdata-function) + - [Rendering: Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+)](#rendering-adding-support-for-imguibackendflags_rendererhastextures-192) ## Introduction @@ -117,15 +118,20 @@ If your application runs on Windows or if you are using multi-viewport, the win3 See https://github.com/ocornut/imgui/wiki/Bindings for the full list (e.g. Adventure Game Studio, Cinder, Cocos2d-x, Game Maker Studio2, Godot, LÖVE+LUA, Magnum, Monogame, Ogre, openFrameworks, OpenSceneGraph, SFML, Sokol, Unity, Unreal Engine and many others). -## Writing your own backend +## Writing your own Backend ### Using a custom engine? You will likely be tempted to start by rewrite your own backend using your own custom/high-level facilities...
Think twice! +TL;DR; +- Writing your own Renderer Backend is easy. +- Writing your own Platform Backend is harder and you are more likely to introduce bugs. +- **It is unlikely you will add value to your project by creating your own backend.** + **Consider using the existing backends as-is**. -You will save lots of time integrating the library. +You will save lots of time integrating the library. Standard backends are battle-tested and handle subtleties that you are likely to implement incorrectly. You can LATER decide to rewrite yourself a custom backend if you really need to. In most situations, custom backends have fewer features and more bugs than the standard backends we provide. @@ -148,23 +154,180 @@ Suggestion: try using a non-portable backend first (e.g. win32 + underlying grap your desktop builds working first. This will get you running faster and get your acquainted with how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API... -TL;DR; -- **It is unlikely you will add value to your project by creating your own backend.** -- Writing your own Renderer Backend is easier. -- Writing your own Platform Backend is harder and you are more likely to introduce bugs. - Also: The [multi-viewports feature](https://github.com/ocornut/imgui/wiki/Multi-Viewports) of the 'docking' branch allows Dear ImGui windows to be seamlessly detached from the main application window. This is achieved using an extra layer to the Platform and Renderer backends, which allows Dear ImGui to communicate platform-specific requests such as: "create an additional OS window", "create a render context", "get the OS position of this -window" etc. See 'ImGuiPlatformIO' for details. +window", but some things are more difficult "find OS window under mouse position BUT with some windows marked as passthrough". See 'ImGuiPlatformIO' for details. Supporting the multi-viewports feature correctly using 100% of your own abstractions is more difficult than supporting single-viewport. If you decide to use unmodified imgui_impl_XXXX.cpp files, you can automatically benefit from improvements and fixes related to viewports and platform windows without extra work on your side. -### Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+) - -Version [1.92.0](https://github.com/ocornut/imgui/releases/tag/v1.92.0), released June 2025, added texture support in Rendering Backends, which is the backbone for supporting dynamic font scaling among other things. -
**In order to move forward and take advantage of all new features, support for `ImGuiBackendFlags_RendererHasTextures` will likely be REQUIRED for all backends before June 2026.** +### Rendering: Implementing your RenderDrawData function + +Note: set `ImGuiBackendFlags_RendererHasVtxOffset` to signify your backend can handle rendering with a vertex offset (`ImDrawCmd::VtxOffset` field). +Otherwise, rendering will be limited to 64K vertices per window, which may be limiting for advanced plot. +As an alternative, you may also use `#define ImDrawIdx unsigned int` in your `imconfig.h` file to support 32-bit indices. + +```cpp +void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) +{ + // TODO: Update textures. + // - Most of the times, the list will have 1 element with an OK status, aka nothing to do. + // - This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates. + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + MyImGuiBackend_UpdateTexture(tex); + + // TODO: Setup render state: + // - Alpha-blending enabled + // - No backface culling + // - No depth testing, no depth writing + // - Scissor enabled + MyEngineSetupenderState(); + + // TODO: Setup texture sampling state + // - Sample with bilinear filtering (NOT point/nearest filtering). + // - Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. + + // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + + // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize + + // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. + + // Render command lists + ImVec2 clip_off = draw_data->DisplayPos; + ImVec2 clip_scale = draw_data->FramebufferScale; + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + const ImDrawList* cmd_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui + const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; + if (pcmd->UserCallback) + { + if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) + MyEngineSetupenderState(); + else + pcmd->UserCallback(cmd_list, pcmd); + } + else + { + // Project scissor/clipping rectangles into framebuffer space + // - Clipping coordinates are provided in imgui coordinates space: + // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size + // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values. + // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), + // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. + // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) + ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); + ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) + continue; + + // We are using scissoring to clip some objects. All low-level graphics API should support it. + // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches + // (some elements visible outside their bounds) but you can fix that once everything else works! + MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y); + + // The texture for the draw call is specified by pcmd->GetTexID(). + // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. + MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); + + // Render 'pcmd->ElemCount/3' indexed triangles. + // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. + MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset); + } + } + } +} +``` + +### Rendering: Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+) + +Version [1.92.0](https://github.com/ocornut/imgui/releases/tag/v1.92.0) (June 2025), added texture support in Rendering Backends, which is the backbone for supporting dynamic font scaling among other things. + +**In order to move forward and take advantage of all new features, support for `ImGuiBackendFlags_RendererHasTextures` will likely be REQUIRED for all backends before June 2026.** + +**TD;DR: List of commits which added support for `ImGuiBackendFlags_RendererHasTextures` in standard backends:** + +- Allegro5: [ee8941e](https://github.com/ocornut/imgui/commit/ee8941e) (+35 lines) +- DirectX9: [75efba7](https://github.com/ocornut/imgui/commit/75efba7) (+48 lines) +- DirectX10: [2d2b1bc](https://github.com/ocornut/imgui/commit/2d2b1bc) (+40 lines) +- DirectX11: [372fd27](https://github.com/ocornut/imgui/commit/372fd27) (+40 lines) +- DirectX12: [eefe5d5](https://github.com/ocornut/imgui/commit/eefe5d5) (+87 lines) +- Metal: [26c017d](https://github.com/ocornut/imgui/commit/26c017d) (+55 lines) +- OpenGL Legacy: [0430c55](https://github.com/ocornut/imgui/commit/0430c55) (+25 lines) +- OpenGL3/WebGL/ES: [dbb91a5](https://github.com/ocornut/imgui/commit/dbb91a5) (+47 lines) +- SDL_Renderer2: [9fa65cd](https://github.com/ocornut/imgui/commit/9fa65cd) (+20 lines) +- SDL_Renderer3: [e538883](https://github.com/ocornut/imgui/commit/e538883) (+19 lines) +- SDL_GPU: [16fe666](https://github.com/ocornut/imgui/commit/16fe666) (+41 lines) +- Vulkan: [abe294b](https://github.com/ocornut/imgui/commit/abe294b) (+33 lines) +- WGPU: [571dae9](https://github.com/ocornut/imgui/commit/571dae9) (+30 lines) + +**Instructions** + +- Set `ImGuiBackendFlags_RendererHasTextures` to signify your backend can handle the feature. +- During rendering, e.g. in your RenderDrawData function, iterate `ImDrawData->Textures` array and process all textures. +- During shutdown, iterate the `ImGui::GetPlatformIO().Textures` and destroy all textures. +- (Both arrays are `ImVector`. They are only in different location because: to allow advanced users to perform multi-threaded rendering, we store a pointer to the texture list in ImDrawData, with the aim that multi-threaded rendering users replace it with their own pointer.) + +Pseudo-code for processing a texture: +```cpp +if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + MyImGuiBackend_UpdateTexture(tex); +``` +```cpp +void MyImGuiBackend_UpdateTexture(ImTextureData* tex) +{ + if (tex->Status == ImTextureStatus_WantCreate) + { + // Create texture based on tex->Width, tex->Height. + // - Most backends only support tex->Format == ImTextureFormat_RGBA32. + // - Backends for particularly memory constrainted platforms may support tex->Format == ImTextureFormat_Alpha8. + + // Upload all texture pixels + // - Read from our CPU-side copy of the texture and copy to your graphics API. + // - Use tex->Width, tex->Height, tex->GetPixels(), tex->GetPixelsAt(), tex->GetPitch() as needed. + + // Store your data, and acknowledge creation. + tex->SetTexID(xxxx); // Specify backend-specific ImTextureID identifier which will be stored in ImDrawCmd. + tex->SetStatus(ImTextureStatus_OK); + tex->BackendUserData = xxxx; // Store more backend data if needed (most backend allocate a small texture to store data in there) + } + if (tex->Status == ImTextureStatus_WantUpdates) + { + // Upload a rectangle of pixels to the existing texture + // - We only ever write to textures regions which have never been used before! + // - Use tex->TexID or tex->BackendUserData to retrieve your stored data. + // - Use tex->UpdateRect.x/y, tex->UpdateRect.w/h to obtain the block position and size. + // - Use tex->Updates[] to obtain individual sub-regions within tex->UpdateRect. Not recommended. + // - Read from our CPU-side copy of the texture and copy to your graphics API. + // - Use tex->Width, tex->Height, tex->GetPixels(), tex->GetPixelsAt(), tex->GetPitch() as needed. + + // Acknowledge update + tex->SetStatus(ImTextureStatus_OK); + } + if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + { + // If you use staged rendering and have in-flight renders, changed tex->UnusedFrames > 0 check to higher count as needed e.g. > 2 + + // Destroy texture + // - Use tex->TexID or tex->BackendUserData to retrieve your stored data. + // - Destroy texture in your graphics API. + + // Acknowledge destruction + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); + } +} +``` +Refer to "List of commits which added support for `ImGuiBackendFlags_RendererHasTextures` in standard backends" above for concrete examples of this. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1b93505d1126..bdd06a7c3934 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,9 @@ THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCE, BUT INEVITABLY SOME USERS OR THIRD-PARTY EXTENSIONS WILL BE AFFECTED. +For instructions to upgrade your custom backend: +--> See https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md + IN ORDER TO HELP US IMPROVE THE TRANSITION PROCESS, INCL. DOCUMENTATION AND COMMENTS, PLEASE REPORT **ANY** DOUBT, CONFUSION, QUESTIONS, FEEDBACK TO: https://github.com/ocornut/imgui/issues/ diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 2826a5ad7946..20851c1589fa 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -3,7 +3,7 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/EXAMP ## Dear ImGui: Examples **The [examples/](https://github.com/ocornut/imgui/blob/master/examples) folder example applications (standalone, ready-to-build) for variety of -platforms and graphics APIs.** They all use standard backends from the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder (see [BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md)). +platforms and graphics APIs.** They all use standard backends from the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder (see [docs/BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md)). The purpose of Examples is to showcase integration with backends, let you try Dear ImGui, and guide you toward integrating Dear ImGui in your own application/game/engine. diff --git a/docs/FAQ.md b/docs/FAQ.md index ad35d5451b0d..10fb60350118 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -19,6 +19,7 @@ or view this file with any Markdown viewer. | **[How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?](#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear-imgui-or-my-application)** | | [How can I enable keyboard or gamepad controls?](#q-how-can-i-enable-keyboard-or-gamepad-controls) | | [How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)](#q-how-can-i-use-this-on-a-machine-without-mouse-keyboard-or-screen-input-share-remote-display) | +| [How can I create my own backend?](q-how-can-i-create-my-own-backend) | [I integrated Dear ImGui in my engine and little squares are showing instead of text...](#q-i-integrated-dear-imgui-in-my-engine-and-little-squares-are-showing-instead-of-text) | | [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) | | [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) | @@ -92,8 +93,8 @@ Many projects are using this branch and it is kept in sync with master regularly ### Q: How to get started? Read [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started).
-Read [EXAMPLES.md](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md).
-Read [BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md).
+Read [docs/EXAMPLES.md](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md).
+Read [docs/BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md).
Read `PROGRAMMER GUIDE` section of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp).
The [Wiki](https://github.com/ocornut/imgui/wiki) is a hub to many resources and links. @@ -159,6 +160,14 @@ Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-lik --- +### Q: How can I create my own backend? +- See [docs/BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md). +- See Documentation at the top of imgui.cpp. + +##### [Return to Index](#index) + +--- + ### Q: I integrated Dear ImGui in my engine and little squares are showing instead of text... Your renderer backend is not using the font texture correctly or it hasn't been uploaded to the GPU. - If this happens using standard backends (before 1.92): A) have you modified the font atlas after `ImGui_ImplXXX_NewFrame()`? B) maybe the texture failed to upload, which **can if your texture atlas is too big**. Also see [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md). diff --git a/imgui.cpp b/imgui.cpp index b5c534c57b78..b256c9ffe2e7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -53,7 +53,7 @@ DOCUMENTATION - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE - HOW A SIMPLE APPLICATION MAY LOOK LIKE - - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE + - USING CUSTOM BACKEND / CUSTOM ENGINE - API BREAKING CHANGES (read me when you update!) - FREQUENTLY ASKED QUESTIONS (FAQ) - Read all answers online: https://www.dearimgui.com/faq, or in docs/FAQ.md (with a Markdown viewer) @@ -274,7 +274,8 @@ CODE HOW A SIMPLE APPLICATION MAY LOOK LIKE -------------------------------------- - EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder). + + USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder). The sub-folders in examples/ contain examples applications following this structure. // Application init: create a dear imgui context, setup some options, load fonts @@ -310,7 +311,27 @@ CODE ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); - EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE + To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application, + you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! + Please read the FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" about this. + + +USING CUSTOM BACKEND / CUSTOM ENGINE +------------------------------------ + +IMPLEMENTING YOUR RenderDrawData() function: + -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md + -> the Renderer Backends in impl_impl_XXX.cpp files contain many implementations of a ImGui_ImplXXXX_RenderDrawData() function. + +IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: + -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md + -> the Renderer Backends in impl_impl_XXX.cpp files contain many implementations of a ImGui_ImplXXXX_UpdateTexture() function. + +IMPLEMENTING YOUR PLATFORM BACKEND: + -> missing documentation. + -> the Platform backends in impl_impl_XXX.cpp files contain many implementations. + + Basic application/backend skeleton: // Application init: create a Dear ImGui context, setup some options, load fonts ImGui::CreateContext(); @@ -319,7 +340,7 @@ CODE io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable keyboard controls // TODO: Load TTF/OTF fonts if you don't want to use the default font. - io.Fonts->AddFontFromFileTTF("NotoSans.ttf", 18.0f); + io.Fonts->AddFontFromFileTTF("NotoSans.ttf"); // Application main loop while (true) @@ -361,95 +382,6 @@ CODE // Shutdown ImGui::DestroyContext(); - To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application, - you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! - Please read the FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" about this. - - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE - --------------------------------------------- - The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. - - void MyImGuiBackend_UpdateTexture(ImTextureData* tex) - { - if (tex->Status == ImTextureStatus_WantCreate) - { - // Width/Height/Pixels> - tex->SetTexID(xxxx); // specify backend-specific ImTextureID identifier - tex->SetStatus(ImTextureStatus_OK); - tex->BackendUserData = xxxx; // store more backend data - } - if (tex->Status == ImTextureStatus_WantUpdates) - { - // UpdateRect> - tex->SetStatus(ImTextureStatus_OK); - } - if (tex->Status == ImTextureStatus_WantDestroy) - { - // - tex->SetTexID(ImTextureID_Invalid); - tex->SetStatus(ImTextureStatus_Destroyed); - } - } - - void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) - { - if (draw_data->Textures != nullptr) - for (ImTextureData* tex : *draw_data->Textures) - if (tex->Status != ImTextureStatus_OK) - MyImGuiBackend_UpdateTexture(tex); - - - // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled - // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. - // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize - // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize - // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color. - ImVec2 clip_off = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui - const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback) - { - if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) - MyEngineResetRenderState(); - else - pcmd->UserCallback(cmd_list, pcmd); - } - else - { - // Project scissor/clipping rectangles into framebuffer space - ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); - ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); - if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) - continue; - - // We are using scissoring to clip some objects. All low-level graphics API should support it. - // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches - // (some elements visible outside their bounds) but you can fix that once everything else works! - // - Clipping coordinates are provided in imgui coordinates space: - // - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size - // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values. - // - In the interest of supporting multi-viewport applications (see 'docking' branch on github), - // always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space. - // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min) - MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max.y); - - // The texture for the draw call is specified by pcmd->GetTexID(). - // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization. - MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); - - // Render 'pcmd->ElemCount/3' indexed triangles. - // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. - MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_buffer, pcmd->VtxOffset); - } - } - } - } API BREAKING CHANGES @@ -15941,7 +15873,12 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); //EndDisabled(); if ((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) + { BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); + BulletText("For instructions, see:"); + SameLine(); + TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md"); + } BulletText("Load a nice font for better results!"); BulletText("Please submit feedback:"); SameLine(); TextLinkOpenURL("#8465", "https://github.com/ocornut/imgui/issues/8465"); diff --git a/imgui.h b/imgui.h index ab23774d19d8..e417731d0b43 100644 --- a/imgui.h +++ b/imgui.h @@ -1691,7 +1691,7 @@ enum ImGuiBackendFlags_ ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Backend Platform supports honoring GetMouseCursor() value to change the OS cursor shape. ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Backend Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3, // Backend Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices. - ImGuiBackendFlags_RendererHasTextures = 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables incremental texture updates and texture reloads. + ImGuiBackendFlags_RendererHasTextures = 1 << 4, // Backend Renderer supports ImTextureData requests to create/update/destroy textures. This enables incremental texture updates and texture reloads. See https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md for instructions on how to upgrade your custom backend. }; // Enumeration for PushStyleColor() / PopStyleColor() diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 94d39587f2f7..c743667c1185 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8230,7 +8230,12 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) // General SeparatorText("General"); if ((GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) + { BulletText("Warning: Font scaling will NOT be smooth, because\nImGuiBackendFlags_RendererHasTextures is not set!"); + BulletText("For instructions, see:"); + SameLine(); + TextLinkOpenURL("docs/BACKENDS.md", "https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md"); + } if (ShowStyleSelector("Colors##Selector")) ref_saved_style = style; From 68046106ddf02b2c518977814b78b47cb27d792b Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 27 Jun 2025 15:15:34 +0200 Subject: [PATCH 677/716] Docs: update Backends with basic Platform backend instructions. --- docs/BACKENDS.md | 57 ++++++++++++++++++++++++++++++++++++++++++------ imgui.cpp | 8 +++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index aae663078bd8..ae5e91b0e309 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -5,10 +5,13 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKE ## Index - [Introduction](#introduction) -- [Using standard backends](#using-standard-backends) -- [List of third-party backends](#list-of-third-party-backends) + - [Getting Started](#getting-started) + - [What are Backends?](#what-are-backends) +- [Using standard Backends](#using-standard-backends) +- [Using third-party Backends](#using-third-party-backends) - [Writing your own Backend](#writing-your-own-backend) - [Using a custom engine?](#using-a-custom-engine) + - [Platform: Implementing your Platform Backend](#platform-implementing-your-platform-backend) - [Rendering: Implementing your RenderDrawData function](#rendering-implementing-your-renderdrawdata-function) - [Rendering: Adding support for `ImGuiBackendFlags_RendererHasTextures` (1.92+)](#rendering-adding-support-for-imguibackendflags_rendererhastextures-192) @@ -19,7 +22,7 @@ _(You may browse this at https://github.com/ocornut/imgui/blob/master/docs/BACKE 💡 The **[Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) wiki guide** has examples of how to integrate Dear ImGui into an existing application.
The [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) documentation may also be worth a read. -### What are backends? +### What are Backends? Dear ImGui is highly portable and only requires a few things to run and render, typically: @@ -46,7 +49,7 @@ and the backends which we are describing here (backends/ folder). - You should be able to write backends for pretty much any platform and any 3D graphics API. e.g. you can get creative and use software rendering or render remotely on a different machine. -## Using standard backends +## Using standard Backends **The [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder contains backends for popular platforms/graphics API, which you can use in your application or engine to easily integrate Dear ImGui.** Each backend is typically self-contained in a pair of files: imgui_impl_XXXX.cpp + imgui_impl_XXXX.h. @@ -65,7 +68,7 @@ For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree **Once Dear ImGui is setup and running, run and refer to `ImGui::ShowDemoWindow()` in imgui_demo.cpp for usage of the end-user API.** -### List of standard backends +### List of standard Backends In the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder: @@ -114,7 +117,7 @@ If you are not sure which backend to use, the recommended platform/frameworks fo If your application runs on Windows or if you are using multi-viewport, the win32 backend handles some details a little better than other backends. -## List of third-party backends +## Using third-party Backends See https://github.com/ocornut/imgui/wiki/Bindings for the full list (e.g. Adventure Game Studio, Cinder, Cocos2d-x, Game Maker Studio2, Godot, LÖVE+LUA, Magnum, Monogame, Ogre, openFrameworks, OpenSceneGraph, SFML, Sokol, Unity, Unreal Engine and many others). @@ -165,6 +168,46 @@ than supporting single-viewport. If you decide to use unmodified imgui_impl_XXXX.cpp files, you can automatically benefit from improvements and fixes related to viewports and platform windows without extra work on your side. +### Platform: Implementing your Platform Backend + +The Platform backends in impl_impl_XXX.cpp files contain many implementations. + +**In your `ImGui_ImplXXX_Init()` function:** +- You can allocate your backend data and use `io.BackendPlatformUserData` to store/retrieve it later. +- Set `io.BackendPlatformName` to a name `"imgui_impl_xxxx"` which will be available in e.g. About box. +- Set `io.BackendPlatformUserData` to your backend data. +- Set `io.BackendFlags` with supported optional features: + - `ImGuiBackendFlags_HasGamepad`: supports gamepad and currently has one connected. + - `ImGuiBackendFlags_HasMouseCursors`: supports honoring GetMouseCursor() value to change the OS cursor shape. + - `ImGuiBackendFlags_HasSetMousePos`: supports io.WantSetMousePos requests to reposition the OS mouse position (only used if io.ConfigNavMoveSetMousePos is set). + - `ImGuiBackendFlags_PlatformHasViewports` supports multiple viewports. (multi-viewports only) + - `ImGuiBackendFlags_HasMouseHoveredViewport` supports calling io.AddMouseViewportEvent() with the viewport under the mouse. IF POSSIBLE, ignore viewports with the ImGuiViewportFlags_NoInputs flag. If this cannot be done, Dear ImGui needs to use a flawed heuristic to find the viewport under mouse position, as it doesn't know about foreign windows. (multi-viewports only) + +**In your `ImGui_ImplXXX_NewFrame()` function:** +- Set `io.DeltaTime` to the time elapsed (in seconds) since last frame. +- Set `io.DisplaySize` to your window size. +- Set `io.DisplayFrameBufferSize` to your window pixel density (macOS/iOS only). +- Update mouse cursor shape is supported. + +**In your `ImGui_ImplXXX_NewFrame()` function or event handlers:** +- **Mouse Support** + - Use `io.AddMousePosEvent()`, `io.AddMouseButtonEvent()`, `io.AddMouseWheelEvent()` to pass mouse events. + - Use `io.AddMouseSourceEvent()` if you are able to distinguish Mouse from TouchScreen from Pen inputs. TouchScreen and Pen inputs requires different logic for some Dear ImGui features. + - Use `io.AddMouseViewportEvent()` to specify which viewport/OS window is being hovered by the mouse. Read instructions carefully as this is not as simple as it seems! (multi-viewports only) +- **Keyboard Support** + - Use `io.AddKeyEvent()` to pass key events. + - Use `io.AddInputCharacter()` to pass text/character events. +- **Gamepad Support** + - Use `io.AddKeyEvent()` and `io.AddKeyAnalogEvent()` to pass gamepad events, using `ImGuiKey_GamepadXXX` values. +- **Miscellaneous** + - Clipboard Support: setup `Platform_GetClipboardTextFn()`, `Platform_SetClipboardTextFn()` handlers in `ImGuiPlatformIO`. + - Open in Shell support: setup `Platform_OpenInShellFn()` handler in `ImGuiPlatformIO`. + - IME Support: setup `Platform_SetImeDataFn()` handler in `ImGuiPlatformIO`. + - Use `io.AddFocusEvent()` to notify when application window gets focused/unfocused. +- **Multi-viewport Support** + - Update monitor list if supported. + - Setup all required handlers in `ImGuiPlatformIO` to create/destroy/move/resize/title/focus/etc. windows. + ### Rendering: Implementing your RenderDrawData function Note: set `ImGuiBackendFlags_RendererHasVtxOffset` to signify your backend can handle rendering with a vertex offset (`ImDrawCmd::VtxOffset` field). @@ -271,7 +314,7 @@ Version [1.92.0](https://github.com/ocornut/imgui/releases/tag/v1.92.0) (June 20 - Vulkan: [abe294b](https://github.com/ocornut/imgui/commit/abe294b) (+33 lines) - WGPU: [571dae9](https://github.com/ocornut/imgui/commit/571dae9) (+30 lines) -**Instructions** +**Instructions:** - Set `ImGuiBackendFlags_RendererHasTextures` to signify your backend can handle the feature. - During rendering, e.g. in your RenderDrawData function, iterate `ImDrawData->Textures` array and process all textures. diff --git a/imgui.cpp b/imgui.cpp index b256c9ffe2e7..acdbf33e4434 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -319,6 +319,10 @@ CODE USING CUSTOM BACKEND / CUSTOM ENGINE ------------------------------------ +IMPLEMENTING YOUR PLATFORM BACKEND: + -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md for basic instructions. + -> the Platform backends in impl_impl_XXX.cpp files contain many implementations. + IMPLEMENTING YOUR RenderDrawData() function: -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md -> the Renderer Backends in impl_impl_XXX.cpp files contain many implementations of a ImGui_ImplXXXX_RenderDrawData() function. @@ -327,10 +331,6 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: -> see https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md -> the Renderer Backends in impl_impl_XXX.cpp files contain many implementations of a ImGui_ImplXXXX_UpdateTexture() function. -IMPLEMENTING YOUR PLATFORM BACKEND: - -> missing documentation. - -> the Platform backends in impl_impl_XXX.cpp files contain many implementations. - Basic application/backend skeleton: // Application init: create a Dear ImGui context, setup some options, load fonts From 8e3aac57449b9ab73dabef187807528a597e837a Mon Sep 17 00:00:00 2001 From: Thomas Quante Date: Fri, 27 Jun 2025 15:52:39 +0200 Subject: [PATCH 678/716] Backends: Vulkan: use nonCoherentAtomSize to align upload_size, fixing validation error on some setups. (#8743, #8744) --- backends/imgui_impl_vulkan.cpp | 10 +++++++++- docs/CHANGELOG.txt | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 5546a59ff03a..059e8c9edb77 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-27: Vulkan: Fixed validation errors during texture upload/update by aligning upload size to 'nonCoherentAtomSize'. (#8743, #8744) // 2025-06-11: Vulkan: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_DestroyFontsTexture(). // 2025-05-07: Vulkan: Fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) // 2025-05-07: Vulkan: Load dynamic rendering functions using vkGetDeviceProcAddr() + try both non-KHR and KHR versions. (#8600, #8326, #8365) @@ -244,6 +245,7 @@ struct ImGui_ImplVulkan_Data { ImGui_ImplVulkan_InitInfo VulkanInitInfo; VkDeviceSize BufferMemoryAlignment; + VkDeviceSize NonCoherentAtomSize; VkPipelineCreateFlags PipelineCreateFlags; VkDescriptorSetLayout DescriptorSetLayout; VkPipelineLayout PipelineLayout; @@ -264,6 +266,7 @@ struct ImGui_ImplVulkan_Data { memset((void*)this, 0, sizeof(*this)); BufferMemoryAlignment = 256; + NonCoherentAtomSize = 64; } }; @@ -751,7 +754,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) VkBuffer upload_buffer; VkDeviceSize upload_pitch = upload_w * tex->BytesPerPixel; - VkDeviceSize upload_size = upload_h * upload_pitch; + VkDeviceSize upload_size = AlignBufferSize(upload_h * upload_pitch, bd->NonCoherentAtomSize); { VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -1225,6 +1228,11 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; + + VkPhysicalDeviceProperties properties; + vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties); + bd->NonCoherentAtomSize = properties.limits.nonCoherentAtomSize; + #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index bdd06a7c3934..5666a03cc168 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) [@cfillion] +- Backends: Vulkan: use nonCoherentAtomSize to align upload_size, fixing + validation error on some setups. (#8743, #8744) [@tquante] ----------------------------------------------------------------------- From fff47f111985ee755256dce0f19e0aaee6e2eb7f Mon Sep 17 00:00:00 2001 From: morrazzzz <123486080+morrazzzz@users.noreply.github.com> Date: Tue, 24 Jun 2025 23:30:38 +0300 Subject: [PATCH 679/716] Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. (#8727) --- backends/imgui_impl_sdl3.cpp | 3 ++- docs/CHANGELOG.txt | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 9c0d6581cea0..48e766bcdf9c 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727) // 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801) @@ -169,7 +170,7 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view SDL_SetTextInputArea(window, &r, 0); bd->ImeWindow = window; } - if (data->WantVisible || data->WantTextInput) + if (!SDL_TextInputActive(window) && (data->WantVisible || data->WantTextInput)) SDL_StartTextInput(window); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5666a03cc168..fd705f1c80f6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. + (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) [@cfillion] - Backends: Vulkan: use nonCoherentAtomSize to align upload_size, fixing From 9fbe56021865d6961859dc40a93bc5dba11e7401 Mon Sep 17 00:00:00 2001 From: Demonese Date: Fri, 27 Jun 2025 10:33:25 +0800 Subject: [PATCH 680/716] Demo: Added "Widgets/Text/Different Size Text" section to show font system changes in v1.92. (#8738) --- imgui_demo.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c743667c1185..8acbfcb3978a 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3548,6 +3548,35 @@ static void DemoWindowWidgetsText() ImGui::TreePop(); } + IMGUI_DEMO_MARKER("Widgets/Text/Different Size Text"); + if (ImGui::TreeNode("Different Size Text")) + { + const ImGuiStyle& style = ImGui::GetStyle(); + + for (float scaling = 0.5f; scaling < 4.01f; scaling += 0.5f) + { + ImGui::PushFont(nullptr, style.FontSizeBase * scaling); + ImGui::Text("Text size is %.1f (style.FontSizeBase * %.1f)", style.FontSizeBase * scaling, scaling); + ImGui::PopFont(); + } + + static float custom_scaling{ 1.0f }; + ImGui::SliderFloat("Custom Scaling##Different Size Text", &custom_scaling, 0.5f, 4.0f, "%.1f"); + ImGui::SameLine(); HelpMarker("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scaling);"); + ImGui::PushFont(nullptr, style.FontSizeBase * custom_scaling); + ImGui::Text("Text size is %.1f (style.FontSizeBase * %.1f)", style.FontSizeBase * custom_scaling, custom_scaling); + ImGui::PopFont(); + + static float custom_font_size{ 16.0f }; + ImGui::SliderFloat("Custom Font Size##Different Size Text", &custom_font_size, 10.0f, 100.0f, "%.1f"); + ImGui::SameLine(); HelpMarker("ImGui::PushFont(nullptr, custom_font_size);"); + ImGui::PushFont(nullptr, custom_font_size); + ImGui::Text("Text size is %.1f", custom_font_size); + ImGui::PopFont(); + + ImGui::TreePop(); + } + IMGUI_DEMO_MARKER("Widgets/Text/Word Wrapping"); if (ImGui::TreeNode("Word Wrapping")) { From 0fe51665313b627957cb11ed177e09ee9ccf9364 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 27 Jun 2025 16:54:16 +0200 Subject: [PATCH 681/716] Demo: amend "Font Size" demo. (#8738) --- imgui_demo.cpp | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8acbfcb3978a..692eb2992c90 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3548,32 +3548,40 @@ static void DemoWindowWidgetsText() ImGui::TreePop(); } - IMGUI_DEMO_MARKER("Widgets/Text/Different Size Text"); - if (ImGui::TreeNode("Different Size Text")) + IMGUI_DEMO_MARKER("Widgets/Text/Font Size"); + if (ImGui::TreeNode("Font Size")) { - const ImGuiStyle& style = ImGui::GetStyle(); + ImGuiStyle& style = ImGui::GetStyle(); + const float global_scale = style.FontScaleMain * style.FontScaleDpi; + ImGui::Text("style.FontScaleMain = %0.2f", style.FontScaleMain); + ImGui::Text("style.FontScaleDpi = %0.2f", style.FontScaleDpi); + ImGui::Text("global_scale = ~%0.2f", global_scale); // This is not technically accurate as internal scales may apply, but conceptually let's pretend it is. + ImGui::Text("FontSize = %0.2f", ImGui::GetFontSize()); + + ImGui::SeparatorText(""); + static float custom_size = 16.0f; + ImGui::SliderFloat("custom_size", &custom_size, 10.0f, 100.0f, "%.0f"); + ImGui::Text("ImGui::PushFont(nullptr, custom_size);"); + ImGui::PushFont(NULL, custom_size); + ImGui::Text("FontSize = %.2f (== %.2f * global_scale)", ImGui::GetFontSize(), custom_size); + ImGui::PopFont(); + + ImGui::SeparatorText(""); + static float custom_scale = 1.0f; + ImGui::SliderFloat("custom_scale", &custom_scale, 0.5f, 4.0f, "%.2f"); + ImGui::Text("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scale);"); + ImGui::PushFont(NULL, style.FontSizeBase * custom_scale); + ImGui::Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui::GetFontSize(), custom_scale); + ImGui::PopFont(); - for (float scaling = 0.5f; scaling < 4.01f; scaling += 0.5f) + ImGui::SeparatorText(""); + for (float scaling = 0.5f; scaling <= 4.0f; scaling += 0.5f) { - ImGui::PushFont(nullptr, style.FontSizeBase * scaling); - ImGui::Text("Text size is %.1f (style.FontSizeBase * %.1f)", style.FontSizeBase * scaling, scaling); + ImGui::PushFont(NULL, style.FontSizeBase * scaling); + ImGui::Text("FontSize = %.2f (== style.FontSizeBase * %.2f * global_scale)", ImGui::GetFontSize(), scaling); ImGui::PopFont(); } - static float custom_scaling{ 1.0f }; - ImGui::SliderFloat("Custom Scaling##Different Size Text", &custom_scaling, 0.5f, 4.0f, "%.1f"); - ImGui::SameLine(); HelpMarker("ImGui::PushFont(nullptr, style.FontSizeBase * custom_scaling);"); - ImGui::PushFont(nullptr, style.FontSizeBase * custom_scaling); - ImGui::Text("Text size is %.1f (style.FontSizeBase * %.1f)", style.FontSizeBase * custom_scaling, custom_scaling); - ImGui::PopFont(); - - static float custom_font_size{ 16.0f }; - ImGui::SliderFloat("Custom Font Size##Different Size Text", &custom_font_size, 10.0f, 100.0f, "%.1f"); - ImGui::SameLine(); HelpMarker("ImGui::PushFont(nullptr, custom_font_size);"); - ImGui::PushFont(nullptr, custom_font_size); - ImGui::Text("Text size is %.1f", custom_font_size); - ImGui::PopFont(); - ImGui::TreePop(); } From bc051dcf91cb0e3c61ce20e582c91654d0049003 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 27 Jun 2025 17:03:13 +0200 Subject: [PATCH 682/716] Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value. --- docs/CHANGELOG.txt | 3 +++ imgui.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fd705f1c80f6..3bf28c689c02 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking changes: Other changes: +- Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: + ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] +- Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress diff --git a/imgui.h b/imgui.h index e417731d0b43..b09d7ee82684 100644 --- a/imgui.h +++ b/imgui.h @@ -3440,7 +3440,7 @@ struct ImTextureData bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. // Functions - ImTextureData() { memset(this, 0, sizeof(*this)); } + ImTextureData() { memset(this, 0, sizeof(*this)); TexID = ImTextureID_Invalid; } ~ImTextureData() { DestroyPixels(); } IMGUI_API void Create(ImTextureFormat format, int w, int h); IMGUI_API void DestroyPixels(); From de7625b8c25b07214a7ed6540d2225a1547c2231 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 Jun 2025 16:45:58 +0200 Subject: [PATCH 683/716] Docs: tweak/fixed comments. (#8750, #8749) --- docs/CHANGELOG.txt | 12 +++++------- docs/FONTS.md | 2 +- imgui.cpp | 9 ++++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3bf28c689c02..b548fb65713b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -117,13 +117,11 @@ Breaking changes: `PushFont(NULL, some_size)` now keeps current change and changes size. - Renamed/moved 'io.FontGlobalScale' to 'style.FontScaleMain'. - Fonts: **IMPORTANT** on Font Merging: - - When searching for a glyph in multiple merged fonts: font inputs are now scanned in order - for the first font input which the desired glyph. This is technically a different behavior - than before! - - e.g. If you are merging fonts you may have glyphs that you expected to load from - Font Source 2 which exists in Font Source 1. After the update and when using a new backend, - those glyphs may now loaded from Font Source 1! - - You can use `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to ignore in given Input: + - When searching for a glyph in multiple merged fonts: we search for the FIRST font source + which contains the desired glyph. Because the user doesn't need to provide glyph ranges + any more, it is possible that a glyph that you expected to fetch from a secondary/merged + icon font may be erroneously fetched from the primary font. + - We added `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to exclude from a given font source: // Add Font Source 1 but ignore ICON_MIN_FA..ICON_MAX_FA range static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; ImFontConfig cfg1; diff --git a/docs/FONTS.md b/docs/FONTS.md index f8431507cf50..ce08f176d903 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -387,7 +387,7 @@ io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\seguiemj.ttf", 16.0f, &cfg); ## Using Custom Glyph Ranges -🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is necessary, so this is not needed.** +🆕 **Since 1.92, with an up to date backend: specifying glyph ranges is unnecessary. Therefore this is not really useful any more.** :rewind: You can use the `ImFontGlyphRangesBuilder` helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. ```cpp diff --git a/imgui.cpp b/imgui.cpp index acdbf33e4434..8aaa901fcd86 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -416,9 +416,12 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - To use old behavior: use 'ImGui::PushFont(font, font->LegacySize)' at call site. - Kept inline single parameter function. Will obsolete. - Fonts: **IMPORTANT** on Font Merging: - - When searching for a glyph in multiple merged fonts: font inputs are now scanned in orderfor the first font input which the desired glyph. This is technically a different behavior than before! - - e.g. If you are merging fonts you may have glyphs that you expected to load from Font Source 2 which exists in Font Source 1. After the update and when using a new backend, those glyphs may now loaded from Font Source 1! - - You can use `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to ignore in given Input: + - When searching for a glyph in multiple merged fonts: we search for the FIRST font source which contains the desired glyph. + Because the user doesn't need to provide glyph ranges any more, it is possible that a glyph that you expected to fetch from a secondary/merged icon font may be erroneously fetched from the primary font. + - When searching for a glyph in multiple merged fonts: we now search for the FIRST font source which contains the desired glyph. This is technically a different behavior than before! + - e.g. If you are merging fonts you may have glyphs that you expected to load from Font Source 2 which exists in Font Source 1. + After the update and when using a new backend, those glyphs may now loaded from Font Source 1! + - We added `ImFontConfig::GlyphExcludeRanges[]` to specify ranges to exclude from a given font source: // Add Font Source 1 but ignore ICON_MIN_FA..ICON_MAX_FA range static ImWchar exclude_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; ImFontConfig cfg1; From d99ab9f90355adb3197f81eef9060b44d1076ae0 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 28 Jun 2025 17:15:18 +0200 Subject: [PATCH 684/716] Backends: SDL2: undef Status for X11. (#8751) --- backends/imgui_impl_sdl2.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 9f5e0374aaee..18035d24fb8c 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -118,6 +118,9 @@ #ifdef __EMSCRIPTEN__ #include #endif +#ifdef Status // X11 headers +#undef Status +#endif #if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1 From 8c61ee5498f1761c057f6aa8f87222c11b4c8eff Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 29 Jun 2025 18:05:28 +0200 Subject: [PATCH 685/716] Tables: fixed comments about DisableDefaultContextMenu. (#8746) --- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui_internal.h b/imgui_internal.h index eeee93778f5e..22fbef4f20f7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2982,7 +2982,7 @@ struct IMGUI_API ImGuiTable bool IsSortSpecsDirty; bool IsUsingHeaders; // Set when the first row had the ImGuiTableRowFlags_Headers flag. bool IsContextPopupOpen; // Set when default context menu is open (also see: ContextPopupColumn, InstanceInteracted). - bool DisableDefaultContextMenu; // Disable default context menu contents. You may submit your own using TableBeginContextMenuPopup()/EndPopup() + bool DisableDefaultContextMenu; // Disable default context menu. You may submit your own using TableBeginContextMenuPopup()/EndPopup() bool IsSettingsRequestLoad; bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data. bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f6d51652145e..069c7299581e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1251,7 +1251,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // [Part 11] Default context menu // - To append to this menu: you can call TableBeginContextMenuPopup()/.../EndPopup(). - // - To modify or replace this: set table->IsContextPopupNoDefaultContents = true, then call TableBeginContextMenuPopup()/.../EndPopup(). + // - To modify or replace this: set table->DisableDefaultContextMenu = true, then call TableBeginContextMenuPopup()/.../EndPopup(). // - You may call TableDrawDefaultContextMenu() with selected flags to display specific sections of the default menu, // e.g. TableDrawDefaultContextMenu(table, table->Flags & ~ImGuiTableFlags_Hideable) will display everything EXCEPT columns visibility options. if (table->DisableDefaultContextMenu == false && TableBeginContextMenuPopup(table)) From 8ccfdf7ba05b74b9d80d8fad728c5510c5634c2c Mon Sep 17 00:00:00 2001 From: Aidan Sun Date: Sun, 29 Jun 2025 17:32:48 -0400 Subject: [PATCH 686/716] CI: Fixed dllimport/dllexport tests. (#8757) --- .github/workflows/build.yml | 20 ++++++-------------- docs/CHANGELOG.txt | 1 + 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86872d21cb85..bc58e25bbe00 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,15 +51,11 @@ jobs: - name: Build example_null (mingw 64-bit, as DLL) shell: bash run: | - echo '#ifdef _EXPORT' > example_single_file.cpp - echo '# define IMGUI_API __declspec(dllexport)' >> example_single_file.cpp - echo '#else' >> example_single_file.cpp - echo '# define IMGUI_API __declspec(dllimport)' >> example_single_file.cpp - echo '#endif' >> example_single_file.cpp + echo '#define IMGUI_API __declspec(dllexport)' > example_single_file.cpp echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp - g++ -I. -Wall -Wformat -D_EXPORT -shared -o libimgui.dll -Wl,--out-implib,libimgui.a example_single_file.cpp -limm32 - g++ -I. -Wall -Wformat -o example_null.exe examples/example_null/main.cpp -L. -limgui + g++ -I. -Wall -Wformat -shared -o libimgui.dll -Wl,--out-implib,libimgui.a example_single_file.cpp -limm32 + g++ -I. -Wall -Wformat -DIMGUI_API='__declspec(dllimport)' -o example_null.exe examples/example_null/main.cpp -L. -limgui rm -f example_null.exe libimgui.* example_single_file.* - name: Build example_null (extra warnings, msvc 64-bit) @@ -99,16 +95,12 @@ jobs: run: | call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat" - echo #ifdef _EXPORT > example_single_file.cpp - echo # define IMGUI_API __declspec(dllexport) >> example_single_file.cpp - echo #else >> example_single_file.cpp - echo # define IMGUI_API __declspec(dllimport) >> example_single_file.cpp - echo #endif >> example_single_file.cpp + echo #define IMGUI_API __declspec(dllexport) > example_single_file.cpp echo #define IMGUI_IMPLEMENTATION >> example_single_file.cpp echo #include "misc/single_file/imgui_single_file.h" >> example_single_file.cpp - cl.exe /D_USRDLL /D_WINDLL /D_EXPORT /I. example_single_file.cpp /LD /FeImGui.dll /link - cl.exe /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp + cl.exe /D_USRDLL /D_WINDLL /I. example_single_file.cpp /LD /FeImGui.dll /link + cl.exe /DIMGUI_API=__declspec(dllimport) /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp - name: Build Win32 example_glfw_opengl2 shell: cmd diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b548fb65713b..216b61524d8c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,7 @@ Other changes: - Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] +- CI: Fixed dllimport/dllexport tests. (#8757) [@AidanSun05] - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress From b7e5d76c7928d66ace9116a9f180153a7c260b59 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 30 Jun 2025 20:01:02 +0200 Subject: [PATCH 687/716] Fonts: added ImFontAtlas::SetFontLoader() to dynamically change font loader at runtime without using internal API. (#8752, #8465) --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 7 ++++--- imgui.h | 5 +++-- imgui_draw.cpp | 9 +++++++-- misc/freetype/imgui_freetype.h | 6 +++--- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 216b61524d8c..0b9d1d9a1fd7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,8 @@ Breaking changes: Other changes: +- Fonts: added ImFontAtlas::SetFontLoader() to dynamically change font + loader at runtime without using internal API. (#8752, #8465) - Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] @@ -211,7 +213,7 @@ Breaking changes: - renamed/reworked ImFontBuilderIO into ImFontLoader, - renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader() - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() - - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader(); + - new: io.Fonts->FontLoader = ImGuiFreeType::GetFontLoader() - DrawList: Renamed ImDrawList::PushTextureID()/PopTextureID() to PushTexture()/PopTexture(). - Fonts: (users of custom rectangles) - Renamed AddCustomRectRegular() to AddCustomRect(). (#8466) diff --git a/imgui.cpp b/imgui.cpp index 8aaa901fcd86..ddc20991ef67 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -453,7 +453,8 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - Fonts: (users of imgui_freetype): renamed ImFontAtlas::FontBuilderFlags to ImFontAtlas::FontLoaderFlags. Renamed ImFontConfig::FontBuilderFlags to ImFontConfig::FontLoaderFlags. Renamed ImGuiFreeTypeBuilderFlags to ImGuiFreeTypeLoaderFlags. If you used runtime imgui_freetype selection rather than the default IMGUI_ENABLE_FREETYPE compile-time option: Renamed/reworked ImFontBuilderIO into ImFontLoader. Renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader(). - old: io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType() - - new: io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader() + - new: io.Fonts->FontLoader = ImGuiFreeType::GetFontLoader() + - new: io.Fonts->SetFontLoader(ImGuiFreeType::GetFontLoader()) to change dynamically at runtime [from 1.92.1] - Fonts: (users of custom rectangles, see #8466): Renamed AddCustomRectRegular() to AddCustomRect(). Added GetCustomRect() as a replacement for GetCustomRectByIndex() + CalcCustomRectUV(). - The output type of GetCustomRect() is now ImFontAtlasRect, which include UV coordinates. X->x, Y->y, Width->w, Height->h. - old: @@ -15902,7 +15903,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) #ifdef IMGUI_ENABLE_STB_TRUETYPE const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype(); if (RadioButton("stb_truetype", loader_current == loader_stbtruetype)) - ImFontAtlasBuildSetupFontLoader(atlas, loader_stbtruetype); + atlas->SetFontLoader(loader_stbtruetype); #else BeginDisabled(); RadioButton("stb_truetype", false); @@ -15913,7 +15914,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) #ifdef IMGUI_ENABLE_FREETYPE const ImFontLoader* loader_freetype = ImGuiFreeType::GetFontLoader(); if (RadioButton("FreeType", loader_current == loader_freetype)) - ImFontAtlasBuildSetupFontLoader(atlas, loader_freetype); + atlas->SetFontLoader(loader_freetype); if (loader_current == loader_freetype) { unsigned int loader_flags = atlas->FontLoaderFlags; diff --git a/imgui.h b/imgui.h index b09d7ee82684..153ce5cadc05 100644 --- a/imgui.h +++ b/imgui.h @@ -3493,7 +3493,7 @@ struct ImFontConfig // [Internal] ImFontFlags Flags; // Font flags (don't use just yet, will be exposed in upcoming 1.92.X updates) ImFont* DstFont; // Target font (as we merging fonts, multiple ImFontConfig may target the same font) - const ImFontLoader* FontLoader; // Custom font backend for this source (other use one stored in ImFontAtlas) + const ImFontLoader* FontLoader; // Custom font backend for this source (default source is the one stored in ImFontAtlas) void* FontLoaderData; // Font loader opaque storage (per font config) IMGUI_API ImFontConfig(); @@ -3590,6 +3590,7 @@ struct ImFontAtlas IMGUI_API void Clear(); // Clear everything (input fonts, output glyphs/textures) IMGUI_API void CompactCache(); // Compact cached glyphs and texture. + IMGUI_API void SetFontLoader(const ImFontLoader* font_loader); // Change font loader at runtime. // As we are transitioning toward a new font system, we expect to obsolete those soon: IMGUI_API void ClearInputData(); // [OBSOLETE] Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts. @@ -3698,7 +3699,7 @@ struct ImFontAtlas int FontNextUniqueID; // Next value to be stored in ImFont->FontID ImVector DrawListSharedDatas; // List of users for this atlas. Typically one per Dear ImGui context. ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public and may be discarded when rebuilding. - const ImFontLoader* FontLoader; // Font loader opaque interface (default to stb_truetype, can be changed to use FreeType by defining IMGUI_ENABLE_FREETYPE). Don't set directly! + const ImFontLoader* FontLoader; // Font loader opaque interface (default to use FreeType when IMGUI_ENABLE_FREETYPE is defined, otherwise default to use stb_truetype). Use SetFontLoader() to change this at runtime. const char* FontLoaderName; // Font loader name (for display e.g. in About box) == FontLoader->Name void* FontLoaderData; // Font backend opaque storage unsigned int FontLoaderFlags; // Shared flags (for all fonts) for font loader. THIS IS BUILD IMPLEMENTATION DEPENDENT (e.g. Per-font override is also available in ImFontConfig). diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e835dcd75ee5..704cc6d2f38b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2659,6 +2659,11 @@ void ImFontAtlas::CompactCache() ImFontAtlasTextureCompact(this); } +void ImFontAtlas::SetFontLoader(const ImFontLoader* font_loader) +{ + ImFontAtlasBuildSetupFontLoader(this, font_loader); +} + void ImFontAtlas::ClearInputData() { IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas!"); @@ -4178,9 +4183,9 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) if (atlas->FontLoader == NULL) { #ifdef IMGUI_ENABLE_FREETYPE - ImFontAtlasBuildSetupFontLoader(atlas, ImGuiFreeType::GetFontLoader()); + atlas->SetFontLoader(ImGuiFreeType::GetFontLoader()); #elif defined(IMGUI_ENABLE_STB_TRUETYPE) - ImFontAtlasBuildSetupFontLoader(atlas, ImFontAtlasGetFontLoaderForStbTruetype()); + atlas->SetFontLoader(ImFontAtlasGetFontLoaderForStbTruetype()); #else IM_ASSERT(0); // Invalid Build function #endif diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 4f73067907fd..85313699dd56 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -8,7 +8,7 @@ // Usage: // - Add '#define IMGUI_ENABLE_FREETYPE' in your imconfig to automatically enable support // for imgui_freetype in imgui. It is equivalent to selecting the default loader with: -// io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader() +// io.Fonts->SetFontLoader(ImGuiFreeType::GetFontLoader()) // Optional support for OpenType SVG fonts: // - Add '#define IMGUI_ENABLE_FREETYPE_PLUTOSVG' to use plutosvg (not provided). See #7927. @@ -62,7 +62,7 @@ namespace ImGuiFreeType { // This is automatically assigned when using '#define IMGUI_ENABLE_FREETYPE'. // If you need to dynamically select between multiple builders: - // - you can manually assign this builder with 'atlas->FontLoader = ImGuiFreeType::GetFontLoader()' + // - you can manually assign this builder with 'atlas->SetFontLoader(ImGuiFreeType::GetFontLoader())' // - prefer deep-copying this into your own ImFontLoader instance if you use hot-reloading that messes up static data. IMGUI_API const ImFontLoader* GetFontLoader(); @@ -75,7 +75,7 @@ namespace ImGuiFreeType // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - //IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType(); // Renamed/changed in 1.92. Change 'io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()' to 'io.Fonts.FontLoader = ImGuiFreeType::GetFontLoader()' if you need runtime selection. + //IMGUI_API const ImFontBuilderIO* GetBuilderForFreeType(); // Renamed/changed in 1.92. Change 'io.Fonts->FontBuilderIO = ImGuiFreeType::GetBuilderForFreeType()' to 'io.Fonts->SetFontLoader(ImGuiFreeType::GetFontLoader())' if you need runtime selection. //static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontLoaderFlags = flags; return atlas->Build(); } // Prefer using '#define IMGUI_ENABLE_FREETYPE' #endif } From 51b3495ad8f7f4a3a4341bf0f9da87fd092a4efd Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 30 Jun 2025 20:59:08 +0200 Subject: [PATCH 688/716] Fonts: set a maximum font size of 512.0f at ImGui:: API level to reduce edge cases. --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 6 +++--- imgui_demo.cpp | 2 +- imgui_internal.h | 2 ++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0b9d1d9a1fd7..99246de8f31a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,9 @@ Other changes: - Fonts: added ImFontAtlas::SetFontLoader() to dynamically change font loader at runtime without using internal API. (#8752, #8465) +- Fonts: set a maximum font size of 512.0f at ImGui:: API level to reduce + edge cases (e.g. out of memory errors). ImDrawList:: API doesn't have the + constraint. (#8758) - Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] diff --git a/imgui.cpp b/imgui.cpp index ddc20991ef67..f34ad7969db0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8824,7 +8824,7 @@ void ImGui::UpdateCurrentFontSize(float restore_font_size_after_scaling) // - We started rounding in 1.90 WIP (18991) as our layout system currently doesn't support non-rounded font size well yet. // - We may support it better later and remove this rounding. final_size = GetRoundedFontSize(final_size); - final_size = ImMax(1.0f, final_size); + final_size = ImClamp(final_size, 1.0f, IMGUI_FONT_SIZE_MAX); if (g.Font != NULL && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) g.Font->CurrentRasterizerDensity = g.FontRasterizerDensity; g.FontSize = final_size; @@ -15871,9 +15871,9 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas) style._NextFrameFontSizeBase = style.FontSizeBase; // FIXME: Temporary hack until we finish remaining work. SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); SameLine(); MetricsHelpMarker("- This is scaling font only. General scaling will come later."); - DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 5.0f); + DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); //BeginDisabled(io.ConfigDpiScaleFonts); - DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); + DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f); //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); //EndDisabled(); if ((io.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 692eb2992c90..05f5e45f1043 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8282,7 +8282,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) SameLine(0.0f, 0.0f); Text(" (out %.2f)", GetFontSize()); DragFloat("FontScaleMain", &style.FontScaleMain, 0.02f, 0.5f, 4.0f); //BeginDisabled(GetIO().ConfigDpiScaleFonts); - DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 5.0f); + DragFloat("FontScaleDpi", &style.FontScaleDpi, 0.02f, 0.5f, 4.0f); //SetItemTooltip("When io.ConfigDpiScaleFonts is set, this value is automatically overwritten."); //EndDisabled(); diff --git a/imgui_internal.h b/imgui_internal.h index 22fbef4f20f7..7ac0c207944d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3711,6 +3711,8 @@ typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- +#define IMGUI_FONT_SIZE_MAX (512.0f) + // Helpers: ImTextureRef ==/!= operators provided as convenience // (note that _TexID and _TexData are never set simultaneously) inline bool operator==(const ImTextureRef& lhs, const ImTextureRef& rhs) { return lhs._TexID == rhs._TexID && lhs._TexData == rhs._TexData; } From fd75bdccb033e74afeba44f500edc8fcef7eb023 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 30 Jun 2025 21:16:20 +0200 Subject: [PATCH 689/716] Fonts: for large size fonts, layout/size calculation only load glyphs metrics. Actual glyphs are renderer+packed when used by drawing functions. (#8758, #8465) (Breaking) breaks signature of ImFontLoader::FontBakedLoadGlyph, sorry. --- docs/CHANGELOG.txt | 2 + imgui_draw.cpp | 90 ++++++++++++++++++++++++++------ imgui_internal.h | 6 ++- misc/freetype/imgui_freetype.cpp | 18 +++++-- 4 files changed, 93 insertions(+), 23 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 99246de8f31a..625a5b927cd7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - Fonts: added ImFontAtlas::SetFontLoader() to dynamically change font loader at runtime without using internal API. (#8752, #8465) +- Fonts: for large size fonts, layout/size calculation only load glyphs metrics. + Actual glyphs are renderer+packed when used by drawing functions. (#8758, #8465) - Fonts: set a maximum font size of 512.0f at ImGui:: API level to reduce edge cases (e.g. out of memory errors). ImDrawList:: API doesn't have the constraint. (#8758) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 704cc6d2f38b..374088573cb5 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2560,6 +2560,7 @@ void ImTextureData::DestroyPixels() //----------------------------------------------------------------------------- // - ImFontBaked_BuildGrowIndex() // - ImFontBaked_BuildLoadGlyph() +// - ImFontBaked_BuildLoadGlyphAdvanceX() // - ImFontAtlasDebugLogTextureRequests() //----------------------------------------------------------------------------- // - ImFontAtlasGetFontLoaderForStbTruetype() @@ -4409,7 +4410,7 @@ static void ImFontAtlas_FontHookRemapCodepoint(ImFontAtlas* atlas, ImFont* font, *c = (ImWchar)font->RemapPairs.GetInt((ImGuiID)*c, (int)*c); } -static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint) +static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codepoint, float* only_load_advance_x) { ImFont* font = baked->ContainerFont; ImFontAtlas* atlas = font->ContainerAtlas; @@ -4442,13 +4443,25 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; if (!src->GlyphExcludeRanges || ImFontAtlasBuildAcceptCodepointForSource(src, codepoint)) { - ImFontGlyph glyph_buf; - if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf)) + if (only_load_advance_x == NULL) { - // FIXME: Add hooks for e.g. #7962 - glyph_buf.Codepoint = src_codepoint; - glyph_buf.SourceIdx = src_n; - return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); + ImFontGlyph glyph_buf; + if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, &glyph_buf, NULL)) + { + // FIXME: Add hooks for e.g. #7962 + glyph_buf.Codepoint = src_codepoint; + glyph_buf.SourceIdx = src_n; + return ImFontAtlasBakedAddFontGlyph(atlas, baked, src, &glyph_buf); + } + } + else + { + // Special mode but only loading glyphs metrics. Will rasterize and pack later. + if (loader->FontBakedLoadGlyph(atlas, src, baked, loader_user_data_p, codepoint, NULL, only_load_advance_x)) + { + ImFontAtlasBakedAddFontGlyphAdvancedX(atlas, baked, src, codepoint, *only_load_advance_x); + return NULL; + } } } loader_user_data_p += loader->FontBakedSrcLoaderDataSize; @@ -4468,12 +4481,27 @@ static ImFontGlyph* ImFontBaked_BuildLoadGlyph(ImFontBaked* baked, ImWchar codep return NULL; } +static float ImFontBaked_BuildLoadGlyphAdvanceX(ImFontBaked* baked, ImWchar codepoint) +{ + if (baked->Size >= IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE) + { + // First load AdvanceX value used by CalcTextSize() API then load the rest when loaded by drawing API. + float only_advance_x = 0.0f; + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint, &only_advance_x); + return glyph ? glyph->AdvanceX : only_advance_x; + } + else + { + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint, NULL); + return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX; + } +} + // The point of this indirection is to not be inlined in debug mode in order to not bloat inner loop.b IM_MSVC_RUNTIME_CHECKS_OFF static float BuildLoadGlyphGetAdvanceOrFallback(ImFontBaked* baked, unsigned int codepoint) { - ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(baked, (ImWchar)codepoint); - return glyph ? glyph->AdvanceX : baked->FallbackAdvanceX; + return ImFontBaked_BuildLoadGlyphAdvanceX(baked, (ImWchar)codepoint); } IM_MSVC_RUNTIME_CHECKS_RESTORE @@ -4594,7 +4622,7 @@ static bool ImGui_ImplStbTrueType_FontBakedInit(ImFontAtlas* atlas, ImFontConfig return true; } -static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph) +static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x) { // Search for first font which has the glyph ImGui_ImplStbTrueType_FontSrcData* bd_font_data = (ImGui_ImplStbTrueType_FontSrcData*)src->FontLoaderData; @@ -4616,7 +4644,14 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC int advance, lsb; stbtt_GetGlyphBitmapBoxSubpixel(&bd_font_data->FontInfo, glyph_index, scale_for_raster_x, scale_for_raster_y, 0, 0, &x0, &y0, &x1, &y1); stbtt_GetGlyphHMetrics(&bd_font_data->FontInfo, glyph_index, &advance, &lsb); - const bool is_visible = (x0 != x1 && y0 != y1); + + // Load metrics only mode + if (out_advance_x != NULL) + { + IM_ASSERT(out_glyph == NULL); + *out_advance_x = advance * scale_for_layout; + return true; + } // Prepare glyph out_glyph->Codepoint = codepoint; @@ -4624,6 +4659,7 @@ static bool ImGui_ImplStbTrueType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontC // Pack and retrieve position inside texture atlas // (generally based on stbtt_PackFontRangesRenderIntoRects) + const bool is_visible = (x0 != x1 && y0 != y1); if (is_visible) { const int w = (x1 - x0 + oversample_h - 1); @@ -5124,6 +5160,29 @@ ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked return glyph; } +// FIXME: Code is duplicated with code above. +void ImFontAtlasBakedAddFontGlyphAdvancedX(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImWchar codepoint, float advance_x) +{ + IM_UNUSED(atlas); + if (src != NULL) + { + // Clamp & recenter if needed + const float ref_size = baked->ContainerFont->Sources[0]->SizePixels; + const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f; + advance_x = ImClamp(advance_x, src->GlyphMinAdvanceX * offsets_scale, src->GlyphMaxAdvanceX * offsets_scale); + + // Snap to pixel + if (src->PixelSnapH) + advance_x = IM_ROUND(advance_x); + + // Bake spacing + advance_x += src->GlyphExtraAdvanceX; + } + + ImFontBaked_BuildGrowIndex(baked, codepoint + 1); + baked->IndexAdvanceX[codepoint] = advance_x; +} + // Copy to texture, post-process and queue update for backend void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch) { @@ -5151,7 +5210,7 @@ ImFontGlyph* ImFontBaked::FindGlyph(ImWchar c) if (i != IM_FONTGLYPH_INDEX_UNUSED) return &Glyphs.Data[i]; } - ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL); return glyph ? glyph : &Glyphs.Data[FallbackGlyphIndex]; } @@ -5167,7 +5226,7 @@ ImFontGlyph* ImFontBaked::FindGlyphNoFallback(ImWchar c) return &Glyphs.Data[i]; } LockLoadingFallback = true; // This is actually a rare call, not done in hot-loop, so we prioritize not adding extra cruft to ImFontBaked_BuildLoadGlyph() call sites. - ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); + ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c, NULL); LockLoadingFallback = false; return glyph; } @@ -5210,10 +5269,7 @@ float ImFontBaked::GetCharAdvance(ImWchar c) if (x >= 0.0f) return x; } - - // Same as BuildLoadGlyphGetAdvanceOrFallback(): - const ImFontGlyph* glyph = ImFontBaked_BuildLoadGlyph(this, c); - return glyph ? glyph->AdvanceX : FallbackAdvanceX; + return ImFontBaked_BuildLoadGlyphAdvanceX(this, c); } IM_MSVC_RUNTIME_CHECKS_RESTORE diff --git a/imgui_internal.h b/imgui_internal.h index 7ac0c207944d..12fdac568219 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3691,7 +3691,7 @@ struct ImFontLoader bool (*FontSrcContainsGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint); bool (*FontBakedInit)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); void (*FontBakedDestroy)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src); - bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph); + bool (*FontBakedLoadGlyph)(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x); // Size of backend data, Per Baked * Per Source. Buffers are managed by core to avoid excessive allocations. // FIXME: At this point the two other types of buffers may be managed by core to be consistent? @@ -3711,7 +3711,8 @@ typedef ImFontLoader ImFontBuilderIO; // [renamed/changed in 1.92] The types are // [SECTION] ImFontAtlas internal API //----------------------------------------------------------------------------- -#define IMGUI_FONT_SIZE_MAX (512.0f) +#define IMGUI_FONT_SIZE_MAX (512.0f) +#define IMGUI_FONT_SIZE_THRESHOLD_FOR_LOADADVANCEXONLYMODE (128.0f) // Helpers: ImTextureRef ==/!= operators provided as convenience // (note that _TexID and _TexData are never set simultaneously) @@ -3829,6 +3830,7 @@ IMGUI_API ImFontBaked* ImFontAtlasBakedGetClosestMatch(ImFontAtlas* atlas, IMGUI_API ImFontBaked* ImFontAtlasBakedAdd(ImFontAtlas* atlas, ImFont* font, float font_size, float font_rasterizer_density, ImGuiID baked_id); IMGUI_API void ImFontAtlasBakedDiscard(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked); IMGUI_API ImFontGlyph* ImFontAtlasBakedAddFontGlyph(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, const ImFontGlyph* in_glyph); +IMGUI_API void ImFontAtlasBakedAddFontGlyphAdvancedX(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImWchar codepoint, float advance_x); IMGUI_API void ImFontAtlasBakedDiscardFontGlyph(ImFontAtlas* atlas, ImFont* font, ImFontBaked* baked, ImFontGlyph* glyph); IMGUI_API void ImFontAtlasBakedSetFontGlyphBitmap(ImFontAtlas* atlas, ImFontBaked* baked, ImFontConfig* src, ImFontGlyph* glyph, ImTextureRect* r, const unsigned char* src_pixels, ImTextureFormat src_fmt, int src_pitch); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index e5f2818dba06..33f2593658d8 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -475,7 +475,7 @@ void ImGui_ImplFreeType_FontBakedDestroy(ImFontAtlas* atlas, ImFontConfig* src, bd_baked_data->~ImGui_ImplFreeType_FontSrcBakedData(); // ~IM_PLACEMENT_DELETE() } -bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph) +bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void* loader_data_for_baked_src, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x) { ImGui_ImplFreeType_FontSrcData* bd_font_data = (ImGui_ImplFreeType_FontSrcData*)src->FontLoaderData; uint32_t glyph_index = FT_Get_Char_Index(bd_font_data->FtFace, codepoint); @@ -494,9 +494,20 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src if (metrics == nullptr) return false; - // Render glyph into a bitmap (currently held by FreeType) FT_Face face = bd_font_data->FtFace; FT_GlyphSlot slot = face->glyph; + const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; + + // Load metrics only mode + const float advance_x = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density; + if (out_advance_x != NULL) + { + IM_ASSERT(out_glyph == NULL); + *out_advance_x = advance_x; + return true; + } + + // Render glyph into a bitmap (currently held by FreeType) FT_Render_Mode render_mode = (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_Monochrome) ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL; FT_Error error = FT_Render_Glyph(slot, render_mode); const FT_Bitmap* ft_bitmap = &slot->bitmap; @@ -506,11 +517,10 @@ bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConfig* src const int w = (int)ft_bitmap->width; const int h = (int)ft_bitmap->rows; const bool is_visible = (w != 0 && h != 0); - const float rasterizer_density = src->RasterizerDensity * baked->RasterizerDensity; // Prepare glyph out_glyph->Codepoint = codepoint; - out_glyph->AdvanceX = (slot->advance.x / FT_SCALEFACTOR) / rasterizer_density; + out_glyph->AdvanceX = advance_x; // Pack and retrieve position inside texture atlas if (is_visible) From 0448428322780d34599e30e5267b4a063374d691 Mon Sep 17 00:00:00 2001 From: Matthew Pohlmann Date: Sat, 5 Jul 2025 08:51:58 -0700 Subject: [PATCH 690/716] Fonts: Change ImFontConfig::FontNo back to int from S8 (#8775) When used with FreeType this value is passed as `face_index` which needs to be 32-bits. # Conflicts: # docs/CHANGELOG.txt --- docs/CHANGELOG.txt | 4 ++++ imgui.h | 4 ++-- misc/freetype/imgui_freetype.cpp | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 625a5b927cd7..00c66b8d5bf7 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,6 +50,10 @@ Other changes: - Fonts: set a maximum font size of 512.0f at ImGui:: API level to reduce edge cases (e.g. out of memory errors). ImDrawList:: API doesn't have the constraint. (#8758) +- Fonts: Restore ImFontConfig::FontNo being a 32-bits value as this is needed + to pass full range of information into e.g. FreeType's face_index, as higher + bits are used from FreeType 2.6.1. (#8775) [@Valakor] + (the field has been erroneously reduced from 32-bits to 8-bit in 1.92.0) - Textures: Fixed support for `#define ImTextureID_Invalid` to non-zero value: ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] diff --git a/imgui.h b/imgui.h index 153ce5cadc05..e605cb676308 100644 --- a/imgui.h +++ b/imgui.h @@ -3473,9 +3473,9 @@ struct ImFontConfig bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights. bool PixelSnapH; // false // Align every glyph AdvanceX to pixel boundaries. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. bool PixelSnapV; // true // Align Scaled GlyphOffset.y to pixel boundaries. - ImS8 FontNo; // 0 // Index of font within TTF/OTF file ImS8 OversampleH; // 0 (2) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1 or 2 depending on size. Note the difference between 2 and 3 is minimal. You can reduce this to 1 for large glyphs save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. ImS8 OversampleV; // 0 (1) // Rasterize at higher quality for sub-pixel positioning. 0 == auto == 1. This is not really useful as we don't use sub-pixel positions on the Y axis. + ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). const ImWchar* GlyphRanges; // NULL // *LEGACY* THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). const ImWchar* GlyphExcludeRanges; // NULL // Pointer to a small user-provided list of Unicode ranges (2 value per range, values are inclusive, zero-terminated list). This is very close to GlyphRanges[] but designed to exclude ranges from a font source, when merging fonts with overlapping glyphs. Use "Input Glyphs Overlap Detection Tool" to find about your overlapping ranges. @@ -3484,11 +3484,11 @@ struct ImFontConfig float GlyphMinAdvanceX; // 0 // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font. Absolute value for default size, other sizes will scale this value. float GlyphMaxAdvanceX; // FLT_MAX // Maximum AdvanceX for glyphs float GlyphExtraAdvanceX; // 0 // Extra spacing (in pixels) between glyphs. Please contact us if you are using this. // FIXME-NEWATLAS: Intentionally unscaled + ImU32 FontNo; // 0 // Index of font within TTF/OTF file unsigned int FontLoaderFlags; // 0 // Settings for custom font builder. THIS IS BUILDER IMPLEMENTATION DEPENDENT. Leave as zero if unsure. //unsigned int FontBuilderFlags; // -- // [Renamed in 1.92] Ue FontLoaderFlags. float RasterizerMultiply; // 1.0f // Linearly brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable. This is a silly thing we may remove in the future. float RasterizerDensity; // 1.0f // [LEGACY: this only makes sense when ImGuiBackendFlags_RendererHasTextures is not supported] DPI scale multiplier for rasterization. Not altering other font metrics: makes it easy to swap between e.g. a 100% and a 400% fonts for a zooming display, or handle Retina screen. IMPORTANT: If you change this it is expected that you increase/decrease font scale roughly to the inverse of this, otherwise quality may look lowered. - ImWchar EllipsisChar; // 0 // Explicitly specify Unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used. // [Internal] ImFontFlags Flags; // Font flags (don't use just yet, will be exposed in upcoming 1.92.X updates) diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 33f2593658d8..7a9468375505 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -174,7 +174,7 @@ struct ImGui_ImplFreeType_FontSrcBakedData bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_font_loader_flags) { - FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (uint32_t)src->FontDataSize, (uint32_t)src->FontNo, &FtFace); + FT_Error error = FT_New_Memory_Face(ft_library, (uint8_t*)src->FontData, (FT_Long)src->FontDataSize, (FT_Long)src->FontNo, &FtFace); if (error != 0) return false; error = FT_Select_Charmap(FtFace, FT_ENCODING_UNICODE); From be6303765425ac3fd3b0ab59b673d90200f87a8f Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 10:34:59 +0200 Subject: [PATCH 691/716] CI: Updated to use latest Windows image + VS2022. (Untested) --- .github/workflows/build.yml | 10 +++++----- docs/CHANGELOG.txt | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc58e25bbe00..edf37ef9e00f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,10 +17,10 @@ on: jobs: Windows: - runs-on: windows-2019 + runs-on: windows-2025 env: - VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\ - MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\ + VS_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\ + MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\ steps: - uses: actions/checkout@v4 @@ -40,8 +40,8 @@ jobs: run: | # CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version. gci -recurse -filter "*.vcxproj" | ForEach-Object { - (Get-Content $_.FullName) -Replace "v\d{3}","v142" | Set-Content -Path $_.FullName - (Get-Content $_.FullName) -Replace "[\d\.]+","10.0.18362.0" | Set-Content -Path $_.FullName + (Get-Content $_.FullName) -Replace "v\d{3}","v143" | Set-Content -Path $_.FullName + (Get-Content $_.FullName) -Replace "[\d\.]+","$(LatestTargetPlatformVersion)" | Set-Content -Path $_.FullName } # Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 00c66b8d5bf7..cdb7da4e6415 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -58,6 +58,7 @@ Other changes: ImTextureData() was incorrectly cleared with zeroes. (#8745) [@rachit7645] - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] - CI: Fixed dllimport/dllexport tests. (#8757) [@AidanSun05] +- CI: Updated to use latest Windows image + VS2022. - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress From 497ebec01dba0d981f99fa4c6a7c43c72e7d8bd1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 10:36:49 +0200 Subject: [PATCH 692/716] CI: Fix/amend be63037. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index edf37ef9e00f..5efd6f389618 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: # CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version. gci -recurse -filter "*.vcxproj" | ForEach-Object { (Get-Content $_.FullName) -Replace "v\d{3}","v143" | Set-Content -Path $_.FullName - (Get-Content $_.FullName) -Replace "[\d\.]+","$(LatestTargetPlatformVersion)" | Set-Content -Path $_.FullName + (Get-Content $_.FullName) -Replace "[\d\.]+","\$(LatestTargetPlatformVersion)" | Set-Content -Path $_.FullName } # Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long. From 4441aa8b605524bb0806d39a22a251491bc18535 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 10:41:01 +0200 Subject: [PATCH 693/716] CI: Fix/amend be63037. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5efd6f389618..21d059913645 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: # CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version. gci -recurse -filter "*.vcxproj" | ForEach-Object { (Get-Content $_.FullName) -Replace "v\d{3}","v143" | Set-Content -Path $_.FullName - (Get-Content $_.FullName) -Replace "[\d\.]+","\$(LatestTargetPlatformVersion)" | Set-Content -Path $_.FullName + (Get-Content $_.FullName) -Replace "[\d\.]+","\\$(LatestTargetPlatformVersion)" | Set-Content -Path $_.FullName } # Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long. From 68971223aa47a5a62dc7ff783c826315276a45dc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 10:42:45 +0200 Subject: [PATCH 694/716] CI: Fix/amend be63037. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 21d059913645..95bcf3e76787 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,7 +41,7 @@ jobs: # CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version. gci -recurse -filter "*.vcxproj" | ForEach-Object { (Get-Content $_.FullName) -Replace "v\d{3}","v143" | Set-Content -Path $_.FullName - (Get-Content $_.FullName) -Replace "[\d\.]+","\\$(LatestTargetPlatformVersion)" | Set-Content -Path $_.FullName + (Get-Content $_.FullName) -Replace "[\d\.]+",'$(LatestTargetPlatformVersion)' | Set-Content -Path $_.FullName } # Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long. From 495d6f1e39acf46b6ee4b1d6d16912940d1a8d58 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 14:51:42 +0200 Subject: [PATCH 695/716] Undef 'Status' in main header file. (#8751, #8765) --- backends/imgui_impl_sdl2.cpp | 4 +--- backends/imgui_impl_vulkan.cpp | 1 + imgui.h | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 18035d24fb8c..4dc2dea6e34d 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -118,9 +118,7 @@ #ifdef __EMSCRIPTEN__ #include #endif -#ifdef Status // X11 headers -#undef Status -#endif +#undef Status // X11 headers are leaking this. #if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1 diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 059e8c9edb77..52ad716b7ee0 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -97,6 +97,7 @@ #ifndef IM_MAX #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) #endif +#undef Status // X11 headers are leaking this. // Visual Studio warnings #ifdef _MSC_VER diff --git a/imgui.h b/imgui.h index e605cb676308..0833e1c82fd2 100644 --- a/imgui.h +++ b/imgui.h @@ -3385,6 +3385,8 @@ struct ImDrawData // FOR ALL OTHER ImTextureXXXX TYPES: ONLY CORE LIBRARY AND RENDERER BACKENDS NEED TO KNOW AND CARE ABOUT THEM. //----------------------------------------------------------------------------- +#undef Status // X11 headers are leaking this. + // We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. // Most standard backends only support RGBA32 but we provide a single channel option for low-resource/embedded systems. enum ImTextureFormat From 94c888ebda6f0123dbf89b27f109298d0818d757 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 15:27:47 +0200 Subject: [PATCH 696/716] Docs: update 1.92.0 changelogs to cover more internal fields. (#8764) --- docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cdb7da4e6415..d53af355d32d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -196,6 +196,7 @@ Breaking changes: While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things: - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef. + - ImFontAtlas::TexID has been changed to ImFontAtlas::TexRef. - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[]. - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. - Each ImFont has a number of ImFontBaked instances corresponding to actively used @@ -213,6 +214,11 @@ Breaking changes: g.Font == ImGui::GetFont() g.FontSize == ImGui::GetFontSize() g.FontBaked == ImGui::GetFontBaked() == ImGui::GetFont()->GetFontBaked(ImGui::GetFontSize()) + - Fields moved from ImFontAtlas to ImTextureData + - ImFontAtlas->TexWidth -> ImFontAtlas->TexData->Width + - ImFontAtlas->TexHeight -> ImFontAtlas->TexData->Height + - ImFontAtlas->TexPixelsAlpha8 -> ImFontAtlas->TexData->GetPixels() (when ImFontAtlas::TexDesiredFormat == ImTextureFormat_Alpha8) + - ImFontAtlas->TexPixelsRGBA32 -> ImFontAtlas->TexData->GetPixels() (when ImFontAtlas::TexDesiredFormat == ImTextureFormat_RGBA32) Please report if you are affected! - Fonts: (users of imgui_freetype) - renamed ImFontAtlas::FontBuilderFlags to ImFontAtlas::FontLoaderFlags. diff --git a/imgui.cpp b/imgui.cpp index f34ad7969db0..0a8582686f7c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -445,10 +445,12 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: - Fonts: obsoleted ImFont::Scale which is not useful anymore. - Fonts: generally reworked Internals of ImFontAtlas and ImFont. While in theory a vast majority of users shouldn't be affected, some use cases or extensions might be. Among other things: - ImDrawCmd::TextureId has been changed to ImDrawCmd::TexRef. + - ImFontAtlas::TexID has been changed to ImFontAtlas::TexRef. - ImFontAtlas::ConfigData[] has been renamed to ImFontAtlas::Sources[] - ImFont::ConfigData[], ConfigDataCount has been renamed to Sources[], SourceCount. - Each ImFont has a number of ImFontBaked instances corresponding to actively used sizes. ImFont::GetFontBaked(size) retrieves the one for a given size. - Fields moved from ImFont to ImFontBaked: IndexAdvanceX[], Glyphs[], Ascent, Descent, FindGlyph(), FindGlyphNoFallback(), GetCharAdvance(). + - Fields moved from ImFontAtlas to ImFontAtlas->Tex: ImFontAtlas::TexWidth => TexData->Width, ImFontAtlas::TexHeight => TexData->Height, ImFontAtlas::TexPixelsAlpha8/TexPixelsRGBA32 => TexData->GetPixels(). - Widget code may use ImGui::GetFontBaked() instead of ImGui::GetFont() to access font data for current font at current font size (and you may use font->GetFontBaked(size) to access it for any other size.) - Fonts: (users of imgui_freetype): renamed ImFontAtlas::FontBuilderFlags to ImFontAtlas::FontLoaderFlags. Renamed ImFontConfig::FontBuilderFlags to ImFontConfig::FontLoaderFlags. Renamed ImGuiFreeTypeBuilderFlags to ImGuiFreeTypeLoaderFlags. If you used runtime imgui_freetype selection rather than the default IMGUI_ENABLE_FREETYPE compile-time option: Renamed/reworked ImFontBuilderIO into ImFontLoader. Renamed ImGuiFreeType::GetBuilderForFreeType() to ImGuiFreeType::GetFontLoader(). From 57a93e1a19892ae194351766b59b0992ba55c7e5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 15:36:24 +0200 Subject: [PATCH 697/716] Backends: Allegro5: fixed texture update broken on some platforms where ALLEGRO_LOCK_WRITEONLY needed all texels to be rewritten. (#8770) --- backends/imgui_impl_allegro5.cpp | 11 +++++------ docs/CHANGELOG.txt | 2 ++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index bd7f10c64296..5cbb893653b4 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-07: Fixed texture update broken on some platforms where ALLEGRO_LOCK_WRITEONLY needed all texels to be rewritten. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture(). // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256). @@ -291,14 +292,12 @@ void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex) { // Update selected blocks. We only ever write to textures regions which have never been used before! // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region. - ImTextureRect r_bb = tex->UpdateRect; // Bounding box encompassing all individual updates + ImTextureRect r = tex->UpdateRect; // Bounding box encompassing all individual updates ALLEGRO_BITMAP* gpu_bitmap = (ALLEGRO_BITMAP*)(intptr_t)tex->TexID; - ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap_region(gpu_bitmap, r_bb.x, r_bb.y, r_bb.w, r_bb.h, al_get_bitmap_format(gpu_bitmap), ALLEGRO_LOCK_WRITEONLY); + ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap_region(gpu_bitmap, r.x, r.y, r.w, r.h, al_get_bitmap_format(gpu_bitmap), ALLEGRO_LOCK_WRITEONLY); IM_ASSERT(locked_region && "Backend failed to update texture!"); - for (ImTextureRect& r : tex->Updates) - for (int y = 0; y < r.h; y++) - memcpy((unsigned char*)locked_region->data + locked_region->pitch * (r.y - r_bb.y + y) + (r.x - r_bb.x) * tex->BytesPerPixel, // dst - tex->GetPixelsAt(r.x, r.y + y), r.w * tex->BytesPerPixel); // src, block pitch + for (int y = 0; y < r.h; y++) + memcpy((unsigned char*)locked_region->data + locked_region->pitch * y, tex->GetPixelsAt(r.x, r.y + y), r.w * tex->BytesPerPixel); // dst, src, block pitch al_unlock_bitmap(gpu_bitmap); tex->SetStatus(ImTextureStatus_OK); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d53af355d32d..6e9c71f8de2c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -63,6 +63,8 @@ Other changes: (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) [@cfillion] +- Backends: Allegro5: fixed texture update broken on some platforms where + ALLEGRO_LOCK_WRITEONLY needed all texels to be rewritten. (#8770) - Backends: Vulkan: use nonCoherentAtomSize to align upload_size, fixing validation error on some setups. (#8743, #8744) [@tquante] From 4ef11452416b1b99179b2d3076ef451484de078e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 16:50:50 +0200 Subject: [PATCH 698/716] Fonts: fixed dynamically changing font loader from losing Fallback and Ellipsis glyphs. (#8763) Only the call to ImFontAtlasBuildSetupFontLoader() is the notable change. The change in ImFontAtlasFontInitOutput() is merely to use an existing helper function. --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6e9c71f8de2c..0cf39ca51092 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other changes: - Fonts: added ImFontAtlas::SetFontLoader() to dynamically change font loader at runtime without using internal API. (#8752, #8465) +- Fonts: fixed a bug where dynamically changing font loader would lose + the Fallback and Ellipsis glyphs under some circumstance. (#8763) - Fonts: for large size fonts, layout/size calculation only load glyphs metrics. Actual glyphs are renderer+packed when used by drawing functions. (#8758, #8465) - Fonts: set a maximum font size of 512.0f at ImGui:: API level to reduce diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 374088573cb5..bce905420809 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3410,6 +3410,9 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon atlas->FontLoader->LoaderInit(atlas); for (ImFont* font : atlas->Fonts) ImFontAtlasFontInitOutput(atlas, font); + for (ImFont* font : atlas->Fonts) + for (ImFontConfig* src : font->Sources) + ImFontAtlasFontSourceAddToFont(atlas, font, src); } // Preload all glyph ranges for legacy backends. @@ -3576,11 +3579,8 @@ bool ImFontAtlasFontInitOutput(ImFontAtlas* atlas, ImFont* font) { bool ret = true; for (ImFontConfig* src : font->Sources) - { - const ImFontLoader* loader = src->FontLoader ? src->FontLoader : atlas->FontLoader; - if (loader && loader->FontSrcInit != NULL && !loader->FontSrcInit(atlas, src)) + if (!ImFontAtlasFontSourceInit(atlas, src)) ret = false; - } IM_ASSERT(ret); // Unclear how to react to this meaningfully. Assume that result will be same as initial AddFont() call. return ret; } From c2d9b075339346881b92c3ddb614f9305e93194b Mon Sep 17 00:00:00 2001 From: Moses Miller Date: Fri, 4 Jul 2025 02:33:55 -0700 Subject: [PATCH 699/716] Backends: Vulkan: fixed texture synchronization. (#8772) --- backends/imgui_impl_vulkan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 52ad716b7ee0..38eaabe909b9 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-07: Vulkan: Fixed texture synchronization issue introduced on 2025-06-11. (#8772) // 2025-06-27: Vulkan: Fixed validation errors during texture upload/update by aligning upload size to 'nonCoherentAtomSize'. (#8743, #8744) // 2025-06-11: Vulkan: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplVulkan_CreateFontsTexture() and ImGui_ImplVulkan_DestroyFontsTexture(). // 2025-05-07: Vulkan: Fixed validation errors during window detach in multi-viewport mode. (#8600, #8176) @@ -808,6 +809,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) { VkImageMemoryBarrier copy_barrier[1] = {}; copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + copy_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; @@ -817,7 +819,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); + vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; From 032e1397d9e728106e6e03e819419e29370b2106 Mon Sep 17 00:00:00 2001 From: Moses Miller Date: Fri, 4 Jul 2025 03:21:54 -0700 Subject: [PATCH 700/716] Backends: Vulkan: use separate barrier for buffer. (#8772) --- backends/imgui_impl_vulkan.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 38eaabe909b9..a5dd75c8e7d3 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -807,9 +807,18 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) // Copy to Image: { + VkBufferMemoryBarrier upload_barrier[1] = {}; + upload_barrier[0].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + upload_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + upload_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + upload_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + upload_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + upload_barrier[0].buffer = upload_buffer; + upload_barrier[0].offset = 0; + upload_barrier[0].size = upload_size; + VkImageMemoryBarrier copy_barrier[1] = {}; copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - copy_barrier[0].srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; @@ -819,7 +828,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, copy_barrier); + vkCmdPipelineBarrier(bd->TexCommandBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, upload_barrier, 1, copy_barrier); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; From c0d02e5ae42d26dbe9b31f76233f1c96c3407162 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 7 Jul 2025 17:02:07 +0200 Subject: [PATCH 701/716] Backends: Vulkan: forgot to update Changelog. (#8772) --- docs/CHANGELOG.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0cf39ca51092..b70e47a739c2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,8 @@ Other changes: ALLEGRO_LOCK_WRITEONLY needed all texels to be rewritten. (#8770) - Backends: Vulkan: use nonCoherentAtomSize to align upload_size, fixing validation error on some setups. (#8743, #8744) [@tquante] +- Backends: Vulkan: fixed texture synchronization issue introduced in 1.92.0, + leading to validation layers reacting. (#8772) [@Majora320] ----------------------------------------------------------------------- From 7c51c0e3de2b04216b9562f5e5d55de943650388 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 8 Jul 2025 11:58:50 +0200 Subject: [PATCH 702/716] Docs: misc update. (#8727, #8764) --- docs/BACKENDS.md | 2 ++ docs/CHANGELOG.txt | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index ae5e91b0e309..fa05d55ea2d1 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -298,6 +298,8 @@ Version [1.92.0](https://github.com/ocornut/imgui/releases/tag/v1.92.0) (June 20 **In order to move forward and take advantage of all new features, support for `ImGuiBackendFlags_RendererHasTextures` will likely be REQUIRED for all backends before June 2026.** +`ImFontAtlas` functions such as `Build()`, `GetTexDataAsRGBA32()`, `GetTexDataAsAlpha8()`, `SetTexID()`, `IsBuilt()` were obsoleted in favor if iterating a `Textures[]` array and updating their state when requested by Dear ImGui. + **TD;DR: List of commits which added support for `ImGuiBackendFlags_RendererHasTextures` in standard backends:** - Allegro5: [ee8941e](https://github.com/ocornut/imgui/commit/ee8941e) (+35 lines) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b70e47a739c2..0a3523621a2e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -62,7 +62,8 @@ Other changes: - CI: Fixed dllimport/dllexport tests. (#8757) [@AidanSun05] - CI: Updated to use latest Windows image + VS2022. - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. - (#8727) [@morrazzzz] + (fixes e.g.: an issue on iOS where the keyboard animation will popup every + time the user types a key + probably other things) (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) [@cfillion] - Backends: Allegro5: fixed texture update broken on some platforms where @@ -168,6 +169,8 @@ Breaking changes: and IsBuilt() functions. The new protocol for backends to handle textures doesn't need them. Kept redirection functions (will obsolete). - A majority of old backends should still work with new code (behaving like they did before). + - For instructions to upgrade your custom backend: + https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md - Calling ImFontAtlas::Build() before initializing new backends will erroneously trigger preloading all glyphs. Will be detected with an assertion after the backend is initialized. - Fonts: ImFontConfig::OversampleH/OversampleV default to automatic (== 0) From 18dca11dd0428dc1de424bc5b71a4cecaf1d889f Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Fri, 27 Jun 2025 13:40:48 +0200 Subject: [PATCH 703/716] Backends: GLFW, SDL2: ImplXXX_GetContentScaleXXX() helpers return 1.0f on emscripten / apple / android (#8742, #8733) We can divide platforms into two cases based on how they report screen geometry: - Case 1: Platforms which report screen size in "physical pixels": Windows (for "Dpi aware" apps), Linux (with Wayland) - Case 2: Platforms which report screen size in "density-independent pixels": macOS, iOS, Android, emscripten As a consequence, there are two important things we need to know: - FramebufferScale: The scaling factor FrameBufferSize / ScreenSize - In case 1, the framebuffer size is equal to the screen size and DisplayFramebufferScale=1. - In case 2, the framebuffer size is equal to the screen size multiplied by a factor, for example DisplayFramebufferScale=2. - ContentScale The scaling factor for the content that we will display - In case 1, the content scale will often need to be > 1 (e.g., 2), because we will need to display bigger elements so that they show with a correct physical size on the screen. - In case 2, the content scale is equal to 1 This commit fixes ContentScale for platforms in case 2. --- backends/imgui_impl_glfw.cpp | 5 +++-- backends/imgui_impl_sdl2.cpp | 3 ++- docs/CHANGELOG.txt | 3 +++ imgui.h | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index d0a75ac78438..98e07ce5cb2e 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -29,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) // 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps. // 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102. @@ -876,7 +877,7 @@ static void ImGui_ImplGlfw_UpdateGamepads() // - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle. float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) { -#if GLFW_HAS_PER_MONITOR_DPI && !defined(__APPLE__) +#if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)) float x_scale, y_scale; glfwGetWindowContentScale(window, &x_scale, &y_scale); return x_scale; @@ -888,7 +889,7 @@ float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) { -#if GLFW_HAS_PER_MONITOR_DPI && !defined(__APPLE__) +#if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__)) float x_scale, y_scale; glfwGetMonitorContentScale(monitor, &x_scale, &y_scale); return x_scale; diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 4dc2dea6e34d..291edb8118af 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps. // 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. @@ -719,7 +720,7 @@ float ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) { #if SDL_HAS_PER_MONITOR_DPI -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) float dpi = 0.0f; if (SDL_GetDisplayDPI(display_index, &dpi, nullptr, nullptr) == 0) return dpi / 96.0f; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0a3523621a2e..d412df107757 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,9 @@ Other changes: - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] - CI: Fixed dllimport/dllexport tests. (#8757) [@AidanSun05] - CI: Updated to use latest Windows image + VS2022. +- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and + ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten + and Android platforms, matching macOS logic. (#8742, #8733) [@pthom] - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. (fixes e.g.: an issue on iOS where the keyboard animation will popup every time the user types a key + probably other things) (#8727) [@morrazzzz] diff --git a/imgui.h b/imgui.h index 0833e1c82fd2..89c2c2e5ddd0 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.1 WIP" -#define IMGUI_VERSION_NUM 19201 +#define IMGUI_VERSION_NUM 19202 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 From ed7d965818f9a7d04de0d5ec76ea9809b49a78e7 Mon Sep 17 00:00:00 2001 From: Pascal Thomet Date: Fri, 27 Jun 2025 16:36:43 +0200 Subject: [PATCH 704/716] Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses port contrib.glfw3 (#8742) This unofficial port offers a better support for HighDPI. See - https://emscripten.org/docs/compiling/Contrib-Ports.html - https://github.com/pongasoft/emscripten-glfw --- docs/CHANGELOG.txt | 2 ++ examples/example_glfw_opengl3/Makefile.emscripten | 5 +++-- examples/example_glfw_wgpu/Makefile.emscripten | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d412df107757..2cab3f6c5d28 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,8 @@ Other changes: - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] - CI: Fixed dllimport/dllexport tests. (#8757) [@AidanSun05] - CI: Updated to use latest Windows image + VS2022. +- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port + 'contrib.glfw3' which offers better HiDPI support. (#8742) [@pthom] - Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) [@pthom] diff --git a/examples/example_glfw_opengl3/Makefile.emscripten b/examples/example_glfw_opengl3/Makefile.emscripten index bba4ac9dc579..8d2f6e7bd8cc 100644 --- a/examples/example_glfw_opengl3/Makefile.emscripten +++ b/examples/example_glfw_opengl3/Makefile.emscripten @@ -32,8 +32,9 @@ EMS = ##--------------------------------------------------------------------- # ("EMS" options gets added to both CPPFLAGS and LDFLAGS, whereas some options are for linker only) -EMS += -s DISABLE_EXCEPTION_CATCHING=1 -LDFLAGS += -s USE_GLFW=3 -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 +# Note: For glfw, we use emscripten-glfw port (contrib.glfw3) instead of ('-s USE_GLFW=3' in LDFLAGS) to get a better support for High DPI displays. +EMS += -s DISABLE_EXCEPTION_CATCHING=1 --use-port=contrib.glfw3 +LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 # Build as single file (binary text encoded in .html file) #LDFLAGS += -sSINGLE_FILE diff --git a/examples/example_glfw_wgpu/Makefile.emscripten b/examples/example_glfw_wgpu/Makefile.emscripten index 78d64b4d3179..8ee398bc8d9c 100644 --- a/examples/example_glfw_wgpu/Makefile.emscripten +++ b/examples/example_glfw_wgpu/Makefile.emscripten @@ -32,8 +32,9 @@ EMS = ##--------------------------------------------------------------------- # ("EMS" options gets added to both CPPFLAGS and LDFLAGS, whereas some options are for linker only) -EMS += -s DISABLE_EXCEPTION_CATCHING=1 -LDFLAGS += -s USE_GLFW=3 -s USE_WEBGPU=1 +# Note: For glfw, we use emscripten-glfw port (contrib.glfw3) instead of (-s USE_GLFW=3) to get a better support for High DPI displays. +EMS += -s DISABLE_EXCEPTION_CATCHING=1 --use-port=contrib.glfw3 +LDFLAGS += -s USE_WEBGPU=1 LDFLAGS += -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s NO_EXIT_RUNTIME=0 -s ASSERTIONS=1 # Build as single file (binary text encoded in .html file) From d9b758661f79a484255de00a9dbf310beec8bfc1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Jul 2025 15:05:10 +0200 Subject: [PATCH 705/716] Misc comments to facilitate update for people who nilly-willy copied entire chunks of internal widgets to create their own. --- imgui.cpp | 4 +++- imgui_internal.h | 11 ++++++++--- imgui_widgets.cpp | 3 ++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0a8582686f7c..84ac433b0ffc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4730,7 +4730,8 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) return true; } -// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). +// Internal facing ItemHoverable() used when submitting widgets. THIS IS A SUBMISSION NOT A HOVER CHECK. +// Returns whether the item was hovered, logic differs slightly from IsItemHovered(). // (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) // FIXME-LEGACY: the 'ImGuiItemFlags item_flags' parameter was added on 2023-06-28. // If you used this in your legacy/custom widgets code: @@ -4742,6 +4743,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag ImGuiWindow* window = g.CurrentWindow; // Detect ID conflicts + // (this is specifically done here by comparing on hover because it allows us a detection of duplicates that is algorithmically extra cheap, 1 u32 compare per item. No O(log N) lookup whatsoever) #ifndef IMGUI_DISABLE_DEBUG_TOOLS if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0) { diff --git a/imgui_internal.h b/imgui_internal.h index 12fdac568219..fecb7b4ddf38 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -976,6 +976,7 @@ enum ImGuiItemStatusFlags_ ImGuiItemStatusFlags_Visible = 1 << 8, // [WIP] Set when item is overlapping the current clipping rectangle (Used internally. Please don't use yet: API/system will change as we refactor Itemadd()). ImGuiItemStatusFlags_HasClipRect = 1 << 9, // g.LastItemData.ClipRect is valid. ImGuiItemStatusFlags_HasShortcut = 1 << 10, // g.LastItemData.Shortcut valid. Set by SetNextItemShortcut() -> ItemAdd(). + //ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Removed IN 1.90.1 (Dec 2023). The trigger is part of g.NavActivateId. See commit 54c1bdeceb. // Additional status + semantic for ImGuiTestEngine #ifdef IMGUI_ENABLE_TEST_ENGINE @@ -1028,6 +1029,7 @@ enum ImGuiButtonFlagsPrivate_ ImGuiButtonFlags_NoFocus = 1 << 22, // [EXPERIMENTAL: Not very well specced]. Don't focus parent window when clicking. ImGuiButtonFlags_PressedOnMask_ = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold, ImGuiButtonFlags_PressedOnDefault_ = ImGuiButtonFlags_PressedOnClickRelease, + //ImGuiButtonFlags_NoKeyModifiers = ImGuiButtonFlags_NoKeyModsAllowed, // Renamed in 1.91.4 }; // Extend ImGuiComboFlags_ @@ -1678,6 +1680,7 @@ enum ImGuiNavRenderCursorFlags_ ImGuiNavHighlightFlags_Compact = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.91.4 ImGuiNavHighlightFlags_AlwaysDraw = ImGuiNavRenderCursorFlags_AlwaysDraw, // Renamed in 1.91.4 ImGuiNavHighlightFlags_NoRounding = ImGuiNavRenderCursorFlags_NoRounding, // Renamed in 1.91.4 + //ImGuiNavHighlightFlags_TypeThin = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.90.2 #endif }; @@ -2269,18 +2272,19 @@ struct ImGuiContext ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow' ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope) ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer) - ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem() + ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItemByID() ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0 ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat) ImGuiActivateFlags NavActivateFlags; ImVector NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain. ImGuiID NavHighlightActivatedId; float NavHighlightActivatedTimer; - ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame. + ImGuiID NavNextActivateId; // Set by ActivateItemByID(), queued until next frame. ImGuiActivateFlags NavNextActivateFlags; ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data. ImS8 NavCursorHideFrames; + //ImGuiID NavActivateInputId; // Removed in 1.89.4 (July 2023). This is now part of g.NavActivateId and sets g.NavActivateFlags |= ImGuiActivateFlags_PreferInput. See commit c9a53aa74, issue #5606. // Navigation: Init & Move Requests bool NavAnyRequest; // ~~ NavMoveRequest || NavInitRequest this is to perform early out in ItemAdd() @@ -3281,7 +3285,7 @@ namespace ImGui // This should be part of a larger set of API: FocusItem(offset = -1), FocusItemByID(id), ActivateItem(offset = -1), ActivateItemByID(id) etc. which are // much harder to design and implement than expected. I have a couple of private branches on this matter but it's not simple. For now implementing the easy ones. IMGUI_API void FocusItem(); // Focus last item (no selection/activation). - IMGUI_API void ActivateItemByID(ImGuiID id); // Activate an item by ID (button, checkbox, tree node etc.). Activation is queued and processed on the next frame when the item is encountered again. + IMGUI_API void ActivateItemByID(ImGuiID id); // Activate an item by ID (button, checkbox, tree node etc.). Activation is queued and processed on the next frame when the item is encountered again. Was called 'ActivateItem()' before 1.89.7. // Inputs // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions. @@ -3663,6 +3667,7 @@ namespace ImGui //inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 //inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! + // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0' diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index afad7b6ecffb..9aa94c799a93 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -573,7 +573,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool bool pressed = false; bool hovered = ItemHoverable(bb, id, item_flags); - // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button + // Special mode for Drag and Drop used by openables (tree nodes, tabs etc.) + // where holding the button pressed for a long time while drag a payload item triggers the button. if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) { From f39b13848734faf9acc3cf9d2313e2f01032af12 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Jul 2025 18:24:14 +0200 Subject: [PATCH 706/716] Internals: rename DebugDrawIdConflicts -> DebugDrawIdConflictsId. --- imgui.cpp | 12 ++++++------ imgui_internal.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 84ac433b0ffc..da7f39e24124 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4032,7 +4032,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas) WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1; WheelingWindowReleaseTimer = 0.0f; - DebugDrawIdConflicts = 0; + DebugDrawIdConflictsId = 0; DebugHookIdInfo = 0; HoveredId = HoveredIdPreviousFrame = 0; HoveredIdPreviousFrameItemCount = 0; @@ -4748,7 +4748,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0) { g.HoveredIdPreviousFrameItemCount++; - if (g.DebugDrawIdConflicts == id) + if (g.DebugDrawIdConflictsId == id) window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f); } #endif @@ -5376,9 +5376,9 @@ void ImGui::NewFrame() // [DEBUG] if (!g.IO.ConfigDebugHighlightIdConflicts || !g.IO.KeyCtrl) // Count is locked while holding CTRL - g.DebugDrawIdConflicts = 0; + g.DebugDrawIdConflictsId = 0; if (g.IO.ConfigDebugHighlightIdConflicts && g.HoveredIdPreviousFrameItemCount > 1) - g.DebugDrawIdConflicts = g.HoveredIdPreviousFrame; + g.DebugDrawIdConflictsId = g.HoveredIdPreviousFrame; // Update HoveredId data if (!g.HoveredIdPreviousFrame) @@ -10841,9 +10841,9 @@ void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip() { #ifndef IMGUI_DISABLE_DEBUG_TOOLS ImGuiContext& g = *GImGui; - if (g.DebugDrawIdConflicts != 0 && g.IO.KeyCtrl == false) + if (g.DebugDrawIdConflictsId != 0 && g.IO.KeyCtrl == false) g.DebugDrawIdConflictsCount = g.HoveredIdPreviousFrameItemCount; - if (g.DebugDrawIdConflicts != 0 && g.DebugItemPickerActive == false && BeginErrorTooltip()) + if (g.DebugDrawIdConflictsId != 0 && g.DebugItemPickerActive == false && BeginErrorTooltip()) { Text("Programmer error: %d visible items with conflicting ID!", g.DebugDrawIdConflictsCount); BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!"); diff --git a/imgui_internal.h b/imgui_internal.h index fecb7b4ddf38..978a51020b07 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2192,7 +2192,7 @@ struct ImGuiContext ImVec2 WheelingAxisAvg; // Item/widgets state and tracking information - ImGuiID DebugDrawIdConflicts; // Set when we detect multiple items with the same identifier + ImGuiID DebugDrawIdConflictsId; // Set when we detect multiple items with the same identifier ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line] ImGuiID HoveredId; // Hovered widget, filled during the frame ImGuiID HoveredIdPreviousFrame; From 0ba02a4ed67b4c8985007f109b413edb21898f41 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Jul 2025 18:43:25 +0200 Subject: [PATCH 707/716] Debug Tools: added IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS. (#8651, #7961, #7669) --- docs/CHANGELOG.txt | 3 +++ imconfig.h | 4 ++++ imgui.cpp | 25 +++++++++++++++++++++++++ imgui_internal.h | 4 ++++ 4 files changed, 36 insertions(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2cab3f6c5d28..4bf17e7854ce 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,9 @@ Other changes: - Demo: Added "Text -> Font Size" demo section. (#8738) [@Demonese] - CI: Fixed dllimport/dllexport tests. (#8757) [@AidanSun05] - CI: Updated to use latest Windows image + VS2022. +- Debug Tools: added IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS to detect + id conflicts _before_ hovering. This is very slow and should only be used + temporarily. (#8651, #7961, #7669) - Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port 'contrib.glfw3' which offers better HiDPI support. (#8742) [@pthom] - Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and diff --git a/imconfig.h b/imconfig.h index a1e29e849bc8..4dab1b60425b 100644 --- a/imconfig.h +++ b/imconfig.h @@ -129,6 +129,10 @@ //#define IM_DEBUG_BREAK IM_ASSERT(0) //#define IM_DEBUG_BREAK __debugbreak() +//---- Debug Tools: Enable highlight ID conflicts _before_ hovering items. When io.ConfigDebugHighlightIdConflicts is set. +// (THIS WILL SLOW DOWN DEAR IMGUI. Only use occasionally and disable after use) +//#define IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS + //---- Debug Tools: Enable slower asserts //#define IMGUI_DEBUG_PARANOID diff --git a/imgui.cpp b/imgui.cpp index da7f39e24124..153ae5c0331b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4263,6 +4263,12 @@ void ImGui::Initialize() #ifdef IMGUI_HAS_DOCK #endif + // Print a debug message when running with debug feature IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS because it is very slow. + // DO NOT COMMENT OUT THIS MESSAGE. IT IS DESIGNED TO REMIND YOU THAT IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS SHOULD ONLY BE TEMPORARILY ENABLED. +#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS + DebugLog("IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS is enabled.\nMust disable after use! Otherwise Dear ImGui will run slower.\n"); +#endif + // ImDrawList/ImFontAtlas are designed to function without ImGui, and 99% of it works without an ImGui context. // But this link allows us to facilitate/handle a few edge cases better. ImFontAtlas* atlas = g.IO.Fonts; @@ -11012,6 +11018,21 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu // Empty identifier are valid and useful in a small amount of cases, but 99.9% of the time you want to use "##something". // READ THE FAQ: https://dearimgui.com/faq IM_ASSERT(id != window->ID && "Cannot have an empty ID at the root of a window. If you need an empty label, use ## and read the FAQ about how the ID Stack works!"); + + // [DEBUG] Highlight all conflicts WITHOUT needing to hover. THIS WILL SLOW DOWN DEAR IMGUI. DON'T KEEP ACTIVATED. + // This will only work for items submitted with ItemAdd(). Some very rare/odd/unrecommended code patterns are calling ButtonBehavior() without ItemAdd(). +#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS + if ((g.LastItemData.ItemFlags & ImGuiItemFlags_AllowDuplicateId) == 0) + { + int* p_alive = g.DebugDrawIdConflictsAliveCount.GetIntRef(id, -1); // Could halve lookups if we knew ImGuiStorage can store 64-bit, or by storing FrameCount as 30-bits + highlight as 2-bits. But the point is that we should not pretend that this is fast. + int* p_highlight = g.DebugDrawIdConflictsHighlightSet.GetIntRef(id, -1); + if (*p_alive == g.FrameCount) + *p_highlight = g.FrameCount; + *p_alive = g.FrameCount; + if (*p_highlight >= g.FrameCount - 1) + window->DrawList->AddRect(bb.Min - ImVec2(1, 1), bb.Max + ImVec2(1, 1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f); + } +#endif } //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG] //if ((g.LastItemData.ItemFlags & ImGuiItemFlags_NoNav) == 0) @@ -16126,6 +16147,10 @@ void ImGui::ShowMetricsWindow(bool* p_open) } }; +#ifdef IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS + TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS is enabled.\nMust disable after use! Otherwise Dear ImGui will run slower.\n"); +#endif + // Tools if (TreeNode("Tools")) { diff --git a/imgui_internal.h b/imgui_internal.h index 978a51020b07..54daf89c43c9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2495,6 +2495,10 @@ struct ImGuiContext ImGuiMetricsConfig DebugMetricsConfig; ImGuiIDStackTool DebugIDStackTool; ImGuiDebugAllocInfo DebugAllocInfo; +#if defined(IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS) && !defined(IMGUI_DISABLE_DEBUG_TOOLS) + ImGuiStorage DebugDrawIdConflictsAliveCount; + ImGuiStorage DebugDrawIdConflictsHighlightSet; +#endif // Misc float FramerateSecPerFrame[60]; // Calculate estimate of framerate for user over the last 60 frames.. From 5d4126876bc10396d4c6511853ff10964414c776 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 9 Jul 2025 18:53:58 +0200 Subject: [PATCH 708/716] Version 1.92.1 --- docs/CHANGELOG.txt | 8 ++++---- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 4 ++-- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4bf17e7854ce..7f12f6a5be1b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -36,12 +36,12 @@ HOW TO UPDATE? - Please report any issue! ----------------------------------------------------------------------- - VERSION 1.92.1 WIP (In Progress) + VERSION 1.92.1 (Released 2025-07-09) ----------------------------------------------------------------------- -Breaking changes: +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.1 -Other changes: +Changes: - Fonts: added ImFontAtlas::SetFontLoader() to dynamically change font loader at runtime without using internal API. (#8752, #8465) @@ -86,7 +86,7 @@ Other changes: VERSION 1.92.0 (Released 2025-06-25) ----------------------------------------------------------------------- -Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92 +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.0 THIS VERSION CONTAINS THE LARGEST AMOUNT OF BREAKING CHANGES SINCE 2015! I TRIED REALLY HARD TO KEEP THEM TO A MINIMUM, REDUCE THE AMOUNT OF INTERFERENCE, diff --git a/imgui.cpp b/imgui.cpp index 153ae5c0331b..99819ffe4cdf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index 89c2c2e5ddd0..a2b2a1faeb5f 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.1 WIP" -#define IMGUI_VERSION_NUM 19202 +#define IMGUI_VERSION "1.92.1" +#define IMGUI_VERSION_NUM 19210 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 05f5e45f1043..991676f78040 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bce905420809..401282678c30 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index 54daf89c43c9..ccb979b8cbc0 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. @@ -2507,7 +2507,7 @@ struct ImGuiContext float FramerateSecPerFrameAccum; int WantCaptureMouseNextFrame; // Explicit capture override via SetNextFrameWantCaptureMouse()/SetNextFrameWantCaptureKeyboard(). Default to -1. int WantCaptureKeyboardNextFrame; // " - int WantTextInputNextFrame; // Copied in EndFrame() from g.PlatformImeData.WanttextInput. Needs to be set for some backends (SDL3) to emit character inputs. + int WantTextInputNextFrame; // Copied in EndFrame() from g.PlatformImeData.WantTextInput. Needs to be set for some backends (SDL3) to emit character inputs. ImVector TempBuffer; // Temporary text buffer char TempKeychordName[64]; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 069c7299581e..119fe7bcca51 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 9aa94c799a93..a0c4f14f5222 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 WIP +// dear imgui, v1.92.1 // (widgets code) /* From 4d745bc602d40b242504c15f03fb0322dedb74b3 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Jul 2025 18:41:05 +0200 Subject: [PATCH 709/716] Version 1.92.2 WIP --- docs/CHANGELOG.txt | 17 +++++++++++++---- imgui.cpp | 2 +- imgui.h | 6 +++--- imgui_demo.cpp | 2 +- imgui_draw.cpp | 2 +- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 2 +- 8 files changed, 22 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 7f12f6a5be1b..f19d5f246701 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,6 +35,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.92.2 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking Changes: + +Other Changes: + + ----------------------------------------------------------------------- VERSION 1.92.1 (Released 2025-07-09) ----------------------------------------------------------------------- @@ -64,13 +73,13 @@ Changes: - Debug Tools: added IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS to detect id conflicts _before_ hovering. This is very slow and should only be used temporarily. (#8651, #7961, #7669) -- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port +- Examples: GLFW+OpenGL3, GLFW+WGPU: Emscripten Makefiles uses GLFW port 'contrib.glfw3' which offers better HiDPI support. (#8742) [@pthom] -- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and - ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten +- Backends: GLFW, SDL2 made ImGui_ImplGLFW_GetContentScaleXXX() and + ImGui_ImplSDL2_GetContentScaleXXXX() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) [@pthom] - Backends: SDL3: avoid calling SDL_StartTextInput() again if already active. - (fixes e.g.: an issue on iOS where the keyboard animation will popup every + (fixes e.g.: an issue on iOS where the keyboard animation will popup every time the user types a key + probably other things) (#8727) [@morrazzzz] - Backends: OSX: added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. (#8739) [@cfillion] diff --git a/imgui.cpp b/imgui.cpp index 99819ffe4cdf..94d94ff8558b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (main code and documentation) // Help: diff --git a/imgui.h b/imgui.h index a2b2a1faeb5f..f474876f12c2 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (headers) // Help: @@ -28,8 +28,8 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.92.1" -#define IMGUI_VERSION_NUM 19210 +#define IMGUI_VERSION "1.92.2 WIP" +#define IMGUI_VERSION_NUM 19211 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 991676f78040..6bc8968a48f6 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (demo code) // Help: diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 401282678c30..93fa8c3449f8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (drawing and font code) /* diff --git a/imgui_internal.h b/imgui_internal.h index ccb979b8cbc0..c5a6640109f9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (internal structures/api) // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 119fe7bcca51..f2fa47d78c05 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (tables and columns code) /* diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index a0c4f14f5222..63dd9dc215cf 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -1,4 +1,4 @@ -// dear imgui, v1.92.1 +// dear imgui, v1.92.2 WIP // (widgets code) /* From c680f54e6c56952885c8f3aebc7eb09d2934e212 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Jul 2025 18:42:39 +0200 Subject: [PATCH 710/716] FIxed IsWindowFocused() using wrong flag types (harmless as values were identical). (#8786) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 94d94ff8558b..0ba16fb31dc6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -12501,10 +12501,10 @@ bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags) IM_ASSERT(cur_window); // Not inside a Begin()/End() const bool popup_hierarchy = (flags & ImGuiFocusedFlags_NoPopupHierarchy) == 0; - if (flags & ImGuiHoveredFlags_RootWindow) + if (flags & ImGuiFocusedFlags_RootWindow) cur_window = GetCombinedRootWindow(cur_window, popup_hierarchy); - if (flags & ImGuiHoveredFlags_ChildWindows) + if (flags & ImGuiFocusedFlags_ChildWindows) return IsWindowChildOf(ref_window, cur_window, popup_hierarchy); else return (ref_window == cur_window); From 0e6e876f237921b7d73bd201f0fc63953fed95d6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 10 Jul 2025 19:04:43 +0200 Subject: [PATCH 711/716] Docs: update docs/comments about ImTextureRef, ImTextureID. (#8783) --- docs/FAQ.md | 38 ++++++++++++++++++++++++++++++-------- imgui.h | 5 +++-- imgui_internal.h | 1 - 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 10fb60350118..286127cb9dbe 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -389,8 +389,8 @@ node open/closed state differently. See what makes more sense in your situation! ### Q: What are ImTextureID/ImTextureRef? **Short explanation:** -- Refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki). - You may use functions such as `ImGui::Image()`, `ImGui::ImageButton()` or lower-level `ImDrawList::AddImage()` to emit draw calls that will use your own textures. +- To load and display your own textures, refer to [Image Loading and Displaying Examples](https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples) on the [Wiki](https://github.com/ocornut/imgui/wiki). - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as an opaque ImTextureID value. - By default ImTextureID can store up to 64-bits. You may `#define` it to a custom type/structure if you need. - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason), but the examples linked above may be useful references. @@ -398,12 +398,20 @@ node open/closed state differently. See what makes more sense in your situation! **Details:** 1.92 introduced `ImTextureRef` in June 2025. -- Most drawing functions using ImTextureID were changed to use ImTextureRef. -- We intentionally do not provide an implicit ImTextureRef -> ImTextureID cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. +- All drawing functions using `ImTextureID` were changed to use `ImTextureRef`. +- You can trivially create a `ImTextureRef` from a `ImTextureID`. +- **If you use Image functions with textures that you have loaded/created yourself, you will mostly likely only ever store/manipulate `ImTextureID` and then pass them as `ImTextureRef`.** +- You only NEED to manipulate `ImTextureRef` when dealing with textures managed by the backend itself, aka mainly the atlas texture for now. +- We intentionally do not provide an implicit `ImTextureRef` -> `ImTextureID` cast operator because it is technically lossy to convert ImTextureRef to ImTextureID before rendering. **ImTextureID = backend specific, low-level identifier for a texture uploaded in GPU/graphics system.** +```cpp +#ifndef ImTextureID +typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. +#endif +``` - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). -- User may submit their own textures to e.g. ImGui::Image() function by passing the same type. +- User may submit their own textures to e.g. `ImGui::Image()` function by passing this value. - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a ImTextureRef, which is stored inside ImDrawCmd. - Compile-time type configuration: - To use something other than a 64-bit value: add '#define ImTextureID MyTextureType*' in your imconfig.h file. @@ -411,13 +419,27 @@ node open/closed state differently. See what makes more sense in your situation! - You may decide to store a higher-level structure containing texture, sampler, shader etc. with various constructors if you like. You will need to implement ==/!= operators. **ImTextureRef = higher-level identifier for a texture.** +```cpp +// Store a ImTextureID _or_ a ImTextureData*. +struct ImTextureRef +{ + ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; } + ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; } + inline ImTextureID GetTexID() const { return _TexData ? _TexData->TexID : _TexID; } + + // Members (either are set, never both!) + ImTextureData* _TexData; // A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded. + ImTextureID _TexID; // _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui::Image() calls. +}; +``` - The identifier is valid even before the texture has been uploaded to the GPU/graphics system. - This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. - This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. - - When a texture is created by user code (e.g. custom images), we directly stores the low-level `ImTextureID`. - - When a texture is created by the backend, we stores a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. - - There is no constructor to create a `ImTextureID` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. - - If you want to bind the current atlas when using custom rectangle, you can use `io.Fonts->TexRef`. + - When a texture is created by user code (e.g. custom images), we directly store the low-level `ImTextureID`. + - Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. + - When a texture is created by the backend, we store a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. + - There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. + - If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`. - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }` **Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.** diff --git a/imgui.h b/imgui.h index f474876f12c2..cef7d7b87a03 100644 --- a/imgui.h +++ b/imgui.h @@ -317,7 +317,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE // - When a Rendered Backend creates a texture, it store its native identifier into a ImTextureID value. // (e.g. Used by DX11 backend to a `ID3D11ShaderResourceView*`; Used by OpenGL backends to store `GLuint`; // Used by SDLGPU backend to store a `SDL_GPUTextureSamplerBinding*`, etc.). -// - User may submit their own textures to e.g. ImGui::Image() function by passing the same type. +// - User may submit their own textures to e.g. ImGui::Image() function by passing this value. // - During the rendering loop, the Renderer Backend retrieve the ImTextureID, which stored inside a // ImTextureRef, which is stored inside a ImDrawCmd. // - Compile-time type configuration: @@ -337,11 +337,12 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or #define ImTextureID_Invalid ((ImTextureID)0) #endif -// ImTextureRef = higher-level identifier for a texture. +// ImTextureRef = higher-level identifier for a texture. Store a ImTextureID _or_ a ImTextureData*. // The identifier is valid even before the texture has been uploaded to the GPU/graphics system. // This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. // This is what gets stored in draw commands (`ImDrawCmd`) to identify a texture during rendering. // - When a texture is created by user code (e.g. custom images), we directly stores the low-level ImTextureID. +// Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. // - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection // to extract the ImTextureID value during rendering, after texture upload has happened. // - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this diff --git a/imgui_internal.h b/imgui_internal.h index c5a6640109f9..bf744d4b1495 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3671,7 +3671,6 @@ namespace ImGui //inline bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0) { return TreeNodeUpdateNextOpen(id, flags); } // Renamed in 1.89 //inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { IM_ASSERT(IsNamedKey(key)); return IsKeyPressed(key, repeat); } // Removed in 1.87: Mapping from named key is always identity! - // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): // Refactored focus/nav/tabbing system in 1.82 and 1.84. If you have old/custom copy-and-pasted widgets which used FocusableItemRegister(): // (Old) IMGUI_VERSION_NUM < 18209: using 'ItemAdd(....)' and 'bool tab_focused = FocusableItemRegister(...)' // (Old) IMGUI_VERSION_NUM >= 18209: using 'ItemAdd(..., ImGuiItemAddFlags_Focusable)' and 'bool tab_focused = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0' From a0d3e405a343677cd326ed704b1b27c000c05d17 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Jul 2025 16:40:35 +0200 Subject: [PATCH 712/716] Textures: ImTextureData::Create() sets status. RegisterUserTexture() increases RefCount. Added comments about ImTextureData::GetTexRef(). (#8789) --- docs/FAQ.md | 2 ++ imgui.cpp | 5 ++++- imgui.h | 9 +++++---- imgui_draw.cpp | 3 ++- imgui_internal.h | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 286127cb9dbe..fb693c7e30df 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -438,6 +438,8 @@ struct ImTextureRef - When a texture is created by user code (e.g. custom images), we directly store the low-level `ImTextureID`. - Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. - When a texture is created by the backend, we store a `ImTextureData*` which becomes an indirection to extract the `ImTextureID` value during rendering, after texture upload has happened. + - To create a `ImTextureRef` from a `ImTextureData*` you can use `ImTextureData::GetTexRef()`. + We intentionally do not provide an `ImTextureRef` constructor for this: we don't expect this to be frequently useful to the end-user, and it would be erroneously called by many legacy code. - There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code. - If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`. - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }` diff --git a/imgui.cpp b/imgui.cpp index 0ba16fb31dc6..31a95716b184 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8732,16 +8732,19 @@ ImFont* ImGui::GetDefaultFont() return g.IO.FontDefault ? g.IO.FontDefault : atlas->Fonts[0]; } +// EXPERIMENTAL: DO NOT USE YET. void ImGui::RegisterUserTexture(ImTextureData* tex) { ImGuiContext& g = *GImGui; - IM_ASSERT(tex->RefCount > 0); + tex->RefCount++; g.UserTextures.push_back(tex); } void ImGui::UnregisterUserTexture(ImTextureData* tex) { ImGuiContext& g = *GImGui; + IM_ASSERT(tex->RefCount > 0); + tex->RefCount--; g.UserTextures.find_erase(tex); } diff --git a/imgui.h b/imgui.h index cef7d7b87a03..ee4e976aeb37 100644 --- a/imgui.h +++ b/imgui.h @@ -345,8 +345,9 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or // Because of this, when displaying your own texture you are likely to ever only manage ImTextureID values on your side. // - When a texture is created by the backend, we stores a ImTextureData* which becomes an indirection // to extract the ImTextureID value during rendering, after texture upload has happened. -// - There is no constructor to create a ImTextureID from a ImTextureData* as we don't expect this -// to be useful to the end-user, and it would be erroneously called by many legacy code. +// - To create a ImTextureRef from a ImTextureData you can use ImTextureData::GetTexRef(). +// We intentionally do not provide an ImTextureRef constructor for this: we don't expect this +// to be frequently useful to the end-user, and it would be erroneously called by many legacy code. // - If you want to bind the current atlas when using custom rectangle, you can use io.Fonts->TexRef. // - Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. // inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; } @@ -3425,7 +3426,7 @@ struct ImTextureRect struct ImTextureData { //------------------------------------------ core / backend --------------------------------------- - int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. + int UniqueID; // w - // [DEBUG] Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! void* BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID. ImTextureID TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. @@ -3443,7 +3444,7 @@ struct ImTextureData bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. // Functions - ImTextureData() { memset(this, 0, sizeof(*this)); TexID = ImTextureID_Invalid; } + ImTextureData() { memset(this, 0, sizeof(*this)); Status = ImTextureStatus_Destroyed; TexID = ImTextureID_Invalid; } ~ImTextureData() { DestroyPixels(); } IMGUI_API void Create(ImTextureFormat format, int w, int h); IMGUI_API void DestroyPixels(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 93fa8c3449f8..d12b8b55d67c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2457,8 +2457,10 @@ const char* ImTextureDataGetFormatName(ImTextureFormat format) void ImTextureData::Create(ImTextureFormat format, int w, int h) { + IM_ASSERT(Status == ImTextureStatus_Destroyed); DestroyPixels(); Format = format; + Status = ImTextureStatus_WantCreate; Width = w; Height = h; BytesPerPixel = ImTextureDataGetFormatBytesPerPixel(format); @@ -3971,7 +3973,6 @@ ImTextureData* ImFontAtlasTextureAdd(ImFontAtlas* atlas, int w, int h) } new_tex->Create(atlas->TexDesiredFormat, w, h); - new_tex->Status = ImTextureStatus_WantCreate; atlas->TexIsBuilt = false; ImFontAtlasBuildSetTexture(atlas, new_tex); diff --git a/imgui_internal.h b/imgui_internal.h index bf744d4b1495..f5f324c6e9b4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -3124,7 +3124,7 @@ namespace ImGui IMGUI_API void SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags); // Fonts, drawing - IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture + IMGUI_API void RegisterUserTexture(ImTextureData* tex); // Register external texture. EXPERIMENTAL: DO NOT USE YET. IMGUI_API void UnregisterUserTexture(ImTextureData* tex); IMGUI_API void RegisterFontAtlas(ImFontAtlas* atlas); IMGUI_API void UnregisterFontAtlas(ImFontAtlas* atlas); From 79d88e2d0b1c915a9ea3d1a4215cf2a4dded3fab Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Jul 2025 16:57:43 +0200 Subject: [PATCH 713/716] Error Handling, Tables: TableGetSortSpecs() silently return NULL when no table (matching most other table getters). TableSetBgColor() uses IM_ASSERT_USER_ERROR. --- docs/CHANGELOG.txt | 3 +++ imgui_tables.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f19d5f246701..70d3c37a37ac 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking Changes: Other Changes: +- Error Handling: minor improvements to error handling for TableGetSortSpecs() + and TableSetBgColor() calls. (#1651, #8499) + ----------------------------------------------------------------------- VERSION 1.92.1 (Released 2025-07-09) diff --git a/imgui_tables.cpp b/imgui_tables.cpp index f2fa47d78c05..a1504853b82f 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1825,6 +1825,11 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; IM_ASSERT(target != ImGuiTableBgTarget_None); + if (table == NULL) + { + IM_ASSERT_USER_ERROR(table != NULL, "Call should only be done while in BeginTable() scope!"); + return; + } if (color == IM_COL32_DISABLE) color = 0; @@ -2876,9 +2881,7 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL); - - if (!(table->Flags & ImGuiTableFlags_Sortable)) + if (table == NULL || !(table->Flags & ImGuiTableFlags_Sortable)) return NULL; // Require layout (in case TableHeadersRow() hasn't been called) as it may alter IsSortSpecsDirty in some paths. From 336d9212fc25055a52107c70441c11acd12e8bb9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 11 Jul 2025 17:41:52 +0200 Subject: [PATCH 714/716] Backends: using range-for to iterate draw_data->CmdLists[]. --- backends/imgui_impl_allegro5.cpp | 4 +--- backends/imgui_impl_dx10.cpp | 6 ++---- backends/imgui_impl_dx11.cpp | 6 ++---- backends/imgui_impl_dx12.cpp | 6 ++---- backends/imgui_impl_dx9.cpp | 6 ++---- backends/imgui_impl_metal.mm | 6 ++---- backends/imgui_impl_opengl2.cpp | 3 +-- backends/imgui_impl_opengl3.cpp | 4 +--- backends/imgui_impl_sdlgpu3.cpp | 6 ++---- backends/imgui_impl_sdlrenderer2.cpp | 3 +-- backends/imgui_impl_sdlrenderer3.cpp | 3 +-- backends/imgui_impl_vulkan.cpp | 6 ++---- backends/imgui_impl_wgpu.cpp | 8 +++----- docs/BACKENDS.md | 3 +-- imgui.h | 2 +- imgui_draw.cpp | 17 ++++++++--------- 16 files changed, 32 insertions(+), 57 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 5cbb893653b4..40417fc63b62 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -160,10 +160,8 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data) ImGui_ImplAllegro5_SetupRenderState(draw_data); // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - ImVector& vertices = bd->BufVertices; #if ALLEGRO_HAS_DRAW_INDEXED_PRIM vertices.resize(draw_list->VtxBuffer.Size); diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 6bc52156ff82..3781a0974277 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -200,9 +200,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) ImDrawIdx* idx_dst = nullptr; bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst); bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst); - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -268,9 +267,8 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 1b28745a38d0..08bf7998f08e 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -208,9 +208,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -282,9 +281,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) int global_vtx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 55785097932c..2932855ed987 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -262,9 +262,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL return; ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource; ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -295,9 +294,8 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index b0159bf371af..94411fabea8f 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -228,9 +228,8 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) // FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and // 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; } - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_src = draw_list->VtxBuffer.Data; for (int i = 0; i < draw_list->VtxBuffer.Size; i++) { @@ -260,9 +259,8 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) int global_vtx_offset = 0; int global_idx_offset = 0; ImVec2 clip_off = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index b1decb2bbb46..a1adc6c9a296 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -223,7 +223,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) + if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. @@ -259,10 +259,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id // Render command lists size_t vertexBufferOffset = 0; size_t indexBufferOffset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index afcafe82606d..7f760cca561c 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -208,9 +208,8 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + offsetof(ImDrawVert, pos))); diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 40b3be68b2df..7e8853017244 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -584,10 +584,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; - // Upload vertex/index buffers // - OpenGL drivers are in a very sorry state nowadays.... // During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 927e511cb8d8..f58324a8960b 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -180,9 +180,8 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff ImDrawVert* vtx_dst = (ImDrawVert*)SDL_MapGPUTransferBuffer(v->Device, fd->VertexTransferBuffer, true); ImDrawIdx* idx_dst = (ImDrawIdx*)SDL_MapGPUTransferBuffer(v->Device, fd->IndexTransferBuffer, true); - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -238,9 +237,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index a39360f5cf8f..3a47f80bf61a 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -169,9 +169,8 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* ImVec2 clip_scale = render_scale; // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index f62949150bde..42c173888c97 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -189,9 +189,8 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* ImVec2 clip_scale = render_scale; // Render command lists - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index a5dd75c8e7d3..1120b4b5ed5e 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -550,9 +550,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm check_vk_result(err); err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)&idx_dst); check_vk_result(err); - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -590,9 +589,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // (Because we merged all buffers into a single one, we maintain our own offset into them) int global_vtx_offset = 0; int global_idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index c0ec2e3f9f42..d20028d55e26 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -367,7 +367,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Avoid rendering when minimized int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); - if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) + if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0) return; // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do. @@ -442,9 +442,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Upload vertex/index data into a single contiguous GPU buffer ImDrawVert* vtx_dst = (ImDrawVert*)fr->VertexBufferHost; ImDrawIdx* idx_dst = (ImDrawIdx*)fr->IndexBufferHost; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += draw_list->VtxBuffer.Size; @@ -471,9 +470,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder int global_idx_offset = 0; ImVec2 clip_scale = draw_data->FramebufferScale; ImVec2 clip_off = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* draw_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index fa05d55ea2d1..629f8d83f042 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -245,9 +245,8 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) // Render command lists ImVec2 clip_off = draw_data->DisplayPos; ImVec2 clip_scale = draw_data->FramebufferScale; - for (int n = 0; n < draw_data->CmdListsCount; n++) + for (const ImDrawList* draw_list : draw_data->CmdLists) { - const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) diff --git a/imgui.h b/imgui.h index ee4e976aeb37..5d947b23d0be 100644 --- a/imgui.h +++ b/imgui.h @@ -3361,7 +3361,7 @@ struct ImDrawList struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - int CmdListsCount; // Number of ImDrawList* to render. (== CmdLists.Size). Exists for legacy reason. + int CmdListsCount; // == CmdLists.Size. (OBSOLETE: exists for legacy reasons). Number of ImDrawList* to render. int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size ImVector CmdLists; // Array of ImDrawList* to render. The ImDrawLists are owned by ImGuiContext and only pointed to from here. diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d12b8b55d67c..f42f966393cc 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2312,17 +2312,16 @@ void ImDrawData::DeIndexAllBuffers() { ImVector new_vtx_buffer; TotalVtxCount = TotalIdxCount = 0; - for (int i = 0; i < CmdListsCount; i++) + for (ImDrawList* draw_list : CmdLists) { - ImDrawList* cmd_list = CmdLists[i]; - if (cmd_list->IdxBuffer.empty()) + if (draw_list->IdxBuffer.empty()) continue; - new_vtx_buffer.resize(cmd_list->IdxBuffer.Size); - for (int j = 0; j < cmd_list->IdxBuffer.Size; j++) - new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]]; - cmd_list->VtxBuffer.swap(new_vtx_buffer); - cmd_list->IdxBuffer.resize(0); - TotalVtxCount += cmd_list->VtxBuffer.Size; + new_vtx_buffer.resize(draw_list->IdxBuffer.Size); + for (int j = 0; j < draw_list->IdxBuffer.Size; j++) + new_vtx_buffer[j] = draw_list->VtxBuffer[draw_list->IdxBuffer[j]]; + draw_list->VtxBuffer.swap(new_vtx_buffer); + draw_list->IdxBuffer.resize(0); + TotalVtxCount += draw_list->VtxBuffer.Size; } } From 8744d10235e58536c5237a2ead3af53b700f40c4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Jul 2025 14:30:50 +0200 Subject: [PATCH 715/716] Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) --- backends/imgui_impl_opengl2.cpp | 3 +++ backends/imgui_impl_opengl3.cpp | 15 ++++++++++++--- backends/imgui_impl_opengl3_loader.h | 1 + docs/CHANGELOG.txt | 2 ++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 7f760cca561c..477e3a0433ca 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -25,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-06-28: OpenGL: ImGui_ImplOpenGL2_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL2_DestroyFontsTexture(). (#7748) @@ -285,6 +286,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); // Store identifiers @@ -304,6 +306,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex) GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); for (ImTextureRect& r : tex->Updates) GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y))); GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 7e8853017244..e9660295e418 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) @@ -709,6 +710,17 @@ static void ImGui_ImplOpenGL3_DestroyTexture(ImTextureData* tex) void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) { + // FIXME: Consider backing up and restoring + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) + { +#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES + GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); +#endif +#ifdef GL_UNPACK_ALIGNMENT + GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1)); +#endif + } + if (tex->Status == ImTextureStatus_WantCreate) { // Create and upload new texture to graphics system @@ -728,9 +740,6 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); -#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES - GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); -#endif GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); // Store identifiers diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index 4ca0536031aa..aa8fdc27e1fe 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -166,6 +166,7 @@ typedef khronos_uint8_t GLubyte; #define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_TEST 0x0C11 #define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_TEXTURE_2D 0x0DE1 diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 70d3c37a37ac..17cf659ba781 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,8 @@ Other Changes: - Error Handling: minor improvements to error handling for TableGetSortSpecs() and TableSetBgColor() calls. (#1651, #8499) +- Backends: OpenGL2, OpenGL3: set GL_UNPACK_ALIGNMENT to 1 before updating + textures. (#8802) [@Daandelange] ----------------------------------------------------------------------- From 643f0e3abf6f84c210ea717f62c02bf411fc2e8c Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 15 Jul 2025 14:34:04 +0200 Subject: [PATCH 716/716] Backends: OpenGL3: restore update path on non-WebGL non-ES targets that doesn't require a CPU copy. (#8802, #8465) Amend/fix dbb91a5 --- backends/imgui_impl_opengl3.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index e9660295e418..00d1d94c3357 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,7 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) +// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy. // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). // 2025-06-04: OpenGL: Made GLES 3.20 contexts not access GL_CONTEXT_PROFILE_MASK nor GL_PRIMITIVE_RESTART. (#8664) // 2025-02-18: OpenGL: Lazily reinitialize embedded GL loader for when calling backend from e.g. other DLL boundaries. (#8406) @@ -758,7 +758,7 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex) GLuint gl_tex_id = (GLuint)(intptr_t)tex->TexID; GL_CALL(glBindTexture(GL_TEXTURE_2D, gl_tex_id)); -#if 0// GL_UNPACK_ROW_LENGTH // Not on WebGL/ES +#if GL_UNPACK_ROW_LENGTH // Not on WebGL/ES GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width)); for (ImTextureRect& r : tex->Updates) GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y)));