change to imgui docker version
rename to work-calendar
This commit is contained in:
@@ -8,8 +8,9 @@
|
||||
// [X] Platform: Clipboard support (from Allegro 5.1.12).
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// Missing features or Issues:
|
||||
// [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually.
|
||||
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
// Missing features or Issues:
|
||||
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// [ ] Platform: Clipboard support.
|
||||
// [ ] Platform: Gamepad support.
|
||||
// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||
// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android.
|
||||
// Important:
|
||||
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
|
||||
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// [ ] Platform: Clipboard support.
|
||||
// [ ] Platform: Gamepad support.
|
||||
// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
|
||||
// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android.
|
||||
// Important:
|
||||
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
|
||||
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -16,6 +17,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
|
||||
// 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
|
||||
// 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
|
||||
@@ -95,6 +97,10 @@ static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX10_InitMultiViewportSupport();
|
||||
static void ImGui_ImplDX10_ShutdownMultiViewportSupport();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device)
|
||||
{
|
||||
@@ -603,6 +609,7 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||
io.BackendRendererName = "imgui_impl_dx10";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
@@ -622,6 +629,8 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
|
||||
if (pDXGIAdapter) pDXGIAdapter->Release();
|
||||
bd->pd3dDevice->AddRef();
|
||||
|
||||
ImGui_ImplDX10_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -631,12 +640,13 @@ void ImGui_ImplDX10_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplDX10_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplDX10_InvalidateDeviceObjects();
|
||||
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -650,6 +660,129 @@ void ImGui_ImplDX10_NewFrame()
|
||||
IM_ASSERT(0 && "ImGui_ImplDX10_CreateDeviceObjects() failed!");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplDX10_ViewportData
|
||||
{
|
||||
IDXGISwapChain* SwapChain;
|
||||
ID3D10RenderTargetView* RTView;
|
||||
|
||||
ImGui_ImplDX10_ViewportData() { SwapChain = nullptr; RTView = nullptr; }
|
||||
~ImGui_ImplDX10_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGui_ImplDX10_ViewportData* vd = IM_NEW(ImGui_ImplDX10_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
|
||||
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
// Create swap chain
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferDesc.Width = (UINT)viewport->Size.x;
|
||||
sd.BufferDesc.Height = (UINT)viewport->Size.y;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 1;
|
||||
sd.OutputWindow = hwnd;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
sd.Flags = 0;
|
||||
|
||||
IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr);
|
||||
bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
|
||||
|
||||
// Create the render target
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D10Texture2D* pBackBuffer;
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == 0 here since we didn't create the data for it.
|
||||
if (ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
if (vd->SwapChain)
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = nullptr;
|
||||
if (vd->RTView)
|
||||
vd->RTView->Release();
|
||||
vd->RTView = nullptr;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||
if (vd->RTView)
|
||||
{
|
||||
vd->RTView->Release();
|
||||
vd->RTView = nullptr;
|
||||
}
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D10Texture2D* pBackBuffer = nullptr;
|
||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX10_SetWindowSize() failed creating buffers.\n"); return; }
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_RenderViewport(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
|
||||
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
bd->pd3dDevice->OMSetRenderTargets(1, &vd->RTView, nullptr);
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
bd->pd3dDevice->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
|
||||
ImGui_ImplDX10_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX10_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX10_ViewportData* vd = (ImGui_ImplDX10_ViewportData*)viewport->RendererUserData;
|
||||
vd->SwapChain->Present(0, 0); // Present without vsync
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX10_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX10_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX10_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX10_RenderViewport;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX10_SwapBuffers;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX10_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -17,8 +18,10 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
|
||||
// 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
|
||||
// 2025-02-24: [Docking] Added undocumented ImGui_ImplDX11_SetSwapChainDescs() to configure swap chain creation for secondary viewports.
|
||||
// 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler.
|
||||
// 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap.
|
||||
// 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
|
||||
@@ -82,6 +85,7 @@ struct ImGui_ImplDX11_Data
|
||||
ID3D11DepthStencilState* pDepthStencilState;
|
||||
int VertexBufferSize;
|
||||
int IndexBufferSize;
|
||||
ImVector<DXGI_SWAP_CHAIN_DESC> SwapChainDescsForViewports;
|
||||
|
||||
ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
|
||||
};
|
||||
@@ -98,6 +102,10 @@ static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX11_InitMultiViewportSupport();
|
||||
static void ImGui_ImplDX11_ShutdownMultiViewportSupport();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* device_ctx)
|
||||
{
|
||||
@@ -619,6 +627,7 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
|
||||
io.BackendRendererName = "imgui_impl_dx11";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
@@ -641,6 +650,8 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
|
||||
bd->pd3dDevice->AddRef();
|
||||
bd->pd3dDeviceContext->AddRef();
|
||||
|
||||
ImGui_ImplDX11_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -650,13 +661,14 @@ void ImGui_ImplDX11_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplDX11_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplDX11_InvalidateDeviceObjects();
|
||||
if (bd->pFactory) { bd->pFactory->Release(); }
|
||||
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||
if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -670,6 +682,150 @@ void ImGui_ImplDX11_NewFrame()
|
||||
IM_ASSERT(0 && "ImGui_ImplDX11_CreateDeviceObjects() failed!");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplDX11_ViewportData
|
||||
{
|
||||
IDXGISwapChain* SwapChain;
|
||||
ID3D11RenderTargetView* RTView;
|
||||
|
||||
ImGui_ImplDX11_ViewportData() { SwapChain = nullptr; RTView = nullptr; }
|
||||
~ImGui_ImplDX11_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); }
|
||||
};
|
||||
|
||||
// Multi-Viewports: configure templates used when creating swapchains for secondary viewports. Will try them in order.
|
||||
// This is intentionally not declared in the .h file yet, so you will need to copy this declaration:
|
||||
void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count);
|
||||
void ImGui_ImplDX11_SetSwapChainDescs(const DXGI_SWAP_CHAIN_DESC* desc_templates, int desc_templates_count)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
bd->SwapChainDescsForViewports.resize(desc_templates_count);
|
||||
memcpy(bd->SwapChainDescsForViewports.Data, desc_templates, sizeof(DXGI_SWAP_CHAIN_DESC));
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ImGui_ImplDX11_ViewportData* vd = IM_NEW(ImGui_ImplDX11_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
|
||||
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr);
|
||||
|
||||
// Create swap chain
|
||||
HRESULT hr = DXGI_ERROR_UNSUPPORTED;
|
||||
for (const DXGI_SWAP_CHAIN_DESC& sd_template : bd->SwapChainDescsForViewports)
|
||||
{
|
||||
IM_ASSERT(sd_template.BufferDesc.Width == 0 && sd_template.BufferDesc.Height == 0 && sd_template.OutputWindow == nullptr);
|
||||
DXGI_SWAP_CHAIN_DESC sd = sd_template;
|
||||
sd.BufferDesc.Width = (UINT)viewport->Size.x;
|
||||
sd.BufferDesc.Height = (UINT)viewport->Size.y;
|
||||
sd.OutputWindow = hwnd;
|
||||
hr = bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain);
|
||||
if (SUCCEEDED(hr))
|
||||
break;
|
||||
}
|
||||
IM_ASSERT(SUCCEEDED(hr));
|
||||
|
||||
// Create the render target
|
||||
if (vd->SwapChain != nullptr)
|
||||
{
|
||||
ID3D11Texture2D* pBackBuffer;
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == nullptr since we didn't create the data for it.
|
||||
if (ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
if (vd->SwapChain)
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = nullptr;
|
||||
if (vd->RTView)
|
||||
vd->RTView->Release();
|
||||
vd->RTView = nullptr;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||
if (vd->RTView)
|
||||
{
|
||||
vd->RTView->Release();
|
||||
vd->RTView = nullptr;
|
||||
}
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D11Texture2D* pBackBuffer = nullptr;
|
||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||
vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
|
||||
if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; }
|
||||
bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView);
|
||||
pBackBuffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
|
||||
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
bd->pd3dDeviceContext->OMSetRenderTargets(1, &vd->RTView, nullptr);
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
bd->pd3dDeviceContext->ClearRenderTargetView(vd->RTView, (float*)&clear_color);
|
||||
ImGui_ImplDX11_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData;
|
||||
vd->SwapChain->Present(0, 0); // Present without vsync
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX11_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX11_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX11_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX11_RenderWindow;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers;
|
||||
|
||||
// Default swapchain format
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 1;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
sd.Flags = 0;
|
||||
ImGui_ImplDX11_SetSwapChainDescs(&sd, 1);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX11_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// FIXME: The transition from removing a viewport and moving the window in an existing hosted viewport tends to flicker.
|
||||
|
||||
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
@@ -20,6 +22,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-06-19: Fixed build on MinGW. (#8702, #4594)
|
||||
// 2025-06-11: DirectX12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
|
||||
// 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
|
||||
@@ -95,14 +98,10 @@ struct ImGui_ImplDX12_Data
|
||||
DXGI_FORMAT DSVFormat;
|
||||
ID3D12DescriptorHeap* pd3dSrvDescHeap;
|
||||
UINT numFramesInFlight;
|
||||
|
||||
ImGui_ImplDX12_RenderBuffers* pFrameResources;
|
||||
UINT frameIndex;
|
||||
|
||||
ImGui_ImplDX12_Texture FontTexture;
|
||||
bool LegacySingleDescriptorUsed;
|
||||
|
||||
ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
|
||||
ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
|
||||
@@ -121,11 +120,88 @@ struct ImGui_ImplDX12_RenderBuffers
|
||||
int VertexBufferSize;
|
||||
};
|
||||
|
||||
// Buffers used for secondary viewports created by the multi-viewports systems
|
||||
struct ImGui_ImplDX12_FrameContext
|
||||
{
|
||||
ID3D12CommandAllocator* CommandAllocator;
|
||||
ID3D12Resource* RenderTarget;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE RenderTargetCpuDescriptors;
|
||||
};
|
||||
|
||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
// Main viewport created by application will only use the Resources field.
|
||||
// Secondary viewports created by this backend will use all the fields (including Window fields),
|
||||
struct ImGui_ImplDX12_ViewportData
|
||||
{
|
||||
// Window
|
||||
ID3D12CommandQueue* CommandQueue;
|
||||
ID3D12GraphicsCommandList* CommandList;
|
||||
ID3D12DescriptorHeap* RtvDescHeap;
|
||||
IDXGISwapChain3* SwapChain;
|
||||
ID3D12Fence* Fence;
|
||||
UINT64 FenceSignaledValue;
|
||||
HANDLE FenceEvent;
|
||||
UINT NumFramesInFlight;
|
||||
ImGui_ImplDX12_FrameContext* FrameCtx;
|
||||
|
||||
// Render buffers
|
||||
UINT FrameIndex;
|
||||
ImGui_ImplDX12_RenderBuffers* FrameRenderBuffers;
|
||||
|
||||
ImGui_ImplDX12_ViewportData(UINT num_frames_in_flight)
|
||||
{
|
||||
CommandQueue = nullptr;
|
||||
CommandList = nullptr;
|
||||
RtvDescHeap = nullptr;
|
||||
SwapChain = nullptr;
|
||||
Fence = nullptr;
|
||||
FenceSignaledValue = 0;
|
||||
FenceEvent = nullptr;
|
||||
NumFramesInFlight = num_frames_in_flight;
|
||||
FrameCtx = new ImGui_ImplDX12_FrameContext[NumFramesInFlight];
|
||||
FrameIndex = UINT_MAX;
|
||||
FrameRenderBuffers = new ImGui_ImplDX12_RenderBuffers[NumFramesInFlight];
|
||||
|
||||
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||
{
|
||||
FrameCtx[i].CommandAllocator = nullptr;
|
||||
FrameCtx[i].RenderTarget = nullptr;
|
||||
|
||||
// Create buffers with a default size (they will later be grown as needed)
|
||||
FrameRenderBuffers[i].IndexBuffer = nullptr;
|
||||
FrameRenderBuffers[i].VertexBuffer = nullptr;
|
||||
FrameRenderBuffers[i].VertexBufferSize = 5000;
|
||||
FrameRenderBuffers[i].IndexBufferSize = 10000;
|
||||
}
|
||||
}
|
||||
~ImGui_ImplDX12_ViewportData()
|
||||
{
|
||||
IM_ASSERT(CommandQueue == nullptr && CommandList == nullptr);
|
||||
IM_ASSERT(RtvDescHeap == nullptr);
|
||||
IM_ASSERT(SwapChain == nullptr);
|
||||
IM_ASSERT(Fence == nullptr);
|
||||
IM_ASSERT(FenceEvent == nullptr);
|
||||
|
||||
for (UINT i = 0; i < NumFramesInFlight; ++i)
|
||||
{
|
||||
IM_ASSERT(FrameCtx[i].CommandAllocator == nullptr && FrameCtx[i].RenderTarget == nullptr);
|
||||
IM_ASSERT(FrameRenderBuffers[i].IndexBuffer == nullptr && FrameRenderBuffers[i].VertexBuffer == nullptr);
|
||||
}
|
||||
|
||||
delete[] FrameCtx; FrameCtx = nullptr;
|
||||
delete[] FrameRenderBuffers; FrameRenderBuffers = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER_DX12
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX12_InitPlatformInterface();
|
||||
static void ImGui_ImplDX12_ShutdownPlatformInterface();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr)
|
||||
{
|
||||
@@ -205,8 +281,9 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
|
||||
|
||||
// FIXME: We are assuming that this only gets called once per frame!
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
bd->frameIndex = bd->frameIndex + 1;
|
||||
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
|
||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)draw_data->OwnerViewport->RendererUserData;
|
||||
vd->FrameIndex++;
|
||||
ImGui_ImplDX12_RenderBuffers* fr = &vd->FrameRenderBuffers[vd->FrameIndex % bd->numFramesInFlight];
|
||||
|
||||
// Create and grow vertex/index buffers if needed
|
||||
if (fr->VertexBuffer == nullptr || fr->VertexBufferSize < draw_data->TotalVtxCount)
|
||||
@@ -779,6 +856,13 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_DestroyRenderBuffers(ImGui_ImplDX12_RenderBuffers* render_buffers)
|
||||
{
|
||||
SafeRelease(render_buffers->IndexBuffer);
|
||||
SafeRelease(render_buffers->VertexBuffer);
|
||||
render_buffers->IndexBufferSize = render_buffers->VertexBufferSize = 0;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||
{
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
@@ -795,13 +879,6 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
|
||||
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||
if (tex->RefCount == 1)
|
||||
ImGui_ImplDX12_DestroyTexture(tex);
|
||||
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
{
|
||||
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
|
||||
SafeRelease(fr->IndexBuffer);
|
||||
SafeRelease(fr->VertexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
@@ -849,6 +926,15 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
|
||||
io.BackendRendererName = "imgui_impl_dx12";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
ImGui_ImplDX12_InitPlatformInterface();
|
||||
|
||||
// Create a dummy ImGui_ImplDX12_ViewportData holder for the main viewport,
|
||||
// Since this is created and managed by the application, we will only use the ->Resources[] fields.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->RendererUserData = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
if (init_info->SrvDescriptorAllocFn == nullptr)
|
||||
@@ -856,18 +942,6 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
|
||||
#endif
|
||||
IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr);
|
||||
|
||||
// Create buffers with a default size (they will later be grown as needed)
|
||||
bd->frameIndex = UINT_MAX;
|
||||
bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[bd->numFramesInFlight];
|
||||
for (int i = 0; i < (int)bd->numFramesInFlight; i++)
|
||||
{
|
||||
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
|
||||
fr->IndexBuffer = nullptr;
|
||||
fr->VertexBuffer = nullptr;
|
||||
fr->IndexBufferSize = 10000;
|
||||
fr->VertexBufferSize = 5000;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -907,13 +981,24 @@ void ImGui_ImplDX12_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// Manually delete main viewport render resources in-case we haven't initialized for viewports
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)main_viewport->RendererUserData)
|
||||
{
|
||||
// We could just call ImGui_ImplDX12_DestroyWindow(main_viewport) as a convenience but that would be misleading since we only use data->Resources[]
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
|
||||
IM_DELETE(vd);
|
||||
main_viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
// Clean up windows and device objects
|
||||
ImGui_ImplDX12_ShutdownPlatformInterface();
|
||||
ImGui_ImplDX12_InvalidateDeviceObjects();
|
||||
delete[] bd->pFrameResources;
|
||||
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -927,6 +1012,246 @@ void ImGui_ImplDX12_NewFrame()
|
||||
IM_ASSERT(0 && "ImGui_ImplDX12_CreateDeviceObjects() failed!");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
ImGui_ImplDX12_ViewportData* vd = IM_NEW(ImGui_ImplDX12_ViewportData)(bd->numFramesInFlight);
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
|
||||
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
vd->FrameIndex = UINT_MAX;
|
||||
|
||||
// Create command queue.
|
||||
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
|
||||
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
|
||||
HRESULT res = S_OK;
|
||||
res = bd->pd3dDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&vd->CommandQueue));
|
||||
IM_ASSERT(res == S_OK);
|
||||
|
||||
// Create command allocator.
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; ++i)
|
||||
{
|
||||
res = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&vd->FrameCtx[i].CommandAllocator));
|
||||
IM_ASSERT(res == S_OK);
|
||||
}
|
||||
|
||||
// Create command list.
|
||||
res = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, vd->FrameCtx[0].CommandAllocator, nullptr, IID_PPV_ARGS(&vd->CommandList));
|
||||
IM_ASSERT(res == S_OK);
|
||||
vd->CommandList->Close();
|
||||
|
||||
// Create fence.
|
||||
res = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&vd->Fence));
|
||||
IM_ASSERT(res == S_OK);
|
||||
|
||||
vd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
IM_ASSERT(vd->FenceEvent != nullptr);
|
||||
|
||||
// Create swap chain
|
||||
// FIXME-VIEWPORT: May want to copy/inherit swap chain settings from the user/application.
|
||||
DXGI_SWAP_CHAIN_DESC1 sd1;
|
||||
ZeroMemory(&sd1, sizeof(sd1));
|
||||
sd1.BufferCount = bd->numFramesInFlight;
|
||||
sd1.Width = (UINT)viewport->Size.x;
|
||||
sd1.Height = (UINT)viewport->Size.y;
|
||||
sd1.Format = bd->RTVFormat;
|
||||
sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd1.SampleDesc.Count = 1;
|
||||
sd1.SampleDesc.Quality = 0;
|
||||
sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
sd1.Scaling = DXGI_SCALING_NONE;
|
||||
sd1.Stereo = FALSE;
|
||||
|
||||
IDXGIFactory4* dxgi_factory = nullptr;
|
||||
res = ::CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory));
|
||||
IM_ASSERT(res == S_OK);
|
||||
|
||||
IDXGISwapChain1* swap_chain = nullptr;
|
||||
res = dxgi_factory->CreateSwapChainForHwnd(vd->CommandQueue, hwnd, &sd1, nullptr, nullptr, &swap_chain);
|
||||
IM_ASSERT(res == S_OK);
|
||||
|
||||
dxgi_factory->Release();
|
||||
|
||||
// Or swapChain.As(&mSwapChain)
|
||||
IM_ASSERT(vd->SwapChain == nullptr);
|
||||
swap_chain->QueryInterface(IID_PPV_ARGS(&vd->SwapChain));
|
||||
swap_chain->Release();
|
||||
|
||||
// Create the render targets
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
D3D12_DESCRIPTOR_HEAP_DESC desc = {};
|
||||
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
|
||||
desc.NumDescriptors = bd->numFramesInFlight;
|
||||
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
desc.NodeMask = 1;
|
||||
|
||||
HRESULT hr = bd->pd3dDevice->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&vd->RtvDescHeap));
|
||||
IM_ASSERT(hr == S_OK);
|
||||
|
||||
SIZE_T rtv_descriptor_size = bd->pd3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle = vd->RtvDescHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
{
|
||||
vd->FrameCtx[i].RenderTargetCpuDescriptors = rtv_handle;
|
||||
rtv_handle.ptr += rtv_descriptor_size;
|
||||
}
|
||||
|
||||
ID3D12Resource* back_buffer;
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
{
|
||||
IM_ASSERT(vd->FrameCtx[i].RenderTarget == nullptr);
|
||||
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
|
||||
}
|
||||
|
||||
static void ImGui_WaitForPendingOperations(ImGui_ImplDX12_ViewportData* vd)
|
||||
{
|
||||
HRESULT hr = S_FALSE;
|
||||
if (vd && vd->CommandQueue && vd->Fence && vd->FenceEvent)
|
||||
{
|
||||
hr = vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
::WaitForSingleObject(vd->FenceEvent, 0); // Reset any forgotten waits
|
||||
hr = vd->Fence->SetEventOnCompletion(vd->FenceSignaledValue, vd->FenceEvent);
|
||||
IM_ASSERT(hr == S_OK);
|
||||
::WaitForSingleObject(vd->FenceEvent, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
if (ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
ImGui_WaitForPendingOperations(vd);
|
||||
|
||||
SafeRelease(vd->CommandQueue);
|
||||
SafeRelease(vd->CommandList);
|
||||
SafeRelease(vd->SwapChain);
|
||||
SafeRelease(vd->RtvDescHeap);
|
||||
SafeRelease(vd->Fence);
|
||||
::CloseHandle(vd->FenceEvent);
|
||||
vd->FenceEvent = nullptr;
|
||||
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
{
|
||||
SafeRelease(vd->FrameCtx[i].RenderTarget);
|
||||
SafeRelease(vd->FrameCtx[i].CommandAllocator);
|
||||
ImGui_ImplDX12_DestroyRenderBuffers(&vd->FrameRenderBuffers[i]);
|
||||
}
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||
|
||||
ImGui_WaitForPendingOperations(vd);
|
||||
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
SafeRelease(vd->FrameCtx[i].RenderTarget);
|
||||
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
ID3D12Resource* back_buffer = nullptr;
|
||||
vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0);
|
||||
for (UINT i = 0; i < bd->numFramesInFlight; i++)
|
||||
{
|
||||
vd->SwapChain->GetBuffer(i, IID_PPV_ARGS(&back_buffer));
|
||||
bd->pd3dDevice->CreateRenderTargetView(back_buffer, nullptr, vd->FrameCtx[i].RenderTargetCpuDescriptors);
|
||||
vd->FrameCtx[i].RenderTarget = back_buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
|
||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||
|
||||
ImGui_ImplDX12_FrameContext* frame_context = &vd->FrameCtx[vd->FrameIndex % bd->numFramesInFlight];
|
||||
UINT back_buffer_idx = vd->SwapChain->GetCurrentBackBufferIndex();
|
||||
|
||||
const ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = vd->FrameCtx[back_buffer_idx].RenderTarget;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
|
||||
// Draw
|
||||
ID3D12GraphicsCommandList* cmd_list = vd->CommandList;
|
||||
|
||||
frame_context->CommandAllocator->Reset();
|
||||
cmd_list->Reset(frame_context->CommandAllocator, nullptr);
|
||||
cmd_list->ResourceBarrier(1, &barrier);
|
||||
cmd_list->OMSetRenderTargets(1, &vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, FALSE, nullptr);
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
cmd_list->ClearRenderTargetView(vd->FrameCtx[back_buffer_idx].RenderTargetCpuDescriptors, (const float*)&clear_color, 0, nullptr);
|
||||
cmd_list->SetDescriptorHeaps(1, &bd->pd3dSrvDescHeap);
|
||||
|
||||
ImGui_ImplDX12_RenderDrawData(viewport->DrawData, cmd_list);
|
||||
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
|
||||
cmd_list->ResourceBarrier(1, &barrier);
|
||||
cmd_list->Close();
|
||||
|
||||
vd->CommandQueue->Wait(vd->Fence, vd->FenceSignaledValue);
|
||||
vd->CommandQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmd_list);
|
||||
vd->CommandQueue->Signal(vd->Fence, ++vd->FenceSignaledValue);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX12_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX12_ViewportData* vd = (ImGui_ImplDX12_ViewportData*)viewport->RendererUserData;
|
||||
|
||||
vd->SwapChain->Present(0, 0);
|
||||
while (vd->Fence->GetCompletedValue() < vd->FenceSignaledValue)
|
||||
::SwitchToThread();
|
||||
}
|
||||
|
||||
void ImGui_ImplDX12_InitPlatformInterface()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX12_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX12_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX12_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX12_RenderWindow;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX12_SwapBuffers;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX12_ShutdownPlatformInterface()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -17,6 +18,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
|
||||
// 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap.
|
||||
// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575)
|
||||
@@ -86,6 +88,12 @@ static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplDX9_InitMultiViewportSupport();
|
||||
static void ImGui_ImplDX9_ShutdownMultiViewportSupport();
|
||||
static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
|
||||
static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
|
||||
|
||||
// Functions
|
||||
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
|
||||
{
|
||||
@@ -295,6 +303,11 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
|
||||
global_vtx_offset += draw_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
// When using multi-viewports, it appears that there's an odd logic in DirectX9 which prevent subsequent windows
|
||||
// from rendering until the first window submits at least one draw call, even once. That's our workaround. (see #2560)
|
||||
if (global_vtx_offset == 0)
|
||||
bd->pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 0, 0, 0);
|
||||
|
||||
// Restore the DX9 transform
|
||||
device->SetTransform(D3DTS_WORLD, &last_world);
|
||||
device->SetTransform(D3DTS_VIEW, &last_view);
|
||||
@@ -335,6 +348,7 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||
io.BackendRendererName = "imgui_impl_dx9";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
|
||||
@@ -343,6 +357,8 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
|
||||
bd->pd3dDevice->AddRef();
|
||||
bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
|
||||
|
||||
ImGui_ImplDX9_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -352,11 +368,12 @@ void ImGui_ImplDX9_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplDX9_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -444,6 +461,7 @@ bool ImGui_ImplDX9_CreateDeviceObjects()
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
if (!bd || !bd->pd3dDevice)
|
||||
return false;
|
||||
ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -462,6 +480,7 @@ void ImGui_ImplDX9_InvalidateDeviceObjects()
|
||||
}
|
||||
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
|
||||
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
|
||||
ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows();
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_NewFrame()
|
||||
@@ -471,6 +490,148 @@ void ImGui_ImplDX9_NewFrame()
|
||||
IM_UNUSED(bd);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplDX9_ViewportData
|
||||
{
|
||||
IDirect3DSwapChain9* SwapChain;
|
||||
D3DPRESENT_PARAMETERS d3dpp;
|
||||
|
||||
ImGui_ImplDX9_ViewportData() { SwapChain = nullptr; ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS)); }
|
||||
~ImGui_ImplDX9_ViewportData() { IM_ASSERT(SwapChain == nullptr); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
ImGui_ImplDX9_ViewportData* vd = IM_NEW(ImGui_ImplDX9_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
|
||||
// PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL's WindowID).
|
||||
// Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND.
|
||||
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
|
||||
IM_ASSERT(hwnd != 0);
|
||||
|
||||
ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
|
||||
vd->d3dpp.Windowed = TRUE;
|
||||
vd->d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
vd->d3dpp.BackBufferWidth = (UINT)viewport->Size.x;
|
||||
vd->d3dpp.BackBufferHeight = (UINT)viewport->Size.y;
|
||||
vd->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
vd->d3dpp.hDeviceWindow = hwnd;
|
||||
vd->d3dpp.EnableAutoDepthStencil = FALSE;
|
||||
vd->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
|
||||
vd->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync
|
||||
|
||||
HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
|
||||
IM_ASSERT(hr == D3D_OK);
|
||||
IM_ASSERT(vd->SwapChain != nullptr);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||
if (ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
if (vd->SwapChain)
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = nullptr;
|
||||
ZeroMemory(&vd->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||
if (vd->SwapChain)
|
||||
{
|
||||
vd->SwapChain->Release();
|
||||
vd->SwapChain = nullptr;
|
||||
vd->d3dpp.BackBufferWidth = (UINT)size.x;
|
||||
vd->d3dpp.BackBufferHeight = (UINT)size.y;
|
||||
HRESULT hr = bd->pd3dDevice->CreateAdditionalSwapChain(&vd->d3dpp, &vd->SwapChain); IM_UNUSED(hr);
|
||||
IM_ASSERT(hr == D3D_OK);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
|
||||
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
LPDIRECT3DSURFACE9 render_target = nullptr;
|
||||
LPDIRECT3DSURFACE9 last_render_target = nullptr;
|
||||
LPDIRECT3DSURFACE9 last_depth_stencil = nullptr;
|
||||
vd->SwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &render_target);
|
||||
bd->pd3dDevice->GetRenderTarget(0, &last_render_target);
|
||||
bd->pd3dDevice->GetDepthStencilSurface(&last_depth_stencil);
|
||||
bd->pd3dDevice->SetRenderTarget(0, render_target);
|
||||
bd->pd3dDevice->SetDepthStencilSurface(nullptr);
|
||||
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*255.0f), (int)(clear_color.y*255.0f), (int)(clear_color.z*255.0f), (int)(clear_color.w*255.0f));
|
||||
bd->pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET, clear_col_dx, 1.0f, 0);
|
||||
}
|
||||
|
||||
ImGui_ImplDX9_RenderDrawData(viewport->DrawData);
|
||||
|
||||
// Restore render target
|
||||
bd->pd3dDevice->SetRenderTarget(0, last_render_target);
|
||||
bd->pd3dDevice->SetDepthStencilSurface(last_depth_stencil);
|
||||
render_target->Release();
|
||||
last_render_target->Release();
|
||||
if (last_depth_stencil) last_depth_stencil->Release();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplDX9_ViewportData* vd = (ImGui_ImplDX9_ViewportData*)viewport->RendererUserData;
|
||||
HRESULT hr = vd->SwapChain->Present(nullptr, nullptr, vd->d3dpp.hDeviceWindow, nullptr, 0);
|
||||
// Let main application handle D3DERR_DEVICELOST by resetting the device.
|
||||
IM_ASSERT(SUCCEEDED(hr) || hr == D3DERR_DEVICELOST);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplDX9_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplDX9_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplDX9_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplDX9_RenderWindow;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplDX9_SwapBuffers;
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_CreateDeviceObjectsForPlatformWindows()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||
if (!platform_io.Viewports[i]->RendererUserData)
|
||||
ImGui_ImplDX9_CreateWindow(platform_io.Viewports[i]);
|
||||
}
|
||||
|
||||
static void ImGui_ImplDX9_InvalidateDeviceObjectsForPlatformWindows()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||
if (platform_io.Viewports[i]->RendererUserData)
|
||||
ImGui_ImplDX9_DestroyWindow(platform_io.Viewports[i]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Multiple Dear ImGui contexts support.
|
||||
// Missing features or Issues:
|
||||
// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround.
|
||||
// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
|
||||
// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -29,11 +31,16 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733)
|
||||
// 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069)
|
||||
// 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps.
|
||||
// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
|
||||
// 2025-04-26: [Docking] Disable multi-viewports under Wayland. (#8587)
|
||||
// 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102.
|
||||
// 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled.
|
||||
// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415)
|
||||
// 2024-11-05: [Docking] Added Linux workaround for spurious mouse up events emitted while dragging and creating new viewport. (#3158, #7733, #7922)
|
||||
// 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
|
||||
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
|
||||
// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
|
||||
@@ -50,6 +57,7 @@
|
||||
// 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034)
|
||||
// 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240)
|
||||
// 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
|
||||
// 2023-01-18: Handle unsupported glfwGetVideoMode() call on e.g. Emscripten.
|
||||
// 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
|
||||
// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
|
||||
// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
|
||||
@@ -100,6 +108,8 @@
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal" // warning: comparing floating-point with '==' or '!=' is unsafe
|
||||
#endif
|
||||
|
||||
// GLFW
|
||||
@@ -135,15 +145,33 @@
|
||||
|
||||
// We gather version tests as define in order to easily see which features are version-dependent.
|
||||
#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
|
||||
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_COMBINED >= 3200) // 3.2+ GLFW_FLOATING
|
||||
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_HOVERED
|
||||
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||
#if defined(__EMSCRIPTEN__) || defined(__SWITCH__) // no Vulkan support in GLFW for Emscripten or homebrew Nintendo Switch
|
||||
#define GLFW_HAS_VULKAN (0)
|
||||
#else
|
||||
#define GLFW_HAS_VULKAN (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||
#endif
|
||||
#define GLFW_HAS_FOCUS_WINDOW (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwFocusWindow
|
||||
#define GLFW_HAS_FOCUS_ON_SHOW (GLFW_VERSION_COMBINED >= 3300) // 3.3+ GLFW_FOCUS_ON_SHOW
|
||||
#define GLFW_HAS_MONITOR_WORK_AREA (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorWorkarea
|
||||
#define GLFW_HAS_OSX_WINDOW_POS_FIX (GLFW_VERSION_COMBINED >= 3301) // 3.3.1+ Fixed: Resizing window repositions it on MacOS #1553
|
||||
#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
|
||||
#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
|
||||
#else
|
||||
#define GLFW_HAS_NEW_CURSORS (0)
|
||||
#endif
|
||||
#ifdef GLFW_MOUSE_PASSTHROUGH // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2020-07-17 (passthrough)
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_MOUSE_PASSTHROUGH
|
||||
#else
|
||||
#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
|
||||
#endif
|
||||
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api
|
||||
#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
|
||||
#define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError()
|
||||
#define GLFW_HAS_GETPLATFORM (GLFW_VERSION_COMBINED >= 3400) // 3.4+ glfwGetPlatform()
|
||||
|
||||
// Map GLFWWindow* to ImGuiContext*.
|
||||
// - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource.
|
||||
@@ -171,7 +199,10 @@ struct ImGui_ImplGlfw_Data
|
||||
double Time;
|
||||
GLFWwindow* MouseWindow;
|
||||
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
|
||||
bool MouseIgnoreButtonUpWaitForFocusLoss;
|
||||
bool MouseIgnoreButtonUp;
|
||||
ImVec2 LastValidMousePos;
|
||||
GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
|
||||
bool InstalledCallbacks;
|
||||
bool CallbacksChainForAllWindows;
|
||||
char BackendPlatformName[32];
|
||||
@@ -215,6 +246,11 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(GLFWwindow* window)
|
||||
return (ImGui_ImplGlfw_Data*)ImGui::GetIO(ctx).BackendPlatformUserData;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplGlfw_UpdateMonitors();
|
||||
static void ImGui_ImplGlfw_InitMultiViewportSupport();
|
||||
static void ImGui_ImplGlfw_ShutdownMultiViewportSupport();
|
||||
|
||||
// Functions
|
||||
|
||||
// Not static to allow third-party code to use that if they want to (but undocumented)
|
||||
@@ -365,10 +401,13 @@ static bool ImGui_ImplGlfw_ShouldChainCallback(ImGui_ImplGlfw_Data* bd, GLFWwind
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
|
||||
|
||||
if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
|
||||
bd->PrevUserCallbackMousebutton(window, button, action, mods);
|
||||
|
||||
// Workaround for Linux: ignore mouse up events which are following an focus loss following a viewport creation
|
||||
if (bd->MouseIgnoreButtonUp && action == GLFW_RELEASE)
|
||||
return;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO(bd->Context);
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(io, window);
|
||||
if (button >= 0 && button < ImGuiMouseButton_COUNT)
|
||||
@@ -436,6 +475,9 @@ void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, i
|
||||
ImGuiIO& io = ImGui::GetIO(bd->Context);
|
||||
ImGui_ImplGlfw_UpdateKeyModifiers(io, window);
|
||||
|
||||
if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows))
|
||||
bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : nullptr;
|
||||
|
||||
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
|
||||
|
||||
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode);
|
||||
@@ -449,6 +491,10 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
|
||||
if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
|
||||
bd->PrevUserCallbackWindowFocus(window, focused);
|
||||
|
||||
// Workaround for Linux: when losing focus with MouseIgnoreButtonUpWaitForFocusLoss set, we will temporarily ignore subsequent Mouse Up events
|
||||
bd->MouseIgnoreButtonUp = (bd->MouseIgnoreButtonUpWaitForFocusLoss && focused == 0);
|
||||
bd->MouseIgnoreButtonUpWaitForFocusLoss = false;
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO(bd->Context);
|
||||
io.AddFocusEvent(focused != 0);
|
||||
}
|
||||
@@ -460,6 +506,13 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
|
||||
bd->PrevUserCallbackCursorPos(window, x, y);
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO(bd->Context);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
int window_x, window_y;
|
||||
glfwGetWindowPos(window, &window_x, &window_y);
|
||||
x += window_x;
|
||||
y += window_y;
|
||||
}
|
||||
io.AddMousePosEvent((float)x, (float)y);
|
||||
bd->LastValidMousePos = ImVec2((float)x, (float)y);
|
||||
}
|
||||
@@ -498,7 +551,7 @@ void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
|
||||
|
||||
void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
|
||||
{
|
||||
// Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
|
||||
// This function is technically part of the API even if we stopped using the callback, so leaving it around.
|
||||
}
|
||||
|
||||
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
|
||||
@@ -521,35 +574,7 @@ static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEven
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
|
||||
// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
|
||||
static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
|
||||
{
|
||||
LPARAM extra_info = ::GetMessageExtraInfo();
|
||||
if ((extra_info & 0xFFFFFF80) == 0xFF515700)
|
||||
return ImGuiMouseSource_Pen;
|
||||
if ((extra_info & 0xFFFFFF80) == 0xFF515780)
|
||||
return ImGuiMouseSource_TouchScreen;
|
||||
return ImGuiMouseSource_Mouse;
|
||||
}
|
||||
static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA");
|
||||
ImGuiIO& io = ImGui::GetIO(bd->Context);
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
|
||||
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
|
||||
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
|
||||
io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam);
|
||||
}
|
||||
static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
|
||||
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
||||
@@ -627,6 +652,20 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
|
||||
bool has_viewports = false;
|
||||
#ifndef __EMSCRIPTEN__
|
||||
has_viewports = true;
|
||||
#if GLFW_HAS_GETPLATFORM
|
||||
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND)
|
||||
has_viewports = false;
|
||||
#endif
|
||||
if (has_viewports)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
#endif
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
|
||||
#endif
|
||||
|
||||
bd->Context = ImGui::GetCurrentContext();
|
||||
bd->Window = window;
|
||||
bd->Time = 0.0;
|
||||
@@ -675,6 +714,11 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
||||
if (install_callbacks)
|
||||
ImGui_ImplGlfw_InstallCallbacks(window);
|
||||
|
||||
// Update monitor a first time during init
|
||||
// (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
|
||||
ImGui_ImplGlfw_UpdateMonitors();
|
||||
glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
|
||||
|
||||
// Set platform dependent data in viewport
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->PlatformHandle = (void*)bd->Window;
|
||||
@@ -685,6 +729,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
||||
#else
|
||||
IM_UNUSED(main_viewport);
|
||||
#endif
|
||||
if (has_viewports)
|
||||
ImGui_ImplGlfw_InitMultiViewportSupport();
|
||||
|
||||
// Windows: register a WndProc hook so we can intercept some messages.
|
||||
#ifdef _WIN32
|
||||
@@ -737,6 +783,8 @@ void ImGui_ImplGlfw_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplGlfw_ShutdownMultiViewportSupport();
|
||||
|
||||
if (bd->InstalledCallbacks)
|
||||
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
|
||||
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
|
||||
@@ -757,7 +805,7 @@ void ImGui_ImplGlfw_Shutdown()
|
||||
|
||||
io.BackendPlatformName = nullptr;
|
||||
io.BackendPlatformUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
|
||||
ImGui_ImplGlfw_ContextMap_Remove(bd->Window);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
@@ -766,10 +814,15 @@ static void ImGui_ImplGlfw_UpdateMouseData()
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
|
||||
// (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
|
||||
ImGuiID mouse_viewport_id = 0;
|
||||
const ImVec2 mouse_pos_prev = io.MousePos;
|
||||
for (int n = 0; n < platform_io.Viewports.Size; n++)
|
||||
{
|
||||
GLFWwindow* window = bd->Window;
|
||||
ImGuiViewport* viewport = platform_io.Viewports[n];
|
||||
GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
|
||||
|
||||
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
|
||||
const bool is_window_focused = true;
|
||||
#else
|
||||
@@ -778,19 +831,54 @@ static void ImGui_ImplGlfw_UpdateMouseData()
|
||||
if (is_window_focused)
|
||||
{
|
||||
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
|
||||
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
|
||||
if (io.WantSetMousePos)
|
||||
glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y);
|
||||
glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
|
||||
|
||||
// (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
|
||||
if (bd->MouseWindow == nullptr)
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(window, &mouse_x, &mouse_y);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
||||
int window_x, window_y;
|
||||
glfwGetWindowPos(window, &window_x, &window_y);
|
||||
mouse_x += window_x;
|
||||
mouse_y += window_y;
|
||||
}
|
||||
bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
|
||||
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
|
||||
// - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag (since we implement hit via our WndProc hook)
|
||||
// On other platforms we rely on the library fallbacking to its own search when reporting a viewport with _NoInputs flag.
|
||||
// - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture.
|
||||
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
|
||||
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
|
||||
// by the backend, and use its flawed heuristic to guess the viewport behind.
|
||||
// - [X] GLFW backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
|
||||
// FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
|
||||
// See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH
|
||||
const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
|
||||
glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
|
||||
#endif
|
||||
#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED
|
||||
if (glfwGetWindowAttrib(window, GLFW_HOVERED))
|
||||
mouse_viewport_id = viewport->ID;
|
||||
#else
|
||||
// We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse.
|
||||
#endif
|
||||
}
|
||||
|
||||
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
|
||||
io.AddMouseViewportEvent(mouse_viewport_id);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
@@ -801,9 +889,10 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
// (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int n = 0; n < platform_io.Viewports.Size; n++)
|
||||
{
|
||||
GLFWwindow* window = bd->Window;
|
||||
GLFWwindow* window = (GLFWwindow*)platform_io.Viewports[n]->PlatformHandle;
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
@@ -872,6 +961,44 @@ static void ImGui_ImplGlfw_UpdateGamepads()
|
||||
#undef MAP_ANALOG
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
|
||||
int monitors_count = 0;
|
||||
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
|
||||
if (monitors_count == 0) // Preserve existing monitor list if there are none. Happens on macOS sleeping (#5683)
|
||||
return;
|
||||
|
||||
platform_io.Monitors.resize(0);
|
||||
for (int n = 0; n < monitors_count; n++)
|
||||
{
|
||||
ImGuiPlatformMonitor monitor;
|
||||
int x, y;
|
||||
glfwGetMonitorPos(glfw_monitors[n], &x, &y);
|
||||
const GLFWvidmode* vid_mode = glfwGetVideoMode(glfw_monitors[n]);
|
||||
if (vid_mode == nullptr)
|
||||
continue; // Failed to get Video mode (e.g. Emscripten does not support this function)
|
||||
monitor.MainPos = monitor.WorkPos = ImVec2((float)x, (float)y);
|
||||
monitor.MainSize = monitor.WorkSize = ImVec2((float)vid_mode->width, (float)vid_mode->height);
|
||||
#if GLFW_HAS_MONITOR_WORK_AREA
|
||||
int w, h;
|
||||
glfwGetMonitorWorkarea(glfw_monitors[n], &x, &y, &w, &h);
|
||||
if (w > 0 && h > 0) // Workaround a small GLFW issue reporting zero on monitor changes: https://github.com/glfw/glfw/pull/1761
|
||||
{
|
||||
monitor.WorkPos = ImVec2((float)x, (float)y);
|
||||
monitor.WorkSize = ImVec2((float)w, (float)h);
|
||||
}
|
||||
#endif
|
||||
float scale = ImGui_ImplGlfw_GetContentScaleForMonitor(glfw_monitors[n]);
|
||||
if (scale == 0.0f)
|
||||
continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
|
||||
monitor.DpiScale = scale;
|
||||
monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes"
|
||||
platform_io.Monitors.push_back(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
// - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend.
|
||||
// - Apple platforms use FramebufferScale so we always return 1.0f.
|
||||
// - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle.
|
||||
@@ -919,6 +1046,7 @@ void ImGui_ImplGlfw_NewFrame()
|
||||
|
||||
// Setup main viewport size (every frame to accommodate for window resizing)
|
||||
ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale);
|
||||
ImGui_ImplGlfw_UpdateMonitors();
|
||||
|
||||
// Setup time step
|
||||
// (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
|
||||
@@ -928,6 +1056,7 @@ void ImGui_ImplGlfw_NewFrame()
|
||||
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
|
||||
bd->Time = current_time;
|
||||
|
||||
bd->MouseIgnoreButtonUp = false;
|
||||
ImGui_ImplGlfw_UpdateMouseData();
|
||||
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||
|
||||
@@ -997,6 +1126,417 @@ void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* c
|
||||
}
|
||||
#endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplGlfw_ViewportData
|
||||
{
|
||||
GLFWwindow* Window; // Stored in ImGuiViewport::PlatformHandle
|
||||
bool WindowOwned;
|
||||
int IgnoreWindowPosEventFrame;
|
||||
int IgnoreWindowSizeEventFrame;
|
||||
#ifdef _WIN32
|
||||
WNDPROC PrevWndProc;
|
||||
#endif
|
||||
|
||||
ImGui_ImplGlfw_ViewportData() { memset((void*)this, 0, sizeof(*this)); IgnoreWindowSizeEventFrame = IgnoreWindowPosEventFrame = -1; }
|
||||
~ImGui_ImplGlfw_ViewportData() { IM_ASSERT(Window == nullptr); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplGlfw_WindowCloseCallback(GLFWwindow* window)
|
||||
{
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
|
||||
viewport->PlatformRequestClose = true;
|
||||
}
|
||||
|
||||
// GLFW may dispatch window pos/size events after calling glfwSetWindowPos()/glfwSetWindowSize().
|
||||
// However: depending on the platform the callback may be invoked at different time:
|
||||
// - on Windows it appears to be called within the glfwSetWindowPos()/glfwSetWindowSize() call
|
||||
// - on Linux it is queued and invoked during glfwPollEvents()
|
||||
// Because the event doesn't always fire on glfwSetWindowXXX() we use a frame counter tag to only
|
||||
// ignore recent glfwSetWindowXXX() calls.
|
||||
static void ImGui_ImplGlfw_WindowPosCallback(GLFWwindow* window, int, int)
|
||||
{
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
|
||||
{
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowPosEventFrame + 1);
|
||||
//data->IgnoreWindowPosEventFrame = -1;
|
||||
if (ignore_event)
|
||||
return;
|
||||
}
|
||||
viewport->PlatformRequestMove = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_WindowSizeCallback(GLFWwindow* window, int, int)
|
||||
{
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle(window))
|
||||
{
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
bool ignore_event = (ImGui::GetFrameCount() <= vd->IgnoreWindowSizeEventFrame + 1);
|
||||
//data->IgnoreWindowSizeEventFrame = -1;
|
||||
if (ignore_event)
|
||||
return;
|
||||
}
|
||||
viewport->PlatformRequestResize = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
// Workaround for Linux: ignore mouse up events corresponding to losing focus of the previously focused window (#7733, #3158, #7922)
|
||||
#ifdef __linux__
|
||||
bd->MouseIgnoreButtonUpWaitForFocusLoss = true;
|
||||
#endif
|
||||
|
||||
// GLFW 3.2 unfortunately always set focus on glfwCreateWindow() if GLFW_VISIBLE is set, regardless of GLFW_FOCUSED
|
||||
// With GLFW 3.3, the hint GLFW_FOCUS_ON_SHOW fixes this problem
|
||||
glfwWindowHint(GLFW_VISIBLE, false);
|
||||
glfwWindowHint(GLFW_FOCUSED, false);
|
||||
#if GLFW_HAS_FOCUS_ON_SHOW
|
||||
glfwWindowHint(GLFW_FOCUS_ON_SHOW, false);
|
||||
#endif
|
||||
glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true);
|
||||
#if GLFW_HAS_WINDOW_TOPMOST
|
||||
glfwWindowHint(GLFW_FLOATING, (viewport->Flags & ImGuiViewportFlags_TopMost) ? true : false);
|
||||
#endif
|
||||
GLFWwindow* share_window = (bd->ClientApi == GlfwClientApi_OpenGL) ? bd->Window : nullptr;
|
||||
vd->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", nullptr, share_window);
|
||||
vd->WindowOwned = true;
|
||||
ImGui_ImplGlfw_ContextMap_Add(vd->Window, bd->Context);
|
||||
viewport->PlatformHandle = (void*)vd->Window;
|
||||
#ifdef _WIN32
|
||||
viewport->PlatformHandleRaw = glfwGetWin32Window(vd->Window);
|
||||
::SetPropA((HWND)viewport->PlatformHandleRaw, "IMGUI_BACKEND_DATA", bd);
|
||||
#elif defined(__APPLE__)
|
||||
viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window);
|
||||
#endif
|
||||
glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
|
||||
|
||||
// Install GLFW callbacks for secondary viewports
|
||||
glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback);
|
||||
glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback);
|
||||
glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback);
|
||||
glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||
glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback);
|
||||
glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback);
|
||||
glfwSetCharCallback(vd->Window, ImGui_ImplGlfw_CharCallback);
|
||||
glfwSetWindowCloseCallback(vd->Window, ImGui_ImplGlfw_WindowCloseCallback);
|
||||
glfwSetWindowPosCallback(vd->Window, ImGui_ImplGlfw_WindowPosCallback);
|
||||
glfwSetWindowSizeCallback(vd->Window, ImGui_ImplGlfw_WindowSizeCallback);
|
||||
if (bd->ClientApi == GlfwClientApi_OpenGL)
|
||||
{
|
||||
glfwMakeContextCurrent(vd->Window);
|
||||
glfwSwapInterval(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
if (vd->WindowOwned)
|
||||
{
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
::RemovePropA(hwnd, "IMGUI_VIEWPORT");
|
||||
#endif
|
||||
|
||||
// Release any keys that were pressed in the window being destroyed and are still held down,
|
||||
// because we will not receive any release events after window is destroyed.
|
||||
for (int i = 0; i < IM_ARRAYSIZE(bd->KeyOwnerWindows); i++)
|
||||
if (bd->KeyOwnerWindows[i] == vd->Window)
|
||||
ImGui_ImplGlfw_KeyCallback(vd->Window, i, 0, GLFW_RELEASE, 0); // Later params are only used for main viewport, on which this function is never called.
|
||||
|
||||
ImGui_ImplGlfw_ContextMap_Remove(vd->Window);
|
||||
glfwDestroyWindow(vd->Window);
|
||||
}
|
||||
vd->Window = nullptr;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// GLFW hack: Hide icon from task bar
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
|
||||
{
|
||||
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
ex_style &= ~WS_EX_APPWINDOW;
|
||||
ex_style |= WS_EX_TOOLWINDOW;
|
||||
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
|
||||
// GLFW hack: install WndProc for mouse source event and WM_NCHITTEST message handler.
|
||||
::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport);
|
||||
vd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
|
||||
::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
|
||||
|
||||
#if !GLFW_HAS_FOCUS_ON_SHOW
|
||||
// GLFW hack: GLFW 3.2 has a bug where glfwShowWindow() also activates/focus the window.
|
||||
// The fix was pushed to GLFW repository on 2018/01/09 and should be included in GLFW 3.3 via a GLFW_FOCUS_ON_SHOW window attribute.
|
||||
// See https://github.com/glfw/glfw/issues/1189
|
||||
// FIXME-VIEWPORT: Implement same work-around for Linux/OSX in the meanwhile.
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
|
||||
{
|
||||
::ShowWindow(hwnd, SW_SHOWNA);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
glfwShowWindow(vd->Window);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
int x = 0, y = 0;
|
||||
glfwGetWindowPos(vd->Window, &x, &y);
|
||||
return ImVec2((float)x, (float)y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount();
|
||||
glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
int w = 0, h = 0;
|
||||
glfwGetWindowSize(vd->Window, &w, &h);
|
||||
return ImVec2((float)w, (float)h);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
#if defined(__APPLE__) && !GLFW_HAS_OSX_WINDOW_POS_FIX
|
||||
// Native OS windows are positioned from the bottom-left corner on macOS, whereas on other platforms they are
|
||||
// positioned from the upper-left corner. GLFW makes an effort to convert macOS style coordinates, however it
|
||||
// doesn't handle it when changing size. We are manually moving the window in order for changes of size to be based
|
||||
// on the upper-left corner.
|
||||
int x, y, width, height;
|
||||
glfwGetWindowPos(vd->Window, &x, &y);
|
||||
glfwGetWindowSize(vd->Window, &width, &height);
|
||||
glfwSetWindowPos(vd->Window, x, y - height + size.y);
|
||||
#endif
|
||||
vd->IgnoreWindowSizeEventFrame = ImGui::GetFrameCount();
|
||||
glfwSetWindowSize(vd->Window, (int)size.x, (int)size.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplGlfw_GetWindowFramebufferScale(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
ImVec2 framebuffer_scale;
|
||||
ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, &framebuffer_scale);
|
||||
return framebuffer_scale;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
glfwSetWindowTitle(vd->Window, title);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
#if GLFW_HAS_FOCUS_WINDOW
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
glfwFocusWindow(vd->Window);
|
||||
#else
|
||||
// FIXME: What are the effect of not having this function? At the moment imgui doesn't actually call SetWindowFocus - we set that up ahead, will answer that question later.
|
||||
(void)viewport;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
return glfwGetWindowAttrib(vd->Window, GLFW_FOCUSED) != 0;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
return glfwGetWindowAttrib(vd->Window, GLFW_ICONIFIED) != 0;
|
||||
}
|
||||
|
||||
#if GLFW_HAS_WINDOW_ALPHA
|
||||
static void ImGui_ImplGlfw_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
glfwSetWindowOpacity(vd->Window, alpha);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ImGui_ImplGlfw_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
if (bd->ClientApi == GlfwClientApi_OpenGL)
|
||||
glfwMakeContextCurrent(vd->Window);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
if (bd->ClientApi == GlfwClientApi_OpenGL)
|
||||
{
|
||||
glfwMakeContextCurrent(vd->Window);
|
||||
glfwSwapBuffers(vd->Window);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Avoid including <vulkan.h> so we can build without it
|
||||
#if GLFW_HAS_VULKAN
|
||||
#ifndef VULKAN_H_
|
||||
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
|
||||
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
|
||||
#else
|
||||
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
|
||||
#endif
|
||||
VK_DEFINE_HANDLE(VkInstance)
|
||||
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR)
|
||||
struct VkAllocationCallbacks;
|
||||
enum VkResult { VK_RESULT_MAX_ENUM = 0x7FFFFFFF };
|
||||
#endif // VULKAN_H_
|
||||
extern "C" { extern GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); }
|
||||
static int ImGui_ImplGlfw_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData;
|
||||
IM_UNUSED(bd);
|
||||
IM_ASSERT(bd->ClientApi == GlfwClientApi_Vulkan);
|
||||
VkResult err = glfwCreateWindowSurface((VkInstance)vk_instance, vd->Window, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
|
||||
return (int)err;
|
||||
}
|
||||
#endif // GLFW_HAS_VULKAN
|
||||
|
||||
static void ImGui_ImplGlfw_InitMultiViewportSupport()
|
||||
{
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplGlfw_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplGlfw_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplGlfw_ShowWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplGlfw_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplGlfw_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplGlfw_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplGlfw_GetWindowSize;
|
||||
platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplGlfw_GetWindowFramebufferScale;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplGlfw_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplGlfw_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplGlfw_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplGlfw_SetWindowTitle;
|
||||
platform_io.Platform_RenderWindow = ImGui_ImplGlfw_RenderWindow;
|
||||
platform_io.Platform_SwapBuffers = ImGui_ImplGlfw_SwapBuffers;
|
||||
#if GLFW_HAS_WINDOW_ALPHA
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplGlfw_SetWindowAlpha;
|
||||
#endif
|
||||
#if GLFW_HAS_VULKAN
|
||||
platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface;
|
||||
#endif
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplGlfw_ViewportData* vd = IM_NEW(ImGui_ImplGlfw_ViewportData)();
|
||||
vd->Window = bd->Window;
|
||||
vd->WindowOwned = false;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
main_viewport->PlatformHandle = (void*)bd->Window;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// WndProc hook (declared here because we will need access to ImGui_ImplGlfw_ViewportData)
|
||||
#ifdef _WIN32
|
||||
static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
|
||||
{
|
||||
LPARAM extra_info = ::GetMessageExtraInfo();
|
||||
if ((extra_info & 0xFFFFFF80) == 0xFF515700)
|
||||
return ImGuiMouseSource_Pen;
|
||||
if ((extra_info & 0xFFFFFF80) == 0xFF515780)
|
||||
return ImGuiMouseSource_TouchScreen;
|
||||
return ImGuiMouseSource_Mouse;
|
||||
}
|
||||
static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA");
|
||||
ImGuiIO& io = ImGui::GetIO(bd->Context);
|
||||
|
||||
WNDPROC prev_wndproc = bd->PrevWndProc;
|
||||
ImGuiViewport* viewport = (ImGuiViewport*)::GetPropA(hWnd, "IMGUI_VIEWPORT");
|
||||
if (viewport != NULL)
|
||||
if (ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData)
|
||||
prev_wndproc = vd->PrevWndProc;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
|
||||
// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
|
||||
case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
|
||||
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
|
||||
case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
|
||||
io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
|
||||
break;
|
||||
|
||||
// We have submitted https://github.com/glfw/glfw/pull/1568 to allow GLFW to support "transparent inputs".
|
||||
// In the meanwhile we implement custom per-platform workarounds here (FIXME-VIEWPORT: Implement same work-around for Linux/OSX!)
|
||||
#if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED
|
||||
case WM_NCHITTEST:
|
||||
{
|
||||
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL).
|
||||
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
|
||||
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
|
||||
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
|
||||
if (viewport && (viewport->Flags & ImGuiViewportFlags_NoInputs))
|
||||
return HTTRANSPARENT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
return ::CallWindowProcW(prev_wndproc, hWnd, msg, wParam, lParam);
|
||||
}
|
||||
#endif // #ifdef _WIN32
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// dear imgui: Platform Backend for GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
@@ -8,10 +9,12 @@
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// [X] Multiple Dear ImGui contexts support.
|
||||
// Missing features or Issues:
|
||||
// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround.
|
||||
// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
|
||||
// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// [ ] Platform: Missing mouse cursor shape/visibility support.
|
||||
// [ ] Platform: Missing clipboard support (not supported by Glut).
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
// [ ] Platform: Missing multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// [ ] Platform: Missing mouse cursor shape/visibility support.
|
||||
// [ ] Platform: Missing clipboard support (not supported by Glut).
|
||||
// [ ] Platform: Missing gamepad support.
|
||||
// [ ] Platform: Missing multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -16,9 +17,10 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2025-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture().
|
||||
// 2025-02-03: Metal: Crash fix. (#8367)
|
||||
// 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419).
|
||||
// 2025-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419).
|
||||
// 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'.
|
||||
// 2022-07-05: Metal: Add dispatch synchronization.
|
||||
// 2022-06-30: Metal: Use __bridge for ARC based systems.
|
||||
@@ -42,6 +44,12 @@
|
||||
#import <time.h>
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplMetal_InitMultiViewportSupport();
|
||||
static void ImGui_ImplMetal_ShutdownMultiViewportSupport();
|
||||
static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows();
|
||||
static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows();
|
||||
|
||||
#pragma mark - Support classes
|
||||
|
||||
// A wrapper around a MTLBuffer object that knows the last time it was reused
|
||||
@@ -136,10 +144,13 @@ bool ImGui_ImplMetal_Init(id<MTLDevice> device)
|
||||
io.BackendRendererName = "imgui_impl_metal";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
bd->SharedMetalContext = [[MetalContext alloc] init];
|
||||
bd->SharedMetalContext.device = device;
|
||||
|
||||
ImGui_ImplMetal_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -148,13 +159,14 @@ void ImGui_ImplMetal_Shutdown()
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
IM_UNUSED(bd);
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGui_ImplMetal_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplMetal_DestroyDeviceObjects();
|
||||
ImGui_ImplMetal_DestroyBackendData();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
}
|
||||
|
||||
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor)
|
||||
@@ -406,6 +418,7 @@ bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
|
||||
depthStencilDescriptor.depthWriteEnabled = NO;
|
||||
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
|
||||
bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
||||
ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows();
|
||||
#ifdef IMGUI_IMPL_METAL_CPP
|
||||
[depthStencilDescriptor release];
|
||||
#endif
|
||||
@@ -422,9 +435,154 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
|
||||
if (tex->RefCount == 1)
|
||||
ImGui_ImplMetal_DestroyTexture(tex);
|
||||
|
||||
ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows();
|
||||
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
|
||||
}
|
||||
|
||||
#pragma mark - Multi-viewport support
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiViewportDataMetal
|
||||
{
|
||||
CAMetalLayer* MetalLayer;
|
||||
id<MTLCommandQueue> CommandQueue;
|
||||
MTLRenderPassDescriptor* RenderPassDescriptor;
|
||||
void* Handle = nullptr;
|
||||
bool FirstFrame = true;
|
||||
};
|
||||
|
||||
static void ImGui_ImplMetal_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
|
||||
ImGuiViewportDataMetal* data = IM_NEW(ImGuiViewportDataMetal)();
|
||||
viewport->RendererUserData = data;
|
||||
|
||||
// PlatformHandleRaw should always be a NSWindow*, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
|
||||
// Some back-ends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the NSWindow*.
|
||||
void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle;
|
||||
IM_ASSERT(handle != nullptr);
|
||||
|
||||
id<MTLDevice> device = bd->SharedMetalContext.device;
|
||||
CAMetalLayer* layer = [CAMetalLayer layer];
|
||||
layer.device = device;
|
||||
layer.framebufferOnly = YES;
|
||||
layer.pixelFormat = bd->SharedMetalContext.framebufferDescriptor.colorPixelFormat;
|
||||
#if TARGET_OS_OSX
|
||||
NSWindow* window = (__bridge NSWindow*)handle;
|
||||
NSView* view = window.contentView;
|
||||
view.layer = layer;
|
||||
view.wantsLayer = YES;
|
||||
#endif
|
||||
data->MetalLayer = layer;
|
||||
data->CommandQueue = [device newCommandQueue];
|
||||
data->RenderPassDescriptor = [[MTLRenderPassDescriptor alloc] init];
|
||||
data->Handle = handle;
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||
if (ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData)
|
||||
IM_DELETE(data);
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
inline static CGSize MakeScaledSize(CGSize size, CGFloat scale)
|
||||
{
|
||||
return CGSizeMake(size.width * scale, size.height * scale);
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData;
|
||||
data->MetalLayer.drawableSize = MakeScaledSize(CGSizeMake(size.x, size.y), viewport->DpiScale);
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGuiViewportDataMetal* data = (ImGuiViewportDataMetal*)viewport->RendererUserData;
|
||||
|
||||
#if TARGET_OS_OSX
|
||||
void* handle = viewport->PlatformHandleRaw ? viewport->PlatformHandleRaw : viewport->PlatformHandle;
|
||||
NSWindow* window = (__bridge NSWindow*)handle;
|
||||
|
||||
// Always render the first frame, regardless of occlusionState, to avoid an initial flicker
|
||||
if ((window.occlusionState & NSWindowOcclusionStateVisible) == 0 && !data->FirstFrame)
|
||||
{
|
||||
// Do not render windows which are completely occluded. Calling -[CAMetalLayer nextDrawable] will hang for
|
||||
// approximately 1 second if the Metal layer is completely occluded.
|
||||
return;
|
||||
}
|
||||
data->FirstFrame = false;
|
||||
|
||||
float fb_scale = (float)window.backingScaleFactor;
|
||||
if (data->MetalLayer.contentsScale != fb_scale)
|
||||
{
|
||||
data->MetalLayer.contentsScale = fb_scale;
|
||||
data->MetalLayer.drawableSize = MakeScaledSize(window.frame.size, fb_scale);
|
||||
}
|
||||
#endif
|
||||
|
||||
id <CAMetalDrawable> drawable = [data->MetalLayer nextDrawable];
|
||||
if (drawable == nil)
|
||||
return;
|
||||
|
||||
MTLRenderPassDescriptor* renderPassDescriptor = data->RenderPassDescriptor;
|
||||
renderPassDescriptor.colorAttachments[0].texture = drawable.texture;
|
||||
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0, 0, 0, 0);
|
||||
if ((viewport->Flags & ImGuiViewportFlags_NoRendererClear) == 0)
|
||||
renderPassDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
||||
|
||||
id <MTLCommandBuffer> commandBuffer = [data->CommandQueue commandBuffer];
|
||||
id <MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
|
||||
ImGui_ImplMetal_RenderDrawData(viewport->DrawData, commandBuffer, renderEncoder);
|
||||
[renderEncoder endEncoding];
|
||||
|
||||
[commandBuffer presentDrawable:drawable];
|
||||
[commandBuffer commit];
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplMetal_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplMetal_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplMetal_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplMetal_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_CreateDeviceObjectsForPlatformWindows()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||
if (!platform_io.Viewports[i]->RendererUserData)
|
||||
ImGui_ImplMetal_CreateWindow(platform_io.Viewports[i]);
|
||||
}
|
||||
|
||||
static void ImGui_ImplMetal_InvalidateDeviceObjectsForPlatformWindows()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int i = 1; i < platform_io.Viewports.Size; i++)
|
||||
if (platform_io.Viewports[i]->RendererUserData)
|
||||
ImGui_ImplMetal_DestroyWindow(platform_io.Viewports[i]);
|
||||
}
|
||||
|
||||
#pragma mark - MetalBuffer implementation
|
||||
|
||||
@implementation MetalBuffer
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features or Issues:
|
||||
// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802)
|
||||
// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture().
|
||||
// 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap.
|
||||
@@ -94,6 +96,10 @@ static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOpenGL2_InitMultiViewportSupport();
|
||||
static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport();
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL2_Init()
|
||||
{
|
||||
@@ -106,6 +112,9 @@ bool ImGui_ImplOpenGL2_Init()
|
||||
io.BackendRendererUserData = (void*)bd;
|
||||
io.BackendRendererName = "imgui_impl_opengl2";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
ImGui_ImplOpenGL2_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -116,10 +125,11 @@ void ImGui_ImplOpenGL2_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL2_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplOpenGL2_DestroyDeviceObjects();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -339,6 +349,35 @@ void ImGui_ImplOpenGL2_DestroyDeviceObjects()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplOpenGL2_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ImGui_ImplOpenGL2_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL2_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL2_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL2_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features or Issues:
|
||||
// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
@@ -23,6 +24,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-07-22: OpenGL: Add and call embedded loader shutdown during ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792)
|
||||
// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy.
|
||||
// 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture().
|
||||
@@ -260,6 +262,10 @@ static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOpenGL3_InitMultiViewportSupport();
|
||||
static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport();
|
||||
|
||||
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
|
||||
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
|
||||
struct ImGui_ImplOpenGL3_VtxAttribState
|
||||
@@ -366,6 +372,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
#endif
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize;
|
||||
@@ -409,6 +416,8 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
}
|
||||
#endif
|
||||
|
||||
ImGui_ImplOpenGL3_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -418,10 +427,11 @@ void ImGui_ImplOpenGL3_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplOpenGL3_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
|
||||
#ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W
|
||||
@@ -1038,6 +1048,34 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
ImGui_ImplOpenGL3_DestroyTexture(tex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// About WebGL/ES:
|
||||
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: IME support.
|
||||
// [x] Platform: Multi-viewport / platform windows.
|
||||
// Missing features or Issues:
|
||||
// [ ] Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration
|
||||
// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: IME support.
|
||||
// [x] Platform: Multi-viewport / platform windows.
|
||||
// Missing features or Issues:
|
||||
// [ ] Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration
|
||||
// [ ] Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -29,8 +33,11 @@
|
||||
|
||||
// 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-07-08: [Docking] Fixed multi-viewport handling broken on 2025-06-02. (#8644, #8777)
|
||||
// 2025-06-27: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
|
||||
// 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644)
|
||||
// 2025-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)
|
||||
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
|
||||
@@ -100,6 +107,9 @@ static void ImGui_ImplOSX_DestroyBackendData() { IM_DELETE(
|
||||
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); }
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplOSX_InitMultiViewportSupport();
|
||||
static void ImGui_ImplOSX_ShutdownMultiViewportSupport();
|
||||
static void ImGui_ImplOSX_UpdateMonitors();
|
||||
static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view);
|
||||
static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
|
||||
|
||||
@@ -147,9 +157,25 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
|
||||
NSWindow* window = view.window;
|
||||
if (!window)
|
||||
return;
|
||||
NSRect contentRect = [window contentRectForFrameRect:window.frame];
|
||||
NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0);
|
||||
_imeRect = [window convertRectToScreen:rect];
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
NSRect frame = window.frame;
|
||||
NSRect contentRect = window.contentLayoutRect;
|
||||
if (window.styleMask & NSWindowStyleMaskFullSizeContentView) // No title bar windows should be considered.
|
||||
contentRect = frame;
|
||||
|
||||
NSRect firstScreenFrame = NSScreen.screens[0].frame;
|
||||
_imeRect = NSMakeRect(_posX, _posY, 0, 0);
|
||||
_imeRect.origin.y = firstScreenFrame.size.height - _imeRect.size.height - _imeRect.origin.y; // Opposite of ConvertNSRect()
|
||||
}
|
||||
else
|
||||
{
|
||||
NSRect contentRect = [window contentRectForFrameRect:window.frame];
|
||||
NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0);
|
||||
_imeRect = [window convertRectToScreen:rect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
@@ -244,6 +270,7 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
|
||||
|
||||
- (void)onApplicationBecomeActive:(NSNotification*)aNotification;
|
||||
- (void)onApplicationBecomeInactive:(NSNotification*)aNotification;
|
||||
- (void)displaysDidChange:(NSNotification*)aNotification;
|
||||
|
||||
@end
|
||||
|
||||
@@ -261,6 +288,11 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view);
|
||||
io.AddFocusEvent(false);
|
||||
}
|
||||
|
||||
- (void)displaysDidChange:(NSNotification*)aNotification
|
||||
{
|
||||
ImGui_ImplOSX_UpdateMonitors();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// Functions
|
||||
@@ -415,11 +447,15 @@ bool ImGui_ImplOSX_Init(NSView* view)
|
||||
io.BackendPlatformName = "imgui_impl_osx";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
//io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
//io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
|
||||
|
||||
bd->Observer = [ImGuiObserver new];
|
||||
bd->Window = view.window ?: NSApp.orderedWindows.firstObject;
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (__bridge_retained void*)bd->Window;
|
||||
ImGui_ImplOSX_UpdateMonitors();
|
||||
ImGui_ImplOSX_InitMultiViewportSupport();
|
||||
|
||||
// Load cursors. Some of them are undocumented.
|
||||
bd->MouseCursorHidden = false;
|
||||
@@ -511,12 +547,12 @@ void ImGui_ImplOSX_Shutdown()
|
||||
bd->Monitor = nullptr;
|
||||
}
|
||||
|
||||
ImGui_ImplOSX_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplOSX_DestroyBackendData();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendPlatformName = nullptr;
|
||||
io.BackendPlatformUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_UpdateMouseCursor()
|
||||
@@ -625,9 +661,9 @@ void ImGui_ImplOSX_NewFrame(NSView* view)
|
||||
// Setup display size
|
||||
if (view)
|
||||
{
|
||||
const float dpi = (float)[view.window backingScaleFactor];
|
||||
const float fb_scale = (float)[view.window backingScaleFactor];
|
||||
io.DisplaySize = ImVec2((float)view.bounds.size.width, (float)view.bounds.size.height);
|
||||
io.DisplayFramebufferScale = ImVec2(dpi, dpi);
|
||||
io.DisplayFramebufferScale = ImVec2(fb_scale, fb_scale);
|
||||
}
|
||||
|
||||
// Setup time step
|
||||
@@ -666,10 +702,10 @@ 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)
|
||||
if (!ImGui::FindViewportByPlatformHandle((__bridge void*)event.window))
|
||||
return false;
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown)
|
||||
{
|
||||
int button = (int)[event buttonNumber];
|
||||
@@ -694,14 +730,23 @@ static bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
|
||||
|
||||
if (event.type == NSEventTypeMouseMoved || event.type == NSEventTypeLeftMouseDragged || event.type == NSEventTypeRightMouseDragged || event.type == NSEventTypeOtherMouseDragged)
|
||||
{
|
||||
NSPoint mousePoint = event.locationInWindow;
|
||||
if (event.window == nil)
|
||||
mousePoint = [[view window] convertPointFromScreen:mousePoint];
|
||||
mousePoint = [view convertPoint:mousePoint fromView:nil];
|
||||
if ([view isFlipped])
|
||||
mousePoint = NSMakePoint(mousePoint.x, mousePoint.y);
|
||||
NSPoint mousePoint;
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
mousePoint = NSEvent.mouseLocation;
|
||||
mousePoint.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - mousePoint.y; // Normalize y coordinate to top-left of main display.
|
||||
}
|
||||
else
|
||||
mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
|
||||
{
|
||||
mousePoint = event.locationInWindow;
|
||||
if (event.window == nil)
|
||||
mousePoint = [[view window] convertPointFromScreen:mousePoint];
|
||||
mousePoint = [view convertPoint:mousePoint fromView:nil]; // Convert to local coordinates of view
|
||||
if ([view isFlipped])
|
||||
mousePoint = NSMakePoint(mousePoint.x, mousePoint.y);
|
||||
else
|
||||
mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
|
||||
}
|
||||
io.AddMouseSourceEvent(GetMouseSource(event));
|
||||
io.AddMousePosEvent((float)mousePoint.x, (float)mousePoint.y);
|
||||
return io.WantCaptureMouse;
|
||||
@@ -827,6 +872,300 @@ static void ImGui_ImplOSX_AddTrackingArea(NSView* _Nonnull view)
|
||||
}];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
struct ImGui_ImplOSX_ViewportData
|
||||
{
|
||||
NSWindow* Window;
|
||||
bool WindowOwned;
|
||||
|
||||
ImGui_ImplOSX_ViewportData() { WindowOwned = false; }
|
||||
~ImGui_ImplOSX_ViewportData() { IM_ASSERT(Window == nil); }
|
||||
};
|
||||
|
||||
@interface ImGui_ImplOSX_Window: NSWindow
|
||||
@end
|
||||
|
||||
@implementation ImGui_ImplOSX_Window
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static void ConvertNSRect(NSRect* r)
|
||||
{
|
||||
NSRect firstScreenFrame = NSScreen.screens[0].frame;
|
||||
IM_ASSERT(firstScreenFrame.origin.x == 0 && firstScreenFrame.origin.y == 0);
|
||||
r->origin.y = firstScreenFrame.size.height - r->origin.y - r->size.height;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||
ImGui_ImplOSX_ViewportData* vd = IM_NEW(ImGui_ImplOSX_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
NSScreen* screen = bd->Window.screen;
|
||||
NSRect rect = NSMakeRect(viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y);
|
||||
ConvertNSRect(&rect);
|
||||
|
||||
NSWindowStyleMask styleMask = 0;
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoDecoration)
|
||||
styleMask |= NSWindowStyleMaskBorderless;
|
||||
else
|
||||
styleMask |= NSWindowStyleMaskTitled | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
||||
|
||||
NSWindow* window = [[ImGui_ImplOSX_Window alloc] initWithContentRect:rect
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:YES
|
||||
screen:screen];
|
||||
if (viewport->Flags & ImGuiViewportFlags_TopMost)
|
||||
[window setLevel:NSFloatingWindowLevel];
|
||||
|
||||
window.title = @"Untitled";
|
||||
window.opaque = YES;
|
||||
|
||||
KeyEventResponder* view = [[KeyEventResponder alloc] initWithFrame:rect];
|
||||
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6 && ceil(NSAppKitVersionNumber) < NSAppKitVersionNumber10_15)
|
||||
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||
|
||||
window.contentView = view;
|
||||
|
||||
vd->Window = window;
|
||||
vd->WindowOwned = true;
|
||||
viewport->PlatformRequestResize = false;
|
||||
viewport->PlatformHandle = viewport->PlatformHandleRaw = (__bridge_retained void*)window;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
if (ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
NSWindow* window = vd->Window;
|
||||
if (window != nil && vd->WindowOwned)
|
||||
{
|
||||
window.contentView = nil;
|
||||
window.contentViewController = nil;
|
||||
[window orderOut:nil];
|
||||
}
|
||||
vd->Window = nil;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = viewport->PlatformHandleRaw = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
|
||||
[vd->Window orderFront:nil];
|
||||
else
|
||||
[vd->Window makeKeyAndOrderFront:nil];
|
||||
|
||||
[vd->Window setIsVisible:YES];
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplOSX_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
NSWindow* window = vd->Window;
|
||||
NSRect frame = window.frame;
|
||||
NSRect contentRect = window.contentLayoutRect;
|
||||
if (window.styleMask & NSWindowStyleMaskFullSizeContentView) // No title bar windows should be considered.
|
||||
contentRect = frame;
|
||||
|
||||
NSRect firstScreenFrame = NSScreen.screens[0].frame;
|
||||
return ImVec2(frame.origin.x, firstScreenFrame.size.height - frame.origin.y - contentRect.size.height);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
NSWindow* window = vd->Window;
|
||||
NSSize size = window.frame.size;
|
||||
|
||||
NSRect r = NSMakeRect(pos.x, pos.y, size.width, size.height);
|
||||
ConvertNSRect(&r);
|
||||
[window setFrameOrigin:r.origin];
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplOSX_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
NSWindow* window = vd->Window;
|
||||
NSSize size = window.contentLayoutRect.size;
|
||||
return ImVec2(size.width, size.height);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
NSWindow* window = vd->Window;
|
||||
NSRect rect = window.frame;
|
||||
rect.origin.y -= (size.y - rect.size.height);
|
||||
rect.size.width = size.x;
|
||||
rect.size.height = size.y;
|
||||
[window setFrame:rect display:YES];
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplOSX_GetWindowFramebufferScale(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
NSWindow* window = vd->Window;
|
||||
const float fb_scale = (float)[window backingScaleFactor];
|
||||
return ImVec2(fb_scale, fb_scale);
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
[vd->Window makeKeyAndOrderFront:bd->Window];
|
||||
}
|
||||
|
||||
static bool ImGui_ImplOSX_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
return vd->Window.isKeyWindow;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplOSX_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
return vd->Window.isMiniaturized;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
vd->Window.title = [NSString stringWithUTF8String:title];
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
|
||||
|
||||
vd->Window.alphaValue = alpha;
|
||||
}
|
||||
|
||||
static float ImGui_ImplOSX_GetWindowDpiScale(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Window != 0);
|
||||
|
||||
return vd->Window.backingScaleFactor;
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_UpdateMonitors()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Monitors.resize(0);
|
||||
|
||||
NSRect firstScreenFrame = NSScreen.screens[0].frame;
|
||||
IM_ASSERT(firstScreenFrame.origin.x == 0 && firstScreenFrame.origin.y == 0);
|
||||
|
||||
for (NSScreen* screen in NSScreen.screens)
|
||||
{
|
||||
NSRect frame = screen.frame;
|
||||
NSRect visibleFrame = screen.visibleFrame;
|
||||
ConvertNSRect(&frame);
|
||||
ConvertNSRect(&visibleFrame);
|
||||
|
||||
ImGuiPlatformMonitor imgui_monitor;
|
||||
imgui_monitor.MainPos = ImVec2(frame.origin.x, frame.origin.y);
|
||||
imgui_monitor.MainSize = ImVec2(frame.size.width, frame.size.height);
|
||||
imgui_monitor.WorkPos = ImVec2(visibleFrame.origin.x, visibleFrame.origin.y);
|
||||
imgui_monitor.WorkSize = ImVec2(visibleFrame.size.width, visibleFrame.size.height);
|
||||
imgui_monitor.DpiScale = screen.backingScaleFactor;
|
||||
imgui_monitor.PlatformHandle = (__bridge_retained void*)screen;
|
||||
|
||||
platform_io.Monitors.push_back(imgui_monitor);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_InitMultiViewportSupport()
|
||||
{
|
||||
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplOSX_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplOSX_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplOSX_ShowWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplOSX_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplOSX_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplOSX_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplOSX_GetWindowSize;
|
||||
platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplOSX_GetWindowFramebufferScale;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplOSX_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplOSX_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplOSX_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplOSX_SetWindowTitle;
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplOSX_SetWindowAlpha;
|
||||
platform_io.Platform_GetWindowDpiScale = ImGui_ImplOSX_GetWindowDpiScale; // FIXME-DPI
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplOSX_ViewportData* vd = IM_NEW(ImGui_ImplOSX_ViewportData)();
|
||||
vd->Window = bd->Window;
|
||||
vd->WindowOwned = false;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
main_viewport->PlatformHandle = (__bridge void*)bd->Window;
|
||||
|
||||
[NSNotificationCenter.defaultCenter addObserver:bd->Observer
|
||||
selector:@selector(displaysDidChange:)
|
||||
name:NSApplicationDidChangeScreenParametersNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
static void ImGui_ImplOSX_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData();
|
||||
[NSNotificationCenter.defaultCenter removeObserver:bd->Observer
|
||||
name:NSApplicationDidChangeScreenParametersNotification
|
||||
object:nil];
|
||||
bd->Observer = nullptr;
|
||||
bd->Window = nullptr;
|
||||
if (bd->Monitor != nullptr)
|
||||
{
|
||||
[NSEvent removeMonitor:bd->Monitor];
|
||||
bd->Monitor = nullptr;
|
||||
}
|
||||
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplOSX_ViewportData* vd = (ImGui_ImplOSX_ViewportData*)main_viewport->PlatformUserData;
|
||||
IM_DELETE(vd);
|
||||
main_viewport->PlatformUserData = nullptr;
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features or Issues:
|
||||
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -21,13 +25,18 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733)
|
||||
// 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps.
|
||||
// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
|
||||
// 2025-04-09: [Docking] Revert update monitors and work areas information every frame. Only do it on Windows. (#8415, #8558)
|
||||
// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
|
||||
// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
|
||||
// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
|
||||
// 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650)
|
||||
// 2025-02-25: [Docking] Revert to use SDL_GetDisplayBounds() for WorkPos/WorkRect if SDL_GetDisplayUsableBounds() failed.
|
||||
// 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
|
||||
// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415)
|
||||
// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
|
||||
// 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler.
|
||||
// 2025-01-20: Made ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_Manual) accept an empty array.
|
||||
@@ -68,7 +77,7 @@
|
||||
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
|
||||
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
|
||||
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
|
||||
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
|
||||
// 2021-06:29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
|
||||
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
|
||||
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
|
||||
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
|
||||
@@ -110,6 +119,7 @@
|
||||
#endif
|
||||
|
||||
// SDL
|
||||
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
#include <stdio.h> // for snprintf()
|
||||
@@ -126,22 +136,31 @@
|
||||
#else
|
||||
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
|
||||
#endif
|
||||
#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5)
|
||||
#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
|
||||
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
|
||||
#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9)
|
||||
#define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14)
|
||||
#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18)
|
||||
#if SDL_HAS_VULKAN
|
||||
#include <SDL_vulkan.h>
|
||||
#else
|
||||
static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
|
||||
#endif
|
||||
|
||||
// SDL Data
|
||||
struct ImGui_ImplSDL2_Data
|
||||
{
|
||||
SDL_Window* Window;
|
||||
Uint32 WindowID;
|
||||
Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID.
|
||||
SDL_Renderer* Renderer;
|
||||
Uint64 Time;
|
||||
char* ClipboardTextData;
|
||||
char BackendPlatformName[48];
|
||||
bool UseVulkan;
|
||||
bool WantUpdateMonitors;
|
||||
|
||||
// Mouse handling
|
||||
Uint32 MouseWindowID;
|
||||
@@ -151,6 +170,7 @@ struct ImGui_ImplSDL2_Data
|
||||
int MouseLastLeaveFrame;
|
||||
bool MouseCanUseGlobalState;
|
||||
bool MouseCanUseCapture;
|
||||
bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state.
|
||||
|
||||
// Gamepad handling
|
||||
ImVector<SDL_GameController*> Gamepads;
|
||||
@@ -169,6 +189,11 @@ static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplSDL2_UpdateMonitors();
|
||||
static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context);
|
||||
static void ImGui_ImplSDL2_ShutdownMultiViewportSupport();
|
||||
|
||||
// Functions
|
||||
static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*)
|
||||
{
|
||||
@@ -185,13 +210,13 @@ static void ImGui_ImplSDL2_SetClipboardText(ImGuiContext*, const char* text)
|
||||
}
|
||||
|
||||
// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
|
||||
static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data)
|
||||
static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
|
||||
{
|
||||
if (data->WantVisible)
|
||||
{
|
||||
SDL_Rect r;
|
||||
r.x = (int)data->InputPos.x;
|
||||
r.y = (int)data->InputPos.y;
|
||||
r.x = (int)(data->InputPos.x - viewport->Pos.x);
|
||||
r.y = (int)(data->InputPos.y - viewport->Pos.y + data->InputLineHeight);
|
||||
r.w = 1;
|
||||
r.h = (int)data->InputLineHeight;
|
||||
SDL_SetTextInputRect(&r);
|
||||
@@ -357,15 +382,13 @@ static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
|
||||
|
||||
static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id)
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr;
|
||||
return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id);
|
||||
}
|
||||
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
@@ -379,6 +402,13 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == nullptr)
|
||||
return false;
|
||||
ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
int window_x, window_y;
|
||||
SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y);
|
||||
mouse_pos.x += window_x;
|
||||
mouse_pos.y += window_y;
|
||||
}
|
||||
io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
|
||||
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
|
||||
return true;
|
||||
@@ -430,20 +460,32 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
{
|
||||
if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == nullptr)
|
||||
ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID);
|
||||
if (viewport == nullptr)
|
||||
return false;
|
||||
//IMGUI_DEBUG_LOG("SDL_KEY%s : key=0x%08X ('%s'), scancode=%d ('%s'), mod=%X, windowID=%d, viewport=%08X\n",
|
||||
// (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod, event->key.windowID, viewport ? viewport->ID : 0);
|
||||
ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
|
||||
//IMGUI_DEBUG_LOG("SDL_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n",
|
||||
// (event->type == SDL_KEYDOWN) ? "DOWN" : "UP ", event->key.keysym.sym, SDL_GetKeyName(event->key.keysym.sym), event->key.keysym.scancode, SDL_GetScancodeName(event->key.keysym.scancode), event->key.keysym.mod);
|
||||
ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode);
|
||||
io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
|
||||
io.SetKeyEventNativeData(key, (int)event->key.keysym.sym, (int)event->key.keysym.scancode, (int)event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
||||
return true;
|
||||
}
|
||||
#if SDL_HAS_DISPLAY_EVENT
|
||||
case SDL_DISPLAYEVENT:
|
||||
{
|
||||
// 2.0.26 has SDL_DISPLAYEVENT_CONNECTED/SDL_DISPLAYEVENT_DISCONNECTED/SDL_DISPLAYEVENT_ORIENTATION,
|
||||
// so change of DPI/Scaling are not reflected in this event. (SDL3 has it)
|
||||
bd->WantUpdateMonitors = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
case SDL_WINDOWEVENT:
|
||||
{
|
||||
if (ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID) == nullptr)
|
||||
ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID);
|
||||
if (viewport == NULL)
|
||||
return false;
|
||||
|
||||
// - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right.
|
||||
// - However we won't get a correct LEAVE event for a captured window.
|
||||
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
|
||||
@@ -457,10 +499,18 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
|
||||
}
|
||||
if (window_event == SDL_WINDOWEVENT_LEAVE)
|
||||
bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1;
|
||||
//if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) { IMGUI_DEBUG_LOG("SDL_WINDOWEVENT_FOCUS_GAINED: windowId %d, viewport: %08X\n", event->window.windowID, viewport ? viewport->ID : 0); }
|
||||
//if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) { IMGUI_DEBUG_LOG("SDL_WINDOWEVENT_FOCUS_LOST: windowId %d, viewport: %08X\n", event->window.windowID, viewport ? viewport->ID : 0); }
|
||||
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
io.AddFocusEvent(true);
|
||||
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
if (window_event == SDL_WINDOWEVENT_FOCUS_LOST)
|
||||
io.AddFocusEvent(false);
|
||||
if (window_event == SDL_WINDOWEVENT_CLOSE)
|
||||
viewport->PlatformRequestClose = true;
|
||||
if (window_event == SDL_WINDOWEVENT_MOVED)
|
||||
viewport->PlatformRequestMove = true;
|
||||
if (window_event == SDL_WINDOWEVENT_RESIZED)
|
||||
viewport->PlatformRequestResize = true;
|
||||
return true;
|
||||
}
|
||||
case SDL_CONTROLLERDEVICEADDED:
|
||||
@@ -484,6 +534,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IMGUI_CHECKVERSION();
|
||||
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
|
||||
//SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2");
|
||||
|
||||
// Obtain compiled and runtime versions
|
||||
SDL_version ver_compiled;
|
||||
@@ -499,11 +550,20 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
io.BackendPlatformName = bd->BackendPlatformName;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
// (ImGuiBackendFlags_PlatformHasViewports may be set just below)
|
||||
|
||||
bd->Window = window;
|
||||
bd->WindowID = SDL_GetWindowID(window);
|
||||
bd->Renderer = renderer;
|
||||
|
||||
// SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
|
||||
// We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame.
|
||||
#ifndef __APPLE__
|
||||
bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState;
|
||||
#else
|
||||
bd->MouseCanReportHoveredViewport = false;
|
||||
#endif
|
||||
|
||||
// Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse()
|
||||
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||
bd->MouseCanUseGlobalState = false;
|
||||
@@ -515,6 +575,8 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
if (strncmp(sdl_backend, item, strlen(item)) == 0)
|
||||
bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true;
|
||||
#endif
|
||||
if (bd->MouseCanUseGlobalState)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
|
||||
@@ -527,6 +589,9 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; };
|
||||
#endif
|
||||
|
||||
// Update monitor a first time during init
|
||||
ImGui_ImplSDL2_UpdateMonitors();
|
||||
|
||||
// Gamepad handling
|
||||
bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst;
|
||||
bd->WantUpdateGamepadsList = true;
|
||||
@@ -581,7 +646,11 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
|
||||
#endif
|
||||
|
||||
(void)sdl_gl_context; // Unused in 'master' branch.
|
||||
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
|
||||
// We left the call to ImGui_ImplSDL2_InitMultiViewportSupport() outside of #ifdef to avoid unused-function warnings.
|
||||
if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
|
||||
ImGui_ImplSDL2_InitMultiViewportSupport(window, sdl_gl_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -595,7 +664,11 @@ bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
|
||||
#if !SDL_HAS_VULKAN
|
||||
IM_ASSERT(0 && "Unsupported");
|
||||
#endif
|
||||
return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
|
||||
if (!ImGui_ImplSDL2_Init(window, nullptr, nullptr))
|
||||
return false;
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
bd->UseVulkan = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
|
||||
@@ -629,6 +702,8 @@ void ImGui_ImplSDL2_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDL2_ShutdownMultiViewportSupport();
|
||||
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
@@ -637,10 +712,11 @@ void ImGui_ImplSDL2_Shutdown()
|
||||
|
||||
io.BackendPlatformName = nullptr;
|
||||
io.BackendPlatformUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
|
||||
static void ImGui_ImplSDL2_UpdateMouseData()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
@@ -660,27 +736,57 @@ static void ImGui_ImplSDL2_UpdateMouseData()
|
||||
}
|
||||
|
||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||
const bool is_app_focused = (bd->Window == focused_window);
|
||||
const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL2_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL));
|
||||
#else
|
||||
SDL_Window* focused_window = bd->Window;
|
||||
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
|
||||
#endif
|
||||
|
||||
if (is_app_focused)
|
||||
{
|
||||
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||
{
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y);
|
||||
else
|
||||
#endif
|
||||
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
|
||||
}
|
||||
|
||||
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
|
||||
const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0;
|
||||
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode)
|
||||
{
|
||||
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||
int window_x, window_y, mouse_x_global, mouse_y_global;
|
||||
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||
SDL_GetWindowPosition(bd->Window, &window_x, &window_y);
|
||||
io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
|
||||
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
||||
int mouse_x, mouse_y, window_x, window_y;
|
||||
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
|
||||
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
|
||||
{
|
||||
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
|
||||
mouse_x -= window_x;
|
||||
mouse_y -= window_y;
|
||||
}
|
||||
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
|
||||
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
|
||||
// - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
|
||||
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
|
||||
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
|
||||
// by the backend, and use its flawed heuristic to guess the viewport behind.
|
||||
// - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
|
||||
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
|
||||
{
|
||||
ImGuiID mouse_viewport_id = 0;
|
||||
if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL2_GetViewportForWindowID(bd->MouseWindowID))
|
||||
mouse_viewport_id = mouse_viewport->ID;
|
||||
io.AddMouseViewportEvent(mouse_viewport_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_UpdateMouseCursor()
|
||||
@@ -832,6 +938,38 @@ static void ImGui_ImplSDL2_UpdateGamepads()
|
||||
ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||
}
|
||||
|
||||
// FIXME: Note that doesn't update with DPI/Scaling change only as SDL2 doesn't have an event for it (SDL3 has).
|
||||
static void ImGui_ImplSDL2_UpdateMonitors()
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Monitors.resize(0);
|
||||
bd->WantUpdateMonitors = false;
|
||||
int display_count = SDL_GetNumVideoDisplays();
|
||||
for (int n = 0; n < display_count; n++)
|
||||
{
|
||||
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
|
||||
ImGuiPlatformMonitor monitor;
|
||||
SDL_Rect r;
|
||||
SDL_GetDisplayBounds(n, &r);
|
||||
monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
|
||||
monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
|
||||
#if SDL_HAS_USABLE_DISPLAY_BOUNDS
|
||||
if (SDL_GetDisplayUsableBounds(n, &r) == 0 && r.w > 0 && r.h > 0)
|
||||
{
|
||||
monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
|
||||
monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
|
||||
}
|
||||
#endif
|
||||
float dpi_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(n);
|
||||
if (dpi_scale <= 0.0f)
|
||||
continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
|
||||
monitor.DpiScale = dpi_scale;
|
||||
monitor.PlatformHandle = (void*)(intptr_t)n;
|
||||
platform_io.Monitors.push_back(monitor);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window, SDL_Renderer* renderer, ImVec2* out_size, ImVec2* out_framebuffer_scale)
|
||||
{
|
||||
int w, h;
|
||||
@@ -862,6 +1000,13 @@ void ImGui_ImplSDL2_NewFrame()
|
||||
// Setup main viewport size (every frame to accommodate for window resizing)
|
||||
ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(bd->Window, bd->Renderer, &io.DisplaySize, &io.DisplayFramebufferScale);
|
||||
|
||||
// Update monitors
|
||||
#ifdef WIN32
|
||||
bd->WantUpdateMonitors = true; // Keep polling under Windows to handle changes of work area when resizing task-bar (#8415)
|
||||
#endif
|
||||
if (bd->WantUpdateMonitors)
|
||||
ImGui_ImplSDL2_UpdateMonitors();
|
||||
|
||||
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
||||
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
@@ -878,6 +1023,13 @@ void ImGui_ImplSDL2_NewFrame()
|
||||
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||
}
|
||||
|
||||
// Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
|
||||
// Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects.
|
||||
if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
|
||||
else
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport;
|
||||
|
||||
ImGui_ImplSDL2_UpdateMouseData();
|
||||
ImGui_ImplSDL2_UpdateMouseCursor();
|
||||
|
||||
@@ -885,6 +1037,266 @@ void ImGui_ImplSDL2_NewFrame()
|
||||
ImGui_ImplSDL2_UpdateGamepads();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplSDL2_ViewportData
|
||||
{
|
||||
SDL_Window* Window;
|
||||
Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID.
|
||||
bool WindowOwned;
|
||||
SDL_GLContext GLContext;
|
||||
|
||||
ImGui_ImplSDL2_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; }
|
||||
~ImGui_ImplSDL2_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
|
||||
ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplSDL2_ViewportData* main_viewport_data = (ImGui_ImplSDL2_ViewportData*)main_viewport->PlatformUserData;
|
||||
|
||||
// Share GL resources with main context
|
||||
bool use_opengl = (main_viewport_data->GLContext != nullptr);
|
||||
SDL_GLContext backup_context = nullptr;
|
||||
if (use_opengl)
|
||||
{
|
||||
backup_context = SDL_GL_GetCurrentContext();
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
||||
SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext);
|
||||
}
|
||||
|
||||
Uint32 sdl_flags = 0;
|
||||
sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0);
|
||||
sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
sdl_flags |= SDL_WINDOW_HIDDEN;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
|
||||
#if !defined(_WIN32)
|
||||
// See SDL hack in ImGui_ImplSDL2_ShowWindow().
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_SKIP_TASKBAR : 0;
|
||||
#endif
|
||||
#if SDL_HAS_ALWAYS_ON_TOP
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
|
||||
#endif
|
||||
vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Pos.x, (int)viewport->Pos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
|
||||
vd->WindowOwned = true;
|
||||
if (use_opengl)
|
||||
{
|
||||
vd->GLContext = SDL_GL_CreateContext(vd->Window);
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
if (use_opengl && backup_context)
|
||||
SDL_GL_MakeCurrent(vd->Window, backup_context);
|
||||
|
||||
viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(vd->Window);
|
||||
viewport->PlatformHandleRaw = nullptr;
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWindowWMInfo(vd->Window, &info))
|
||||
{
|
||||
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
|
||||
viewport->PlatformHandleRaw = info.info.win.window;
|
||||
#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
|
||||
viewport->PlatformHandleRaw = (void*)info.info.cocoa.window;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
if (ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
if (vd->GLContext && vd->WindowOwned)
|
||||
SDL_GL_DeleteContext(vd->GLContext);
|
||||
if (vd->Window && vd->WindowOwned)
|
||||
SDL_DestroyWindow(vd->Window);
|
||||
vd->GLContext = nullptr;
|
||||
vd->Window = nullptr;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)))
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
|
||||
// SDL hack: Hide icon from task bar
|
||||
// Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition.
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
|
||||
{
|
||||
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
ex_style &= ~WS_EX_APPWINDOW;
|
||||
ex_style |= WS_EX_TOOLWINDOW;
|
||||
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT
|
||||
SDL_SetHint(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "1" : "0");
|
||||
#elif defined(_WIN32)
|
||||
// SDL hack: SDL always activate/focus windows :/
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
|
||||
{
|
||||
::ShowWindow(hwnd, SW_SHOWNA);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SDL_ShowWindow(vd->Window);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
int x = 0, y = 0;
|
||||
SDL_GetWindowPosition(vd->Window, &x, &y);
|
||||
return ImVec2((float)x, (float)y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
int w = 0, h = 0;
|
||||
SDL_GetWindowSize(vd->Window, &w, &h);
|
||||
return ImVec2((float)w, (float)h);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL2_GetWindowFramebufferScale(ImGuiViewport* viewport)
|
||||
{
|
||||
// FIXME: SDL_Renderer does not support multi-viewport.
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
ImVec2 framebuffer_scale;
|
||||
ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, nullptr, &framebuffer_scale);
|
||||
return framebuffer_scale;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowTitle(vd->Window, title);
|
||||
}
|
||||
|
||||
#if SDL_HAS_WINDOW_ALPHA
|
||||
static void ImGui_ImplSDL2_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowOpacity(vd->Window, alpha);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ImGui_ImplSDL2_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_RaiseWindow(vd->Window);
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL2_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL2_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
if (vd->GLContext)
|
||||
SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
if (vd->GLContext)
|
||||
{
|
||||
SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
|
||||
SDL_GL_SwapWindow(vd->Window);
|
||||
}
|
||||
}
|
||||
|
||||
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
|
||||
// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
|
||||
#if SDL_HAS_VULKAN
|
||||
#include <SDL_vulkan.h>
|
||||
static int ImGui_ImplSDL2_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
|
||||
{
|
||||
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
|
||||
(void)vk_allocator;
|
||||
SDL_bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (VkSurfaceKHR*)out_vk_surface);
|
||||
return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY
|
||||
}
|
||||
#endif // SDL_HAS_VULKAN
|
||||
|
||||
static void ImGui_ImplSDL2_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplSDL2_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplSDL2_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplSDL2_ShowWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplSDL2_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplSDL2_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplSDL2_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplSDL2_GetWindowSize;
|
||||
platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplSDL2_GetWindowFramebufferScale;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplSDL2_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplSDL2_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL2_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplSDL2_SetWindowTitle;
|
||||
platform_io.Platform_RenderWindow = ImGui_ImplSDL2_RenderWindow;
|
||||
platform_io.Platform_SwapBuffers = ImGui_ImplSDL2_SwapBuffers;
|
||||
#if SDL_HAS_WINDOW_ALPHA
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL2_SetWindowAlpha;
|
||||
#endif
|
||||
#if SDL_HAS_VULKAN
|
||||
platform_io.Platform_CreateVkSurface = ImGui_ImplSDL2_CreateVkSurface;
|
||||
#endif
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplSDL2_ViewportData* vd = IM_NEW(ImGui_ImplSDL2_ViewportData)();
|
||||
vd->Window = window;
|
||||
vd->WindowID = SDL_GetWindowID(window);
|
||||
vd->WindowOwned = false;
|
||||
vd->GLContext = sdl_gl_context;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL2_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
// Missing features or Issues:
|
||||
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
// [ ] Platform: Multi-viewport: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: IME support.
|
||||
// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
|
||||
// Missing features or Issues:
|
||||
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -20,18 +23,25 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727)
|
||||
// 2025-05-15: [Docking] Add Platform_GetWindowFramebufferScale() handler, to allow varying Retina display density on multiple monitors.
|
||||
// 2025-05-06: [Docking] macOS: fixed secondary viewports not appearing on other monitors before of parenting.
|
||||
// 2025-04-09: [Docking] Revert update monitors and work areas information every frame. Only do it on Windows. (#8415, #8558)
|
||||
// 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible.
|
||||
// 2025-04-09: Don't attempt to call SDL_CaptureMouse() on drivers where we don't call SDL_GetGlobalMouseState(). (#8561)
|
||||
// 2025-03-30: Update for SDL3 api changes: Revert SDL_GetClipboardText() memory ownership change. (#8530, #7801)
|
||||
// 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set.
|
||||
// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
|
||||
// 2025-02-26: Only start SDL_CaptureMouse() when mouse is being dragged, to mitigate issues with e.g.Linux debuggers not claiming capture back. (#6410, #3650)
|
||||
// 2025-02-25: [Docking] Revert to use SDL_GetDisplayBounds() for WorkPos/WorkRect if SDL_GetDisplayUsableBounds() failed.
|
||||
// 2025-02-24: Avoid calling SDL_GetGlobalMouseState() when mouse is in relative mode.
|
||||
// 2025-02-21: [Docking] Update monitors and work areas information every frame, as the later may change regardless of monitor changes. (#8415)
|
||||
// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
|
||||
// 2025-02-10: Using SDL_OpenURL() in platform_io.Platform_OpenInShellFn handler.
|
||||
// 2025-01-20: Made ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_Manual) accept an empty array.
|
||||
// 2024-10-24: Emscripten: SDL_EVENT_MOUSE_WHEEL event doesn't require dividing by 100.0f on Emscripten.
|
||||
// 2024-09-11: (Docking) Added support for viewport->ParentViewportId field to support parenting at OS level. (#7973)
|
||||
// 2024-09-03: Update for SDL3 api changes: SDL_GetGamepads() memory ownership revert. (#7918, #7898, #7807)
|
||||
// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
|
||||
// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
|
||||
@@ -105,6 +115,8 @@ struct ImGui_ImplSDL3_Data
|
||||
Uint64 Time;
|
||||
char* ClipboardTextData;
|
||||
char BackendPlatformName[48];
|
||||
bool UseVulkan;
|
||||
bool WantUpdateMonitors;
|
||||
|
||||
// IME handling
|
||||
SDL_Window* ImeWindow;
|
||||
@@ -117,11 +129,12 @@ struct ImGui_ImplSDL3_Data
|
||||
int MousePendingLeaveFrame;
|
||||
bool MouseCanUseGlobalState;
|
||||
bool MouseCanUseCapture;
|
||||
bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state.
|
||||
|
||||
// Gamepad handling
|
||||
ImVector<SDL_Gamepad*> Gamepads;
|
||||
ImVector<SDL_Gamepad*> Gamepads;
|
||||
ImGui_ImplSDL3_GamepadMode GamepadMode;
|
||||
bool WantUpdateGamepadsList;
|
||||
bool WantUpdateGamepadsList;
|
||||
|
||||
ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
@@ -135,6 +148,11 @@ static ImGui_ImplSDL3_Data* ImGui_ImplSDL3_GetBackendData()
|
||||
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL3_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
|
||||
}
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplSDL3_UpdateMonitors();
|
||||
static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context);
|
||||
static void ImGui_ImplSDL3_ShutdownMultiViewportSupport();
|
||||
|
||||
// Functions
|
||||
static const char* ImGui_ImplSDL3_GetClipboardText(ImGuiContext*)
|
||||
{
|
||||
@@ -163,8 +181,8 @@ static void ImGui_ImplSDL3_PlatformSetImeData(ImGuiContext*, ImGuiViewport* view
|
||||
if (data->WantVisible)
|
||||
{
|
||||
SDL_Rect r;
|
||||
r.x = (int)data->InputPos.x;
|
||||
r.y = (int)data->InputPos.y;
|
||||
r.x = (int)(data->InputPos.x - viewport->Pos.x);
|
||||
r.y = (int)(data->InputPos.y - viewport->Pos.y + data->InputLineHeight);
|
||||
r.w = 1;
|
||||
r.h = (int)data->InputLineHeight;
|
||||
SDL_SetTextInputArea(window, &r, 0);
|
||||
@@ -336,18 +354,15 @@ static void ImGui_ImplSDL3_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
|
||||
io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL_KMOD_GUI) != 0);
|
||||
}
|
||||
|
||||
|
||||
static ImGuiViewport* ImGui_ImplSDL3_GetViewportForWindowID(SDL_WindowID window_id)
|
||||
{
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
return (window_id == bd->WindowID) ? ImGui::GetMainViewport() : nullptr;
|
||||
return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id);
|
||||
}
|
||||
|
||||
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
||||
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
|
||||
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
|
||||
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
||||
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
||||
bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event)
|
||||
{
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
@@ -361,6 +376,13 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event)
|
||||
if (ImGui_ImplSDL3_GetViewportForWindowID(event->motion.windowID) == nullptr)
|
||||
return false;
|
||||
ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
int window_x, window_y;
|
||||
SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y);
|
||||
mouse_pos.x += window_x;
|
||||
mouse_pos.y += window_y;
|
||||
}
|
||||
io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
|
||||
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
|
||||
return true;
|
||||
@@ -404,16 +426,26 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event)
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
{
|
||||
if (ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID) == nullptr)
|
||||
ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->key.windowID);
|
||||
if (viewport == nullptr)
|
||||
return false;
|
||||
//IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=0x%08X ('%s'), scancode=%d ('%s'), mod=%X, windowID=%d, viewport=%08X\n",
|
||||
// (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod, event->key.windowID, viewport ? viewport->ID : 0);
|
||||
ImGui_ImplSDL3_UpdateKeyModifiers((SDL_Keymod)event->key.mod);
|
||||
//IMGUI_DEBUG_LOG("SDL_EVENT_KEY_%s : key=%d ('%s'), scancode=%d ('%s'), mod=%X\n",
|
||||
// (event->type == SDL_EVENT_KEY_DOWN) ? "DOWN" : "UP ", event->key.key, SDL_GetKeyName(event->key.key), event->key.scancode, SDL_GetScancodeName(event->key.scancode), event->key.mod);
|
||||
ImGuiKey key = ImGui_ImplSDL3_KeyEventToImGuiKey(event->key.key, event->key.scancode);
|
||||
io.AddKeyEvent(key, (event->type == SDL_EVENT_KEY_DOWN));
|
||||
io.SetKeyEventNativeData(key, (int)event->key.key, (int)event->key.scancode, (int)event->key.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
||||
return true;
|
||||
}
|
||||
case SDL_EVENT_DISPLAY_ORIENTATION:
|
||||
case SDL_EVENT_DISPLAY_ADDED:
|
||||
case SDL_EVENT_DISPLAY_REMOVED:
|
||||
case SDL_EVENT_DISPLAY_MOVED:
|
||||
case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED:
|
||||
{
|
||||
bd->WantUpdateMonitors = true;
|
||||
return true;
|
||||
}
|
||||
case SDL_EVENT_WINDOW_MOUSE_ENTER:
|
||||
{
|
||||
if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr)
|
||||
@@ -436,11 +468,28 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event)
|
||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||
{
|
||||
if (ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID) == nullptr)
|
||||
ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID);
|
||||
if (viewport == nullptr)
|
||||
return false;
|
||||
//IMGUI_DEBUG_LOG("%s: windowId %d, viewport: %08X\n", (event->type == SDL_EVENT_WINDOW_FOCUS_GAINED) ? "SDL_EVENT_WINDOW_FOCUS_GAINED" : "SDL_WINDOWEVENT_FOCUS_LOST", event->window.windowID, viewport ? viewport->ID : 0);
|
||||
io.AddFocusEvent(event->type == SDL_EVENT_WINDOW_FOCUS_GAINED);
|
||||
return true;
|
||||
}
|
||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||
case SDL_EVENT_WINDOW_MOVED:
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
{
|
||||
ImGuiViewport* viewport = ImGui_ImplSDL3_GetViewportForWindowID(event->window.windowID);
|
||||
if (viewport == NULL)
|
||||
return false;
|
||||
if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED)
|
||||
viewport->PlatformRequestClose = true;
|
||||
if (event->type == SDL_EVENT_WINDOW_MOVED)
|
||||
viewport->PlatformRequestMove = true;
|
||||
if (event->type == SDL_EVENT_WINDOW_RESIZED)
|
||||
viewport->PlatformRequestResize = true;
|
||||
return true;
|
||||
}
|
||||
case SDL_EVENT_GAMEPAD_ADDED:
|
||||
case SDL_EVENT_GAMEPAD_REMOVED:
|
||||
{
|
||||
@@ -470,6 +519,7 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
IMGUI_CHECKVERSION();
|
||||
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
|
||||
IM_UNUSED(sdl_gl_context); // Unused in this branch
|
||||
//SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2");
|
||||
|
||||
const int ver_linked = SDL_GetVersion();
|
||||
|
||||
@@ -481,11 +531,20 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
io.BackendPlatformName = bd->BackendPlatformName;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
// (ImGuiBackendFlags_PlatformHasViewports may be set just below)
|
||||
|
||||
bd->Window = window;
|
||||
bd->WindowID = SDL_GetWindowID(window);
|
||||
bd->Renderer = renderer;
|
||||
|
||||
// SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
|
||||
// We will use 'MouseCanReportHoveredViewport' to set 'ImGuiBackendFlags_HasMouseHoveredViewport' dynamically each frame.
|
||||
#ifndef __APPLE__
|
||||
bd->MouseCanReportHoveredViewport = bd->MouseCanUseGlobalState;
|
||||
#else
|
||||
bd->MouseCanReportHoveredViewport = false;
|
||||
#endif
|
||||
|
||||
// Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse()
|
||||
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
||||
bd->MouseCanUseGlobalState = false;
|
||||
@@ -497,6 +556,8 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
if (strncmp(sdl_backend, item, strlen(item)) == 0)
|
||||
bd->MouseCanUseGlobalState = bd->MouseCanUseCapture = true;
|
||||
#endif
|
||||
if (bd->MouseCanUseGlobalState)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL3_SetClipboardText;
|
||||
@@ -504,6 +565,9 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
platform_io.Platform_SetImeDataFn = ImGui_ImplSDL3_PlatformSetImeData;
|
||||
platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { return SDL_OpenURL(url) == 0; };
|
||||
|
||||
// Update monitor a first time during init
|
||||
ImGui_ImplSDL3_UpdateMonitors();
|
||||
|
||||
// Gamepad handling
|
||||
bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst;
|
||||
bd->WantUpdateGamepadsList = true;
|
||||
@@ -530,28 +594,36 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
|
||||
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
|
||||
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
|
||||
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
|
||||
// you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
|
||||
#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
|
||||
// you can ignore SDL_EVENT_MOUSE_BUTTON_DOWN events coming right after a SDL_EVENT_WINDOW_FOCUS_GAINED)
|
||||
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
|
||||
#endif
|
||||
|
||||
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
|
||||
#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE
|
||||
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
|
||||
#endif
|
||||
|
||||
// SDL 3.x : see https://github.com/libsdl-org/SDL/issues/6659
|
||||
SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "0");
|
||||
|
||||
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
|
||||
// We left the call to ImGui_ImplSDL3_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
|
||||
if (io.BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
|
||||
ImGui_ImplSDL3_InitMultiViewportSupport(window, sdl_gl_context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should technically be a SDL_GLContext but due to typedef it is sane to keep it void* in public interface.
|
||||
bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
|
||||
return ImGui_ImplSDL3_Init(window, nullptr, sdl_gl_context);
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window)
|
||||
{
|
||||
return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
|
||||
if (!ImGui_ImplSDL3_Init(window, nullptr, nullptr))
|
||||
return false;
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
bd->UseVulkan = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window)
|
||||
@@ -590,6 +662,8 @@ void ImGui_ImplSDL3_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDL3_ShutdownMultiViewportSupport();
|
||||
|
||||
if (bd->ClipboardTextData)
|
||||
SDL_free(bd->ClipboardTextData);
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
@@ -598,10 +672,11 @@ void ImGui_ImplSDL3_Shutdown()
|
||||
|
||||
io.BackendPlatformName = nullptr;
|
||||
io.BackendPlatformUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
|
||||
static void ImGui_ImplSDL3_UpdateMouseData()
|
||||
{
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
@@ -621,7 +696,7 @@ static void ImGui_ImplSDL3_UpdateMouseData()
|
||||
}
|
||||
|
||||
SDL_Window* focused_window = SDL_GetKeyboardFocus();
|
||||
const bool is_app_focused = (bd->Window == focused_window);
|
||||
const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL3_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL));
|
||||
#else
|
||||
SDL_Window* focused_window = bd->Window;
|
||||
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
|
||||
@@ -630,20 +705,48 @@ static void ImGui_ImplSDL3_UpdateMouseData()
|
||||
{
|
||||
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
|
||||
if (io.WantSetMousePos)
|
||||
SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y);
|
||||
{
|
||||
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
SDL_WarpMouseGlobal(io.MousePos.x, io.MousePos.y);
|
||||
else
|
||||
#endif
|
||||
SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y);
|
||||
}
|
||||
|
||||
// (Optional) Fallback to provide mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured)
|
||||
const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode(bd->Window);
|
||||
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode)
|
||||
{
|
||||
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||
float mouse_x_global, mouse_y_global;
|
||||
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
||||
float mouse_x, mouse_y;
|
||||
int window_x, window_y;
|
||||
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
|
||||
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
|
||||
io.AddMousePosEvent(mouse_x_global - window_x, mouse_y_global - window_y);
|
||||
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
|
||||
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
|
||||
{
|
||||
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
|
||||
mouse_x -= window_x;
|
||||
mouse_y -= window_y;
|
||||
}
|
||||
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
|
||||
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
|
||||
// - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
|
||||
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
|
||||
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
|
||||
// by the backend, and use its flawed heuristic to guess the viewport behind.
|
||||
// - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
|
||||
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
|
||||
{
|
||||
ImGuiID mouse_viewport_id = 0;
|
||||
if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL3_GetViewportForWindowID(bd->MouseWindowID))
|
||||
mouse_viewport_id = mouse_viewport->ID;
|
||||
io.AddMouseViewportEvent(mouse_viewport_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_UpdateMouseCursor()
|
||||
@@ -775,6 +878,38 @@ static void ImGui_ImplSDL3_UpdateGamepads()
|
||||
ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_UpdateMonitors()
|
||||
{
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Monitors.resize(0);
|
||||
bd->WantUpdateMonitors = false;
|
||||
|
||||
int display_count;
|
||||
SDL_DisplayID* displays = SDL_GetDisplays(&display_count);
|
||||
for (int n = 0; n < display_count; n++)
|
||||
{
|
||||
// Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
|
||||
SDL_DisplayID display_id = displays[n];
|
||||
ImGuiPlatformMonitor monitor;
|
||||
SDL_Rect r;
|
||||
SDL_GetDisplayBounds(display_id, &r);
|
||||
monitor.MainPos = monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
|
||||
monitor.MainSize = monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
|
||||
if (SDL_GetDisplayUsableBounds(display_id, &r) && r.w > 0 && r.h > 0)
|
||||
{
|
||||
monitor.WorkPos = ImVec2((float)r.x, (float)r.y);
|
||||
monitor.WorkSize = ImVec2((float)r.w, (float)r.h);
|
||||
}
|
||||
monitor.DpiScale = SDL_GetDisplayContentScale(display_id); // See https://wiki.libsdl.org/SDL3/README-highdpi for details.
|
||||
monitor.PlatformHandle = (void*)(intptr_t)n;
|
||||
if (monitor.DpiScale <= 0.0f)
|
||||
continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
|
||||
platform_io.Monitors.push_back(monitor);
|
||||
}
|
||||
SDL_free(displays);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(SDL_Window* window, ImVec2* out_size, ImVec2* out_framebuffer_scale)
|
||||
{
|
||||
int w, h;
|
||||
@@ -798,6 +933,13 @@ void ImGui_ImplSDL3_NewFrame()
|
||||
// Setup main viewport size (every frame to accommodate for window resizing)
|
||||
ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale);
|
||||
|
||||
// Update monitors
|
||||
#ifdef WIN32
|
||||
bd->WantUpdateMonitors = true; // Keep polling under Windows to handle changes of work area when resizing task-bar (#8415)
|
||||
#endif
|
||||
if (bd->WantUpdateMonitors)
|
||||
ImGui_ImplSDL3_UpdateMonitors();
|
||||
|
||||
// Setup time step (we could also use SDL_GetTicksNS() available since SDL3)
|
||||
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
|
||||
static Uint64 frequency = SDL_GetPerformanceFrequency();
|
||||
@@ -814,6 +956,13 @@ void ImGui_ImplSDL3_NewFrame()
|
||||
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
|
||||
}
|
||||
|
||||
// Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
|
||||
// Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects.
|
||||
if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
|
||||
else
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasMouseHoveredViewport;
|
||||
|
||||
ImGui_ImplSDL3_UpdateMouseData();
|
||||
ImGui_ImplSDL3_UpdateMouseCursor();
|
||||
|
||||
@@ -821,6 +970,273 @@ void ImGui_ImplSDL3_NewFrame()
|
||||
ImGui_ImplSDL3_UpdateGamepads();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplSDL3_ViewportData
|
||||
{
|
||||
SDL_Window* Window;
|
||||
SDL_Window* ParentWindow;
|
||||
Uint32 WindowID; // Stored in ImGuiViewport::PlatformHandle. Use SDL_GetWindowFromID() to get SDL_Window* from Uint32 WindowID.
|
||||
bool WindowOwned;
|
||||
SDL_GLContext GLContext;
|
||||
|
||||
ImGui_ImplSDL3_ViewportData() { Window = ParentWindow = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; }
|
||||
~ImGui_ImplSDL3_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); }
|
||||
};
|
||||
|
||||
static SDL_Window* ImGui_ImplSDL3_GetSDLWindowFromViewportID(ImGuiID viewport_id)
|
||||
{
|
||||
if (viewport_id != 0)
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByID(viewport_id))
|
||||
{
|
||||
SDL_WindowID window_id = (SDL_WindowID)(intptr_t)viewport->PlatformHandle;
|
||||
return SDL_GetWindowFromID(window_id);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
|
||||
ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
vd->ParentWindow = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId);
|
||||
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplSDL3_ViewportData* main_viewport_data = (ImGui_ImplSDL3_ViewportData*)main_viewport->PlatformUserData;
|
||||
|
||||
// Share GL resources with main context
|
||||
bool use_opengl = (main_viewport_data->GLContext != nullptr);
|
||||
SDL_GLContext backup_context = nullptr;
|
||||
if (use_opengl)
|
||||
{
|
||||
backup_context = SDL_GL_GetCurrentContext();
|
||||
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
|
||||
SDL_GL_MakeCurrent(main_viewport_data->Window, main_viewport_data->GLContext);
|
||||
}
|
||||
|
||||
SDL_WindowFlags sdl_flags = 0;
|
||||
sdl_flags |= SDL_WINDOW_HIDDEN;
|
||||
sdl_flags |= use_opengl ? SDL_WINDOW_OPENGL : (bd->UseVulkan ? SDL_WINDOW_VULKAN : 0);
|
||||
sdl_flags |= SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_HIGH_PIXEL_DENSITY;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) ? SDL_WINDOW_UTILITY : 0;
|
||||
sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0;
|
||||
vd->Window = SDL_CreateWindow("No Title Yet", (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags);
|
||||
#ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor
|
||||
SDL_SetWindowParent(vd->Window, vd->ParentWindow);
|
||||
#endif
|
||||
SDL_SetWindowPosition(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
|
||||
vd->WindowOwned = true;
|
||||
if (use_opengl)
|
||||
{
|
||||
vd->GLContext = SDL_GL_CreateContext(vd->Window);
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
if (use_opengl && backup_context)
|
||||
SDL_GL_MakeCurrent(vd->Window, backup_context);
|
||||
|
||||
ImGui_ImplSDL3_SetupPlatformHandles(viewport, vd->Window);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
if (ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
if (vd->GLContext && vd->WindowOwned)
|
||||
SDL_GL_DestroyContext(vd->GLContext);
|
||||
if (vd->Window && vd->WindowOwned)
|
||||
SDL_DestroyWindow(vd->Window);
|
||||
vd->GLContext = nullptr;
|
||||
vd->Window = nullptr;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)))
|
||||
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
|
||||
|
||||
// SDL hack: Show icon in task bar (#7989)
|
||||
// Note: SDL_WINDOW_UTILITY can be used to control task bar visibility, but on Windows, it does not affect child windows.
|
||||
if (!(viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon))
|
||||
{
|
||||
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
ex_style |= WS_EX_APPWINDOW;
|
||||
ex_style &= ~WS_EX_TOOLWINDOW;
|
||||
::ShowWindow(hwnd, SW_HIDE);
|
||||
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, "1"); // Otherwise new window appear under
|
||||
#else
|
||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "0" : "1");
|
||||
#endif
|
||||
SDL_ShowWindow(vd->Window);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_UpdateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
IM_UNUSED(vd);
|
||||
|
||||
#ifndef __APPLE__ // On Mac, SDL3 Parenting appears to prevent viewport from appearing in another monitor
|
||||
// Update SDL3 parent if it changed _after_ creation.
|
||||
// This is for advanced apps that are manipulating ParentViewportID manually.
|
||||
SDL_Window* new_parent = ImGui_ImplSDL3_GetSDLWindowFromViewportID(viewport->ParentViewportId);
|
||||
if (new_parent != vd->ParentWindow)
|
||||
{
|
||||
vd->ParentWindow = new_parent;
|
||||
SDL_SetWindowParent(vd->Window, vd->ParentWindow);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL3_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
int x = 0, y = 0;
|
||||
SDL_GetWindowPosition(vd->Window, &x, &y);
|
||||
return ImVec2((float)x, (float)y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL3_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
int w = 0, h = 0;
|
||||
SDL_GetWindowSize(vd->Window, &w, &h);
|
||||
return ImVec2((float)w, (float)h);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplSDL3_GetWindowFramebufferScale(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
ImVec2 framebuffer_scale;
|
||||
ImGui_ImplSDL3_GetWindowSizeAndFramebufferScale(vd->Window, nullptr, &framebuffer_scale);
|
||||
return framebuffer_scale;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowTitle(vd->Window, title);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_SetWindowOpacity(vd->Window, alpha);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
SDL_RaiseWindow(vd->Window);
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL3_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplSDL3_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
return (SDL_GetWindowFlags(vd->Window) & SDL_WINDOW_MINIMIZED) != 0;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
if (vd->GLContext)
|
||||
SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
if (vd->GLContext)
|
||||
{
|
||||
SDL_GL_MakeCurrent(vd->Window, vd->GLContext);
|
||||
SDL_GL_SwapWindow(vd->Window);
|
||||
}
|
||||
}
|
||||
|
||||
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
|
||||
// SDL is graceful enough to _not_ need <vulkan/vulkan.h> so we can safely include this.
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
static int ImGui_ImplSDL3_CreateVkSurface(ImGuiViewport* viewport, ImU64 vk_instance, const void* vk_allocator, ImU64* out_vk_surface)
|
||||
{
|
||||
ImGui_ImplSDL3_ViewportData* vd = (ImGui_ImplSDL3_ViewportData*)viewport->PlatformUserData;
|
||||
(void)vk_allocator;
|
||||
bool ret = SDL_Vulkan_CreateSurface(vd->Window, (VkInstance)vk_instance, (const VkAllocationCallbacks*)vk_allocator, (VkSurfaceKHR*)out_vk_surface);
|
||||
return ret ? 0 : 1; // ret ? VK_SUCCESS : VK_NOT_READY
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_InitMultiViewportSupport(SDL_Window* window, void* sdl_gl_context)
|
||||
{
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplSDL3_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplSDL3_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplSDL3_ShowWindow;
|
||||
platform_io.Platform_UpdateWindow = ImGui_ImplSDL3_UpdateWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplSDL3_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplSDL3_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplSDL3_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplSDL3_GetWindowSize;
|
||||
platform_io.Platform_GetWindowFramebufferScale = ImGui_ImplSDL3_GetWindowFramebufferScale;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplSDL3_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplSDL3_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplSDL3_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplSDL3_SetWindowTitle;
|
||||
platform_io.Platform_RenderWindow = ImGui_ImplSDL3_RenderWindow;
|
||||
platform_io.Platform_SwapBuffers = ImGui_ImplSDL3_SwapBuffers;
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplSDL3_SetWindowAlpha;
|
||||
platform_io.Platform_CreateVkSurface = ImGui_ImplSDL3_CreateVkSurface;
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplSDL3_ViewportData* vd = IM_NEW(ImGui_ImplSDL3_ViewportData)();
|
||||
vd->Window = window;
|
||||
vd->WindowID = SDL_GetWindowID(window);
|
||||
vd->WindowOwned = false;
|
||||
vd->GLContext = (SDL_GLContext)sdl_gl_context;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDL3_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: IME support.
|
||||
// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
|
||||
// Missing features or Issues:
|
||||
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
|
||||
// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
@@ -22,6 +23,7 @@
|
||||
// Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info.
|
||||
|
||||
// CHANGELOG
|
||||
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2025-08-08: *BREAKING* Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988)
|
||||
// 2025-08-08: Expose SamplerDefault and SamplerCurrent in ImGui_ImplSDLGPU3_RenderState. Allow callback to change sampler.
|
||||
// 2025-06-25: Mapping transfer buffer for texture update use cycle=true. Fixes artifacts e.g. on Metal backend.
|
||||
@@ -614,6 +616,9 @@ void ImGui_ImplSDLGPU3_DestroyDeviceObjects()
|
||||
if (bd->Pipeline) { SDL_ReleaseGPUGraphicsPipeline(v->Device, bd->Pipeline); bd->Pipeline = nullptr; }
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLGPU3_InitMultiViewportSupport();
|
||||
static void ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport();
|
||||
|
||||
bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
@@ -626,12 +631,15 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info)
|
||||
io.BackendRendererName = "imgui_impl_sdlgpu3";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
IM_ASSERT(info->Device != nullptr);
|
||||
IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID);
|
||||
|
||||
bd->InitInfo = *info;
|
||||
|
||||
ImGui_ImplSDLGPU3_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -641,10 +649,11 @@ void ImGui_ImplSDLGPU3_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport();
|
||||
ImGui_ImplSDLGPU3_DestroyDeviceObjects();
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -657,4 +666,75 @@ void ImGui_ImplSDLGPU3_NewFrame()
|
||||
ImGui_ImplSDLGPU3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplSDLGPU3_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData();
|
||||
SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle);
|
||||
SDL_ClaimWindowForGPUDevice(data->InitInfo.Device, window);
|
||||
viewport->RendererUserData = (void*)1;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLGPU3_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData();
|
||||
SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle);
|
||||
|
||||
ImDrawData* draw_data = viewport->DrawData;
|
||||
|
||||
SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(data->InitInfo.Device);
|
||||
|
||||
SDL_GPUTexture* swapchain_texture;
|
||||
SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr);
|
||||
|
||||
if (swapchain_texture != nullptr)
|
||||
{
|
||||
ImGui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer); // FIXME-OPT: Not optimal, may this be done earlier?
|
||||
SDL_GPUColorTargetInfo target_info = {};
|
||||
target_info.texture = swapchain_texture;
|
||||
target_info.clear_color = SDL_FColor{ 0.0f,0.0f,0.0f,1.0f };
|
||||
target_info.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||
target_info.store_op = SDL_GPU_STOREOP_STORE;
|
||||
target_info.mip_level = 0;
|
||||
target_info.layer_or_depth_plane = 0;
|
||||
target_info.cycle = false;
|
||||
SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &target_info, 1, nullptr);
|
||||
ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass);
|
||||
SDL_EndGPURenderPass(render_pass);
|
||||
}
|
||||
|
||||
SDL_SubmitGPUCommandBuffer(command_buffer);
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLGPU3_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplSDLGPU3_Data* data = ImGui_ImplSDLGPU3_GetBackendData();
|
||||
if (viewport->RendererUserData)
|
||||
{
|
||||
SDL_Window* window = SDL_GetWindowFromID((SDL_WindowID)(intptr_t)viewport->PlatformHandle);
|
||||
SDL_ReleaseWindowFromGPUDevice(data->InitInfo.Device, window);
|
||||
}
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLGPU3_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplSDLGPU3_RenderWindow;
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplSDLGPU3_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplSDLGPU3_DestroyWindow;
|
||||
}
|
||||
|
||||
static void ImGui_ImplSDLGPU3_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// Missing features:
|
||||
// [ ] Renderer: Multi-viewport support (multiple windows).
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
|
||||
|
||||
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
@@ -27,6 +28,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-07-27: Vulkan: Fixed texture update corruption introduced on 2025-06-11. (#8801, #8755, #8840)
|
||||
// 2025-07-07: Vulkan: Fixed texture synchronization issue introduced on 2025-06-11. (#8772)
|
||||
// 2025-06-27: Vulkan: Fixed validation errors during texture upload/update by aligning upload size to 'nonCoherentAtomSize'. (#8743, #8744)
|
||||
@@ -115,6 +117,7 @@ void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulka
|
||||
void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_DestroyFrame(VkDevice device, ImGui_ImplVulkanH_Frame* fd, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH_FrameSemaphores* fsd, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator);
|
||||
void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator);
|
||||
|
||||
@@ -131,15 +134,18 @@ static bool g_FunctionsLoaded = true;
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateCommandBuffers) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateDescriptorSets) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAllocateMemory) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkAcquireNextImageKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBeginCommandBuffer) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindBufferMemory) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkBindImageMemory) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBeginRenderPass) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindDescriptorSets) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindIndexBuffer) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindPipeline) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdBindVertexBuffers) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdCopyBufferToImage) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdDrawIndexed) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdEndRenderPass) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPipelineBarrier) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdPushConstants) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkCmdSetScissor) \
|
||||
@@ -191,8 +197,10 @@ static bool g_FunctionsLoaded = true;
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceFormatsKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfacePresentModesKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetPhysicalDeviceSurfaceSupportKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkGetSwapchainImagesKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkMapMemory) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueuePresentKHR) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueSubmit) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkQueueWaitIdle) \
|
||||
IMGUI_VULKAN_FUNC_MAP_MACRO(vkResetCommandPool) \
|
||||
@@ -243,6 +251,20 @@ struct ImGui_ImplVulkan_Texture
|
||||
ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
// For multi-viewport support:
|
||||
// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplVulkan_ViewportData
|
||||
{
|
||||
ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only
|
||||
ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports
|
||||
bool WindowOwned;
|
||||
bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame
|
||||
bool SwapChainSuboptimal; // Flag when VK_SUBOPTIMAL_KHR was returned.
|
||||
|
||||
ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = SwapChainSuboptimal = false; memset((void*)&RenderBuffers, 0, sizeof(RenderBuffers)); }
|
||||
~ImGui_ImplVulkan_ViewportData() { }
|
||||
};
|
||||
|
||||
// Vulkan data
|
||||
struct ImGui_ImplVulkan_Data
|
||||
{
|
||||
@@ -252,7 +274,8 @@ struct ImGui_ImplVulkan_Data
|
||||
VkPipelineCreateFlags PipelineCreateFlags;
|
||||
VkDescriptorSetLayout DescriptorSetLayout;
|
||||
VkPipelineLayout PipelineLayout;
|
||||
VkPipeline Pipeline;
|
||||
VkPipeline Pipeline; // pipeline for main render pass (created by app)
|
||||
VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend)
|
||||
VkShaderModule ShaderModuleVert;
|
||||
VkShaderModule ShaderModuleFrag;
|
||||
VkDescriptorPool DescriptorPool;
|
||||
@@ -277,6 +300,10 @@ struct ImGui_ImplVulkan_Data
|
||||
// SHADERS
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplVulkan_InitMultiViewportSupport();
|
||||
static void ImGui_ImplVulkan_ShutdownMultiViewportSupport();
|
||||
|
||||
// backends/vulkan/glsl_shader.vert, compiled with:
|
||||
// # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
||||
/*
|
||||
@@ -521,8 +548,10 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
|
||||
if (pipeline == VK_NULL_HANDLE)
|
||||
pipeline = bd->Pipeline;
|
||||
|
||||
// Allocate array to store enough vertex/index buffers
|
||||
ImGui_ImplVulkan_WindowRenderBuffers* wrb = &bd->MainWindowRenderBuffers;
|
||||
// Allocate array to store enough vertex/index buffers. Each unique viewport gets its own storage.
|
||||
ImGui_ImplVulkan_ViewportData* viewport_renderer_data = (ImGui_ImplVulkan_ViewportData*)draw_data->OwnerViewport->RendererUserData;
|
||||
IM_ASSERT(viewport_renderer_data != nullptr);
|
||||
ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers;
|
||||
if (wrb->FrameRenderBuffers.Size == 0)
|
||||
{
|
||||
wrb->Index = 0;
|
||||
@@ -1121,7 +1150,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
|
||||
ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator);
|
||||
|
||||
// Destroy all textures
|
||||
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||
@@ -1136,6 +1165,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
|
||||
if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
|
||||
if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
|
||||
if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
|
||||
if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; }
|
||||
if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; }
|
||||
}
|
||||
|
||||
@@ -1228,6 +1258,7 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
||||
io.BackendRendererName = "imgui_impl_vulkan";
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
|
||||
|
||||
IM_ASSERT(info->Instance != VK_NULL_HANDLE);
|
||||
IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE);
|
||||
@@ -1262,6 +1293,12 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
||||
if (!ImGui_ImplVulkan_CreateDeviceObjects())
|
||||
IM_ASSERT(0 && "ImGui_ImplVulkan_CreateDeviceObjects() failed!"); // <- Can't be hit yet.
|
||||
|
||||
// Our render function expect RendererUserData to be storing the window render buffer we need (for the main viewport we won't use ->Window)
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->RendererUserData = IM_NEW(ImGui_ImplVulkan_ViewportData)();
|
||||
|
||||
ImGui_ImplVulkan_InitMultiViewportSupport();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1271,14 +1308,24 @@ void ImGui_ImplVulkan_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
// First destroy objects in all viewports
|
||||
ImGui_ImplVulkan_DestroyDeviceObjects();
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
IM_FREE((void*)const_cast<VkFormat*>(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats));
|
||||
#endif
|
||||
|
||||
// Manually delete main viewport render data in-case we haven't initialized for viewports
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)main_viewport->RendererUserData)
|
||||
IM_DELETE(vd);
|
||||
main_viewport->RendererUserData = nullptr;
|
||||
|
||||
// Clean up windows
|
||||
ImGui_ImplVulkan_ShutdownMultiViewportSupport();
|
||||
|
||||
io.BackendRendererName = nullptr;
|
||||
io.BackendRendererUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures | ImGuiBackendFlags_RendererHasViewports);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -1296,10 +1343,12 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
|
||||
if (bd->VulkanInitInfo.MinImageCount == min_image_count)
|
||||
return;
|
||||
|
||||
IM_ASSERT(0); // FIXME-VIEWPORT: Unsupported. Need to recreate all swap chains!
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
VkResult err = vkDeviceWaitIdle(v->Device);
|
||||
check_vk_result(err);
|
||||
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &bd->MainWindowRenderBuffers, v->Allocator);
|
||||
ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator);
|
||||
|
||||
bd->VulkanInitInfo.MinImageCount = min_image_count;
|
||||
}
|
||||
|
||||
@@ -1576,8 +1625,6 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
|
||||
wd->ImageCount = 0;
|
||||
if (wd->RenderPass)
|
||||
vkDestroyRenderPass(device, wd->RenderPass, allocator);
|
||||
if (wd->Pipeline)
|
||||
vkDestroyPipeline(device, wd->Pipeline, allocator);
|
||||
|
||||
// If min image count was not specified, request different count of images dependent on selected present mode
|
||||
if (min_image_count == 0)
|
||||
@@ -1729,6 +1776,7 @@ void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevic
|
||||
IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!");
|
||||
(void)instance;
|
||||
ImGui_ImplVulkanH_CreateWindowSwapChain(physical_device, device, wd, allocator, width, height, min_image_count);
|
||||
//ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, g_VulkanInitInfo.Subpass);
|
||||
ImGui_ImplVulkanH_CreateWindowCommandBuffers(physical_device, device, wd, queue_family, allocator);
|
||||
|
||||
// FIXME: to submit the command buffer, we need a queue. In the examples folder, the ImGui_ImplVulkanH_CreateOrResizeWindow function is called
|
||||
@@ -1819,7 +1867,6 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui
|
||||
ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator);
|
||||
wd->Frames.clear();
|
||||
wd->FrameSemaphores.clear();
|
||||
vkDestroyPipeline(device, wd->Pipeline, allocator);
|
||||
vkDestroyRenderPass(device, wd->RenderPass, allocator);
|
||||
vkDestroySwapchainKHR(device, wd->Swapchain, allocator);
|
||||
vkDestroySurfaceKHR(instance, wd->Surface, allocator);
|
||||
@@ -1847,6 +1894,296 @@ void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH
|
||||
fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(VkDevice device, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
for (int n = 0; n < platform_io.Viewports.Size; n++)
|
||||
if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)platform_io.Viewports[n]->RendererUserData)
|
||||
ImGui_ImplVulkan_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)();
|
||||
viewport->RendererUserData = vd;
|
||||
ImGui_ImplVulkanH_Window* wd = &vd->Window;
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
|
||||
// Create surface
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface);
|
||||
check_vk_result(err);
|
||||
|
||||
// Check for WSI support
|
||||
VkBool32 res;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res);
|
||||
if (res != VK_TRUE)
|
||||
{
|
||||
IM_ASSERT(0); // Error: no WSI support on physical device
|
||||
return;
|
||||
}
|
||||
|
||||
// Select Surface Format
|
||||
ImVector<VkFormat> requestSurfaceImageFormats;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
for (uint32_t n = 0; n < v->PipelineRenderingCreateInfo.colorAttachmentCount; n++)
|
||||
requestSurfaceImageFormats.push_back(v->PipelineRenderingCreateInfo.pColorAttachmentFormats[n]);
|
||||
#endif
|
||||
const VkFormat defaultFormats[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
|
||||
for (VkFormat format : defaultFormats)
|
||||
requestSurfaceImageFormats.push_back(format);
|
||||
|
||||
const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
|
||||
wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, wd->Surface, requestSurfaceImageFormats.Data, (size_t)requestSurfaceImageFormats.Size, requestSurfaceColorSpace);
|
||||
|
||||
// Select Present Mode
|
||||
// FIXME-VULKAN: Even thought mailbox seems to get us maximum framerate with a single window, it halves framerate with a second window etc. (w/ Nvidia and SDK 1.82.1)
|
||||
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
|
||||
wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(v->PhysicalDevice, wd->Surface, &present_modes[0], IM_ARRAYSIZE(present_modes));
|
||||
//printf("[vulkan] Secondary window selected PresentMode = %d\n", wd->PresentMode);
|
||||
|
||||
// Create SwapChain, RenderPass, Framebuffer, etc.
|
||||
wd->ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true;
|
||||
wd->UseDynamicRendering = v->UseDynamicRendering;
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount);
|
||||
vd->WindowOwned = true;
|
||||
|
||||
// Create pipeline (shared by all secondary viewports)
|
||||
if (bd->PipelineForViewports == VK_NULL_HANDLE)
|
||||
ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &bd->PipelineForViewports, 0);
|
||||
}
|
||||
|
||||
static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
if (ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData)
|
||||
{
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
if (vd->WindowOwned)
|
||||
ImGui_ImplVulkanH_DestroyWindow(v->Instance, v->Device, &vd->Window, v->Allocator);
|
||||
ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator);
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->RendererUserData = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplVulkan_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
|
||||
if (vd == nullptr) // This is nullptr for the main viewport (which is left to the user/app to handle)
|
||||
return;
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
vd->Window.ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true;
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, &vd->Window, v->QueueFamily, v->Allocator, (int)size.x, (int)size.y, v->MinImageCount);
|
||||
}
|
||||
|
||||
static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
|
||||
ImGui_ImplVulkanH_Window* wd = &vd->Window;
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
VkResult err;
|
||||
|
||||
if (vd->SwapChainNeedRebuild || vd->SwapChainSuboptimal)
|
||||
{
|
||||
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount);
|
||||
vd->SwapChainNeedRebuild = vd->SwapChainSuboptimal = false;
|
||||
}
|
||||
|
||||
ImGui_ImplVulkanH_Frame* fd = nullptr;
|
||||
ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
|
||||
{
|
||||
{
|
||||
err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex);
|
||||
if (err == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
vd->SwapChainNeedRebuild = true; // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame.
|
||||
return;
|
||||
}
|
||||
if (err == VK_SUBOPTIMAL_KHR)
|
||||
vd->SwapChainSuboptimal = true;
|
||||
else
|
||||
check_vk_result(err);
|
||||
fd = &wd->Frames[wd->FrameIndex];
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
err = vkWaitForFences(v->Device, 1, &fd->Fence, VK_TRUE, 100);
|
||||
if (err == VK_SUCCESS) break;
|
||||
if (err == VK_TIMEOUT) continue;
|
||||
check_vk_result(err);
|
||||
}
|
||||
{
|
||||
err = vkResetCommandPool(v->Device, fd->CommandPool, 0);
|
||||
check_vk_result(err);
|
||||
VkCommandBufferBeginInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
|
||||
check_vk_result(err);
|
||||
}
|
||||
{
|
||||
ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
memcpy(&wd->ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
|
||||
}
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
if (v->UseDynamicRendering)
|
||||
{
|
||||
// Transition swapchain image to a layout suitable for drawing.
|
||||
VkImageMemoryBarrier barrier = {};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
barrier.image = fd->Backbuffer;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_NONE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
VkRenderingAttachmentInfo attachmentInfo = {};
|
||||
attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
|
||||
attachmentInfo.imageView = fd->BackbufferView;
|
||||
attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachmentInfo.resolveMode = VK_RESOLVE_MODE_NONE;
|
||||
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentInfo.clearValue = wd->ClearValue;
|
||||
|
||||
VkRenderingInfo renderingInfo = {};
|
||||
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
|
||||
renderingInfo.renderArea.extent.width = wd->Width;
|
||||
renderingInfo.renderArea.extent.height = wd->Height;
|
||||
renderingInfo.layerCount = 1;
|
||||
renderingInfo.viewMask = 0;
|
||||
renderingInfo.colorAttachmentCount = 1;
|
||||
renderingInfo.pColorAttachments = &attachmentInfo;
|
||||
|
||||
ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR(fd->CommandBuffer, &renderingInfo);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
VkRenderPassBeginInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
info.renderPass = wd->RenderPass;
|
||||
info.framebuffer = fd->Framebuffer;
|
||||
info.renderArea.extent.width = wd->Width;
|
||||
info.renderArea.extent.height = wd->Height;
|
||||
info.clearValueCount = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? 0 : 1;
|
||||
info.pClearValues = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? nullptr : &wd->ClearValue;
|
||||
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui_ImplVulkan_RenderDrawData(viewport->DrawData, fd->CommandBuffer, bd->PipelineForViewports);
|
||||
|
||||
{
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
if (v->UseDynamicRendering)
|
||||
{
|
||||
ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR(fd->CommandBuffer);
|
||||
|
||||
// Transition image to a layout suitable for presentation
|
||||
VkImageMemoryBarrier barrier = {};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
barrier.image = fd->Backbuffer;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(fd->CommandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
vkCmdEndRenderPass(fd->CommandBuffer);
|
||||
}
|
||||
{
|
||||
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkSubmitInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
info.waitSemaphoreCount = 1;
|
||||
info.pWaitSemaphores = &fsd->ImageAcquiredSemaphore;
|
||||
info.pWaitDstStageMask = &wait_stage;
|
||||
info.commandBufferCount = 1;
|
||||
info.pCommandBuffers = &fd->CommandBuffer;
|
||||
info.signalSemaphoreCount = 1;
|
||||
info.pSignalSemaphores = &fsd->RenderCompleteSemaphore;
|
||||
|
||||
err = vkEndCommandBuffer(fd->CommandBuffer);
|
||||
check_vk_result(err);
|
||||
err = vkResetFences(v->Device, 1, &fd->Fence);
|
||||
check_vk_result(err);
|
||||
err = vkQueueSubmit(v->Queue, 1, &info, fd->Fence);
|
||||
check_vk_result(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_ViewportData* vd = (ImGui_ImplVulkan_ViewportData*)viewport->RendererUserData;
|
||||
ImGui_ImplVulkanH_Window* wd = &vd->Window;
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
|
||||
if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering
|
||||
return;
|
||||
|
||||
VkResult err;
|
||||
uint32_t present_index = wd->FrameIndex;
|
||||
|
||||
ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
|
||||
VkPresentInfoKHR info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
info.waitSemaphoreCount = 1;
|
||||
info.pWaitSemaphores = &fsd->RenderCompleteSemaphore;
|
||||
info.swapchainCount = 1;
|
||||
info.pSwapchains = &wd->Swapchain;
|
||||
info.pImageIndices = &present_index;
|
||||
err = vkQueuePresentKHR(v->Queue, &info);
|
||||
if (err == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
vd->SwapChainNeedRebuild = true;
|
||||
return;
|
||||
}
|
||||
if (err == VK_SUBOPTIMAL_KHR)
|
||||
vd->SwapChainSuboptimal = true;
|
||||
else
|
||||
check_vk_result(err);
|
||||
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
|
||||
}
|
||||
|
||||
void ImGui_ImplVulkan_InitMultiViewportSupport()
|
||||
{
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
if (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_PlatformHasViewports)
|
||||
IM_ASSERT(platform_io.Platform_CreateVkSurface != nullptr && "Platform needs to setup the CreateVkSurface handler.");
|
||||
platform_io.Renderer_CreateWindow = ImGui_ImplVulkan_CreateWindow;
|
||||
platform_io.Renderer_DestroyWindow = ImGui_ImplVulkan_DestroyWindow;
|
||||
platform_io.Renderer_SetWindowSize = ImGui_ImplVulkan_SetWindowSize;
|
||||
platform_io.Renderer_RenderWindow = ImGui_ImplVulkan_RenderWindow;
|
||||
platform_io.Renderer_SwapBuffers = ImGui_ImplVulkan_SwapBuffers;
|
||||
}
|
||||
|
||||
void ImGui_ImplVulkan_ShutdownMultiViewportSupport()
|
||||
{
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // #ifndef IMGUI_DISABLE
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
// [x] Renderer: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
|
||||
|
||||
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
|
||||
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
|
||||
@@ -163,8 +164,8 @@ struct ImGui_ImplVulkanH_Frame;
|
||||
struct ImGui_ImplVulkanH_Window;
|
||||
|
||||
// Helpers
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wnd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wnd, const VkAllocationCallbacks* allocator);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_CreateOrResizeWindow(VkInstance instance, VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator, int w, int h, uint32_t min_image_count);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui_ImplVulkanH_Window* wd, const VkAllocationCallbacks* allocator);
|
||||
IMGUI_IMPL_API VkSurfaceFormatKHR ImGui_ImplVulkanH_SelectSurfaceFormat(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkFormat* request_formats, int request_formats_count, VkColorSpaceKHR request_color_space);
|
||||
IMGUI_IMPL_API VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VkPresentModeKHR* request_modes, int request_modes_count);
|
||||
IMGUI_IMPL_API VkPhysicalDevice ImGui_ImplVulkanH_SelectPhysicalDevice(VkInstance instance);
|
||||
@@ -201,7 +202,6 @@ struct ImGui_ImplVulkanH_Window
|
||||
VkSurfaceFormatKHR SurfaceFormat;
|
||||
VkPresentModeKHR PresentMode;
|
||||
VkRenderPass RenderPass;
|
||||
VkPipeline Pipeline; // The window pipeline may uses a different VkRenderPass than the one passed in ImGui_ImplVulkan_InitInfo
|
||||
bool UseDynamicRendering;
|
||||
bool ClearEnable;
|
||||
VkClearValue ClearValue;
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
// [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: 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.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
// [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: 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.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
@@ -21,9 +22,16 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (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-06-02: [Docking] WM_DPICHANGED also apply io.ConfigDpiScaleViewports for main viewport instead of letting it be done by application code.
|
||||
// 2025-04-30: Inputs: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594)
|
||||
// 2025-03-26: [Docking] Viewports: fixed an issue when closing a window from the OS close button (with io.ConfigViewportsNoDecoration = false) while user code was discarding the 'bool* p_open = false' output from Begin(). Because we allowed the Win32 window to close early, Windows destroyed it and our imgui window became not visible even though user code was still submitting it.
|
||||
// 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468)
|
||||
// 2025-02-21: [Docking] WM_SETTINGCHANGE's SPI_SETWORKAREA message also triggers a refresh of monitor list. (#8415)
|
||||
// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
|
||||
// 2024-11-21: [Docking] Fixed a crash when multiple processes are running with multi-viewports, caused by misusage of GetProp(). (#8162, #8069)
|
||||
// 2024-10-28: [Docking] Rely on property stored inside HWND to retrieve context/viewport, should facilitate attempt to use this for parallel contexts. (#8069)
|
||||
// 2024-09-16: [Docking] Inputs: fixed an issue where a viewport destroyed while clicking would hog mouse tracking and temporary lead to incorrect update of HoveredWindow. (#7971)
|
||||
// 2024-07-08: Inputs: Fixed ImGuiMod_Super being mapped to VK_APPS instead of VK_LWIN||VK_RWIN. (#7768)
|
||||
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
|
||||
// 2023-09-25: Inputs: Synthesize key-down event on key-up for VK_SNAPSHOT / ImGuiKey_PrintScreen as Windows doesn't emit it (same behavior as GLFW/SDL).
|
||||
@@ -106,6 +114,11 @@ typedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*);
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
|
||||
#endif
|
||||
|
||||
// Forward Declarations
|
||||
static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc);
|
||||
static void ImGui_ImplWin32_ShutdownMultiViewportSupport();
|
||||
static void ImGui_ImplWin32_UpdateMonitors();
|
||||
|
||||
struct ImGui_ImplWin32_Data
|
||||
{
|
||||
HWND hWnd;
|
||||
@@ -116,6 +129,7 @@ struct ImGui_ImplWin32_Data
|
||||
INT64 TicksPerSecond;
|
||||
ImGuiMouseCursor LastMouseCursor;
|
||||
UINT32 KeyboardCodePage;
|
||||
bool WantUpdateMonitors;
|
||||
|
||||
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
bool HasGamepad;
|
||||
@@ -170,6 +184,8 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc)
|
||||
io.BackendPlatformName = "imgui_impl_win32";
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
|
||||
|
||||
bd->hWnd = (HWND)hwnd;
|
||||
bd->TicksPerSecond = perf_frequency;
|
||||
@@ -177,10 +193,17 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc)
|
||||
bd->LastMouseCursor = ImGuiMouseCursor_COUNT;
|
||||
ImGui_ImplWin32_UpdateKeyboardCodePage(io);
|
||||
|
||||
// Set platform dependent data in viewport
|
||||
// Update monitor a first time during init
|
||||
ImGui_ImplWin32_UpdateMonitors();
|
||||
|
||||
// Our mouse update function expect PlatformHandle to be filled for the main viewport
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd;
|
||||
IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch
|
||||
|
||||
// Be aware that GetPropA()/SetPropA() may be accessed from other processes.
|
||||
// So as we store a pointer in IMGUI_CONTEXT we need to make sure we only call GetPropA() on windows owned by our process.
|
||||
::SetPropA(bd->hWnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext());
|
||||
ImGui_ImplWin32_InitMultiViewportSupport(platform_has_own_dc);
|
||||
|
||||
// Dynamically load XInput library
|
||||
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
@@ -223,6 +246,9 @@ void ImGui_ImplWin32_Shutdown()
|
||||
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
::SetPropA(bd->hWnd, "IMGUI_CONTEXT", nullptr);
|
||||
ImGui_ImplWin32_ShutdownMultiViewportSupport();
|
||||
|
||||
// Unload XInput library
|
||||
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
|
||||
if (bd->XInputDLL)
|
||||
@@ -231,7 +257,7 @@ void ImGui_ImplWin32_Shutdown()
|
||||
|
||||
io.BackendPlatformName = nullptr;
|
||||
io.BackendPlatformUserData = nullptr;
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
|
||||
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad | ImGuiBackendFlags_PlatformHasViewports | ImGuiBackendFlags_HasMouseHoveredViewport);
|
||||
IM_DELETE(bd);
|
||||
}
|
||||
|
||||
@@ -303,32 +329,69 @@ static void ImGui_ImplWin32_UpdateKeyModifiers(ImGuiIO& io)
|
||||
io.AddKeyEvent(ImGuiMod_Super, IsVkDown(VK_LWIN) || IsVkDown(VK_RWIN));
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io)
|
||||
static ImGuiViewport* ImGui_ImplWin32_FindViewportByPlatformHandle(ImGuiPlatformIO& platform_io, HWND hwnd)
|
||||
{
|
||||
// We cannot use ImGui::FindViewportByPlatformHandle() because it doesn't take a context.
|
||||
// When called from ImGui_ImplWin32_WndProcHandler_PlatformWindow() we don't assume that context is bound.
|
||||
//return ImGui::FindViewportByPlatformHandle((void*)hwnd);
|
||||
for (ImGuiViewport* viewport : platform_io.Viewports)
|
||||
if (viewport->PlatformHandle == hwnd)
|
||||
return viewport;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
|
||||
// Because of that, it is a little more complicated than your typical single-viewport binding code!
|
||||
static void ImGui_ImplWin32_UpdateMouseData(ImGuiIO& io, ImGuiPlatformIO& platform_io)
|
||||
{
|
||||
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(io);
|
||||
IM_ASSERT(bd->hWnd != 0);
|
||||
|
||||
POINT mouse_screen_pos;
|
||||
bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0;
|
||||
|
||||
HWND focused_window = ::GetForegroundWindow();
|
||||
const bool is_app_focused = (focused_window == bd->hWnd);
|
||||
const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, focused_window)));
|
||||
if (is_app_focused)
|
||||
{
|
||||
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
|
||||
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
|
||||
if (::ClientToScreen(bd->hWnd, &pos))
|
||||
::SetCursorPos(pos.x, pos.y);
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
|
||||
::ClientToScreen(focused_window, &pos);
|
||||
::SetCursorPos(pos.x, pos.y);
|
||||
}
|
||||
|
||||
// (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
|
||||
// This also fills a short gap when clicking non-client area: WM_NCMOUSELEAVE -> modal OS move -> gap -> WM_NCMOUSEMOVE
|
||||
if (!io.WantSetMousePos && bd->MouseTrackedArea == 0)
|
||||
if (!io.WantSetMousePos && bd->MouseTrackedArea == 0 && has_mouse_screen_pos)
|
||||
{
|
||||
POINT pos;
|
||||
if (::GetCursorPos(&pos) && ::ScreenToClient(bd->hWnd, &pos))
|
||||
io.AddMousePosEvent((float)pos.x, (float)pos.y);
|
||||
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
|
||||
// (This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.)
|
||||
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
|
||||
// (This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.)
|
||||
POINT mouse_pos = mouse_screen_pos;
|
||||
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
|
||||
::ScreenToClient(bd->hWnd, &mouse_pos);
|
||||
io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
|
||||
}
|
||||
}
|
||||
|
||||
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
|
||||
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
|
||||
// - [X] Win32 backend correctly ignore viewports with the _NoInputs flag (here using ::WindowFromPoint with WM_NCHITTEST + HTTRANSPARENT in WndProc does that)
|
||||
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
|
||||
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
|
||||
// by the backend, and use its flawed heuristic to guess the viewport behind.
|
||||
// - [X] Win32 backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
|
||||
ImGuiID mouse_viewport_id = 0;
|
||||
if (has_mouse_screen_pos)
|
||||
if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
|
||||
if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hovered_hwnd))
|
||||
mouse_viewport_id = viewport->ID;
|
||||
io.AddMouseViewportEvent(mouse_viewport_id);
|
||||
}
|
||||
|
||||
// Gamepad navigation mapping
|
||||
@@ -387,16 +450,50 @@ static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io)
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc(HMONITOR monitor, HDC, LPRECT, LPARAM)
|
||||
{
|
||||
MONITORINFO info = {};
|
||||
info.cbSize = sizeof(MONITORINFO);
|
||||
if (!::GetMonitorInfo(monitor, &info))
|
||||
return TRUE;
|
||||
ImGuiPlatformMonitor imgui_monitor;
|
||||
imgui_monitor.MainPos = ImVec2((float)info.rcMonitor.left, (float)info.rcMonitor.top);
|
||||
imgui_monitor.MainSize = ImVec2((float)(info.rcMonitor.right - info.rcMonitor.left), (float)(info.rcMonitor.bottom - info.rcMonitor.top));
|
||||
imgui_monitor.WorkPos = ImVec2((float)info.rcWork.left, (float)info.rcWork.top);
|
||||
imgui_monitor.WorkSize = ImVec2((float)(info.rcWork.right - info.rcWork.left), (float)(info.rcWork.bottom - info.rcWork.top));
|
||||
imgui_monitor.DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
|
||||
imgui_monitor.PlatformHandle = (void*)monitor;
|
||||
if (imgui_monitor.DpiScale <= 0.0f)
|
||||
return TRUE; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
|
||||
ImGuiPlatformIO& io = ImGui::GetPlatformIO();
|
||||
if (info.dwFlags & MONITORINFOF_PRIMARY)
|
||||
io.Monitors.push_front(imgui_monitor);
|
||||
else
|
||||
io.Monitors.push_back(imgui_monitor);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_UpdateMonitors()
|
||||
{
|
||||
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||
ImGui::GetPlatformIO().Monitors.resize(0);
|
||||
::EnumDisplayMonitors(nullptr, nullptr, ImGui_ImplWin32_UpdateMonitors_EnumFunc, 0);
|
||||
bd->WantUpdateMonitors = false;
|
||||
}
|
||||
|
||||
void ImGui_ImplWin32_NewFrame()
|
||||
{
|
||||
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized? Did you call ImGui_ImplWin32_Init()?");
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
|
||||
// Setup display size (every frame to accommodate for window resizing)
|
||||
RECT rect = { 0, 0, 0, 0 };
|
||||
::GetClientRect(bd->hWnd, &rect);
|
||||
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
|
||||
if (bd->WantUpdateMonitors)
|
||||
ImGui_ImplWin32_UpdateMonitors();
|
||||
|
||||
// Setup time step
|
||||
INT64 current_time = 0;
|
||||
@@ -405,7 +502,7 @@ void ImGui_ImplWin32_NewFrame()
|
||||
bd->Time = current_time;
|
||||
|
||||
// Update OS mouse position
|
||||
ImGui_ImplWin32_UpdateMouseData(io);
|
||||
ImGui_ImplWin32_UpdateMouseData(io, platform_io);
|
||||
|
||||
// Process workarounds for known Windows key handling issues
|
||||
ImGui_ImplWin32_ProcessKeyEventsWorkarounds(io);
|
||||
@@ -610,6 +707,10 @@ static ImGuiMouseSource ImGui_ImplWin32_GetMouseSourceFromMessageExtraInfo()
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // Use ImGui::GetCurrentContext()
|
||||
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ImGuiIO& io); // Doesn't use ImGui::GetCurrentContext()
|
||||
|
||||
#ifndef WM_DPICHANGED
|
||||
#define WM_DPICHANGED 0x02E0 // From Windows SDK 8.1+ headers
|
||||
#endif
|
||||
|
||||
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Most backends don't have silent checks like this one, but we need it because WndProc are called early in CreateWindow().
|
||||
@@ -644,8 +745,11 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA
|
||||
bd->MouseTrackedArea = area;
|
||||
}
|
||||
POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) };
|
||||
if (msg == WM_NCMOUSEMOVE && ::ScreenToClient(hwnd, &mouse_pos) == FALSE) // WM_NCMOUSEMOVE are provided in absolute coordinates.
|
||||
return 0;
|
||||
bool want_absolute_pos = (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != 0;
|
||||
if (msg == WM_MOUSEMOVE && want_absolute_pos) // WM_MOUSEMOVE are client-relative coordinates.
|
||||
::ClientToScreen(hwnd, &mouse_pos);
|
||||
if (msg == WM_NCMOUSEMOVE && !want_absolute_pos) // WM_NCMOUSEMOVE are absolute coordinates.
|
||||
::ScreenToClient(hwnd, &mouse_pos);
|
||||
io.AddMouseSourceEvent(mouse_source);
|
||||
io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
|
||||
return 0;
|
||||
@@ -794,6 +898,20 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandlerEx(HWND hwnd, UINT msg, WPA
|
||||
bd->WantUpdateHasGamepad = true;
|
||||
#endif
|
||||
return 0;
|
||||
case WM_DISPLAYCHANGE:
|
||||
bd->WantUpdateMonitors = true;
|
||||
return 0;
|
||||
case WM_SETTINGCHANGE:
|
||||
if (wParam == SPI_SETWORKAREA)
|
||||
bd->WantUpdateMonitors = true;
|
||||
return 0;
|
||||
case WM_DPICHANGED:
|
||||
{
|
||||
const RECT* suggested_rect = (RECT*)lParam;
|
||||
if (io.ConfigDpiScaleViewports)
|
||||
::SetWindowPos(hwnd, nullptr, suggested_rect->left, suggested_rect->top, suggested_rect->right - suggested_rect->left, suggested_rect->bottom - suggested_rect->top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -858,6 +976,10 @@ typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWAR
|
||||
// Helper function to enable DPI awareness without setting up a manifest
|
||||
void ImGui_ImplWin32_EnableDpiAwareness()
|
||||
{
|
||||
// Make sure monitors will be updated with latest correct scaling
|
||||
if (ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData())
|
||||
bd->WantUpdateMonitors = true;
|
||||
|
||||
if (_IsWindows10OrGreater())
|
||||
{
|
||||
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
|
||||
@@ -957,6 +1079,386 @@ void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
|
||||
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
|
||||
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Helper structure we store in the void* PlatformUserData field of each ImGuiViewport to easily retrieve our backend data.
|
||||
struct ImGui_ImplWin32_ViewportData
|
||||
{
|
||||
HWND Hwnd; // Stored in ImGuiViewport::PlatformHandle + PlatformHandleRaw
|
||||
HWND HwndParent;
|
||||
bool HwndOwned;
|
||||
DWORD DwStyle;
|
||||
DWORD DwExStyle;
|
||||
|
||||
ImGui_ImplWin32_ViewportData() { Hwnd = HwndParent = nullptr; HwndOwned = false; DwStyle = DwExStyle = 0; }
|
||||
~ImGui_ImplWin32_ViewportData() { IM_ASSERT(Hwnd == nullptr); }
|
||||
};
|
||||
|
||||
static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags(ImGuiViewportFlags flags, DWORD* out_style, DWORD* out_ex_style)
|
||||
{
|
||||
if (flags & ImGuiViewportFlags_NoDecoration)
|
||||
*out_style = WS_POPUP;
|
||||
else
|
||||
*out_style = WS_OVERLAPPEDWINDOW;
|
||||
|
||||
if (flags & ImGuiViewportFlags_NoTaskBarIcon)
|
||||
*out_ex_style = WS_EX_TOOLWINDOW;
|
||||
else
|
||||
*out_ex_style = WS_EX_APPWINDOW;
|
||||
|
||||
if (flags & ImGuiViewportFlags_TopMost)
|
||||
*out_ex_style |= WS_EX_TOPMOST;
|
||||
}
|
||||
|
||||
static HWND ImGui_ImplWin32_GetHwndFromViewportID(ImGuiID viewport_id)
|
||||
{
|
||||
if (viewport_id != 0)
|
||||
if (ImGuiViewport* viewport = ImGui::FindViewportByID(viewport_id))
|
||||
return (HWND)viewport->PlatformHandle;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
|
||||
viewport->PlatformUserData = vd;
|
||||
|
||||
// Select style and parent window
|
||||
ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &vd->DwStyle, &vd->DwExStyle);
|
||||
vd->HwndParent = ImGui_ImplWin32_GetHwndFromViewportID(viewport->ParentViewportId);
|
||||
|
||||
// Create window
|
||||
RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
|
||||
::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle);
|
||||
vd->Hwnd = ::CreateWindowExW(
|
||||
vd->DwExStyle, L"ImGui Platform", L"Untitled", vd->DwStyle, // Style, class name, window name
|
||||
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, // Window area
|
||||
vd->HwndParent, nullptr, ::GetModuleHandle(nullptr), nullptr); // Owner window, Menu, Instance, Param
|
||||
vd->HwndOwned = true;
|
||||
viewport->PlatformRequestResize = false;
|
||||
viewport->PlatformHandle = viewport->PlatformHandleRaw = vd->Hwnd;
|
||||
|
||||
// Secondary viewports store their imgui context
|
||||
::SetPropA(vd->Hwnd, "IMGUI_CONTEXT", ImGui::GetCurrentContext());
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||
if (ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData)
|
||||
{
|
||||
if (::GetCapture() == vd->Hwnd)
|
||||
{
|
||||
// Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
|
||||
::ReleaseCapture();
|
||||
::SetCapture(bd->hWnd);
|
||||
}
|
||||
if (vd->Hwnd && vd->HwndOwned)
|
||||
::DestroyWindow(vd->Hwnd);
|
||||
vd->Hwnd = nullptr;
|
||||
IM_DELETE(vd);
|
||||
}
|
||||
viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_ShowWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
|
||||
// ShowParent() also brings parent to front, which is not always desirable,
|
||||
// so we temporarily disable parenting. (#7354)
|
||||
if (vd->HwndParent != NULL)
|
||||
::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)nullptr);
|
||||
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
|
||||
::ShowWindow(vd->Hwnd, SW_SHOWNA);
|
||||
else
|
||||
::ShowWindow(vd->Hwnd, SW_SHOW);
|
||||
|
||||
// Restore
|
||||
if (vd->HwndParent != NULL)
|
||||
::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_UpdateWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
|
||||
// Update Win32 parent if it changed _after_ creation
|
||||
// Unlike style settings derived from configuration flags, this is more likely to change for advanced apps that are manipulating ParentViewportID manually.
|
||||
HWND new_parent = ImGui_ImplWin32_GetHwndFromViewportID(viewport->ParentViewportId);
|
||||
if (new_parent != vd->HwndParent)
|
||||
{
|
||||
// Win32 windows can either have a "Parent" (for WS_CHILD window) or an "Owner" (which among other thing keeps window above its owner).
|
||||
// Our Dear Imgui-side concept of parenting only mostly care about what Win32 call "Owner".
|
||||
// The parent parameter of CreateWindowEx() sets up Parent OR Owner depending on WS_CHILD flag. In our case an Owner as we never use WS_CHILD.
|
||||
// Calling ::SetParent() here would be incorrect: it will create a full child relation, alter coordinate system and clipping.
|
||||
// Calling ::SetWindowLongPtr() with GWLP_HWNDPARENT seems correct although poorly documented.
|
||||
// https://devblogs.microsoft.com/oldnewthing/20100315-00/?p=14613
|
||||
vd->HwndParent = new_parent;
|
||||
::SetWindowLongPtr(vd->Hwnd, GWLP_HWNDPARENT, (LONG_PTR)vd->HwndParent);
|
||||
}
|
||||
|
||||
// (Optional) Update Win32 style if it changed _after_ creation.
|
||||
// Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
|
||||
DWORD new_style;
|
||||
DWORD new_ex_style;
|
||||
ImGui_ImplWin32_GetWin32StyleFromViewportFlags(viewport->Flags, &new_style, &new_ex_style);
|
||||
|
||||
// Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
|
||||
if (vd->DwStyle != new_style || vd->DwExStyle != new_ex_style)
|
||||
{
|
||||
// (Optional) Update TopMost state if it changed _after_ creation
|
||||
bool top_most_changed = (vd->DwExStyle & WS_EX_TOPMOST) != (new_ex_style & WS_EX_TOPMOST);
|
||||
HWND insert_after = top_most_changed ? ((viewport->Flags & ImGuiViewportFlags_TopMost) ? HWND_TOPMOST : HWND_NOTOPMOST) : 0;
|
||||
UINT swp_flag = top_most_changed ? 0 : SWP_NOZORDER;
|
||||
|
||||
// Apply flags and position (since it is affected by flags)
|
||||
vd->DwStyle = new_style;
|
||||
vd->DwExStyle = new_ex_style;
|
||||
::SetWindowLong(vd->Hwnd, GWL_STYLE, vd->DwStyle);
|
||||
::SetWindowLong(vd->Hwnd, GWL_EXSTYLE, vd->DwExStyle);
|
||||
RECT rect = { (LONG)viewport->Pos.x, (LONG)viewport->Pos.y, (LONG)(viewport->Pos.x + viewport->Size.x), (LONG)(viewport->Pos.y + viewport->Size.y) };
|
||||
::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen
|
||||
::SetWindowPos(vd->Hwnd, insert_after, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, swp_flag | SWP_NOACTIVATE | SWP_FRAMECHANGED);
|
||||
::ShowWindow(vd->Hwnd, SW_SHOWNA); // This is necessary when we alter the style
|
||||
viewport->PlatformRequestMove = viewport->PlatformRequestResize = true;
|
||||
}
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplWin32_GetWindowPos(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
POINT pos = { 0, 0 };
|
||||
::ClientToScreen(vd->Hwnd, &pos);
|
||||
return ImVec2((float)pos.x, (float)pos.y);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_UpdateWin32StyleFromWindow(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
vd->DwStyle = ::GetWindowLongW(vd->Hwnd, GWL_STYLE);
|
||||
vd->DwExStyle = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
RECT rect = { (LONG)pos.x, (LONG)pos.y, (LONG)pos.x, (LONG)pos.y };
|
||||
if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)
|
||||
ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using
|
||||
::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle);
|
||||
::SetWindowPos(vd->Hwnd, nullptr, rect.left, rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
static ImVec2 ImGui_ImplWin32_GetWindowSize(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
RECT rect;
|
||||
::GetClientRect(vd->Hwnd, &rect);
|
||||
return ImVec2(float(rect.right - rect.left), float(rect.bottom - rect.top));
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_SetWindowSize(ImGuiViewport* viewport, ImVec2 size)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
RECT rect = { 0, 0, (LONG)size.x, (LONG)size.y };
|
||||
if (viewport->Flags & ImGuiViewportFlags_OwnedByApp)
|
||||
ImGui_ImplWin32_UpdateWin32StyleFromWindow(viewport); // Not our window, poll style before using
|
||||
::AdjustWindowRectEx(&rect, vd->DwStyle, FALSE, vd->DwExStyle); // Client to Screen
|
||||
::SetWindowPos(vd->Hwnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_SetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
::BringWindowToTop(vd->Hwnd);
|
||||
::SetForegroundWindow(vd->Hwnd);
|
||||
::SetFocus(vd->Hwnd);
|
||||
}
|
||||
|
||||
static bool ImGui_ImplWin32_GetWindowFocus(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
return ::GetForegroundWindow() == vd->Hwnd;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplWin32_GetWindowMinimized(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
return ::IsIconic(vd->Hwnd) != 0;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_SetWindowTitle(ImGuiViewport* viewport, const char* title)
|
||||
{
|
||||
// ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string.
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
int n = ::MultiByteToWideChar(CP_UTF8, 0, title, -1, nullptr, 0);
|
||||
ImVector<wchar_t> title_w;
|
||||
title_w.resize(n);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w.Data, n);
|
||||
|
||||
// Calling SetWindowTextW() in a project where UNICODE is not set doesn't work but there's a trick
|
||||
// which is to pass it directly to the DefWindowProcW() handler.
|
||||
// See: https://stackoverflow.com/questions/9410681/setwindowtextw-in-an-ansi-project
|
||||
//::SetWindowTextW(vd->Hwnd, title_w.Data);
|
||||
::DefWindowProcW(vd->Hwnd, WM_SETTEXT, 0, (LPARAM)title_w.Data);
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_SetWindowAlpha(ImGuiViewport* viewport, float alpha)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
IM_ASSERT(alpha >= 0.0f && alpha <= 1.0f);
|
||||
if (alpha < 1.0f)
|
||||
{
|
||||
DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) | WS_EX_LAYERED;
|
||||
::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style);
|
||||
::SetLayeredWindowAttributes(vd->Hwnd, 0, (BYTE)(255 * alpha), LWA_ALPHA);
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD ex_style = ::GetWindowLongW(vd->Hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED;
|
||||
::SetWindowLongW(vd->Hwnd, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
}
|
||||
|
||||
static float ImGui_ImplWin32_GetWindowDpiScale(ImGuiViewport* viewport)
|
||||
{
|
||||
ImGui_ImplWin32_ViewportData* vd = (ImGui_ImplWin32_ViewportData*)viewport->PlatformUserData;
|
||||
IM_ASSERT(vd->Hwnd != 0);
|
||||
return ImGui_ImplWin32_GetDpiScaleForHwnd(vd->Hwnd);
|
||||
}
|
||||
|
||||
// FIXME-DPI: Testing DPI related ideas
|
||||
static void ImGui_ImplWin32_OnChangedViewport(ImGuiViewport* viewport)
|
||||
{
|
||||
(void)viewport;
|
||||
#if 0
|
||||
ImGuiStyle default_style;
|
||||
//default_style.WindowPadding = ImVec2(0, 0);
|
||||
//default_style.WindowBorderSize = 0.0f;
|
||||
//default_style.ItemSpacing.y = 3.0f;
|
||||
//default_style.FramePadding = ImVec2(0, 0);
|
||||
default_style.ScaleAllSizes(viewport->DpiScale);
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style = default_style;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); extern ImGuiPlatformIO& GetPlatformIO(ImGuiContext*); }
|
||||
|
||||
static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Allow secondary viewport WndProc to be called regardless of current context
|
||||
ImGuiContext* ctx = (ImGuiContext*)::GetPropA(hWnd, "IMGUI_CONTEXT");
|
||||
if (ctx == NULL)
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam); // unlike ImGui_ImplWin32_WndProcHandler() we are called directly by Windows, we can't just return 0.
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO(ctx);
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(ctx);
|
||||
LRESULT result = 0;
|
||||
if (ImGui_ImplWin32_WndProcHandlerEx(hWnd, msg, wParam, lParam, io))
|
||||
result = 1;
|
||||
else if (ImGuiViewport* viewport = ImGui_ImplWin32_FindViewportByPlatformHandle(platform_io, hWnd))
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_CLOSE:
|
||||
viewport->PlatformRequestClose = true;
|
||||
return 0; // 0 = Operating system will ignore the message and not destroy the window. We close ourselves.
|
||||
case WM_MOVE:
|
||||
viewport->PlatformRequestMove = true;
|
||||
break;
|
||||
case WM_SIZE:
|
||||
viewport->PlatformRequestResize = true;
|
||||
break;
|
||||
case WM_MOUSEACTIVATE:
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnClick)
|
||||
result = MA_NOACTIVATE;
|
||||
break;
|
||||
case WM_NCHITTEST:
|
||||
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() correctly. (which is optional).
|
||||
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
|
||||
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
|
||||
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
|
||||
if (viewport->Flags & ImGuiViewportFlags_NoInputs)
|
||||
result = HTTRANSPARENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == 0)
|
||||
result = DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_InitMultiViewportSupport(bool platform_has_own_dc)
|
||||
{
|
||||
WNDCLASSEXW wcex;
|
||||
wcex.cbSize = sizeof(WNDCLASSEXW);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW | (platform_has_own_dc ? CS_OWNDC : 0);
|
||||
wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = ::GetModuleHandle(nullptr);
|
||||
wcex.hIcon = nullptr;
|
||||
wcex.hCursor = nullptr;
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
|
||||
wcex.lpszMenuName = nullptr;
|
||||
wcex.lpszClassName = L"ImGui Platform";
|
||||
wcex.hIconSm = nullptr;
|
||||
::RegisterClassExW(&wcex);
|
||||
|
||||
ImGui_ImplWin32_UpdateMonitors();
|
||||
|
||||
// Register platform interface (will be coupled with a renderer interface)
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
platform_io.Platform_CreateWindow = ImGui_ImplWin32_CreateWindow;
|
||||
platform_io.Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow;
|
||||
platform_io.Platform_ShowWindow = ImGui_ImplWin32_ShowWindow;
|
||||
platform_io.Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos;
|
||||
platform_io.Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos;
|
||||
platform_io.Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize;
|
||||
platform_io.Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize;
|
||||
platform_io.Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus;
|
||||
platform_io.Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus;
|
||||
platform_io.Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized;
|
||||
platform_io.Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle;
|
||||
platform_io.Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha;
|
||||
platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
|
||||
platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
|
||||
platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
|
||||
|
||||
// Register main window handle (which is owned by the main application, not by us)
|
||||
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
|
||||
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
|
||||
ImGui_ImplWin32_ViewportData* vd = IM_NEW(ImGui_ImplWin32_ViewportData)();
|
||||
vd->Hwnd = bd->hWnd;
|
||||
vd->HwndOwned = false;
|
||||
main_viewport->PlatformUserData = vd;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin32_ShutdownMultiViewportSupport()
|
||||
{
|
||||
::UnregisterClassW(L"ImGui Platform", ::GetModuleHandle(nullptr));
|
||||
ImGui::DestroyPlatformWindows();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__GNUC__)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy VK_* values are obsolete since 1.87 and not supported since 1.91.5]
|
||||
// [X] Platform: Gamepad support.
|
||||
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
|
||||
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
|
||||
|
||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
|
||||
|
||||
Reference in New Issue
Block a user