Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_osx.mm
#	backends/imgui_impl_wgpu.cpp
#	backends/imgui_impl_wgpu.h
This commit is contained in:
ocornut
2025-06-13 17:43:30 +02:00
10 changed files with 202 additions and 120 deletions

View File

@@ -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.

View File

@@ -35,6 +35,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2025-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644)
// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
// 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)
@@ -697,6 +698,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)

View File

@@ -6,8 +6,8 @@
// [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'.
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
// Missing features or Issues:
// [ ] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@@ -20,6 +20,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.
@@ -74,11 +75,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)
@@ -235,23 +240,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);
@@ -382,6 +372,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();
@@ -537,33 +534,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;
@@ -572,19 +588,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 = {};
@@ -592,29 +624,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);
}
// 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);
if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
ImGui_ImplWGPU_DestroyTexture(tex);
}
static void ImGui_ImplWGPU_CreateUniformBuffer()
@@ -758,16 +775,26 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
bd->pipelineState = wgpuDeviceCreateRenderPipeline(bd->wgpuDevice, &graphics_pipeline_desc);
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);
@@ -792,8 +819,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]);
@@ -818,6 +847,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;
@@ -827,8 +857,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;
@@ -867,7 +895,7 @@ void ImGui_ImplWGPU_Shutdown()
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
IM_DELETE(bd);
}

View File

@@ -13,8 +13,8 @@
// [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'.
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
// Missing features or Issues:
// [ ] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [ ] Renderer: Multi-viewport support (multiple windows), useful for desktop.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@@ -58,6 +58,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)

View File

@@ -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
@@ -115,8 +118,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.
@@ -302,6 +305,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)
@@ -365,32 +369,14 @@ 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:
- Backends: DX9/DX10/DX11/DX12, Vulkan, OpenGL2/3, Metal, SDLGPU3, SDLRenderer2/3, Allegro5:
- 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: 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
@@ -409,6 +395,27 @@ 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)
- 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:

View File

@@ -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)**

View File

@@ -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.
@@ -348,12 +349,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();
}
@@ -373,25 +374,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;
// <create texture based on tex->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;
// <update texture blocks based on tex->UpdateRect>
tex->SetStatus(ImTextureStatus_OK);
}
if (tex->Status == ImTextureStatus_WantDestroy)
{
// destroy texture
// call tex->SetTexID(ImTextureID_Invalid)
// tex->Status = ImTextureStatus_Destroyed;
// <destroy texture>
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
@@ -408,7 +416,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
{
@@ -480,7 +491,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:
@@ -4567,12 +4578,15 @@ static void SetCurrentWindow(ImGuiWindow* window)
g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
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();
}
}
@@ -5467,13 +5481,16 @@ 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.");
// (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);
}
}
}
@@ -7482,8 +7499,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;
@@ -9292,6 +9313,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()
{
@@ -9404,12 +9440,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;
@@ -22799,7 +22833,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++)

View File

@@ -2722,12 +2722,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)

View File

@@ -957,6 +957,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.
@@ -1034,6 +1035,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,
};
@@ -4131,7 +4133,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);

View File

@@ -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
}