Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_dx12.cpp
#	docs/CHANGELOG.txt
#	imgui.cpp
This commit is contained in:
ocornut
2025-10-13 15:13:06 +02:00
14 changed files with 233 additions and 170 deletions

View File

@@ -42,5 +42,5 @@ jobs:
fi fi
cd examples/example_null cd examples/example_null
pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1 pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
pvs-studio-analyzer analyze --disableLicenseExpirationCheck -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log

View File

@@ -23,6 +23,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
// 2025-09-29: DirectX12: Rework synchronization logic. (#8961) // 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
// 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965) // 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965)
// 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963) // 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963)
@@ -111,6 +112,9 @@ struct ImGui_ImplDX12_Data
ID3D12CommandAllocator* pTexCmdAllocator; ID3D12CommandAllocator* pTexCmdAllocator;
ID3D12GraphicsCommandList* pTexCmdList; ID3D12GraphicsCommandList* pTexCmdList;
ID3D12Resource* pTexUploadBuffer;
UINT pTexUploadBufferSize;
void* pTexUploadBufferMapped;
ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); } ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); }
}; };
@@ -513,44 +517,53 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
UINT upload_pitch_dst = (upload_pitch_src + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u); 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; UINT upload_size = upload_pitch_dst * upload_h;
D3D12_RESOURCE_DESC desc; if (bd->pTexUploadBuffer == nullptr || upload_size > bd->pTexUploadBufferSize)
ZeroMemory(&desc, sizeof(desc)); {
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; if (bd->pTexUploadBufferMapped)
desc.Alignment = 0; {
desc.Width = upload_size; D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
desc.Height = 1; bd->pTexUploadBuffer->Unmap(0, &range);
desc.DepthOrArraySize = 1; bd->pTexUploadBufferMapped = nullptr;
desc.MipLevels = 1; }
desc.Format = DXGI_FORMAT_UNKNOWN; SafeRelease(bd->pTexUploadBuffer);
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
D3D12_HEAP_PROPERTIES props; D3D12_RESOURCE_DESC desc;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES)); ZeroMemory(&desc, sizeof(desc));
props.Type = D3D12_HEAP_TYPE_UPLOAD; desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; desc.Alignment = 0;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; desc.Width = upload_size;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
// FIXME-OPT: Could upload buffer be kept around, reused, and grown only when needed? Would that be worth it? D3D12_HEAP_PROPERTIES props;
ID3D12Resource* uploadBuffer = nullptr; memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, props.Type = D3D12_HEAP_TYPE_UPLOAD;
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&uploadBuffer)); props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
IM_ASSERT(SUCCEEDED(hr)); props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bd->pTexUploadBuffer));
IM_ASSERT(SUCCEEDED(hr));
D3D12_RANGE range = {0, upload_size};
hr = bd->pTexUploadBuffer->Map(0, &range, &bd->pTexUploadBufferMapped);
IM_ASSERT(SUCCEEDED(hr));
bd->pTexUploadBufferSize = upload_size;
}
bd->pTexCmdAllocator->Reset(); bd->pTexCmdAllocator->Reset();
bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr); bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList; ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
// Copy to upload buffer // 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 < upload_h; y++) 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); memcpy((void*)((uintptr_t)bd->pTexUploadBufferMapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
uploadBuffer->Unmap(0, &range);
if (need_barrier_before_copy) if (need_barrier_before_copy)
{ {
@@ -567,7 +580,7 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
D3D12_TEXTURE_COPY_LOCATION srcLocation = {}; D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
D3D12_TEXTURE_COPY_LOCATION dstLocation = {}; D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
{ {
srcLocation.pResource = uploadBuffer; srcLocation.pResource = bd->pTexUploadBuffer;
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srcLocation.PlacedFootprint.Footprint.Width = upload_w; srcLocation.PlacedFootprint.Footprint.Width = upload_w;
@@ -591,9 +604,8 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
cmdList->ResourceBarrier(1, &barrier); cmdList->ResourceBarrier(1, &barrier);
} }
hr = cmdList->Close(); HRESULT hr = cmdList->Close();
IM_ASSERT(SUCCEEDED(hr)); IM_ASSERT(SUCCEEDED(hr));
ID3D12CommandQueue* cmdQueue = bd->pCommandQueue; ID3D12CommandQueue* cmdQueue = bd->pCommandQueue;
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList); cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue); hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
@@ -606,7 +618,6 @@ void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent); bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
::WaitForSingleObject(bd->FenceEvent, INFINITE); ::WaitForSingleObject(bd->FenceEvent, INFINITE);
uploadBuffer->Release();
tex->SetStatus(ImTextureStatus_OK); tex->SetStatus(ImTextureStatus_OK);
} }
@@ -886,6 +897,13 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
bd->commandQueueOwned = false; bd->commandQueueOwned = false;
SafeRelease(bd->pRootSignature); SafeRelease(bd->pRootSignature);
SafeRelease(bd->pPipelineState); SafeRelease(bd->pPipelineState);
if (bd->pTexUploadBufferMapped)
{
D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
bd->pTexUploadBuffer->Unmap(0, &range);
bd->pTexUploadBufferMapped = nullptr;
}
SafeRelease(bd->pTexUploadBuffer);
SafeRelease(bd->pTexCmdList); SafeRelease(bd->pTexCmdList);
SafeRelease(bd->pTexCmdAllocator); SafeRelease(bd->pTexCmdAllocator);
SafeRelease(bd->Fence); SafeRelease(bd->Fence);

View File

@@ -48,7 +48,7 @@
#include "imgui.h" #include "imgui.h"
// When targeting native platforms (i.e. NOT emscripten), one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN // 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. // or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details.
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) #if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) == defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)

View File

@@ -34,7 +34,7 @@
// Initialization data, for ImGui_ImplWGPU_Init() // Initialization data, for ImGui_ImplWGPU_Init()
struct ImGui_ImplWGPU_InitInfo struct ImGui_ImplWGPU_InitInfo
{ {
WGPUDevice Device; WGPUDevice Device = nullptr;
int NumFramesInFlight = 3; int NumFramesInFlight = 3;
WGPUTextureFormat RenderTargetFormat = WGPUTextureFormat_Undefined; WGPUTextureFormat RenderTargetFormat = WGPUTextureFormat_Undefined;
WGPUTextureFormat DepthStencilFormat = WGPUTextureFormat_Undefined; WGPUTextureFormat DepthStencilFormat = WGPUTextureFormat_Undefined;

View File

@@ -45,78 +45,97 @@ Breaking Changes:
io.ConfigViewportPlatformFocusSetsImGuiFocus io.ConfigViewportPlatformFocusSetsImGuiFocus
to io.ConfigViewportsPlatformFocusSetsImGuiFocus. (#6299, #6462) to io.ConfigViewportsPlatformFocusSetsImGuiFocus. (#6299, #6462)
It was really a typo in the first place, and introduced in 1.92.2. It was really a typo in the first place, and introduced in 1.92.2.
- Backends: Vulkan: moved some fields in ImGui_ImplVulkan_InitInfo: - Backends:
init_info.RenderPass --> init_info.PipelineInfoMain.RenderPass - Vulkan: moved some fields in ImGui_ImplVulkan_InitInfo:
init_info.Subpass --> init_info.PipelineInfoMain.Subpass init_info.RenderPass --> init_info.PipelineInfoMain.RenderPass
init_info.MSAASamples --> init_info.PipelineInfoMain.MSAASamples init_info.Subpass --> init_info.PipelineInfoMain.Subpass
init_info.PipelineRenderingCreateInfo --> init_info.PipelineInfoMain.PipelineRenderingCreateInfo init_info.MSAASamples --> init_info.PipelineInfoMain.MSAASamples
It makes things more consistent and was desirable to introduce new settings for init_info.PipelineRenderingCreateInfo --> init_info.PipelineInfoMain.PipelineRenderingCreateInfo
secondary viewports. (#8946, #8110, #8111, #8686) [@ocornut, @SuperRonan, @sylmroz] It makes things more consistent and was desirable to introduce new settings for
- Backends: Vulkan: renamed ImGui_ImplVulkan_MainPipelineCreateInfo --> ImGui_ImplVulkan_PipelineInfo secondary viewports. (#8946, #8110, #8111, #8686) [@ocornut, @SuperRonan, @sylmroz]
(introduced very recently and only used by `ImGui_ImplVulkan_CreateMainPipeline()` - Vulkan: renamed ImGui_ImplVulkan_MainPipelineCreateInfo --> ImGui_ImplVulkan_PipelineInfo
so it should not affect many users). (#8110, #8111) (introduced very recently and only used by `ImGui_ImplVulkan_CreateMainPipeline()`
- Backends: Vulkan: helper ImGui_ImplVulkanH_CreateOrResizeWindow() added a so it should not affect many users). (#8110, #8111)
`VkImageUsageFlags image_usage` argument to specific extra flags for calls to - Vulkan: helper ImGui_ImplVulkanH_CreateOrResizeWindow() added a
vkCreateSwapchainKHR() done for secondary viewports. We automatically add `VkImageUsageFlags image_usage` argument.
`VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT`. In theory the function is an internal It was previously hardcoded to `VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT` and defaults
helper but since it's used by our examples some may have used it. (#8946, #8111, #8686) to that when the value is 0. In theory the function is an internal helper but
since it's used by our examples some may have used it. (#8946, #8111, #8686)
Other Changes: Other Changes:
- Windows: added lower-right resize grip on child windows using both - Windows: added lower-right resize grip on child windows using both
ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY flags. (#8501) [@aleksijuvani] ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY flags. (#8501) [@aleksijuvani]
The grip is not visible before hovering to reduce clutter. The grip is not visible before hovering to reduce clutter.
- InputText: fixed single-line InputText() not applying fine character clipping - Style: added ImGuiCol_UnsavedMarker, color of the unsaved document marker when
properly (regression in 1.92.3). (#8967) [@Cyphall] using ImGuiWindowFlags_UnsavedDocument/ImGuiTabItemFlags_UnsavedDocument. (#8983)
- IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers() - IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers()
helpers to null all handlers. (#8945, #2769) helpers to null all handlers. (#8945, #2769)
- Inputs:
- Shortcuts: added support for combining ImGuiInputFlags_RouteFocused
(which is the default route) with ImGuiInputFlags_RouteOverActive, allowing
to steal shortcuts from active item without using global routing. (#9004)
- InputText:
- Fixed single-line InputText() not applying fine character clipping
properly (regression in 1.92.3). (#8967) [@Cyphall]
- Fixed an infinite loop error happening if a custom input text
callback modifies/clear BufTextLen before calling InsertChars().
(regression from 1.92.3). Note that this never really worked correctly, but
previously it would only temporary wreck cursor position, and since 1.92.3 it
would go in an infinite loop. (#8994, #3237)
- Textures:
- Fixed a crash if texture status is set to _WantDestroy by a backend after
it had already been destroyed. This would typically happen when calling backend's
ImGui_ImplXXXX_InvalidateDeviceObjects() helpers twice in a row. (#8977, #8811)
- Allowed backend to destroy texture while inside the NewFrame/EndFrame
scope. Basically if a backend decide to destroy a texture that we didn't request
to destroy (for e.g. freeing resources) the texture is immediately set to
a _WantCreate status again. (#8811)
- Fixed an issue preventing multi-contexts sharing a ImFontAtlas from
being possible to destroy in any order.
- Fixed not updating ImTextureData's RefCount when destroying a context
using a shared ImFontAtlas, leading standard backends to not properly
free texture resources. (#8975) [@icrashstuff]
- Demo: fixed layout issue in "Layout & Scrolling -> Scrolling" section.
- Misc: Debuggers: added type formatters for the LLDB debuggers (e.g. Xcode, - Misc: Debuggers: added type formatters for the LLDB debuggers (e.g. Xcode,
Android Studio & more) to provide nicer display for ImVec2, ImVec4, ImVector etc. Android Studio & more) to provide nicer display for ImVec2, ImVec4, ImVector etc.
See misc/debuggers/ for details. (#8950) [@mentlerd] See misc/debuggers/ for details. (#8950) [@mentlerd]
- Textures: fixed a crash if texture status is set to _WantDestroy by a backend after - CI: updated Windows CI scripts to generate/use VulkanSDK. (#8925, #8778) [@yaz0r]
it had already been destroyed. This would typically happen when calling backend's
ImGui_ImplXXXX_InvalidateDeviceObjects() helpers twice in a row. (#8977, #8811)
- Textures: allowed backend to destroy texture while inside the NewFrame/EndFrame
scope. Basically if a backend decide to destroy a texture that we didn't request
to destroy (for e.g. freeing resources) the texture is immediately set to
a _WantCreate status again. (#8811)
- Textures: fixed an issue preventing multi-contexts sharing a ImFontAtlas from
being possible to destroy in any order.
- Textures: fixed not updating ImTextureData's RefCount when destroying a context
using a shared ImFontAtlas, leading standard backends to not properly free
texture resources. (#8975) [@icrashstuff]
- CI: Updates Windows CI scripts to generate/use VulkanSDK. (#8925, #8778) [@yaz0r]
- Backends: all backends call ImGuiPlatformIO::ClearPlatformHandlers() and
ClearRendererHandlers() on shutdown, so as not to leave function pointers
which may be dangling when using backend in e.g. DLL. (#8945, #2769)
- Docs: updated FAQ with new "What is the difference between Dear ImGui and - Docs: updated FAQ with new "What is the difference between Dear ImGui and
traditional UI toolkits?" entry. (#8862) traditional UI toolkits?" entry. (#8862)
- Backends: DirectX12: reuse a command list and allocator for texture uploads instead - Backends:
of recreating them each time. (#8963, #8465) [@RT2Code] - All backends call ImGuiPlatformIO::ClearPlatformHandlers() and
- Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code] ClearRendererHandlers() on shutdown, so as not to leave function pointers
(presumably fixes old hard-to-repro crash issues such as #3463, #5018) which may be dangling when using backend in e.g. DLL. (#8945, #2769)
- Backends: DirectX12: Enable swapchain tearing if available. (#8965) [@RT2Code] - DirectX12: reuse a command list and allocator for texture uploads instead
- Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support of recreating them each time. (#8963, #8465) [@RT2Code]
`RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes] - DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
- Backends: GLFW: fixed build on platform that are neither Windows, macOS or (presumably fixes old hard-to-repro crash issues such as #3463, #5018)
known Unixes (Regression in 1.92.3). (#8969, #8920, #8921) [@oktonion] - DirectX12: Reuse texture upload buffer and grow it only when
- Backends: SDL2,SDL3: avoid using the SDL_GetGlobalMouseState() path when one of our necessary. (#9002) [@RT2Code]
window is hovered, as the event data is reliable and enough in this case. - DirectX12: Enable swapchain tearing if available. (#8965) [@RT2Code]
- Fix mouse coordinates issue in fullscreen apps with macOS notch. (#7919, #7786) - OpenGL3: fixed GL loader to work on Haiku OS which does not support
- Essentially a working for SDL3 bug which will be fixed in SDL 3.3.0. `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes]
- Better perf on X11 as querying global position requires a round trip to X11 server. - GLFW: fixed build on platform that are neither Windows, macOS or
- Backends: Win32: minor optimization not submitting gamepad io again if known Unixes (Regression in 1.92.3). (#8969, #8920, #8921) [@oktonion]
XInput's dwPacketNumber has not changed. (#8556) [@MidTerm-CN] - SDL2,SDL3: avoid using the SDL_GetGlobalMouseState() path when one of our
- Backends: Vulkan: added a way to specify custom shaders by filling init fields window is hovered, as the event data is reliable and enough in this case.
CustomShaderVertCreateInfo and CustomShaderFragCreateInfo. (#8585, #8271) [@johan0A] - Fix mouse coordinates issue in fullscreen apps with macOS notch. (#7919, #7786)
- Backends: DX9,DX10,DX11,DX12,Metal,Vulkan,WGPU,SDLRenderer2,SDLRenderer3: - Essentially a workaround for SDL3 bug which will be fixed in SDL 3.3.0.
ensure that a texture in _WantDestroy state always turn to _Destroyed even - Better perf on X11 as querying global position requires a round trip to X11 server.
if your underlying graphics data was already destroyed. (#8977) - Win32: minor optimization not submitting gamepad io again if
- Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is XInput's dwPacketNumber has not changed. (#8556) [@MidTerm-CN]
not available. (#5924, #5562) - Vulkan: added a way to specify custom shaders by filling init fields
- Examples: SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82] CustomShaderVertCreateInfo and CustomShaderFragCreateInfo. (#8585, #8271) [@johan0A]
- Examples: Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code] - DX9,DX10,DX11,DX12,Metal,Vulkan,WGPU,SDLRenderer2,SDLRenderer3:
- Examples: made examples's main.cpp consistent with returning 1 on error. ensure that a texture in _WantDestroy state always turn to _Destroyed even
if your underlying graphics data was already destroyed. (#8977)
- Examples:
- SDL2+DirectX11: Try WARP software driver if hardware driver is
not available. (#5924, #5562)
- SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82]
- Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
- Made examples's main.cpp consistent with returning 1 on error.
Docking+Viewports Branch: Docking+Viewports Branch:

View File

@@ -1,4 +1,4 @@
// Dear ImGui: standalone example application for using GLFW + WebGPU // Dear ImGui: standalone example application for GLFW + WebGPU
// - Emscripten is supported for publishing on web. See https://emscripten.org. // - Emscripten is supported for publishing on web. See https://emscripten.org.
// - Dawn is used as a WebGPU implementation on desktop. // - Dawn is used as a WebGPU implementation on desktop.
@@ -12,36 +12,32 @@
#include "imgui_impl_glfw.h" #include "imgui_impl_glfw.h"
#include "imgui_impl_wgpu.h" #include "imgui_impl_wgpu.h"
#include <stdio.h> #include <stdio.h>
#include <GLFW/glfw3.h>
// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details.
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
#include <emscripten.h> #include <emscripten.h>
#include <emscripten/html5.h> #include <emscripten/html5.h>
#include <emscripten/html5_webgpu.h> #include <emscripten/html5_webgpu.h>
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#else #else
#include <webgpu/webgpu_glfw.h> #include <webgpu/webgpu_glfw.h>
#endif #endif
#include <GLFW/glfw3.h>
#include <webgpu/webgpu.h> #include <webgpu/webgpu.h>
#include <webgpu/webgpu_cpp.h> #include <webgpu/webgpu_cpp.h>
// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. // Data
#ifdef __EMSCRIPTEN__
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif
// Global WebGPU required states
static WGPUInstance wgpu_instance = nullptr; static WGPUInstance wgpu_instance = nullptr;
static WGPUDevice wgpu_device = nullptr; static WGPUDevice wgpu_device = nullptr;
static WGPUSurface wgpu_surface = nullptr; static WGPUSurface wgpu_surface = nullptr;
static WGPUTextureFormat wgpu_preferred_fmt = WGPUTextureFormat_RGBA8Unorm; static WGPUTextureFormat wgpu_preferred_fmt = WGPUTextureFormat_RGBA8Unorm;
static WGPUSwapChain wgpu_swap_chain = nullptr; static WGPUSwapChain wgpu_swap_chain = nullptr;
static int wgpu_swap_chain_width = 1280; static int wgpu_surface_width = 1280;
static int wgpu_swap_chain_height = 800; static int wgpu_surface_height = 800;
// Forward declarations // Forward declarations
static bool InitWGPU(GLFWwindow* window); static bool InitWGPU(GLFWwindow* window);
static void CreateSwapChain(int width, int height); static void ResizeSurface(int width, int height);
static void glfw_error_callback(int error, const char* description) static void glfw_error_callback(int error, const char* description)
{ {
@@ -72,19 +68,23 @@ int main(int, char**)
// Make sure GLFW does not initialize any graphics context. // Make sure GLFW does not initialize any graphics context.
// This needs to be done explicitly later. // This needs to be done explicitly later.
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
GLFWwindow* window = glfwCreateWindow(wgpu_swap_chain_width, wgpu_swap_chain_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr);
// Create window
float main_scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfwGetPrimaryMonitor()); // Valid on GLFW 3.3+ only
wgpu_surface_width *= main_scale;
wgpu_surface_height *= main_scale;
GLFWwindow* window = glfwCreateWindow(wgpu_surface_width, wgpu_surface_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr);
if (window == nullptr) if (window == nullptr)
return 1; return 1;
// Initialize the WebGPU environment // Initialize the WebGPU environment
if (!InitWGPU(window)) if (!InitWGPU(window))
{ {
if (window) glfwDestroyWindow(window);
glfwDestroyWindow(window);
glfwTerminate(); glfwTerminate();
return 1; return 1;
} }
CreateSwapChain(wgpu_swap_chain_width, wgpu_swap_chain_height); ResizeSurface(wgpu_surface_width, wgpu_surface_height);
glfwShowWindow(window); glfwShowWindow(window);
// Setup Dear ImGui context // Setup Dear ImGui context
@@ -99,6 +99,11 @@ int main(int, char**)
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
//ImGui::StyleColorsLight(); //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 // Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOther(window, true); ImGui_ImplGlfw_InitForOther(window, true);
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
@@ -118,15 +123,14 @@ int main(int, char**)
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - 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. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author!
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - 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. // - Our Emscripten build process allows embedding fonts to be accessible at runtime from the "fonts/" folder. See Makefile.emscripten for details.
//io.Fonts->AddFontDefault();
//style.FontSizeBase = 20.0f; //style.FontSizeBase = 20.0f;
//io.Fonts->AddFontDefault();
#ifndef IMGUI_DISABLE_FILE_FUNCTIONS #ifndef IMGUI_DISABLE_FILE_FUNCTIONS
//io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf"); //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf"); //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf"); //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf"); //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf");
//io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf"); //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf");
//IM_ASSERT(font != nullptr); //IM_ASSERT(font != nullptr);
#endif #endif
@@ -161,10 +165,10 @@ int main(int, char**)
// React to changes in screen size // React to changes in screen size
int width, height; int width, height;
glfwGetFramebufferSize((GLFWwindow*)window, &width, &height); glfwGetFramebufferSize((GLFWwindow*)window, &width, &height);
if (width != wgpu_swap_chain_width || height != wgpu_swap_chain_height) if (width != wgpu_surface_width || height != wgpu_surface_height)
{ {
ImGui_ImplWGPU_InvalidateDeviceObjects(); ImGui_ImplWGPU_InvalidateDeviceObjects();
CreateSwapChain(width, height); ResizeSurface(width, height);
ImGui_ImplWGPU_CreateDeviceObjects(); ImGui_ImplWGPU_CreateDeviceObjects();
} }
@@ -239,8 +243,8 @@ int main(int, char**)
WGPUCommandBufferDescriptor cmd_buffer_desc = {}; WGPUCommandBufferDescriptor cmd_buffer_desc = {};
WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc); WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc);
WGPUQueue queue = wgpuDeviceGetQueue(wgpu_device); WGPUQueue wgpu_queue = wgpuDeviceGetQueue(wgpu_device);
wgpuQueueSubmit(queue, 1, &cmd_buffer); wgpuQueueSubmit(wgpu_queue, 1, &cmd_buffer);
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
wgpuSwapChainPresent(wgpu_swap_chain); wgpuSwapChainPresent(wgpu_swap_chain);
@@ -312,10 +316,10 @@ static bool InitWGPU(GLFWwindow* window)
#endif #endif
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
wgpu::SurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; wgpu::SurfaceDescriptorFromCanvasHTMLSelector canvas_desc = {};
html_surface_desc.selector = "#canvas"; canvas_desc.selector = "#canvas";
wgpu::SurfaceDescriptor surface_desc = {}; wgpu::SurfaceDescriptor surface_desc = {};
surface_desc.nextInChain = &html_surface_desc; surface_desc.nextInChain = &canvas_desc;
wgpu::Surface surface = instance.CreateSurface(&surface_desc); wgpu::Surface surface = instance.CreateSurface(&surface_desc);
wgpu::Adapter adapter = {}; wgpu::Adapter adapter = {};
@@ -327,6 +331,7 @@ static bool InitWGPU(GLFWwindow* window)
wgpu_preferred_fmt = WGPUTextureFormat_BGRA8Unorm; wgpu_preferred_fmt = WGPUTextureFormat_BGRA8Unorm;
#endif #endif
// Moving Dawn objects into WGPU handles
wgpu_instance = instance.MoveToCHandle(); wgpu_instance = instance.MoveToCHandle();
wgpu_surface = surface.MoveToCHandle(); wgpu_surface = surface.MoveToCHandle();
@@ -335,12 +340,12 @@ static bool InitWGPU(GLFWwindow* window)
return true; return true;
} }
static void CreateSwapChain(int width, int height) static void ResizeSurface(int width, int height)
{ {
if (wgpu_swap_chain) if (wgpu_swap_chain)
wgpuSwapChainRelease(wgpu_swap_chain); wgpuSwapChainRelease(wgpu_swap_chain);
wgpu_swap_chain_width = width; wgpu_surface_width = width;
wgpu_swap_chain_height = height; wgpu_surface_height = height;
WGPUSwapChainDescriptor swap_chain_desc = {}; WGPUSwapChainDescriptor swap_chain_desc = {};
swap_chain_desc.usage = WGPUTextureUsage_RenderAttachment; swap_chain_desc.usage = WGPUTextureUsage_RenderAttachment;
swap_chain_desc.format = wgpu_preferred_fmt; swap_chain_desc.format = wgpu_preferred_fmt;

View File

@@ -83,6 +83,7 @@
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided). // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// Note that imgui_freetype.cpp may be used _without_ this define, if you manually call ImFontAtlas::SetFontLoader(). The define is simply a convenience.
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE //#define IMGUI_ENABLE_FREETYPE

View File

@@ -3767,6 +3767,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
case ImGuiCol_TreeLines: return "TreeLines"; case ImGuiCol_TreeLines: return "TreeLines";
case ImGuiCol_DragDropTarget: return "DragDropTarget"; case ImGuiCol_DragDropTarget: return "DragDropTarget";
case ImGuiCol_UnsavedMarker: return "UnsavedMarker";
case ImGuiCol_NavCursor: return "NavCursor"; case ImGuiCol_NavCursor: return "NavCursor";
case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg"; case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
@@ -7551,7 +7552,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f; marker_pos.y = (layout_r.Min.y + layout_r.Max.y) * 0.5f;
if (marker_pos.x > layout_r.Min.x) if (marker_pos.x > layout_r.Min.x)
{ {
RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_Text)); RenderBullet(window->DrawList, marker_pos, GetColorU32(ImGuiCol_UnsavedMarker));
clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f)); clip_r.Max.x = ImMin(clip_r.Max.x, marker_pos.x - (int)(marker_size_x * 0.5f));
} }
} }
@@ -7572,7 +7573,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
} }
if (parent_window && (flags & ImGuiWindowFlags_Popup)) if (parent_window && (flags & ImGuiWindowFlags_Popup))
window->RootWindowPopupTree = parent_window->RootWindowPopupTree; window->RootWindowPopupTree = parent_window->RootWindowPopupTree;
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) // FIXME: simply use _NoTitleBar ? if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip))) // FIXME: simply use _NoTitleBar ?
window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight; window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
while (window->RootWindowForNav->ChildFlags & ImGuiChildFlags_NavFlattened) while (window->RootWindowForNav->ChildFlags & ImGuiChildFlags_NavFlattened)
{ {
@@ -7717,7 +7718,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
ImGuiWindow* parent_window_in_stack = (window->DockIsActive && window->DockNode->HostWindow) ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window; ImGuiWindow* parent_window_in_stack = (window->DockIsActive && window->DockNode->HostWindow) ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow; ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) ? parent_window_in_stack : NULL) : window->ParentWindow;
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow)); IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
// We allow window memory to be compacted so recreate the base stack when needed. // We allow window memory to be compacted so recreate the base stack when needed.
@@ -9997,7 +9998,7 @@ static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt)
routing_entry->RoutingCurrScore = routing_entry->RoutingNextScore; routing_entry->RoutingCurrScore = routing_entry->RoutingNextScore;
routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry routing_entry->RoutingCurr = routing_entry->RoutingNext; // Update entry
routing_entry->RoutingNext = ImGuiKeyOwner_NoOwner; routing_entry->RoutingNext = ImGuiKeyOwner_NoOwner;
routing_entry->RoutingNextScore = 255; routing_entry->RoutingNextScore = 0;
if (routing_entry->RoutingCurr == ImGuiKeyOwner_NoOwner) if (routing_entry->RoutingCurr == ImGuiKeyOwner_NoOwner)
continue; continue;
rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer
@@ -10066,23 +10067,24 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
return routing_data; return routing_data;
} }
// Current score encoding (lower is highest priority): // Current score encoding
// - 0: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive // - 0: Never route
// - 1: ImGuiInputFlags_ActiveItem or ImGuiInputFlags_RouteFocused (if item active) // - 1: ImGuiInputFlags_RouteGlobal (lower priority)
// - 2: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused // - 100..199: ImGuiInputFlags_RouteFocused (if window in focus-stack)
// - 3+: ImGuiInputFlags_RouteFocused (if window in focus-stack) // 200: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused
// - 254: ImGuiInputFlags_RouteGlobal // 300: ImGuiInputFlags_RouteActive or ImGuiInputFlags_RouteFocused (if item active)
// - 255: never route // 400: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive
// - 500..599: ImGuiInputFlags_RouteFocused | ImGuiInputFlags_RouteOverActive (if window in focus-stack) (higher priority)
// 'flags' should include an explicit routing policy // 'flags' should include an explicit routing policy
static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInputFlags flags) static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInputFlags flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (flags & ImGuiInputFlags_RouteFocused) if (flags & ImGuiInputFlags_RouteFocused)
{ {
// ActiveID gets top priority // ActiveID gets high priority
// (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it) // (we don't check g.ActiveIdUsingAllKeys here. Routing is applied but if input ownership is tested later it may discard it)
if (owner_id != 0 && g.ActiveId == owner_id) if (owner_id != 0 && g.ActiveId == owner_id)
return 1; return 300;
// Score based on distance to focused window (lower is better) // Score based on distance to focused window (lower is better)
// Assuming both windows are submitting a routing request, // Assuming both windows are submitting a routing request,
@@ -10092,25 +10094,32 @@ static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInput
// - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score. // - When Window/ChildB is focused -> Window scores 4 (best), Window/ChildB doesn't have a score.
// This essentially follow the window->ParentWindowForFocusRoute chain. // This essentially follow the window->ParentWindowForFocusRoute chain.
if (focus_scope_id == 0) if (focus_scope_id == 0)
return 255; return 0;
for (int index_in_focus_path = 0; index_in_focus_path < g.NavFocusRoute.Size; index_in_focus_path++) for (int index_in_focus_path = 0; index_in_focus_path < g.NavFocusRoute.Size; index_in_focus_path++)
if (g.NavFocusRoute.Data[index_in_focus_path].ID == focus_scope_id) if (g.NavFocusRoute.Data[index_in_focus_path].ID == focus_scope_id)
return 3 + index_in_focus_path; {
return 255; if (flags & ImGuiInputFlags_RouteOverActive) // && g.ActiveId != 0 && g.ActiveId != owner_id)
return 599 - index_in_focus_path;
else
return 199 - index_in_focus_path;
}
return 0;
} }
else if (flags & ImGuiInputFlags_RouteActive) else if (flags & ImGuiInputFlags_RouteActive)
{ {
if (owner_id != 0 && g.ActiveId == owner_id) if (owner_id != 0 && g.ActiveId == owner_id)
return 1; return 300;
return 255; return 0;
} }
else if (flags & ImGuiInputFlags_RouteGlobal) else if (flags & ImGuiInputFlags_RouteGlobal)
{ {
if (flags & ImGuiInputFlags_RouteOverActive) if (flags & ImGuiInputFlags_RouteOverActive)
return 0; return 400;
if (owner_id != 0 && g.ActiveId == owner_id)
return 300;
if (flags & ImGuiInputFlags_RouteOverFocused) if (flags & ImGuiInputFlags_RouteOverFocused)
return 2; return 200;
return 254; return 1;
} }
IM_ASSERT(0); IM_ASSERT(0);
return 0; return 0;
@@ -10150,8 +10159,10 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiInputFlags flags, I
else else
IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteTypeMask_)); // Check that only 1 routing flag is used IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteTypeMask_)); // Check that only 1 routing flag is used
IM_ASSERT(owner_id != ImGuiKeyOwner_Any && owner_id != ImGuiKeyOwner_NoOwner); IM_ASSERT(owner_id != ImGuiKeyOwner_Any && owner_id != ImGuiKeyOwner_NoOwner);
if (flags & (ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused)) if (flags & (ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteUnlessBgFocused))
IM_ASSERT(flags & ImGuiInputFlags_RouteGlobal); IM_ASSERT(flags & ImGuiInputFlags_RouteGlobal);
if (flags & ImGuiInputFlags_RouteOverActive)
IM_ASSERT(flags & (ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteFocused));
// Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified. // Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified.
key_chord = FixupKeyChord(key_chord); key_chord = FixupKeyChord(key_chord);
@@ -10206,17 +10217,17 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiInputFlags flags, I
const int score = CalcRoutingScore(focus_scope_id, owner_id, flags); const int score = CalcRoutingScore(focus_scope_id, owner_id, flags);
IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> score %d\n", GetKeyChordName(key_chord), flags, owner_id, score); IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> score %d\n", GetKeyChordName(key_chord), flags, owner_id, score);
if (score == 255) if (score == 0)
return false; return false;
// Submit routing for NEXT frame (assuming score is sufficient) // Submit routing for NEXT frame (assuming score is sufficient)
// FIXME: Could expose a way to use a "serve last" policy for same score resolution (using <= instead of <). // FIXME: Could expose a way to use a "serve last" policy for same score resolution (using >= instead of >).
ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord);
//const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score <= routing_data->RoutingNextScore) : (score < routing_data->RoutingNextScore); //const bool set_route = (flags & ImGuiInputFlags_ServeLast) ? (score >= routing_data->RoutingNextScore) : (score > routing_data->RoutingNextScore);
if (score < routing_data->RoutingNextScore) if (score > routing_data->RoutingNextScore)
{ {
routing_data->RoutingNext = owner_id; routing_data->RoutingNext = owner_id;
routing_data->RoutingNextScore = (ImU8)score; routing_data->RoutingNextScore = (ImU16)score;
} }
// Return routing state for CURRENT frame // Return routing state for CURRENT frame

View File

@@ -29,7 +29,7 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.4 WIP" #define IMGUI_VERSION "1.92.4 WIP"
#define IMGUI_VERSION_NUM 19234 #define IMGUI_VERSION_NUM 19236
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
@@ -1851,6 +1851,7 @@ enum ImGuiCol_
ImGuiCol_TextSelectedBg, // Selected text inside an InputText ImGuiCol_TextSelectedBg, // Selected text inside an InputText
ImGuiCol_TreeLines, // Tree node hierarchy outlines when using ImGuiTreeNodeFlags_DrawLines ImGuiCol_TreeLines, // Tree node hierarchy outlines when using ImGuiTreeNodeFlags_DrawLines
ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target
ImGuiCol_UnsavedMarker, // Unsaved Document marker (in window title and tabs)
ImGuiCol_NavCursor, // Color of keyboard/gamepad navigation cursor/rectangle, when visible ImGuiCol_NavCursor, // Color of keyboard/gamepad navigation cursor/rectangle, when visible
ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB
ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active

View File

@@ -4879,15 +4879,18 @@ static void DemoWindowLayout()
ImGui::Checkbox("Decoration", &enable_extra_decorations); ImGui::Checkbox("Decoration", &enable_extra_decorations);
ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
ImGui::SameLine();
ImGui::Checkbox("Track", &enable_track); ImGui::Checkbox("Track", &enable_track);
ImGui::PushItemWidth(100);
ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
bool scroll_to_off = ImGui::Button("Scroll Offset"); bool scroll_to_off = ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px"); ImGui::SameLine();
scroll_to_off |= ImGui::Button("Scroll Offset");
bool scroll_to_pos = ImGui::Button("Scroll To Pos"); bool scroll_to_pos = ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px"); ImGui::SameLine();
scroll_to_pos |= ImGui::Button("Scroll To Pos");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
if (scroll_to_off || scroll_to_pos) if (scroll_to_off || scroll_to_pos)

View File

@@ -242,6 +242,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_UnsavedMarker] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); colors[ImGuiCol_NavCursor] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
@@ -309,6 +310,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_UnsavedMarker] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
@@ -377,6 +379,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border]; colors[ImGuiCol_TreeLines] = colors[ImGuiCol_Border];
colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_UnsavedMarker] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered]; colors[ImGuiCol_NavCursor] = colors[ImGuiCol_HeaderHovered];
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);

View File

@@ -1578,12 +1578,12 @@ struct ImGuiKeyRoutingData
{ {
ImGuiKeyRoutingIndex NextEntryIndex; ImGuiKeyRoutingIndex NextEntryIndex;
ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits.
ImU8 RoutingCurrScore; // [DEBUG] For debug display ImU16 RoutingCurrScore; // [DEBUG] For debug display
ImU8 RoutingNextScore; // Lower is better (0: perfect score) ImU16 RoutingNextScore; // Lower is better (0: perfect score)
ImGuiID RoutingCurr; ImGuiID RoutingCurr;
ImGuiID RoutingNext; ImGuiID RoutingNext;
ImGuiKeyRoutingData() { NextEntryIndex = -1; Mods = 0; RoutingCurrScore = RoutingNextScore = 255; RoutingCurr = RoutingNext = ImGuiKeyOwner_NoOwner; } ImGuiKeyRoutingData() { NextEntryIndex = -1; Mods = 0; RoutingCurrScore = RoutingNextScore = 0; RoutingCurr = RoutingNext = ImGuiKeyOwner_NoOwner; }
}; };
// Routing table: maintain a desired owner for each possible key-chord (key + mods), and setup owner in NewFrame() when mods are matching. // Routing table: maintain a desired owner for each possible key-chord (key + mods), and setup owner in NewFrame() when mods are matching.
@@ -2511,7 +2511,7 @@ struct ImGuiContext
float NavHighlightActivatedTimer; float NavHighlightActivatedTimer;
ImGuiID NavNextActivateId; // Set by ActivateItemByID(), queued until next frame. ImGuiID NavNextActivateId; // Set by ActivateItemByID(), queued until next frame.
ImGuiActivateFlags NavNextActivateFlags; ImGuiActivateFlags NavNextActivateFlags;
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Gamepad
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. 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; 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. //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.
@@ -2691,7 +2691,7 @@ struct ImGuiContext
ImGuiWindow* LogWindow; ImGuiWindow* LogWindow;
ImFileHandle LogFile; // If != NULL log to stdout/ file 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. ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators.
const char* LogNextPrefix; const char* LogNextPrefix; // See comment in LogSetNextTextDecoration(): doesn't copy underlying data, use carefully!
const char* LogNextSuffix; const char* LogNextSuffix;
float LogLinePosY; float LogLinePosY;
bool LogLineFirstItem; bool LogLineFirstItem;
@@ -4219,7 +4219,7 @@ extern const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ctx, ImGuiI
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional)
#define IMGUI_TEST_ENGINE_LOG(_FMT,...) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log #define IMGUI_TEST_ENGINE_LOG(_FMT,...) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log
#else #else
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID) ((void)0) #define IMGUI_TEST_ENGINE_ITEM_ADD(_ID,_BB,_ITEM_DATA) ((void)0)
#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g) #define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS) ((void)g)
#endif #endif

View File

@@ -3947,6 +3947,7 @@ static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, c
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
ImGuiInputTextState* obj = &g.InputTextState; ImGuiInputTextState* obj = &g.InputTextState;
IM_ASSERT(text_end_display >= text_begin && text_end_display <= text_end);
return ImFontCalcTextSizeEx(g.Font, g.FontSize, FLT_MAX, obj->WrapWidth, text_begin, text_end_display, text_end, out_remaining, out_offset, flags); return ImFontCalcTextSizeEx(g.Font, g.FontSize, FLT_MAX, obj->WrapWidth, text_begin, text_end_display, text_end, out_remaining, out_offset, flags);
} }
@@ -4327,11 +4328,12 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char)); memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
Buf[BufTextLen + new_text_len] = '\0'; Buf[BufTextLen + new_text_len] = '\0';
if (CursorPos >= pos)
CursorPos += new_text_len;
SelectionStart = SelectionEnd = CursorPos;
BufDirty = true; BufDirty = true;
BufTextLen += new_text_len; BufTextLen += new_text_len;
if (CursorPos >= pos)
CursorPos += new_text_len;
CursorPos = ImClamp(CursorPos, 0, BufTextLen);
SelectionStart = SelectionEnd = CursorPos;
} }
void ImGui::PushPasswordFont() void ImGui::PushPasswordFont()
@@ -10840,8 +10842,8 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
const bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x) && (!close_button_visible || !is_hovered); 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) if (unsaved_marker_visible)
{ {
const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz)); ImVec2 bullet_pos = button_pos + ImVec2(button_sz, button_sz) * 0.5f;
RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text)); RenderBullet(draw_list, bullet_pos, GetColorU32(ImGuiCol_UnsavedMarker));
} }
else if (close_button_visible) else if (close_button_visible)
{ {

View File

@@ -7,7 +7,7 @@ Build font atlases using FreeType instead of stb_truetype (which is the default
1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype --triplet=x64-windows`, `vcpkg integrate install`). 1. Get latest FreeType binaries or build yourself (under Windows you may use vcpkg with `vcpkg install freetype --triplet=x64-windows`, `vcpkg integrate install`).
2. Add imgui_freetype.h/cpp alongside your project files. 2. Add imgui_freetype.h/cpp alongside your project files.
3. Add `#define IMGUI_ENABLE_FREETYPE` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file 3. Add `#define IMGUI_ENABLE_FREETYPE` in your [imconfig.h](https://github.com/ocornut/imgui/blob/master/imconfig.h) file to make Dear ImGui automatically use the imgui_freetype loader. If your copy Dear ImGui is precompiled, you can always enable imgui_freetype by calling ImFontAtlas::SetFontLoader().
### About Gamma Correct Blending ### About Gamma Correct Blending