diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..3ba13e0cec6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false diff --git a/.github/ISSUE_TEMPLATE/issue_template.yml b/.github/ISSUE_TEMPLATE/issue_template.yml new file mode 100644 index 000000000000..792d8f63ed49 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue_template.yml @@ -0,0 +1,90 @@ +name: "Ask a question, report a bug, request a feature, etc." +description: "Ask any question, discuss best practices, report a bug, request a feature." +body: + - type: markdown + attributes: + value: | + FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions) + For anything else: we are happy to use 'GitHub Issues' for many types of open-ended questions. We are encouraging 'Issues' becoming a large, centralized and cross-referenced database of Dear ImGui contents. + + Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users. + - type: markdown + attributes: + value: | + **Prerequisites:** + - I have read [Frequently Asked Questions](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md). + - I have read [Contributing Guidelines -> General Advices](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#getting-started--general-advice). + - I have read [Contributing Guidelines -> How to open an Issue](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#how-to-open-an-issue). + - I have searched [Github Issues and PR](https://github.com/ocornut/imgui/issues?q=) for discussion of similar topics. + + ---- + - type: input + id: specs_version + attributes: + label: "Version/Branch of Dear ImGui:" + description: "(please specify if you have made substantial modifications to your copy)" + value: "Version 1.XX, Branch: XXX (master/docking/etc.)" + placeholder: "Version 1.XX, Branch: XXX (master/docking/etc.)" + validations: + required: true + - type: input + id: specs_backend + attributes: + label: "Back-ends:" + description: (or specify when using custom engine/back-ends) + value: "imgui_impl_XXX.cpp + imgui_impl_XXX.cpp" + placeholder: "imgui_impl_XXX.cpp + imgui_impl_XXX.cpp or n/a" + validations: + required: true + - type: input + id: specs_compiler_os + attributes: + label: "Compiler, OS:" + placeholder: "e.g. Windows 11 + MSVC 2022, macOS + Clang 12, Linux + GCC etc." + validations: + required: true + - type: textarea + id: specs_full + attributes: + label: "Full config/build information:" + placeholder: | + (If you can run, you may go to 'Demo->Tools->About Dear ImGui->Config/Build Info' to obtain detailed information that you can paste here) + validations: + required: false + - type: textarea + id: issue_description + attributes: + label: "Details:" + description: "Try to be explicit with your goals, your expectations and what you have tried. Be mindful of [The XY Problem](https://xyproblem.info). What you have in mind or in your code is not obvious to other people. People frequently discuss problems and suggest incorrect solutions without first clarifying their goals. When requesting a new feature, please describe the usage context (how you intend to use it, why you need it, etc.). If you tried something and it failed, show us what you tried. If you are reporting a bug, explain what's the bug, how does it occur, etc. If you are reporting a crash, please include a debugger callstack." + value: | + **My Issue/Question:** + + XXX _(please provide as much context as possible)_ + validations: + required: true + - type: textarea + id: screenshots + attributes: + label: "Screenshots/Video:" + description: "Attach screenshots or gif/videos to clarify the context. They often convey useful information that is omitted by the description." + placeholder: "(You can drag files here)" + validations: + required: false + - type: textarea + id: repro_code + attributes: + label: "Minimal, Complete and Verifiable Example code:" + description: "Provide an [MCVE](https://stackoverflow.com/help/mcve) to demonstrate your problem. An ideal submission includes a small piece of code that anyone can paste into one of the examples applications (examples/*/main.cpp) or the demo (imgui_demo.cpp) to understand and reproduce it. Narrowing your problem to its shortest and purest form is the easiest way to understand it, explain it and fix it. Please test your shortened code to ensure it exhibits the problem. Often while creating the MCVE you will solve the problem! Many questions that are missing a standalone verifiable example are missing the actual cause of their issue in the description, which ends up wasting everyone's time." + value: | + ```cpp + // Here's some code anyone can copy and paste to reproduce your issue + ImGui::Begin("Example Bug"); + MoreCodeToExplainMyIssue(); + ImGui::End(); + ``` + validations: + required: false + - type: markdown + attributes: + value: | + Thank you for taking the time to read prerequisites, filling this template and double-checking your message and your code! diff --git a/.github/issue_template.md b/.github/issue_template.md deleted file mode 100644 index 0172e093e331..000000000000 --- a/.github/issue_template.md +++ /dev/null @@ -1,46 +0,0 @@ -(Click "Preview" above ^ to turn URL into clickable links) - -1. FOR FIRST-TIME USERS PROBLEMS COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). EVERYTHING ELSE CAN BE POSTED HERE! - -2. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md) - -3. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md) - -4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the links above. - -5. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users. - -6. Delete points 1-6 and PLEASE FILL THE TEMPLATE BELOW before submitting your issue. - -Thank you! - ----- - -_(you may also go to Demo>About Window, and click "Config/Build Information" to obtain a bunch of detailed information that you can paste here)_ - -**Version/Branch of Dear ImGui:** - -Version: XXX -Branch: XXX _(master/viewport/docking/etc.)_ - -**Back-end/Renderer/Compiler/OS** - -Back-ends: imgui_impl_XXX.cpp + imgui_impl_XXX.cpp _(or specify if using a custom engine/back-end)_ -Compiler: XXX _(if the question is related to building or platform specific features)_ -Operating System: XXX - -**My Issue/Question:** - -XXX _(please provide as much context as possible)_ - -**Screenshots/Video** - -XXX _(you can drag files here)_ - -**Standalone, minimal, complete and verifiable example:** _(see https://github.com/ocornut/imgui/issues/2261)_ -``` -// Here's some code anyone can copy and paste to reproduce your issue -ImGui::Begin("Example Bug"); -MoreCodeToExplainMyIssue(); -ImGui::End(); -``` diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 45688c470343..48082d056392 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: VS_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\ MSBUILD_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\ steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Dependencies shell: powershell @@ -209,7 +209,7 @@ jobs: Linux: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -402,7 +402,7 @@ jobs: MacOS: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -462,7 +462,7 @@ jobs: iOS: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build example_apple_metal run: | @@ -472,7 +472,7 @@ jobs: Emscripten: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -489,17 +489,17 @@ jobs: popd make -C examples/example_sdl2_opengl3 -f Makefile.emscripten - - name: Build example_emscripten_wgpu + - name: Build example_glfw_wgpu run: | pushd emsdk-master source ./emsdk_env.sh popd - make -C examples/example_emscripten_wgpu + make -C examples/example_glfw_wgpu -f Makefile.emscripten Android: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build example_android_opengl3 run: | diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index caa9b3a4e44f..69df5cdf8031 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -12,7 +12,7 @@ jobs: PVS-Studio: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 1 diff --git a/.gitignore b/.gitignore index 211d21dda88d..64b5e1221c04 100644 --- a/.gitignore +++ b/.gitignore @@ -40,8 +40,9 @@ examples/*.o.tmp examples/*.out.js examples/*.out.wasm examples/example_glfw_opengl3/web/* +examples/example_glfw_wgpu/web/* +examples/example_glfw_wgpu/external/* examples/example_sdl2_opengl3/web/* -examples/example_emscripten_wgpu/web/* ## JetBrains IDE artifacts .idea diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 8bbbb130e6de..000000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,233 +0,0 @@ -cmake_minimum_required(VERSION 3.16) -project(imgui CXX) - -set(CMAKE_DEBUG_POSTFIX d) - -if(APPLE) - set(CMAKE_CXX_STANDARD 11) - enable_language(OBJCXX) -endif() - -add_library(${PROJECT_NAME} "") -add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_include_directories( - ${PROJECT_NAME} - PUBLIC - $ - $ -) - -target_sources( - ${PROJECT_NAME} - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/imgui.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/imgui_demo.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/imgui_draw.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/imgui_tables.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/imgui_widgets.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/microstrain/NativeChildWindow.cpp -) - -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) - -if(IMGUI_BUILD_ALLEGRO5_BINDING) - find_path(ALLEGRO5_INCLUDE_DIRS allegro5/allegro.h) - target_include_directories(${PROJECT_NAME} PRIVATE ${ALLEGRO5_INCLUDE_DIRS}) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_allegro5.cpp) -endif() - -if(IMGUI_BUILD_DX9_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx9.cpp) -endif() - -if(IMGUI_BUILD_DX10_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx10.cpp) -endif() - -if(IMGUI_BUILD_DX11_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx11.cpp) -endif() - -if(IMGUI_BUILD_DX12_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx12.cpp) -endif() - -if(IMGUI_BUILD_GLFW_BINDING) - if(NOT EMSCRIPTEN) - find_package(glfw3 CONFIG REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC glfw) - endif() - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glfw.cpp) -endif() - -if(IMGUI_BUILD_GLUT_BINDING) - find_package(GLUT REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC GLUT::GLUT) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glut.cpp) -endif() - -if(IMGUI_BUILD_METAL_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_metal.mm) - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_metal.mm PROPERTIES COMPILE_FLAGS -fobjc-weak) -endif() - -if(IMGUI_BUILD_OPENGL2_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl2.cpp) -endif() - -if(IMGUI_BUILD_OPENGL3_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp) -endif() - -if(IMGUI_BUILD_OSX_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_osx.mm) -endif() - -if(IMGUI_BUILD_SDL2_BINDING) - find_package(SDL2 CONFIG REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdl2.cpp) -endif() - -if(IMGUI_BUILD_SDL2_RENDERER_BINDING) - find_package(SDL2 CONFIG REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC SDL2::SDL2) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdlrenderer.cpp) -endif() - -if(IMGUI_BUILD_VULKAN_BINDING) - find_package(Vulkan REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC Vulkan::Vulkan) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_vulkan.cpp) -endif() - -if(IMGUI_BUILD_WIN32_BINDING) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_win32.cpp) -endif() - -if(IMGUI_FREETYPE) - find_package(freetype CONFIG REQUIRED) - target_link_libraries(${PROJECT_NAME} PUBLIC freetype) - target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp) - target_compile_definitions(${PROJECT_NAME} PUBLIC IMGUI_ENABLE_FREETYPE) -endif() - -if(IMGUI_USE_WCHAR32) - target_compile_definitions(${PROJECT_NAME} PUBLIC IMGUI_USE_WCHAR32) -endif() - -list(REMOVE_DUPLICATES BINDINGS_SOURCES) - -install( - TARGETS ${PROJECT_NAME} - EXPORT ${PROJECT_NAME}_target - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin -) - -foreach(BINDING_TARGET ${BINDING_TARGETS}) - install( - TARGETS ${BINDING_TARGET} - EXPORT ${PROJECT_NAME}_target - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin - ) -endforeach() - -if(NOT IMGUI_SKIP_HEADERS) - install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/imgui.h - ${CMAKE_CURRENT_SOURCE_DIR}/imconfig.h - ${CMAKE_CURRENT_SOURCE_DIR}/imgui_internal.h - ${CMAKE_CURRENT_SOURCE_DIR}/imstb_textedit.h - ${CMAKE_CURRENT_SOURCE_DIR}/imstb_rectpack.h - ${CMAKE_CURRENT_SOURCE_DIR}/imstb_truetype.h - ${CMAKE_CURRENT_SOURCE_DIR}/misc/cpp/imgui_stdlib.h - DESTINATION include - ) - - if(IMGUI_BUILD_ALLEGRO5_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_allegro5.h DESTINATION include) - endif() - - if(IMGUI_BUILD_DX9_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx9.h DESTINATION include) - endif() - - if(IMGUI_BUILD_DX10_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx10.h DESTINATION include) - endif() - - if(IMGUI_BUILD_DX11_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx11.h DESTINATION include) - endif() - - if(IMGUI_BUILD_DX12_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_dx12.h DESTINATION include) - endif() - - if(IMGUI_BUILD_GLFW_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glfw.h DESTINATION include) - endif() - - if(IMGUI_BUILD_GLUT_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_glut.h DESTINATION include) - endif() - - if(IMGUI_BUILD_METAL_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_metal.h DESTINATION include) - endif() - - if(IMGUI_BUILD_OPENGL2_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl2.h DESTINATION include) - endif() - - if(IMGUI_BUILD_OPENGL3_BINDING) - install( - FILES - ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl3.h - ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_opengl3_loader.h - DESTINATION - include - ) - endif() - - if(IMGUI_BUILD_OSX_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_osx.h DESTINATION include) - endif() - - if(IMGUI_BUILD_SDL2_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdl2.h DESTINATION include) - endif() - - if(IMGUI_BUILD_SDL2_RENDERER_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_sdlrenderer.h DESTINATION include) - endif() - - if(IMGUI_BUILD_VULKAN_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_vulkan.h DESTINATION include) - endif() - - if(IMGUI_BUILD_WIN32_BINDING) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/backends/imgui_impl_win32.h DESTINATION include) - endif() - - if(IMGUI_FREETYPE) - install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/misc/freetype/imgui_freetype.h DESTINATION include) - endif() -endif() - -include(CMakePackageConfigHelpers) -configure_package_config_file(imgui-config.cmake.in imgui-config.cmake INSTALL_DESTINATION share/imgui) - -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/imgui-config.cmake DESTINATION share/imgui) - -install( - EXPORT ${PROJECT_NAME}_target - NAMESPACE ${PROJECT_NAME}:: - FILE ${PROJECT_NAME}-targets.cmake - DESTINATION share/${PROJECT_NAME} -) diff --git a/LICENSE.txt b/LICENSE.txt index fb715bdc84a1..3282f5b5b105 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2023 Omar Cornut +Copyright (c) 2014-2024 Omar Cornut Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 1264e8d04feb..3ef024a34b7f 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -28,7 +28,7 @@ // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+). // 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates. // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range. -// 2021-12-08: Renderer: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. +// 2021-12-08: Renderer: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. // 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events. // 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-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_android.cpp b/backends/imgui_impl_android.cpp index 011294e1c3e0..f387c4830f49 100644 --- a/backends/imgui_impl_android.cpp +++ b/backends/imgui_impl_android.cpp @@ -184,7 +184,7 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event) case AKEY_EVENT_ACTION_UP: { ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code); - if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP)) + if (key != ImGuiKey_None) { io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN); io.SetKeyEventNativeData(key, event_key_code, event_scan_code); diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 75c546700aa2..d4d0b5a3461e 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 7b02636564ad..804d20adb796 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 428e47ee096f..31ee73727261 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -25,7 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). // 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) @@ -899,7 +899,7 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport) sd1.SampleDesc.Quality = 0; sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; - sd1.Scaling = DXGI_SCALING_STRETCH; + sd1.Scaling = DXGI_SCALING_NONE; sd1.Stereo = FALSE; IDXGIFactory4* dxgi_factory = nullptr; diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 0aeb43dc9b71..2f03fa6e3889 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -16,7 +16,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575) // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. // 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-06-25: DirectX9: Explicitly disable texture state stages after >= 1. @@ -330,6 +331,24 @@ void ImGui_ImplDX9_Shutdown() IM_DELETE(bd); } +static bool ImGui_ImplDX9_CheckFormatSupport(IDirect3DDevice9* pDevice, D3DFORMAT format) +{ + IDirect3D9* pd3d = nullptr; + if (pDevice->GetDirect3D(&pd3d) != D3D_OK) + return false; + D3DDEVICE_CREATION_PARAMETERS param = {}; + D3DDISPLAYMODE mode = {}; + if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK) + { + pd3d->Release(); + return false; + } + // Font texture should support linear filter, color blend and write to render-target + bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK; + pd3d->Release(); + return support; +} + static bool ImGui_ImplDX9_CreateFontsTexture() { // Build texture atlas @@ -341,18 +360,21 @@ static bool ImGui_ImplDX9_CreateFontsTexture() // Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices) #ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (io.Fonts->TexPixelsUseColors) + const bool rgba_support = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8); + if (!rgba_support && io.Fonts->TexPixelsUseColors) { ImU32* dst_start = (ImU32*)ImGui::MemAlloc((size_t)width * height * bytes_per_pixel); for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + (size_t)width * height; dst < dst_end; src++, dst++) *dst = IMGUI_COL_TO_DX9_ARGB(*src); pixels = (unsigned char*)dst_start; } +#else + const bool rgba_support = false; #endif // Upload texture to graphics system bd->FontTexture = nullptr; - if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) + if (bd->pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, rgba_support ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &bd->FontTexture, nullptr) < 0) return false; D3DLOCKED_RECT tex_locked_rect; if (bd->FontTexture->LockRect(0, &tex_locked_rect, nullptr, 0) != D3D_OK) @@ -365,7 +387,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() io.Fonts->SetTexID((ImTextureID)bd->FontTexture); #ifndef IMGUI_USE_BGRA_PACKED_COLOR - if (io.Fonts->TexPixelsUseColors) + if (!rgba_support && io.Fonts->TexPixelsUseColors) ImGui::MemFree(pixels); #endif diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index d5d3769ee95c..c3cd91c1ac05 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -10,9 +10,8 @@ // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. - // Issues: -// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [ ] 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. @@ -24,7 +23,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2023-12-19: Emscripten: Added ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to register canvas selector and auto-resize GLFW window. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys. // 2023-07-18: Inputs: Revert ignoring mouse data on GLFW_CURSOR_DISABLED as it can be used differently. User may set ImGuiConfigFLags_NoMouse if desired. (#5625, #6609) // 2023-06-12: Accept glfwGetTime() not returning a monotonically increasing value. This seems to happens on some Windows setup when peripherals disconnect, and is likely to also happen on browser + Emscripten. (#6491) @@ -137,7 +137,7 @@ enum GlfwClientApi { GlfwClientApi_Unknown, GlfwClientApi_OpenGL, - GlfwClientApi_Vulkan + GlfwClientApi_Vulkan, }; struct ImGui_ImplGlfw_Data @@ -152,6 +152,9 @@ struct ImGui_ImplGlfw_Data bool InstalledCallbacks; bool CallbacksChainForAllWindows; bool WantUpdateMonitors; +#ifdef __EMSCRIPTEN__ + const char* CanvasSelector; +#endif // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. GLFWwindowfocusfun PrevUserCallbackWindowFocus; @@ -577,7 +580,7 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw #ifndef __EMSCRIPTEN__ io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional) #endif -#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)) +#if GLFW_HAS_MOUSE_PASSTHROUGH || GLFW_HAS_WINDOW_HOVERED io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional) #endif @@ -644,9 +647,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw // Windows: register a WndProc hook so we can intercept some messages. #ifdef _WIN32 - bd->PrevWndProc = (WNDPROC)::GetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC); + bd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC); IM_ASSERT(bd->PrevWndProc != nullptr); - ::SetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); + ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); #endif bd->ClientApi = client_api; @@ -688,7 +691,7 @@ void ImGui_ImplGlfw_Shutdown() // Windows: restore our WndProc hook #ifdef _WIN32 ImGuiViewport* main_viewport = ImGui::GetMainViewport(); - ::SetWindowLongPtr((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc); + ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc); bd->PrevWndProc = nullptr; #endif @@ -704,7 +707,6 @@ static void ImGui_ImplGlfw_UpdateMouseData() ImGuiIO& io = ImGui::GetIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGuiID mouse_viewport_id = 0; const ImVec2 mouse_pos_prev = io.MousePos; for (int n = 0; n < platform_io.Viewports.Size; n++) @@ -745,7 +747,8 @@ static void ImGui_ImplGlfw_UpdateMouseData() // (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. + // - [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 @@ -753,12 +756,12 @@ static void ImGui_ImplGlfw_UpdateMouseData() // - [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 || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32)) - const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0; #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 (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input) +#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. @@ -923,6 +926,43 @@ void ImGui_ImplGlfw_NewFrame() ImGui_ImplGlfw_UpdateGamepads(); } +#ifdef __EMSCRIPTEN__ +static EM_BOOL ImGui_ImplGlfw_OnCanvasSizeChange(int event_type, const EmscriptenUiEvent* event, void* user_data) +{ + ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; + double canvas_width, canvas_height; + emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height); + glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height); + return true; +} + +static EM_BOOL ImGui_ImplEmscripten_FullscreenChangeCallback(int event_type, const EmscriptenFullscreenChangeEvent* event, void* user_data) +{ + ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data; + double canvas_width, canvas_height; + emscripten_get_element_css_size(bd->CanvasSelector, &canvas_width, &canvas_height); + glfwSetWindowSize(bd->Window, (int)canvas_width, (int)canvas_height); + return true; +} + +// 'canvas_selector' is a CSS selector. The event listener is applied to the first element that matches the query. +// STRING MUST PERSIST FOR THE APPLICATION DURATION. PLEASE USE A STRING LITERAL OR ENSURE POINTER WILL STAY VALID. +void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector) +{ + IM_ASSERT(canvas_selector != nullptr); + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplGlfw_InitForXXX()?"); + + bd->CanvasSelector = canvas_selector; + emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, bd, false, ImGui_ImplGlfw_OnCanvasSizeChange); + emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, bd, false, ImGui_ImplEmscripten_FullscreenChangeCallback); + + // Change the size of the GLFW window according to the size of the canvas + ImGui_ImplGlfw_OnCanvasSizeChange(EMSCRIPTEN_EVENT_RESIZE, {}, bd); +} +#endif + + //-------------------------------------------------------------------------------------------------------- // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT // This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. @@ -1076,8 +1116,8 @@ static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport) // GLFW hack: install hook for WM_NCHITTEST message handler #if !GLFW_HAS_MOUSE_PASSTHROUGH && GLFW_HAS_WINDOW_HOVERED && defined(_WIN32) ::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport); - vd->PrevWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC); - ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); + vd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + ::SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc); #endif #if !GLFW_HAS_FOCUS_ON_SHOW @@ -1264,7 +1304,7 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface() //----------------------------------------------------------------------------- -// WndProc hook (declared here because we will need access to ImGui_ImplGlfw_ViewportData) +// WndProc hook (declared here because we will need access to ImGui_ImplGlfw_ViewportData) #ifdef _WIN32 static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo() { @@ -1311,7 +1351,7 @@ static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wPara } #endif } - return ::CallWindowProc(prev_wndproc, hWnd, msg, wParam, lParam); + return ::CallWindowProcW(prev_wndproc, hWnd, msg, wParam, lParam); } #endif // #ifdef _WIN32 diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index d2fcbbb8bfd7..6fe6882cbe03 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -8,11 +8,10 @@ // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only). // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. -// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). +// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+). // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. - // Issues: -// [ ] Platform: Multi-viewport support: ParentViewportID not honored, and so io.ConfigViewportsNoDefaultParent has no effect (minor). +// [ ] 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. @@ -35,6 +34,11 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); +// Emscripten related initialization phase methods +#ifdef __EMSCRIPTEN__ +IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector); +#endif + // GLFW callbacks install // - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any. // - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks. diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 20754d65061a..bae0468d7217 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -16,7 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. // 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. diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 3a21c091356f..30cf50f5131e 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -23,9 +23,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. -// 2021-12-08: OpenGL: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. +// 2021-12-08: OpenGL: Fixed mishandling of the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86. // 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-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) // 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications. diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index f93cda161711..0be98b63975e 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,8 +23,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. -// 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accomodating for NetBSD systems having only "libGL.so.3" available. (#6983) +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-01-09: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" and variants, fixing regression on distros missing a symlink. +// 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accommodating for NetBSD systems having only "libGL.so.3" available. (#6983) // 2023-10-05: OpenGL: Rename symbols in our internal loader so that LTO compilation with another copy of gl3w is possible. (#6875, #6668, #4445) // 2023-06-20: OpenGL: Fixed erroneous use glGetIntegerv(GL_CONTEXT_PROFILE_MASK) on contexts lower than 3.2. (#6539, #6333) // 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375) @@ -177,9 +178,20 @@ #define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES #endif -// Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have. -#ifdef GL_POLYGON_MODE -#define IMGUI_IMPL_HAS_POLYGON_MODE +// Desktop GL 2.0+ has extension and glPolygonMode() which GL ES and WebGL don't have.. +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) +#define IMGUI_IMPL_OPENGL_HAS_EXTENSIONS // has glGetIntegerv(GL_NUM_EXTENSIONS) +#define IMGUI_IMPL_OPENGL_HAS_POLYGON_MODE // has glPolygonMode() +#endif + +// Desktop GL 2.1+ and GL ES 3.0+ have glBindBuffer() with GL_PIXEL_UNPACK_BUFFER target. +#if !defined(IMGUI_IMPL_OPENGL_ES2) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK +#endif + +// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1) +#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART #endif // Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have. @@ -192,16 +204,6 @@ #define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER #endif -// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state -#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1) -#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART -#endif - -// Desktop GL use extension detection -#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) -#define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS -#endif - // [Debugging] //#define IMGUI_IMPL_OPENGL_DEBUG #ifdef IMGUI_IMPL_OPENGL_DEBUG @@ -365,7 +367,7 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version) // Detect extensions we support bd->HasClipOrigin = (bd->GlVersion >= 450); -#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS +#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS GLint num_extensions = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); for (GLint i = 0; i < num_extensions; i++) @@ -421,7 +423,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid if (bd->GlVersion >= 310) glDisable(GL_PRIMITIVE_RESTART); #endif -#ifdef IMGUI_IMPL_HAS_POLYGON_MODE +#ifdef IMGUI_IMPL_OPENGL_HAS_POLYGON_MODE glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif @@ -510,7 +512,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object); #endif -#ifdef IMGUI_IMPL_HAS_POLYGON_MODE +#ifdef IMGUI_IMPL_OPENGL_HAS_POLYGON_MODE GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); #endif GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); @@ -649,7 +651,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); } #endif -#ifdef IMGUI_IMPL_HAS_POLYGON_MODE +#ifdef IMGUI_IMPL_OPENGL_HAS_POLYGON_MODE // Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons if (bd->GlVersion <= 310 || bd->GlProfileIsCompat) { @@ -660,7 +662,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); } -#endif // IMGUI_IMPL_HAS_POLYGON_MODE +#endif // IMGUI_IMPL_OPENGL_HAS_POLYGON_MODE glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); @@ -757,6 +759,10 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() GLint last_texture, last_array_buffer; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK + GLint last_pixel_unpack_buffer; + if (bd->GlVersion >= 210) { glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &last_pixel_unpack_buffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } +#endif #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); @@ -930,6 +936,9 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects() // Restore modified GL state glBindTexture(GL_TEXTURE_2D, last_texture); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); +#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK + if (bd->GlVersion >= 210) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, last_pixel_unpack_buffer); } +#endif #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY glBindVertexArray(last_vertex_array); #endif diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index 15ba44f5c677..4019f937fb24 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -260,6 +260,8 @@ typedef khronos_intptr_t GLintptr; #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_STREAM_DRAW 0x88E0 +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer); typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers); typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers); @@ -668,6 +670,10 @@ static int open_libgl(void) { // While most systems use libGL.so.1, NetBSD seems to use that libGL.so.3. See https://github.com/ocornut/imgui/issues/6983 libgl = dlopen("libGL.so", RTLD_LAZY | RTLD_LOCAL); + if (!libgl) + libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL); + if (!libgl) + libgl = dlopen("libGL.so.3", RTLD_LAZY | RTLD_LOCAL); if (!libgl) return GL3W_ERROR_LIBRARY_OPEN; *(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB"); diff --git a/backends/imgui_impl_osx.h b/backends/imgui_impl_osx.h index 360317fc838d..1f2254bcc5ab 100644 --- a/backends/imgui_impl_osx.h +++ b/backends/imgui_impl_osx.h @@ -10,7 +10,10 @@ // [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: IME support. -// [X] Platform: Multi-viewport / platform windows. +// [x] Platform: Multi-viewport / platform windows. +// Issues: +// [ ] Platform: Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration +// [ ] 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. diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 56de6c169a97..e570c81aa95c 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -10,7 +10,10 @@ // [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend). // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: IME support. -// [X] Platform: Multi-viewport / platform windows. +// [x] Platform: Multi-viewport / platform windows. +// Issues: +// [ ] Platform: Multi-viewport: Window size not correctly reported when enabling io.ConfigViewportsNoDecoration +// [ ] 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. @@ -30,7 +33,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Added support for multiple windows via the ImGuiPlatformIO interface. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F20 function keys. Stopped mapping F13 into PrintScreen. // 2023-04-09: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_Pen. // 2023-02-01: Fixed scroll wheel scaling for devices emitting events with hasPreciseScrollingDeltas==false (e.g. non-Apple mices). @@ -140,12 +143,28 @@ - (void)setImePosX:(float)posX imePosY:(float)posY - (void)updateImePosWithView:(NSView *)view { - NSWindow *window = view.window; + 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 @@ -418,6 +437,7 @@ bool ImGui_ImplOSX_Init(NSView* view) 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(); if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui_ImplOSX_InitPlatformInterface(); @@ -553,7 +573,6 @@ static void ImGui_ImplOSX_UpdateMouseCursor() static void ImGui_ImplOSX_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - memset(io.NavInputs, 0, sizeof(io.NavInputs)); if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. return; @@ -862,9 +881,11 @@ - (BOOL)canBecomeKeyWindow @end -static void ConvertNSRect(NSScreen* screen, NSRect* r) +static void ConvertNSRect(NSRect* r) { - r->origin.y = screen.frame.size.height - r->origin.y - r->size.height; + 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) @@ -875,7 +896,7 @@ static void ImGui_ImplOSX_CreateWindow(ImGuiViewport* viewport) NSScreen* screen = bd->Window.screen; NSRect rect = NSMakeRect(viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y); - ConvertNSRect(screen, &rect); + ConvertNSRect(&rect); NSWindowStyleMask styleMask = 0; if (viewport->Flags & ImGuiViewportFlags_NoDecoration) @@ -945,11 +966,13 @@ static ImVec2 ImGui_ImplOSX_GetWindowPos(ImGuiViewport* viewport) IM_ASSERT(data->Window != 0); NSWindow* window = data->Window; - NSScreen* screen = window.screen; - NSSize size = screen.frame.size; NSRect frame = window.frame; - NSRect rect = window.contentLayoutRect; - return ImVec2(frame.origin.x, size.height - frame.origin.y - rect.size.height); + 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) @@ -961,7 +984,7 @@ static void ImGui_ImplOSX_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) NSSize size = window.frame.size; NSRect r = NSMakeRect(pos.x, pos.y, size.width, size.height); - ConvertNSRect(window.screen, &r); + ConvertNSRect(&r); [window setFrameOrigin:r.origin]; } @@ -1042,10 +1065,15 @@ 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); @@ -1062,7 +1090,6 @@ static void ImGui_ImplOSX_UpdateMonitors() static void ImGui_ImplOSX_InitPlatformInterface() { ImGui_ImplOSX_Data* bd = ImGui_ImplOSX_GetBackendData(); - ImGui_ImplOSX_UpdateMonitors(); // Register platform interface (will be coupled with a renderer interface) ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index e4aa852ca108..afed7b4abb6d 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -10,8 +10,9 @@ // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features: -// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows). +// 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). // [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -24,7 +25,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode(). // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306) // 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702) @@ -83,13 +85,6 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_sdl2.h" -#include "microstrain/NativeChildWindow.hpp" -#include -#include // Must be after mip command includes due to #define Status - -#if defined __linux__ -#include -#endif // Clang warnings with -Weverything #if defined(__clang__) @@ -123,19 +118,26 @@ static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; // SDL Data struct ImGui_ImplSDL2_Data { - SDL_Window* Window; - SDL_Renderer* Renderer; - Uint64 Time; - Uint32 MouseWindowID; - int MouseButtonsDown; - SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; - SDL_Cursor* LastMouseCursor; - int PendingMouseLeaveFrame; - char* ClipboardTextData; - bool MouseCanUseGlobalState; - bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. - bool UseVulkan; - bool WantUpdateMonitors; + SDL_Window* Window; + SDL_Renderer* Renderer; + Uint64 Time; + char* ClipboardTextData; + bool UseVulkan; + bool WantUpdateMonitors; + + // Mouse handling + Uint32 MouseWindowID; + int MouseButtonsDown; + SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; + SDL_Cursor* MouseLastCursor; + int MouseLastLeaveFrame; + bool MouseCanUseGlobalState; + bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. + + // Gamepad handling + ImVector Gamepads; + ImGui_ImplSDL2_GamepadMode GamepadMode; + bool WantUpdateGamepadsList; ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -408,50 +410,37 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, // causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why // we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details. - Uint8 window_event = event->window.event; if (window_event == SDL_WINDOWEVENT_ENTER) { bd->MouseWindowID = event->window.windowID; - bd->PendingMouseLeaveFrame = 0; + bd->MouseLastLeaveFrame = 0; } if (window_event == SDL_WINDOWEVENT_LEAVE) - { - bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1; - } + bd->MouseLastLeaveFrame = ImGui::GetFrameCount() + 1; if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED) - { io.AddFocusEvent(true); - } else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST) - { io.AddFocusEvent(false); - } if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED) - { if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID))) { 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; } - - } return true; } - default: + case SDL_CONTROLLERDEVICEADDED: + case SDL_CONTROLLERDEVICEREMOVED: { - }break; + bd->WantUpdateGamepadsList = true; + return true; + } } return false; } @@ -499,6 +488,10 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void io.ClipboardUserData = nullptr; io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData; + // Gamepad handling + bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst; + bd->WantUpdateGamepadsList = true; + // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); @@ -595,6 +588,8 @@ bool ImGui_ImplSDL2_InitForOther(SDL_Window* window) return ImGui_ImplSDL2_Init(window, nullptr, nullptr); } +static void ImGui_ImplSDL2_CloseGamepads(); + void ImGui_ImplSDL2_Shutdown() { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); @@ -607,7 +602,7 @@ void ImGui_ImplSDL2_Shutdown() SDL_free(bd->ClipboardTextData); for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) SDL_FreeCursor(bd->MouseCursors[cursor_n]); - bd->LastMouseCursor = nullptr; + ImGui_ImplSDL2_CloseGamepads(); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -623,12 +618,14 @@ static void ImGui_ImplSDL2_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE +// MicroStrain start #if !defined(_WIN32) && defined(NDEBUG) - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside // On linux, this can get the mouse stuck when a breakpoint is hit, so disable for debug builds. // See https://github.com/ocornut/imgui/issues/4197 and https://github.com/ocornut/imgui/issues/3650 +// MicroStrain end + // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE); -#endif +#endif // MicroStrain SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window))); #else @@ -700,59 +697,118 @@ static void ImGui_ImplSDL2_UpdateMouseCursor() { // Show OS mouse cursor SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; - if (bd->LastMouseCursor != expected_cursor) + if (bd->MouseLastCursor != expected_cursor) { SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113) - bd->LastMouseCursor = expected_cursor; + bd->MouseLastCursor = expected_cursor; } SDL_ShowCursor(SDL_TRUE); } } +static void ImGui_ImplSDL2_CloseGamepads() +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + if (bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) + for (SDL_GameController* gamepad : bd->Gamepads) + SDL_GameControllerClose(gamepad); + bd->Gamepads.resize(0); +} + +void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array, int manual_gamepads_count) +{ + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); + ImGui_ImplSDL2_CloseGamepads(); + if (mode == ImGui_ImplSDL2_GamepadMode_Manual) + { + IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); + for (int n = 0; n < manual_gamepads_count; n++) + bd->Gamepads.push_back(manual_gamepads_array[n]); + } + else + { + IM_ASSERT(manual_gamepads_array == nullptr && manual_gamepads_count <= 0); + bd->WantUpdateGamepadsList = true; + } + bd->GamepadMode = mode; +} + +static void ImGui_ImplSDL2_UpdateGamepadButton(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerButton button_no) +{ + bool merged_value = false; + for (SDL_GameController* gamepad : bd->Gamepads) + merged_value |= SDL_GameControllerGetButton(gamepad, button_no) != 0; + io.AddKeyEvent(key, merged_value); +} + +static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } +static void ImGui_ImplSDL2_UpdateGamepadAnalog(ImGui_ImplSDL2_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GameControllerAxis axis_no, float v0, float v1) +{ + float merged_value = 0.0f; + for (SDL_GameController* gamepad : bd->Gamepads) + { + float vn = Saturate((float)(SDL_GameControllerGetAxis(gamepad, axis_no) - v0) / (float)(v1 - v0)); + if (merged_value < vn) + merged_value = vn; + } + io.AddKeyAnalogEvent(key, merged_value > 0.1f, merged_value); +} + static void ImGui_ImplSDL2_UpdateGamepads() { + ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - return; - // Get gamepad + // Update list of controller(s) to use + if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL2_GamepadMode_Manual) + { + ImGui_ImplSDL2_CloseGamepads(); + int joystick_count = SDL_NumJoysticks(); + for (int n = 0; n < joystick_count; n++) + if (SDL_IsGameController(n)) + if (SDL_GameController* gamepad = SDL_GameControllerOpen(n)) + { + bd->Gamepads.push_back(gamepad); + if (bd->GamepadMode == ImGui_ImplSDL2_GamepadMode_AutoFirst) + break; + } + bd->WantUpdateGamepadsList = false; + } + + // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; - SDL_GameController* game_controller = SDL_GameControllerOpen(0); - if (!game_controller) + if (bd->Gamepads.Size == 0) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; // Update gamepad inputs - #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) - #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); } - #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); } - const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. - MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START); - MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); - MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square - MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle - MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle - MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross - MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); - MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); - MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); - MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); - MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); - MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); - MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767); - MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767); - MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK); - MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK); - MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767); - #undef MAP_BUTTON - #undef MAP_ANALOG + const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK); + ImGui_ImplSDL2_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767); + ImGui_ImplSDL2_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768); + 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). @@ -821,10 +877,10 @@ void ImGui_ImplSDL2_NewFrame() io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; - if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) + if (bd->MouseLastLeaveFrame && bd->MouseLastLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) { bd->MouseWindowID = 0; - bd->PendingMouseLeaveFrame = 0; + bd->MouseLastLeaveFrame = 0; io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); } @@ -855,7 +911,7 @@ struct ImGui_ImplSDL2_ViewportData Uint32 WindowID; bool WindowOwned; SDL_GLContext GLContext; - NativeChildWindow *ChildWindow = nullptr; + ImGui_ImplSDL2_ViewportData() { Window = nullptr; WindowID = 0; WindowOwned = false; GLContext = nullptr; } ~ImGui_ImplSDL2_ViewportData() { IM_ASSERT(Window == nullptr && GLContext == nullptr); } }; @@ -892,83 +948,8 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) #if SDL_HAS_ALWAYS_ON_TOP sdl_flags |= (viewport->Flags & ImGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; #endif - - //Microstrain Custom - if(viewport->Flags & ImGuiViewportFlags_NativeChild) - { - float x_pos = viewport->Pos.x - main_viewport->Pos.x; - float y_pos = viewport->Pos.y - main_viewport->Pos.y; - - NativeChildWindow *child_window = new NativeChildWindow; - - ImGuiViewport *parent_viewport = ImGui::FindViewportByID(viewport->ParentViewportId); - - while (parent_viewport->Flags & ImGuiViewportFlags_NativeChild) - parent_viewport = ImGui::FindViewportByID(parent_viewport->ParentViewportId); - - ImGui_ImplSDL2_ViewportData *parent_viewport_data = (ImGui_ImplSDL2_ViewportData *)parent_viewport->PlatformUserData; - - void *parent_ptr = nullptr; - SDL_Window *parent_window = parent_viewport_data->Window; - -#ifdef __linux__ - parent_ptr = parent_window; -#else - if (parent_window != nullptr) - { - SDL_SysWMinfo wmInfo; - SDL_VERSION(&wmInfo.version); - SDL_GetWindowWMInfo(parent_window, &wmInfo); - -#if defined _WIN32 - parent_ptr = wmInfo.info.win.window; -#endif - -#if defined __APPLE__ - parent_ptr = wmInfo.info.cocoa.window; -#endif - } - else - { - parent_ptr = main_viewport->PlatformHandleRaw; - } - -#endif - - if(child_window->create(parent_ptr, (int)(x_pos), (int)(y_pos), (int)viewport->Size.x, (int)viewport->Size.y)) - { - void *native_child_window = child_window->get(); - -//#ifdef __linux__ - - //SDL_SysWMinfo info = SDL_SysWMinfo(); - //SDL_VERSION(&info.version); - - //vd->Window = (SDL_Window *)native_child_window; -//#else - char address[100]; - - sprintf(address, "%p", (SDL_Window*)main_viewport->PlatformHandle); - SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, address); - SDL_SetHint(SDL_HINT_VIDEO_FOREIGN_WINDOW_OPENGL, "1"); - - vd->Window = SDL_CreateWindowFrom(native_child_window); - - child_window->enableHighDpi(); -//#endif - vd->ChildWindow = child_window; - } - else - return; - } - //Standard window creation - else - { - 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->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); @@ -978,10 +959,9 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) SDL_GL_MakeCurrent(vd->Window, backup_context); viewport->PlatformHandle = (void*)vd->Window; - + viewport->PlatformHandleRaw = nullptr; SDL_SysWMinfo info; SDL_VERSION(&info.version); - if (SDL_GetWindowWMInfo(vd->Window, &info)) { #if defined(SDL_VIDEO_DRIVER_WINDOWS) @@ -1000,14 +980,6 @@ static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport) SDL_GL_DeleteContext(vd->GLContext); if (vd->Window && vd->WindowOwned) SDL_DestroyWindow(vd->Window); - - if(vd->ChildWindow != nullptr) - { - NativeChildWindow *child_window = (NativeChildWindow *)vd->ChildWindow; - child_window->destroy(); - delete child_window; - } - vd->GLContext = nullptr; vd->Window = nullptr; IM_DELETE(vd); @@ -1053,38 +1025,7 @@ static ImVec2 ImGui_ImplSDL2_GetWindowPos(ImGuiViewport* viewport) static void ImGui_ImplSDL2_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) { ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - - int pos_x = (int)pos.x, pos_y = (int)pos.y; - - ImGuiViewport *parent_viewport = ImGui::FindViewportByID(viewport->ParentViewportId); - - while (parent_viewport->Flags & ImGuiViewportFlags_NativeChild) - parent_viewport = ImGui::FindViewportByID(parent_viewport->ParentViewportId); - - //Microstrain edit (use child coordinates for child windows) -#if defined(_WIN32) - if(vd->ChildWindow != nullptr) - { - pos_x = (int)(viewport->Pos.x - parent_viewport->Pos.x); - pos_y = (int)(viewport->Pos.y - parent_viewport->Pos.y); - - SetWindowPos((HWND)vd->ChildWindow->get(), HWND_TOP, pos_x, pos_y, 0, 0, SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOSIZE); - } -#elif defined __linux__ - if(vd->ChildWindow != nullptr) - { - pos_x = viewport->Pos.x - parent_viewport->Pos.x; - pos_y = viewport->Pos.y - parent_viewport->Pos.y; - - if(vd->ChildWindow) - { - vd->ChildWindow->setSize(pos_x, pos_y, viewport->Size.x, viewport->Size.y); - } - } - -#else - SDL_SetWindowPosition(vd->Window, pos_x, pos_y); -#endif + SDL_SetWindowPosition(vd->Window, (int)pos.x, (int)pos.y); } static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport) @@ -1098,17 +1039,7 @@ static ImVec2 ImGui_ImplSDL2_GetWindowSize(ImGuiViewport* viewport) static void ImGui_ImplSDL2_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) { ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData; - - //Microstrain edit (use child coordinates for child windows) -#if defined(_WIN32) - if (vd->ChildWindow != nullptr) - { - SetWindowPos((HWND)vd->ChildWindow->get(), HWND_TOP, 0, 0, size.x, size.y, SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOMOVE); - } -#else - SDL_SetWindowSize(vd->Window, (int)size.x, (int)size.y); -#endif } static void ImGui_ImplSDL2_SetWindowTitle(ImGuiViewport* viewport, const char* title) diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index dee37fb62138..1fba66c2eb40 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -9,8 +9,9 @@ // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. -// Missing features: -// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows). +// 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). // [x] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. @@ -27,6 +28,7 @@ struct SDL_Window; struct SDL_Renderer; +struct _SDL_GameController; typedef union SDL_Event SDL_Event; IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); @@ -39,8 +41,9 @@ IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter -#endif +// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. +// When using manual mode, caller is responsible for opening/closing gamepad. +enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = NULL, int manual_gamepads_count = -1); #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index d7adc03ca5a0..34672735cb69 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -10,9 +10,10 @@ // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [x] Platform: 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: -// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows). -// [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. +// 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). +// [ ] Platform: IME SUPPORT IS BROKEN IN SDL3 BECAUSE INPUTS GETS SENT TO BOTH APP AND IME + 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. @@ -24,7 +25,9 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-04-15: Inputs: Re-enable calling SDL_StartTextInput()/SDL_StopTextInput() as SDL3 no longer enables it by default and should play nicer with IME. +// 2024-02-13: Inputs: Fixed gamepad support. Handle gamepad disconnection. Added ImGui_ImplSDL3_SetGamepadMode(). // 2023-11-13: Updated for recent SDL3 API changes. // 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys. // 2023-05-04: Fixed build on Emscripten/iOS/Android. (#6391) @@ -64,19 +67,26 @@ // SDL Data struct ImGui_ImplSDL3_Data { - SDL_Window* Window; - SDL_Renderer* Renderer; - Uint64 Time; - Uint32 MouseWindowID; - int MouseButtonsDown; - SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; - SDL_Cursor* LastMouseCursor; - int PendingMouseLeaveFrame; - char* ClipboardTextData; - bool MouseCanUseGlobalState; - bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. - bool UseVulkan; - bool WantUpdateMonitors; + SDL_Window* Window; + SDL_Renderer* Renderer; + Uint64 Time; + char* ClipboardTextData; + bool UseVulkan; + bool WantUpdateMonitors; + + // Mouse handling + Uint32 MouseWindowID; + int MouseButtonsDown; + SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT]; + SDL_Cursor* MouseLastCursor; + int MousePendingLeaveFrame; + bool MouseCanUseGlobalState; + bool MouseCanReportHoveredViewport; // This is hard to use/unreliable on SDL so we'll set ImGuiBackendFlags_HasMouseHoveredViewport dynamically based on state. + + // Gamepad handling + ImVector Gamepads; + ImGui_ImplSDL3_GamepadMode GamepadMode; + bool WantUpdateGamepadsList; ImGui_ImplSDL3_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -120,6 +130,11 @@ static void ImGui_ImplSDL3_SetPlatformImeData(ImGuiViewport* viewport, ImGuiPlat r.w = 1; r.h = (int)data->InputLineHeight; SDL_SetTextInputRect(&r); + SDL_StartTextInput(); + } + else + { + SDL_StopTextInput(); } } @@ -339,7 +354,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) case SDL_EVENT_WINDOW_MOUSE_ENTER: { bd->MouseWindowID = event->window.windowID; - bd->PendingMouseLeaveFrame = 0; + bd->MousePendingLeaveFrame = 0; return true; } // - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late, @@ -348,7 +363,7 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) // FIXME: Unconfirmed whether this is still needed with SDL3. case SDL_EVENT_WINDOW_MOUSE_LEAVE: { - bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1; + bd->MousePendingLeaveFrame = ImGui::GetFrameCount() + 1; return true; } case SDL_EVENT_WINDOW_FOCUS_GAINED: @@ -371,6 +386,12 @@ bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event) return true; } return true; + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: + { + bd->WantUpdateGamepadsList = true; + return true; + } } return false; } @@ -430,6 +451,10 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void io.ClipboardUserData = nullptr; io.SetPlatformImeDataFn = ImGui_ImplSDL3_SetPlatformImeData; + // Gamepad handling + bd->GamepadMode = ImGui_ImplSDL3_GamepadMode_AutoFirst; + bd->WantUpdateGamepadsList = true; + // Load mouse cursors bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); @@ -504,6 +529,8 @@ bool ImGui_ImplSDL3_InitForOther(SDL_Window* window) return ImGui_ImplSDL3_Init(window, nullptr, nullptr); } +static void ImGui_ImplSDL3_CloseGamepads(); + void ImGui_ImplSDL3_Shutdown() { ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); @@ -516,7 +543,7 @@ void ImGui_ImplSDL3_Shutdown() SDL_free(bd->ClipboardTextData); for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) SDL_DestroyCursor(bd->MouseCursors[cursor_n]); - bd->LastMouseCursor = nullptr; + ImGui_ImplSDL3_CloseGamepads(); io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; @@ -532,11 +559,14 @@ static void ImGui_ImplSDL3_UpdateMouseData() // We forward mouse input when hovered or captured (via SDL_EVENT_MOUSE_MOTION) or when focused (below) #if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE +// MicroStrain start #if !defined(_WIN32) && defined(NDEBUG) - // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside // On linux, this can get the mouse stuck when a breakpoint is hit, so disable for debug builds. + // See https://github.com/ocornut/imgui/issues/4197 and https://github.com/ocornut/imgui/issues/3650 +// MicroStrain end + // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE); -#endif +#endif // MicroStrain SDL_Window* focused_window = SDL_GetKeyboardFocus(); const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window))); #else @@ -608,59 +638,119 @@ static void ImGui_ImplSDL3_UpdateMouseCursor() { // Show OS mouse cursor SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]; - if (bd->LastMouseCursor != expected_cursor) + if (bd->MouseLastCursor != expected_cursor) { SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113) - bd->LastMouseCursor = expected_cursor; + bd->MouseLastCursor = expected_cursor; } SDL_ShowCursor(); } } +static void ImGui_ImplSDL3_CloseGamepads() +{ + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); + if (bd->GamepadMode != ImGui_ImplSDL3_GamepadMode_Manual) + for (SDL_Gamepad* gamepad : bd->Gamepads) + SDL_CloseGamepad(gamepad); + bd->Gamepads.resize(0); +} + +void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array, int manual_gamepads_count) +{ + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); + ImGui_ImplSDL3_CloseGamepads(); + if (mode == ImGui_ImplSDL3_GamepadMode_Manual) + { + IM_ASSERT(manual_gamepads_array != nullptr && manual_gamepads_count > 0); + for (int n = 0; n < manual_gamepads_count; n++) + bd->Gamepads.push_back(manual_gamepads_array[n]); + } + else + { + IM_ASSERT(manual_gamepads_array == nullptr && manual_gamepads_count <= 0); + bd->WantUpdateGamepadsList = true; + } + bd->GamepadMode = mode; +} + +static void ImGui_ImplSDL3_UpdateGamepadButton(ImGui_ImplSDL3_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GamepadButton button_no) +{ + bool merged_value = false; + for (SDL_Gamepad* gamepad : bd->Gamepads) + merged_value |= SDL_GetGamepadButton(gamepad, button_no) != 0; + io.AddKeyEvent(key, merged_value); +} + +static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; } +static void ImGui_ImplSDL3_UpdateGamepadAnalog(ImGui_ImplSDL3_Data* bd, ImGuiIO& io, ImGuiKey key, SDL_GamepadAxis axis_no, float v0, float v1) +{ + float merged_value = 0.0f; + for (SDL_Gamepad* gamepad : bd->Gamepads) + { + float vn = Saturate((float)(SDL_GetGamepadAxis(gamepad, axis_no) - v0) / (float)(v1 - v0)); + if (merged_value < vn) + merged_value = vn; + } + io.AddKeyAnalogEvent(key, merged_value > 0.1f, merged_value); +} + static void ImGui_ImplSDL3_UpdateGamepads() { ImGuiIO& io = ImGui::GetIO(); - if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. - return; + ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); + + // Update list of gamepads to use + if (bd->WantUpdateGamepadsList && bd->GamepadMode != ImGui_ImplSDL3_GamepadMode_Manual) + { + ImGui_ImplSDL3_CloseGamepads(); + int sdl_gamepads_count = 0; + SDL_JoystickID* sdl_gamepads = SDL_GetGamepads(&sdl_gamepads_count); + for (int n = 0; n < sdl_gamepads_count; n++) + if (SDL_Gamepad* gamepad = SDL_OpenGamepad(sdl_gamepads[n])) + { + bd->Gamepads.push_back(gamepad); + if (bd->GamepadMode == ImGui_ImplSDL3_GamepadMode_AutoFirst) + break; + } + SDL_free(sdl_gamepads); + bd->WantUpdateGamepadsList = false; + } - // Get gamepad + // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs. + if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) + return; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; - SDL_Gamepad* gamepad = SDL_OpenGamepad(0); - if (!gamepad) + if (bd->Gamepads.Size == 0) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; // Update gamepad inputs - #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) - #define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GetGamepadButton(gamepad, BUTTON_NO) != 0); } - #define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GetGamepadAxis(gamepad, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); } - const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. - MAP_BUTTON(ImGuiKey_GamepadStart, SDL_GAMEPAD_BUTTON_START); - MAP_BUTTON(ImGuiKey_GamepadBack, SDL_GAMEPAD_BUTTON_BACK); - MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_GAMEPAD_BUTTON_WEST); // Xbox X, PS Square - MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_GAMEPAD_BUTTON_EAST); // Xbox B, PS Circle - MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_GAMEPAD_BUTTON_NORTH); // Xbox Y, PS Triangle - MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_GAMEPAD_BUTTON_SOUTH); // Xbox A, PS Cross - MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT); - MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT); - MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_GAMEPAD_BUTTON_DPAD_UP); - MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN); - MAP_BUTTON(ImGuiKey_GamepadL1, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER); - MAP_BUTTON(ImGuiKey_GamepadR1, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER); - MAP_ANALOG(ImGuiKey_GamepadL2, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0.0f, 32767); - MAP_ANALOG(ImGuiKey_GamepadR2, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0.0f, 32767); - MAP_BUTTON(ImGuiKey_GamepadL3, SDL_GAMEPAD_BUTTON_LEFT_STICK); - MAP_BUTTON(ImGuiKey_GamepadR3, SDL_GAMEPAD_BUTTON_RIGHT_STICK); - MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_GAMEPAD_AXIS_LEFTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_GAMEPAD_AXIS_LEFTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_GAMEPAD_AXIS_LEFTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_GAMEPAD_AXIS_LEFTY, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_GAMEPAD_AXIS_RIGHTX, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_GAMEPAD_AXIS_RIGHTX, +thumb_dead_zone, +32767); - MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_GAMEPAD_AXIS_RIGHTY, -thumb_dead_zone, -32768); - MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767); - #undef MAP_BUTTON - #undef MAP_ANALOG + const int thumb_dead_zone = 8000; // SDL_gamepad.h suggests using this value. + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadStart, SDL_GAMEPAD_BUTTON_START); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadBack, SDL_GAMEPAD_BUTTON_BACK); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceLeft, SDL_GAMEPAD_BUTTON_WEST); // Xbox X, PS Square + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceRight, SDL_GAMEPAD_BUTTON_EAST); // Xbox B, PS Circle + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceUp, SDL_GAMEPAD_BUTTON_NORTH); // Xbox Y, PS Triangle + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadFaceDown, SDL_GAMEPAD_BUTTON_SOUTH); // Xbox A, PS Cross + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadLeft, SDL_GAMEPAD_BUTTON_DPAD_LEFT); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadRight, SDL_GAMEPAD_BUTTON_DPAD_RIGHT); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadUp, SDL_GAMEPAD_BUTTON_DPAD_UP); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadDpadDown, SDL_GAMEPAD_BUTTON_DPAD_DOWN); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL1, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR1, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadL2, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 0.0f, 32767); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadR2, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 0.0f, 32767); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadL3, SDL_GAMEPAD_BUTTON_LEFT_STICK); + ImGui_ImplSDL3_UpdateGamepadButton(bd, io, ImGuiKey_GamepadR3, SDL_GAMEPAD_BUTTON_RIGHT_STICK); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickLeft, SDL_GAMEPAD_AXIS_LEFTX, -thumb_dead_zone, -32768); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickRight, SDL_GAMEPAD_AXIS_LEFTX, +thumb_dead_zone, +32767); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickUp, SDL_GAMEPAD_AXIS_LEFTY, -thumb_dead_zone, -32768); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadLStickDown, SDL_GAMEPAD_AXIS_LEFTY, +thumb_dead_zone, +32767); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickLeft, SDL_GAMEPAD_AXIS_RIGHTX, -thumb_dead_zone, -32768); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickRight, SDL_GAMEPAD_AXIS_RIGHTX, +thumb_dead_zone, +32767); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickUp, SDL_GAMEPAD_AXIS_RIGHTY, -thumb_dead_zone, -32768); + ImGui_ImplSDL3_UpdateGamepadAnalog(bd, io, ImGuiKey_GamepadRStickDown, SDL_GAMEPAD_AXIS_RIGHTY, +thumb_dead_zone, +32767); } static void ImGui_ImplSDL3_UpdateMonitors() @@ -722,10 +812,10 @@ void ImGui_ImplSDL3_NewFrame() io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f); bd->Time = current_time; - if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) + if (bd->MousePendingLeaveFrame && bd->MousePendingLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) { bd->MouseWindowID = 0; - bd->PendingMouseLeaveFrame = 0; + bd->MousePendingLeaveFrame = 0; io.AddMousePosEvent(-FLT_MAX, -FLT_MAX); } diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 1a4b317061dd..ef5497e88c54 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -10,9 +10,11 @@ // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [x] Platform: 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: -// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows). +// 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). // [x] Platform: Basic IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!. +// [ ] Platform: IME SUPPORT IS BROKEN IN SDL3 BECAUSE INPUTS GETS SENT TO BOTH APP AND IME + 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. @@ -28,6 +30,7 @@ struct SDL_Window; struct SDL_Renderer; +struct SDL_Gamepad; typedef union SDL_Event SDL_Event; IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); @@ -40,4 +43,9 @@ IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); +// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. +// When using manual mode, caller is responsible for opening/closing gamepad. +enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual }; +IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = NULL, int manual_gamepads_count = -1); + #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 29671be0dc47..6675356e4f50 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -22,6 +22,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2024-02-12: Amend to query SDL_RenderViewportSet() and restore viewport accordingly. // 2023-05-30: Initial version. #include "imgui.h" @@ -131,10 +132,12 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data) struct BackupSDLRendererState { SDL_Rect Viewport; + bool ViewportEnabled; bool ClipEnabled; SDL_Rect ClipRect; }; BackupSDLRendererState old = {}; + old.ViewportEnabled = SDL_RenderViewportSet(bd->SDLRenderer) == SDL_TRUE; old.ClipEnabled = SDL_RenderClipEnabled(bd->SDLRenderer) == SDL_TRUE; SDL_GetRenderViewport(bd->SDLRenderer, &old.Viewport); SDL_GetRenderClipRect(bd->SDLRenderer, &old.ClipRect); @@ -180,11 +183,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data) const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos)); const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv)); -#if SDL_VERSION_ATLEAST(2,0,19) const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+ -#else - const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18 -#endif // Bind texture, Draw SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); @@ -199,7 +198,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data) } // Restore modified SDL_Renderer state - SDL_SetRenderViewport(bd->SDLRenderer, &old.Viewport); + SDL_SetRenderViewport(bd->SDLRenderer, old.ViewportEnabled ? &old.Viewport : nullptr); SDL_SetRenderClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : nullptr); } diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index c02aada2d855..e7f7c8d82559 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -34,7 +34,13 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-02-14: *BREAKING CHANGE*: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. +// 2024-02-12: *BREAKING CHANGE*: Dynamic rendering now require filling PipelineRenderingCreateInfo structure. +// 2024-01-19: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by allocating one extra semaphore than in-flight frames. (#7236) +// 2024-01-11: Vulkan: Fixed vkMapMemory() calls unnecessarily using full buffer size (#3957). Fixed MinAllocationSize handing (#7189). +// 2024-01-03: Vulkan: Added MinAllocationSize field in ImGui_ImplVulkan_InitInfo to workaround zealous "best practice" validation layer. (#7189, #4238) +// 2024-01-03: Vulkan: Stopped creating command pools with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT as we don't reset them. // 2023-11-29: Vulkan: Fixed mismatching allocator passed to vkCreateCommandPool() vs vkDestroyCommandPool(). (#7075) // 2023-11-10: *BREAKING CHANGE*: Removed parameter from ImGui_ImplVulkan_CreateFontsTexture(): backend now creates its own command-buffer to upload fonts. // *BREAKING CHANGE*: Removed ImGui_ImplVulkan_DestroyFontUploadObjects() which is now unecessary as we create and destroy those objects in the backend. @@ -81,85 +87,24 @@ #ifndef IMGUI_DISABLE #include "imgui_impl_vulkan.h" #include +#ifndef IM_MAX +#define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) +#endif // Visual Studio warnings #ifdef _MSC_VER #pragma warning (disable: 4127) // condition expression is constant #endif -// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() -// [Please zero-clear before use!] -struct ImGui_ImplVulkanH_FrameRenderBuffers -{ - VkDeviceMemory VertexBufferMemory; - VkDeviceMemory IndexBufferMemory; - VkDeviceSize VertexBufferSize; - VkDeviceSize IndexBufferSize; - VkBuffer VertexBuffer; - VkBuffer IndexBuffer; -}; - -// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers -// [Please zero-clear before use!] -struct ImGui_ImplVulkanH_WindowRenderBuffers -{ - uint32_t Index; - uint32_t Count; - ImGui_ImplVulkanH_FrameRenderBuffers* FrameRenderBuffers; -}; - -// 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 -{ - bool WindowOwned; - ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only - ImGui_ImplVulkanH_WindowRenderBuffers RenderBuffers; // Used by all viewports - - ImGui_ImplVulkan_ViewportData() { WindowOwned = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } - ~ImGui_ImplVulkan_ViewportData() { } -}; - -// Vulkan data -struct ImGui_ImplVulkan_Data -{ - ImGui_ImplVulkan_InitInfo VulkanInitInfo; - VkRenderPass RenderPass; - VkDeviceSize BufferMemoryAlignment; - VkPipelineCreateFlags PipelineCreateFlags; - VkDescriptorSetLayout DescriptorSetLayout; - VkPipelineLayout PipelineLayout; - VkPipeline Pipeline; - uint32_t Subpass; - VkShaderModule ShaderModuleVert; - VkShaderModule ShaderModuleFrag; - - // Font data - VkSampler FontSampler; - VkDeviceMemory FontMemory; - VkImage FontImage; - VkImageView FontView; - VkDescriptorSet FontDescriptorSet; - VkCommandPool FontCommandPool; - VkCommandBuffer FontCommandBuffer; - - // Render buffers for main window - ImGui_ImplVulkanH_WindowRenderBuffers MainWindowRenderBuffers; - - ImGui_ImplVulkan_Data() - { - memset((void*)this, 0, sizeof(*this)); - BufferMemoryAlignment = 256; - } -}; - // Forward Declarations +struct ImGui_ImplVulkan_FrameRenderBuffers; +struct ImGui_ImplVulkan_WindowRenderBuffers; bool ImGui_ImplVulkan_CreateDeviceObjects(); void ImGui_ImplVulkan_DestroyDeviceObjects(); +void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator); +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_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator); -void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, 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); @@ -251,12 +196,75 @@ IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF) #undef IMGUI_VULKAN_FUNC_DEF #endif // VK_NO_PROTOTYPES -#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) -#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING static PFN_vkCmdBeginRenderingKHR ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR; static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR; #endif +// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData() +// [Please zero-clear before use!] +struct ImGui_ImplVulkan_FrameRenderBuffers +{ + VkDeviceMemory VertexBufferMemory; + VkDeviceMemory IndexBufferMemory; + VkDeviceSize VertexBufferSize; + VkDeviceSize IndexBufferSize; + VkBuffer VertexBuffer; + VkBuffer IndexBuffer; +}; + +// Each viewport will hold 1 ImGui_ImplVulkanH_WindowRenderBuffers +// [Please zero-clear before use!] +struct ImGui_ImplVulkan_WindowRenderBuffers +{ + uint32_t Index; + uint32_t Count; + ImGui_ImplVulkan_FrameRenderBuffers* FrameRenderBuffers; +}; + +// 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 +{ + bool WindowOwned; + ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only + ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports + + ImGui_ImplVulkan_ViewportData() { WindowOwned = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } + ~ImGui_ImplVulkan_ViewportData() { } +}; + +// Vulkan data +struct ImGui_ImplVulkan_Data +{ + ImGui_ImplVulkan_InitInfo VulkanInitInfo; + VkDeviceSize BufferMemoryAlignment; + VkPipelineCreateFlags PipelineCreateFlags; + VkDescriptorSetLayout DescriptorSetLayout; + VkPipelineLayout PipelineLayout; + VkPipeline Pipeline; + VkShaderModule ShaderModuleVert; + VkShaderModule ShaderModuleFrag; + + // Font data + VkSampler FontSampler; + VkDeviceMemory FontMemory; + VkImage FontImage; + VkImageView FontView; + VkDescriptorSet FontDescriptorSet; + VkCommandPool FontCommandPool; + VkCommandBuffer FontCommandBuffer; + + // Render buffers for main window + ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers; + + ImGui_ImplVulkan_Data() + { + memset((void*)this, 0, sizeof(*this)); + BufferMemoryAlignment = 256; + } +}; + //----------------------------------------------------------------------------- // SHADERS //----------------------------------------------------------------------------- @@ -265,7 +273,7 @@ static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR; static void ImGui_ImplVulkan_InitPlatformInterface(); static void ImGui_ImplVulkan_ShutdownPlatformInterface(); -// glsl_shader.vert, compiled with: +// backends/vulkan/glsl_shader.vert, compiled with: // # glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert /* #version 450 core @@ -329,7 +337,7 @@ static uint32_t __glsl_shader_vert_spv[] = 0x0000002d,0x0000002c,0x000100fd,0x00010038 }; -// glsl_shader.frag, compiled with: +// backends/vulkan/glsl_shader.frag, compiled with: // # glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag /* #version 450 core @@ -404,7 +412,13 @@ static void check_vk_result(VkResult err) v->CheckVkResultFn(err); } -static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& p_buffer_size, size_t new_size, VkBufferUsageFlagBits usage) +// Same as IM_MEMALIGN(). 'alignment' must be a power of two. +static inline VkDeviceSize AlignBufferSize(VkDeviceSize size, VkDeviceSize alignment) +{ + return (size + alignment - 1) & ~(alignment - 1); +} + +static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory, VkDeviceSize& buffer_size, size_t new_size, VkBufferUsageFlagBits usage) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; @@ -414,10 +428,10 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory if (buffer_memory != VK_NULL_HANDLE) vkFreeMemory(v->Device, buffer_memory, v->Allocator); - VkDeviceSize vertex_buffer_size_aligned = ((new_size - 1) / bd->BufferMemoryAlignment + 1) * bd->BufferMemoryAlignment; + VkDeviceSize buffer_size_aligned = AlignBufferSize(IM_MAX(v->MinAllocationSize, new_size), bd->BufferMemoryAlignment); VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buffer_info.size = vertex_buffer_size_aligned; + buffer_info.size = buffer_size_aligned; buffer_info.usage = usage; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; err = vkCreateBuffer(v->Device, &buffer_info, v->Allocator, &buffer); @@ -435,10 +449,10 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory err = vkBindBufferMemory(v->Device, buffer, buffer_memory, 0); check_vk_result(err); - p_buffer_size = req.size; + buffer_size = buffer_size_aligned; } -static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkanH_FrameRenderBuffers* rb, int fb_width, int fb_height) +static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline pipeline, VkCommandBuffer command_buffer, ImGui_ImplVulkan_FrameRenderBuffers* rb, int fb_width, int fb_height) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); @@ -499,23 +513,23 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // 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_ImplVulkanH_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; + ImGui_ImplVulkan_WindowRenderBuffers* wrb = &viewport_renderer_data->RenderBuffers; if (wrb->FrameRenderBuffers == nullptr) { wrb->Index = 0; wrb->Count = v->ImageCount; - wrb->FrameRenderBuffers = (ImGui_ImplVulkanH_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); - memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkanH_FrameRenderBuffers) * wrb->Count); + wrb->FrameRenderBuffers = (ImGui_ImplVulkan_FrameRenderBuffers*)IM_ALLOC(sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); + memset(wrb->FrameRenderBuffers, 0, sizeof(ImGui_ImplVulkan_FrameRenderBuffers) * wrb->Count); } IM_ASSERT(wrb->Count == v->ImageCount); wrb->Index = (wrb->Index + 1) % wrb->Count; - ImGui_ImplVulkanH_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index]; + ImGui_ImplVulkan_FrameRenderBuffers* rb = &wrb->FrameRenderBuffers[wrb->Index]; if (draw_data->TotalVtxCount > 0) { // Create or resize the vertex/index buffers - size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); - size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); + size_t vertex_size = AlignBufferSize(draw_data->TotalVtxCount * sizeof(ImDrawVert), bd->BufferMemoryAlignment); + size_t index_size = AlignBufferSize(draw_data->TotalIdxCount * sizeof(ImDrawIdx), bd->BufferMemoryAlignment); if (rb->VertexBuffer == VK_NULL_HANDLE || rb->VertexBufferSize < vertex_size) CreateOrResizeBuffer(rb->VertexBuffer, rb->VertexBufferMemory, rb->VertexBufferSize, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); if (rb->IndexBuffer == VK_NULL_HANDLE || rb->IndexBufferSize < index_size) @@ -524,9 +538,9 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm // Upload vertex/index data into a single contiguous GPU buffer ImDrawVert* vtx_dst = nullptr; ImDrawIdx* idx_dst = nullptr; - VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, rb->VertexBufferSize, 0, (void**)(&vtx_dst)); + VkResult err = vkMapMemory(v->Device, rb->VertexBufferMemory, 0, vertex_size, 0, (void**)&vtx_dst); check_vk_result(err); - err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, rb->IndexBufferSize, 0, (void**)(&idx_dst)); + err = vkMapMemory(v->Device, rb->IndexBufferMemory, 0, index_size, 0, (void**)&idx_dst); check_vk_result(err); for (int n = 0; n < draw_data->CmdListsCount; n++) { @@ -645,7 +659,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + info.flags = 0; info.queueFamilyIndex = v->QueueFamily; vkCreateCommandPool(v->Device, &info, v->Allocator, &bd->FontCommandPool); } @@ -697,7 +711,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() vkGetImageMemoryRequirements(v->Device, bd->FontImage, &req); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = req.size; + alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, req.memoryTypeBits); err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &bd->FontMemory); check_vk_result(err); @@ -738,7 +752,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() bd->BufferMemoryAlignment = (bd->BufferMemoryAlignment > req.alignment) ? bd->BufferMemoryAlignment : req.alignment; VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - alloc_info.allocationSize = req.size; + alloc_info.allocationSize = IM_MAX(v->MinAllocationSize, req.size); alloc_info.memoryTypeIndex = ImGui_ImplVulkan_MemoryType(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); err = vkAllocateMemory(v->Device, &alloc_info, v->Allocator, &upload_buffer_memory); check_vk_result(err); @@ -812,7 +826,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture() err = vkQueueSubmit(v->Queue, 1, &end_info, VK_NULL_HANDLE); check_vk_result(err); - err = vkDeviceWaitIdle(v->Device); + err = vkQueueWaitIdle(v->Queue); check_vk_result(err); vkDestroyBuffer(v->Device, upload_buffer, v->Allocator); @@ -966,13 +980,11 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC info.subpass = subpass; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - VkPipelineRenderingCreateInfoKHR pipelineRenderingCreateInfo = {}; - pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; - pipelineRenderingCreateInfo.colorAttachmentCount = 1; - pipelineRenderingCreateInfo.pColorAttachmentFormats = &bd->VulkanInitInfo.ColorAttachmentFormat; if (bd->VulkanInitInfo.UseDynamicRendering) { - info.pNext = &pipelineRenderingCreateInfo; + IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); + IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be NULL"); + info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } #endif @@ -1037,7 +1049,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, bd->RenderPass, v->MSAASamples, &bd->Pipeline, bd->Subpass); + ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass); return true; } @@ -1049,6 +1061,7 @@ void ImGui_ImplVulkan_DestroyDeviceObjects() ImGui_ImplVulkanH_DestroyAllViewportsRenderBuffers(v->Device, v->Allocator); ImGui_ImplVulkan_DestroyFontsTexture(); + if (bd->FontCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->FontCommandPool, 1, &bd->FontCommandBuffer); bd->FontCommandBuffer = VK_NULL_HANDLE; } if (bd->FontCommandPool) { vkDestroyCommandPool(v->Device, bd->FontCommandPool, v->Allocator); bd->FontCommandPool = VK_NULL_HANDLE; } if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; } if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; } @@ -1086,7 +1099,7 @@ bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const ch return true; } -bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass) +bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) { IM_ASSERT(g_FunctionsLoaded && "Need to call ImGui_ImplVulkan_LoadFunctions() if IMGUI_IMPL_VULKAN_NO_PROTOTYPES or VK_NO_PROTOTYPES are set!"); @@ -1122,11 +1135,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); if (info->UseDynamicRendering == false) - IM_ASSERT(render_pass != VK_NULL_HANDLE); + IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); bd->VulkanInitInfo = *info; - bd->RenderPass = render_pass; - bd->Subpass = info->Subpass; ImGui_ImplVulkan_CreateDeviceObjects(); @@ -1232,6 +1243,26 @@ void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set) vkFreeDescriptorSets(v->Device, v->DescriptorPool, 1, &descriptor_set); } +void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) +{ + if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; } + if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; } + if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; } + if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; } + buffers->VertexBufferSize = 0; + buffers->IndexBufferSize = 0; +} + +void ImGui_ImplVulkan_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkan_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator) +{ + for (uint32_t n = 0; n < buffers->Count; n++) + ImGui_ImplVulkan_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator); + IM_FREE(buffers->FrameRenderBuffers); + buffers->FrameRenderBuffers = nullptr; + buffers->Index = 0; + buffers->Count = 0; +} + //------------------------------------------------------------------------- // Internal / Miscellaneous Vulkan Helpers // (Used by example's main.cpp. Used by multi-viewport features. PROBABLY NOT used by your own app.) @@ -1319,19 +1350,17 @@ VkPresentModeKHR ImGui_ImplVulkanH_SelectPresentMode(VkPhysicalDevice physical_d void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_device, VkDevice device, ImGui_ImplVulkanH_Window* wd, uint32_t queue_family, const VkAllocationCallbacks* allocator) { IM_ASSERT(physical_device != VK_NULL_HANDLE && device != VK_NULL_HANDLE); - (void)physical_device; - (void)allocator; + IM_UNUSED(physical_device); // Create Command Buffers VkResult err; for (uint32_t i = 0; i < wd->ImageCount; i++) { ImGui_ImplVulkanH_Frame* fd = &wd->Frames[i]; - ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i]; { VkCommandPoolCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + info.flags = 0; info.queueFamilyIndex = queue_family; err = vkCreateCommandPool(device, &info, allocator, &fd->CommandPool); check_vk_result(err); @@ -1352,6 +1381,11 @@ void ImGui_ImplVulkanH_CreateWindowCommandBuffers(VkPhysicalDevice physical_devi err = vkCreateFence(device, &info, allocator, &fd->Fence); check_vk_result(err); } + } + + for (uint32_t i = 0; i < wd->SemaphoreCount; i++) + { + ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[i]; { VkSemaphoreCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; @@ -1387,10 +1421,9 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // We don't use ImGui_ImplVulkanH_DestroyWindow() because we want to preserve the old swapchain to create the new one. // Destroy old Framebuffer for (uint32_t i = 0; i < wd->ImageCount; i++) - { ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); + for (uint32_t i = 0; i < wd->SemaphoreCount; i++) ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - } IM_FREE(wd->Frames); IM_FREE(wd->FrameSemaphores); wd->Frames = nullptr; @@ -1449,11 +1482,12 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V err = vkGetSwapchainImagesKHR(device, wd->Swapchain, &wd->ImageCount, backbuffers); check_vk_result(err); - IM_ASSERT(wd->Frames == nullptr); + IM_ASSERT(wd->Frames == nullptr && wd->FrameSemaphores == nullptr); + wd->SemaphoreCount = wd->ImageCount + 1; wd->Frames = (ImGui_ImplVulkanH_Frame*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_Frame) * wd->ImageCount); - wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->ImageCount); + wd->FrameSemaphores = (ImGui_ImplVulkanH_FrameSemaphores*)IM_ALLOC(sizeof(ImGui_ImplVulkanH_FrameSemaphores) * wd->SemaphoreCount); memset(wd->Frames, 0, sizeof(wd->Frames[0]) * wd->ImageCount); - memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->ImageCount); + memset(wd->FrameSemaphores, 0, sizeof(wd->FrameSemaphores[0]) * wd->SemaphoreCount); for (uint32_t i = 0; i < wd->ImageCount; i++) wd->Frames[i].Backbuffer = backbuffers[i]; } @@ -1499,7 +1533,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V // We do not create a pipeline by default as this is also used by examples' main.cpp, // but secondary viewport in multi-viewport mode may want to create one with: - //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, bd->Subpass); + //ImGui_ImplVulkan_CreatePipeline(device, allocator, VK_NULL_HANDLE, wd->RenderPass, VK_SAMPLE_COUNT_1_BIT, &wd->Pipeline, v->Subpass); } // Create The Image Views @@ -1561,10 +1595,9 @@ void ImGui_ImplVulkanH_DestroyWindow(VkInstance instance, VkDevice device, ImGui //vkQueueWaitIdle(bd->Queue); for (uint32_t i = 0; i < wd->ImageCount; i++) - { ImGui_ImplVulkanH_DestroyFrame(device, &wd->Frames[i], allocator); + for (uint32_t i = 0; i < wd->SemaphoreCount; i++) ImGui_ImplVulkanH_DestroyFrameSemaphores(device, &wd->FrameSemaphores[i], allocator); - } IM_FREE(wd->Frames); IM_FREE(wd->FrameSemaphores); wd->Frames = nullptr; @@ -1597,32 +1630,12 @@ void ImGui_ImplVulkanH_DestroyFrameSemaphores(VkDevice device, ImGui_ImplVulkanH fsd->ImageAcquiredSemaphore = fsd->RenderCompleteSemaphore = VK_NULL_HANDLE; } -void ImGui_ImplVulkanH_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkanH_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator) -{ - if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; } - if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; } - if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; } - if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; } - buffers->VertexBufferSize = 0; - buffers->IndexBufferSize = 0; -} - -void ImGui_ImplVulkanH_DestroyWindowRenderBuffers(VkDevice device, ImGui_ImplVulkanH_WindowRenderBuffers* buffers, const VkAllocationCallbacks* allocator) -{ - for (uint32_t n = 0; n < buffers->Count; n++) - ImGui_ImplVulkanH_DestroyFrameRenderBuffers(device, &buffers->FrameRenderBuffers[n], allocator); - IM_FREE(buffers->FrameRenderBuffers); - buffers->FrameRenderBuffers = nullptr; - buffers->Index = 0; - buffers->Count = 0; -} - 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_ImplVulkanH_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator); + ImGui_ImplVulkan_DestroyWindowRenderBuffers(device, &vd->RenderBuffers, allocator); } //-------------------------------------------------------------------------------------------------------- @@ -1654,13 +1667,17 @@ static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport) } // Select Surface Format - const VkFormat requestSurfaceImageFormat[] = { -#if defined(IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING) - v->UseDynamicRendering && v->ColorAttachmentFormat ? v->ColorAttachmentFormat : VK_FORMAT_B8G8R8A8_UNORM, + ImVector 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 - VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM }; + 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, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); + 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) @@ -1684,7 +1701,7 @@ static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport) ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; if (vd->WindowOwned) ImGui_ImplVulkanH_DestroyWindow(v->Instance, v->Device, &vd->Window, v->Allocator); - ImGui_ImplVulkanH_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator); + ImGui_ImplVulkan_DestroyWindowRenderBuffers(v->Device, &vd->RenderBuffers, v->Allocator); IM_DELETE(vd); } viewport->RendererUserData = nullptr; @@ -1858,8 +1875,8 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) else check_vk_result(err); - wd->FrameIndex = (wd->FrameIndex + 1) % wd->ImageCount; // This is for the next vkWaitForFences() - wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores + wd->FrameIndex = (wd->FrameIndex + 1) % wd->ImageCount; // This is for the next vkWaitForFences() + wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } void ImGui_ImplVulkan_InitPlatformInterface() diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 45a1627a5b00..e1bbb4e224d4 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -47,9 +47,20 @@ #if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES) #define VK_NO_PROTOTYPES #endif +#if defined(VK_USE_PLATFORM_WIN32_KHR) && !defined(NOMINMAX) +#define NOMINMAX #include +#else +#include +#endif +#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) +#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +#endif // Initialization data, for ImGui_ImplVulkan_Init() +// - VkDescriptorPool should be created with VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, +// and must contain a pool size large enough to hold an ImGui VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor. +// - When using dynamic rendering, set UseDynamicRendering=true and fill PipelineRenderingCreateInfo structure. // [Please zero-clear before use!] struct ImGui_ImplVulkan_InitInfo { @@ -58,24 +69,31 @@ struct ImGui_ImplVulkan_InitInfo VkDevice Device; uint32_t QueueFamily; VkQueue Queue; + VkDescriptorPool DescriptorPool; // See requirements in note above + VkRenderPass RenderPass; // Ignored if using dynamic rendering + uint32_t MinImageCount; // >= 2 + uint32_t ImageCount; // >= MinImageCount + VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT + + // (Optional) VkPipelineCache PipelineCache; - VkDescriptorPool DescriptorPool; uint32_t Subpass; - uint32_t MinImageCount; // >= 2 - uint32_t ImageCount; // >= MinImageCount - VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT (0 -> default to VK_SAMPLE_COUNT_1_BIT) - // Dynamic Rendering (Optional) - bool UseDynamicRendering; // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. - VkFormat ColorAttachmentFormat; // Required for dynamic rendering + // (Optional) Dynamic Rendering + // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. + bool UseDynamicRendering; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; +#endif - // Allocation, Debugging + // (Optional) Allocation, Debugging const VkAllocationCallbacks* Allocator; void (*CheckVkResultFn)(VkResult err); + VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. }; // Called by user code -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass); +IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); @@ -155,6 +173,7 @@ struct ImGui_ImplVulkanH_Window VkClearValue ClearValue; uint32_t FrameIndex; // Current frame being rendered to (0 <= FrameIndex < FrameInFlightCount) uint32_t ImageCount; // Number of simultaneous in-flight frames (returned by vkGetSwapchainImagesKHR, usually derived from min_image_count) + uint32_t SemaphoreCount; // Number of simultaneous in-flight frames + 1, to be able to use it in vkAcquireNextImageKHR uint32_t SemaphoreIndex; // Current set of swapchain wait semaphores we're using (needs to be distinct from per frame data) ImGui_ImplVulkanH_Frame* Frames; ImGui_ImplVulkanH_FrameSemaphores* FrameSemaphores; diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 0e0c77b7cb21..6e82ebf4f25b 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -18,6 +18,10 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2024-01-22: Added configurable PipelineMultisampleState struct. (#7240) +// 2024-01-22: (Breaking) ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure instead of variety of parameters, allowing for easier further changes. +// 2024-01-22: Fixed pipeline layout leak. (#7245) +// 2024-01-17: Explicitly fill all of WGPUDepthStencilState since standard removed defaults. // 2023-07-13: Use WGPUShaderModuleWGSLDescriptor's code instead of source. use WGPUMipmapFilterMode_Linear instead of WGPUFilterMode_Linear. (#6602) // 2023-04-11: Align buffer sizes. Use WGSL shaders instead of precompiled SPIR-V. // 2023-04-11: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX). @@ -74,16 +78,17 @@ struct Uniforms struct ImGui_ImplWGPU_Data { - WGPUDevice wgpuDevice = nullptr; - WGPUQueue defaultQueue = nullptr; - WGPUTextureFormat renderTargetFormat = WGPUTextureFormat_Undefined; - WGPUTextureFormat depthStencilFormat = WGPUTextureFormat_Undefined; - WGPURenderPipeline pipelineState = nullptr; - - RenderResources renderResources; - FrameResources* pFrameResources = nullptr; - unsigned int numFramesInFlight = 0; - unsigned int frameIndex = UINT_MAX; + ImGui_ImplWGPU_InitInfo initInfo; + WGPUDevice wgpuDevice = nullptr; + WGPUQueue defaultQueue = nullptr; + WGPUTextureFormat renderTargetFormat = WGPUTextureFormat_Undefined; + WGPUTextureFormat depthStencilFormat = WGPUTextureFormat_Undefined; + WGPURenderPipeline pipelineState = nullptr; + + RenderResources renderResources; + FrameResources* pFrameResources = nullptr; + unsigned int numFramesInFlight = 0; + unsigned int frameIndex = UINT_MAX; }; // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts @@ -181,6 +186,12 @@ static void SafeRelease(WGPUBuffer& res) wgpuBufferRelease(res); res = nullptr; } +static void SafeRelease(WGPUPipelineLayout& res) +{ + if (res) + wgpuPipelineLayoutRelease(res); + res = nullptr; +} static void SafeRelease(WGPURenderPipeline& res) { if (res) @@ -331,7 +342,9 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder) { // Avoid rendering when minimized - if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdListsCount == 0) return; // FIXME: Assuming that this only gets called once per frame! @@ -450,6 +463,12 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder // Project scissor/clipping rectangles into framebuffer space ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); + + // Clamp to viewport as wgpuRenderPassEncoderSetScissorRect() won't accept values that are off bounds + if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } + if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } + if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; } + if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; } if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) continue; @@ -559,9 +578,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() graphics_pipeline_desc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined; graphics_pipeline_desc.primitive.frontFace = WGPUFrontFace_CW; graphics_pipeline_desc.primitive.cullMode = WGPUCullMode_None; - graphics_pipeline_desc.multisample.count = 1; - graphics_pipeline_desc.multisample.mask = UINT_MAX; - graphics_pipeline_desc.multisample.alphaToCoverageEnabled = false; + graphics_pipeline_desc.multisample = bd->initInfo.PipelineMultisampleState; // Bind group layouts WGPUBindGroupLayoutEntry common_bg_layout_entries[2] = {}; @@ -648,7 +665,13 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() depth_stencil_state.depthWriteEnabled = false; depth_stencil_state.depthCompare = WGPUCompareFunction_Always; depth_stencil_state.stencilFront.compare = WGPUCompareFunction_Always; + depth_stencil_state.stencilFront.failOp = WGPUStencilOperation_Keep; + depth_stencil_state.stencilFront.depthFailOp = WGPUStencilOperation_Keep; + depth_stencil_state.stencilFront.passOp = WGPUStencilOperation_Keep; depth_stencil_state.stencilBack.compare = WGPUCompareFunction_Always; + depth_stencil_state.stencilBack.failOp = WGPUStencilOperation_Keep; + depth_stencil_state.stencilBack.depthFailOp = WGPUStencilOperation_Keep; + depth_stencil_state.stencilBack.passOp = WGPUStencilOperation_Keep; // Configure disabled depth-stencil state graphics_pipeline_desc.depthStencil = (bd->depthStencilFormat == WGPUTextureFormat_Undefined) ? nullptr : &depth_stencil_state; @@ -678,6 +701,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() SafeRelease(vertex_shader_desc.module); SafeRelease(pixel_shader_desc.module); + SafeRelease(graphics_pipeline_desc.layout); SafeRelease(bg_layouts[0]); return true; @@ -699,7 +723,7 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects() SafeRelease(bd->pFrameResources[i]); } -bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format, WGPUTextureFormat depth_format) +bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info) { ImGuiIO& io = ImGui::GetIO(); IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); @@ -710,11 +734,12 @@ bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextur io.BackendRendererName = "imgui_impl_webgpu"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. - bd->wgpuDevice = device; + bd->initInfo = *init_info; + bd->wgpuDevice = init_info->Device; bd->defaultQueue = wgpuDeviceGetQueue(bd->wgpuDevice); - bd->renderTargetFormat = rt_format; - bd->depthStencilFormat = depth_format; - bd->numFramesInFlight = num_frames_in_flight; + bd->renderTargetFormat = init_info->RenderTargetFormat; + bd->depthStencilFormat = init_info->DepthStencilFormat; + bd->numFramesInFlight = init_info->NumFramesInFlight; bd->frameIndex = UINT_MAX; bd->renderResources.FontTexture = nullptr; @@ -727,8 +752,8 @@ bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextur bd->renderResources.ImageBindGroupLayout = nullptr; // Create buffers with a default size (they will later be grown as needed) - bd->pFrameResources = new FrameResources[num_frames_in_flight]; - for (int i = 0; i < num_frames_in_flight; i++) + bd->pFrameResources = new FrameResources[bd->numFramesInFlight]; + for (unsigned int i = 0; i < bd->numFramesInFlight; i++) { FrameResources* fr = &bd->pFrameResources[i]; fr->IndexBuffer = nullptr; diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index b83ef0e83a36..a43f34c08ef9 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -22,7 +22,24 @@ #include -IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(WGPUDevice device, int num_frames_in_flight, WGPUTextureFormat rt_format, WGPUTextureFormat depth_format = WGPUTextureFormat_Undefined); +// Initialization data, for ImGui_ImplWGPU_Init() +struct ImGui_ImplWGPU_InitInfo +{ + WGPUDevice Device; + int NumFramesInFlight = 3; + WGPUTextureFormat RenderTargetFormat = WGPUTextureFormat_Undefined; + WGPUTextureFormat DepthStencilFormat = WGPUTextureFormat_Undefined; + WGPUMultisampleState PipelineMultisampleState = {}; + + ImGui_ImplWGPU_InitInfo() + { + PipelineMultisampleState.count = 1; + PipelineMultisampleState.mask = UINT32_MAX; + PipelineMultisampleState.alphaToCoverageEnabled = false; + } +}; + +IMGUI_IMPL_API bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info); IMGUI_IMPL_API void ImGui_ImplWGPU_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWGPU_NewFrame(); IMGUI_IMPL_API void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder); diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 924f2f1d7a66..8cc0d9a11f8b 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -40,7 +40,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); // CHANGELOG // (minor and older changes stripped away, please see git history for details) -// 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 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). // 2023-09-07: Inputs: Added support for keyboard codepage conversion for when application is compiled in MBCS mode and using a non-Unicode window. @@ -1067,10 +1067,20 @@ 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) diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index e5aa79be1638..88a96a6bd9df 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -79,14 +79,14 @@ List of Renderer Backends: imgui_impl_sdlrenderer2.cpp ; SDL_Renderer (optional component of SDL2 available from SDL 2.0.18+) imgui_impl_sdlrenderer3.cpp ; SDL_Renderer (optional component of SDL3 available from SDL 3.0.0+) imgui_impl_vulkan.cpp ; Vulkan - imgui_impl_wgpu.cpp ; WebGPU + imgui_impl_wgpu.cpp ; WebGPU (web and desktop) List of high-level Frameworks Backends (combining Platform + Renderer): imgui_impl_allegro5.cpp Emscripten is also supported! -The SDL+GL, GLFW+GL and SDL+WebGPU examples are all ready to build and run with Emscripten. +The SDL+GL, GLFW+GL and GLFW+WebGPU examples are all ready to build and run with Emscripten. ### Backends for third-party frameworks, graphics API or other languages diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b7c60db8c2a5..9ff5a712c171 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -35,40 +35,350 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.90.6 WIP (In Progress) +----------------------------------------------------------------------- + +Breaking changes: + +Other changes: + +- Fonts: Fixed font ascent and descent calculation when a font hits exact integer values. + It is possible that some prior manual use of ImFontConfig::GlyphOffset may become + duplicate with this fix. (#7399, #7404) [@GamingMinds-DanielC] +- Text, DrawList: Improved handling of long single-line wrapped text. Faster and + mitigitate issues with reading vertex indexing limits with 16-bit indices. (#7496, #5720) +- Backends: SDL3: Fixed text inputs. Re-enable calling SDL_StartTextInput()/SDL_StopTextInput() + as SDL3 no longer enables it by default. (#7452, #6306, #6071, #1953) [@Green-Sky] +- Examples: GLFW+WebGPU: Added support for WebGPU-native/Dawn (#7435, #7132) [@eliasdaler, @Zelif] +- Examples: GLFW+WebGPU: Renamed example_emscripten_wgpu/ to example_glfw_wgpu/. (#7435, #7132) + +Docking+Viewports Branch: + +- Docking: when io.ConfigDockingWithShift is enabled, fixed help tooltip erroneously + reading SetNextWindowXXX() data. (#6709, #4643, #7491) [@ocornut, @cfillion] + ----------------------------------------------------------------------- - VERSION 1.90.1 WIP (In Progress) + VERSION 1.90.5 (Released 2024-04-11) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.5 + Breaking changes: +- More formally obsoleted GetKeyIndex() when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is set. + It has been unnecessary and a no-op since 1.87 (it returns the same value as passed + when used with a 1.87+ backend using io.AddKeyEvent() function). (#4921) + - IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) --> IsKeyPressed(ImGuiKey_XXX) +- ImDrawList: Merged the radius_x/radius_y parameters in AddEllipse(), AddEllipseFilled() + and PathEllipticalArcTo() into a single ImVec2 parameter. Exceptionally, because those + functions were added recently in 1.90, we are not adding inline redirection functions. + The transition is easy and should affect few users. (#2743, #7417) [@cfillion] + +Other changes: + +- Windows: Scrollbar visibility decision uses current size when both size and contents + size are submitted by API. (#7252) +- Windows: Double-click to collapse may be disabled via key-ownership mechanism. (#7369) +- Windows: BeginChild(): Extend outer resize borders to the edges when there are no corner + grips. Essentially affects resizable child windows. (#7440, #1710) [@cfillion] +- Windows: BeginChild(): Resizing logic for child windows evaluates whether per-axis clamping + should be applied based on parent scrollbars, not child scrollbars. (#7440, #1710) [@cfillion] + Adjust those resizing limits to match window padding rather than inner clipping rectangle. +- Tables: Fixed auto-width columns when using synced-instances of same table, width of + one instance would bleed into next one instead of sharing their widths. (#7218) +- Tables: Angled headers: fixed border hit box extending beyond when used within + non-scrollable tables. (#7416) [@cfillion] +- Tables: Angled headers: fixed borders not moving back up after TableAngleHeadersRow() + stops being called. (#7416) [@cfillion] +- Tables: Angled headers: rounding header size to nearest integers, fixes some issues + when using clipper. +- Menus, Popups: Fixed an issue where sibling menu popups re-opening in successive + frames would erroneously close the window. While it is technically a popup issue + it would generally manifest when fast moving the mouse bottom to top in a sub-menu. + (#7325, #7287, #7063) +- ProgressBar: Fixed passing fraction==NaN from leading to a crash. (#7451) +- ListBox: Fixed text-baseline offset when using SameLine()+Text() after a labeled ListBox(). +- Drags, Sliders, Inputs: Fixed io.PlatformLocaleDecimalPoint decimal point localization + feature not working regression from 1.90.1. (#7389, #6719, #2278) [@GamingMinds-DanielC] +- Style: Added ImGuiStyleVar_TabBorderSize, ImGuiStyleVar_TableAngledHeadersAngle for + consistency. (#7411) [@cfillion] +- DrawList: Added AddConcavePolyFilled(), PathFillConcave() concave filling. (#760) [@thedmd] + Note that only simple polygons (no self-intersections, no holes) are supported. +- DrawList: Allow AddText() to accept null ranges. (#3615, 7391) +- Docs: added more wiki links to headers of imgui.h/imgui.cpp to facilitate discovery + of interesting resources, because github doesn't allow Wiki to be crawled by search engines. + - This is the main wiki: https://github.com/ocornut/imgui/wiki + - This is the crawlable version: https://github-wiki-see.page/m/ocornut/imgui/wiki + Adding a link to the crawlable version, even though it is not intended for humans, + to increase its search rank. + +Docking+Viewports Branch: + +- Backends: Win32: made it so that an appearing viewport showing up doesn't bring + its parent to front. (#7354) + + +----------------------------------------------------------------------- + VERSION 1.90.4 (Released 2024-02-22) +----------------------------------------------------------------------- + +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.4 + Other changes: -- Windows: BeginChild(): Fixed auto-resizing erroneously limiting size to host viewport - minus padding. There are no limit to a child width/height. (#7063) [@Devyre] -- Nav, IO: SetNextFrameWantCaptureKeyboard(false) calls are not overrided back to true when - navigation is enabled. SetNextFrameWantCaptureKeyboard() is always higher priority. (#6997) -- Drag and Drop: Fixed drop target highlight on items temporarily pushing a widened clip rect - (namely Selectables and Treenodes using SpanAllColumn flag) so the highlight properly covers - all columns. (#7049, #4281, #3272) -- Menus: Tweaked hover slack logic, adding a timer to avoid situations where a slow vertical - movements toward another parent BeginMenu() can keep the wrong child menu open. (#6671, #6926) -- Debug Tools: Added DebugFlashStyleColor() to identify a style color. Added to Style Editor. +- Nav: Fixed SetKeyboardFocusHere() or programmatic tabbing API from not working on + windows with the ImGuiWindowFlags_NoNavInputs flag (regression in 1.90.2, which + among other things broke imgui_memory_editor). +- Menus, Popups: Fixed an issue where hovering a parent-menu upward would + erroneously close the window. (#7325, #7287, #7063) +- Popups: Fixed resizable popup minimum size being too small. Standardized minimum + size logic. (#7329). +- Modals: Temporary changes of ImGuiCol_ModalWindowDimBg are properly handled by + BeginPopupModal(). (#7340) +- Tables: Angled headers: fixed support for multi-line labels. (#6917) +- Tables: Angled headers: various fixes to accurately handle CellPadding changes. (#6917) +- Tables: Angled headers: properly registers horizontal component of angled headers + for auto-resizing of columns. (#6917) +- Tables: Angled headers: fixed TableAngledHeadersRow() incorrect background fill + drawn too low, particularly visible with tables that have no scrolling. (#6917) +- ProgressBar: Fixed a minor tessellation issue when rendering rounded progress bars, + where in some situations the rounded section wouldn't follow regular tessellation rules. +- Debug Tools: Item Picker: Promoted ImGui::DebugStartItemPicker() to public API. (#2673) +- Debug Tools: Item Picker: Menu entry visible in Demo->Tools but greyed out unless + io.ConfigDebugIsDebuggerPresent is set. (#2673) +- Misc: Added optional alpha multiplier parameter to GetColorU32(ImU32) variant. +- Demo: Custom Rendering: better demonstrate PathArcTo(), PathBezierQuadraticCurveTo(), + PathBezierCubicCurveTo(), PathStroke(), PathFillConvex() functions. + +Docking+Viewports Branch: + +- Backends: GLFW: enable ImGuiBackendFlags_HasMouseHoveredViewport support with GLFW 3.3.x, + as required specs for it was relaxed in 1.87. This enable better viewport hovering detection + without GLFW 3.4's GLFW_MOUSE_PASSTHROUGH, with less reliance on dear imgui's own heuristic + of platform windows order. (#7316) + + +----------------------------------------------------------------------- + VERSION 1.90.3 (Released 2024-02-14) +----------------------------------------------------------------------- + +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.3 + +Breaking changes: + +- Backends: SDL2: Removed obsolete ImGui_ImplSDL2_NewFrame(SDL_Window*) signature which + was obsoleted in 1.84. Calling ImGui_ImplSDL2_NewFrame() is fine. +- Backends: Vulkan: Moved RenderPass parameter from ImGui_ImplVulkan_Init() function to + ImGui_ImplVulkan_InitInfo structure. Not required when using dynamic rendering. (#7308) [@shawnhatori] +- Backends: Vulkan: Using dynamic rendering now require filling the PipelineRenderingCreateInfo + structure in ImGui_ImplVulkan_InitInfo, allowing to configure color/depth/stencil formats. + Removed ColorAttachmentFormat field previously provided for dynamic rendering. + (#7166, #6855, #5446, #5037) [@shawnhatori] + +Other changes: + +- Menus, Popups: Fixed menus and popups with ChildWindow flag erroneously not displaying + a scrollbar when contents is over parent viewport size. (#7287, #7063) [@ZingBallyhoo] +- Backends: SDL2, SDL3: Handle gamepad disconnection + fixed increasing gamepad reference + counter continuously. Added support for multiple simultaneous gamepads. + Added ImGui_ImplSDL2_SetGamepadMode()) function to select whether to automatically pick + first available gamepad, all gamepads, or specific gamepads. + (#3884, #6559, #6890, #7180) [@ocornut, @lethal-guitar, @wn2000, @bog-dan-ro] +- Backends: SDL3: Fixed gamepad handling. (#7180) [@bog-dan-ro] +- Backends: SDLRenderer3: query newly added SDL_RenderViewportSet() to not restore + a wrong viewport if none was initially set. +- Backends: DirectX9: Using RGBA format when allowed by the driver to avoid CPU side + conversion. (#6575) [@Demonese] +- Internals: Fixed ImFileOpen not working before context is created, preventing creation + of a font atlas before main context creation. (#7314, #7315) [@PathogenDavid, @ocornut] + + +----------------------------------------------------------------------- + VERSION 1.90.2 (Released 2024-02-09) +----------------------------------------------------------------------- + +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.2 + +Breaking changes: + +- Commented out ImGuiIO::ImeWindowHandle obsoleted in 1.87 in favor of writing + to 'void* ImGuiViewport::PlatformHandleRaw'. +- Backends: WebGPU: ImGui_ImplWGPU_Init() now takes a ImGui_ImplWGPU_InitInfo structure + instead of variety of parameters, allowing for easier further changes. (#7240) + +Other changes: + +- Nav: keyboard/gamepad activation mark widgets as held to give better visual feedback. +- Nav: tweak to logic marking navigated item as hovered when using keyboard, allowing + the hover highlight to stay even while another item is activated. +- Nav: Fixed SetKeyboardFocusHere() not working when current nav focus is in different scope, + regression from 1.90.1 related to code scoping Tab presses to local scope. (#7226) [@bratpilz] +- Nav: Fixed pressing Escape while in a child window with _NavFlattened flag. (#7237) +- Nav: Improve handling of Alt key to toggle menu so that key ownership may be claimed on + individual left/right alt key without interfering with the other. +- Nav, Menus: Fixed click on a BeginMenu() followed by right-arrow from making the child menu + reopen and flicker (using ImGuiPopupFlags_NoReopen). +- Nav: ImGuiWindowFlags_NoNavInputs is tested during scoring so NavFlattened windows can use it. +- Popups: OpenPopup(): added ImGuiPopupFlags_NoReopen flag to specifically not close and reopen + a popup when it is already open. (#1497, #1533) + (Note that this differs from specific handling we already have in place for the case of calling + OpenPopup() repeatedly every frame: we already didn't reopen in that specific situation, otherwise + the effect would be very disastrous in term of confusion, as reopening would steal focus). +- Popups: Slight change to popup closing logic (e.g. after focusing another window) which skipped + over popups that are also child windows. +- Combo: Fixed not reusing windows optimally when used inside a popup stack. +- Debug Tools: Metrics: Fixed debug break in SetShortcutRouting() not handling ImGuiMod_Shortcut redirect. +- Debug Tools: Metrics: Improved Monitors and Viewports minimap display. Highlight on hover. +- Debug Tools: Debug Log: Added "Input Routing" logging. +- Debug Tools: Added "nop" to IM_DEBUG_BREAK macro on GCC to work around GDB bug (#7266) [@Peter0x44] +- Backends: Vulkan: Fixed vkAcquireNextImageKHR() validation errors in VulkanSDK 1.3.275 by + allocating one extra semaphore than in-flight frames. (#7236) [@mklefrancois] +- Backends: Vulkan: Fixed vkMapMemory() calls unnecessarily using full buffer size. (#3957) +- Backends: Vulkan: Fixed handling of ImGui_ImplVulkan_InitInfo::MinAllocationSize field. (#7189, #4238) +- Backends: WebGPU: Added ImGui_ImplWGPU_InitInfo::PipelineMultisampleState. (#7240) +- Backends: WebGPU: Filling all WGPUDepthStencilState fields explicitly as a recent Dawn + update stopped setting default values. (#7232) [@GrigoryGraborenko] +- Backends: WebGPU: Fixed pipeline layout leak. (#7245) [@rajveermalviya] +- Backends: OpenGL3: Backup and restore GL_PIXEL_UNPACK_BUFFER. (#7253) +- Internals: Many improvements related to yet unpublicized shortcut routing and input ownership systems. +- Internals: InputText: Added internal helpers to force reload of user-buf when active. (#2890) [@kudaba, @ocornut] + Often requested in some form (#6962, #5219, #3290, #4627, #5054, #3878, #2881, #1506, #1216, #968), + and useful for interactive completion/suggestions popups (#2057, #718) + +Docking+Viewports Branch: + +- Added ImGuiWindowClass::FocusRouteParentWindowId as a way to connect the focus route between + a tool window to a parent document window, so that Shortcuts in the documents are routed when the + tool is focused (regardless of whether the tool is docked or in a floating viewport, etc.) (#6798) +- Added ImGuiDockNodeFlags_DockedWindowsInFocusRoute to automatically make a dockspace connect + the focus route of its docked window. This is provided a convenience in case you have windows + where a connection is not explicit. (#6798) +- Viewports: Fixed moving accross monitors when io.ConfigWindowsMoveFromTitleBarOnly is set. (#7299, #3071) +- Backends: OSX: Fixed not submitting Monitors info when viewports are not enabled, leading to + missing e.g. DpiScale info. (#7257) [@actboy168] + + +----------------------------------------------------------------------- + VERSION 1.90.1 (Released 2024-01-10) +----------------------------------------------------------------------- + +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90.1 + +Breaking changes: + +- imgui_freetype: commented out ImGuiFreeType::BuildFontAtlas() obsoleted in 1.81. + Prefer using #define IMGUI_ENABLE_FREETYPE or see commented code for manual calls. +- Removed CalcListClipping() marked obsolete in 1.86. (#3841) + Prefer using ImGuiListClipper which can return non-contiguous ranges. +- Internals, Columns: commented out legacy ImGuiColumnsFlags_XXX symbols redirecting + to ImGuiOldColumnsFlags_XXX, obsoleted from imgui_internal.h in 1.80. +- Commented out obsolete ImGuiKey_KeyPadEnter redirection to ImGuiKey_KeypadEnter. (#2625, #7143) + +Other changes: + +- Windows: + - BeginChild(): Fixed auto-resizing erroneously limiting size to host viewport + minus padding. There are no limit to a child width/height. (#7063) [@Devyre] + - BeginChild(): Resize borders rendered even when ImGuiWindowFlags_NoBackground + is specified. (#1710, #7194) + - Fixed some auto-resizing path using style.WindowMinSize.x (instead of x/y) + for both axises since 1.90. (#7106) [@n0bodysec] + - Scrolling: internal scrolling value is rounded instead of truncated, as a way to reduce + speed asymmetry when (incorrectly) attempting to scroll by non-integer amount. (#6677) +- Navigation (Keyboard/gamepad): + - Nav, IO: SetNextFrameWantCaptureKeyboard(false) calls are not overridden back to true when + navigation is enabled. SetNextFrameWantCaptureKeyboard() is always higher priority. (#6997) + - Nav: Activation can also be performed with Keypad Enter. (#5606) +- Drag and Drop: + - Fixed drop target highlight on items temporarily pushing a widened clip rect + (namely Selectables and Treenodes using SpanAllColumn flag) so the highlight properly covers + all columns. (#7049, #4281, #3272) +- InputText: + - InputTextMultiline: Fixed Tab character input not repeating (1.89.4 regression). + - InputTextMultiline: Tabbing through a multi-line text editor which allows Tab character inputs + (using the ImGuiInputTextFlags_AllowTabInput flag) doesn't automatically activate it, in order + to allow passing through multiple widgets easily. (#3092, #5759, #787) +- Drags, Sliders, Inputs: + - DragScalarN, SliderScalarN, InputScalarN: Fixed incorrect pushes into ItemWidth + stack when number of components is 1. [#7095] [@Nahor] + - Drags, Sliders, Inputs: removed all attempts to filter non-numerical characters during text + editing. Invalid inputs not applied to value, visibly reverted after validation. (#6810, #7096) + - Drags, Sliders, Inputs: removal of filter means that "nan" and "inf" values may be input. (#7096) + - DragScalarN, SliderScalarN, InputScalarN, PushMultiItemsWidths: improve multi-components + width computation to better distribute the error. (#7120, #7121) [@Nahor] +- Menus: + - Tweaked hover slack logic, adding an extra timeout to avoid situations where a slow vertical + movements toward another parent BeginMenu() can keep the wrong child menu open. (#6671, #6926) +- Color Editors: + - ColorEdit: Layout tweaks for very small sizes. (#7120, #7121) + - ColorPicker: Fixed saturation/value cursor radius not scaling properly. +- Tabs: Added ImGuiTabItemFlags_NoAssumedClosure to enable app to react on closure attempt, + without having to draw an unsaved document marker (ImGuiTabItemFlags_UnsavedDocument sets + _NoAssumedClosure automatically). (#7084) +- Debug Tools: + - Added io.ConfigDebugIsDebuggerPresent option. When enabled, this adds buttons in various + locations of Metrics/Debugger to manually request a debugger break: + - Request a debug break in a Begin() call. + - Request a debug break in a ItemAdd() call via debug log and hovering 0xXXXXXX identifiers. + - Request a debug break in a BeginTable() call. + - Request a debug break in a SetShortcutRouting()/Shortcut() call. [Internal] + - Metrics: Reorganize Tools menu. + - Added DebugFlashStyleColor() to identify a style color. Added to Style Editor. + - Debug Log: Hide its own clipper log to reduce noise in the output. (#5855) + - Debug Log: Clicking any filter with SHIFT held enables it for 2 frames only, + making it easier when dealing with spammy logs. (#5855) +- Settings: Fixed an issue marking settings as dirty when merely clicking on a border or resize + grip without moving it. - Misc: Added IMGUI_USER_H_FILENAME to change the path included when using IMGUI_INCLUDE_IMGUI_USER_H. (#7039) [@bryceberger] +- Misc: Rework debug display of texture id in Metrics window to avoid compile-error when + ImTextureID is defined to be larger than 64-bits. (#7090) - Misc: Added extra courtesy ==/!= operators when IMGUI_DEFINE_MATH_OPERATORS is defined. - Misc: Fixed text functions fast-path for handling "%s" and "%.*s" to handle null pointers gracefully, like most printf implementations. (#7016, #3466, #6846) [@codefrog2002] - Misc: Renamed some defines in imstb_textedit.h to avoid conflicts when using unity/jumbo builds on a codebase where another copy of the library is used. -- Backends: Vulkan: Fixed mismatching allocator passed to vkCreateCommandPool() vs - vkDestroyCommandPool(). (#7075) [@FoonTheRaccoon] +- Misc: During shutdown, check that io.BackendPlatformUserData and io.BackendRendererUserData are NULL + in order to catch cases where backend was not shut down. (#7175) +- Misc: Reworked Issue Template to a shinier and better form. (#5927) [@Panquesito7, @PathogenDavid, @ocornut] +- Backends: + - GLFW, Emscripten: Added ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback() to + register canvas selector and auto-resize GLFW window. (#6751) [@Traveller23, @ypujante] + - GLFW: Fixed Windows specific hooks to use Unicode version of WndProc even when + compiling in MBCS mode. (#7174) [@kimidaisuki22] + - OpenGL3: Update GL3W based imgui_impl_opengl3_loader.h to load libGL.so variants in + case of missing symlink. Fix 1.90 regression for some distros. (#6983) + - Vulkan: Fixed mismatching allocator passed to vkCreateCommandPool() vs + vkDestroyCommandPool(). (#7075) [@FoonTheRaccoon] + - Vulkan: Added MinAllocationSize field in ImGui_ImplVulkan_InitInfo to workaround zealous + "best practice" validation layer. (#7189, #4238) [@philae-ael] + - Vulkan: Stopped creating command pools with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT + as we don't reset them. + - WebGPU: Fixed wgpuRenderPassEncoderSetScissorRect() crash when rendering modal window's + dimming layer, which has an unclipped value in ImDrawCmd::ClipRect. (#7191) [@aparis69] +- Examples: + - Examples: GLFW+Emscripten: Fixed examples not consistently resizing according to host canvas. + (#6751) [@Traveller23, @ypujante] + - Examples: SDL3: Minor fixes following recent SDL3 in-progress development. + +Docking+Viewports Branch: + +- Windows: Fixed ImGuiCol_TitleBg/Active alpha being used for viewport-owned windows. (#7181) [@PathogenDavid] +- Backends: DX12: Changed swapchain scaling mode to DXGI_SCALING_NONE to reduce artifacts as + queued frames aren't synchronized with platform window resizes. (#7152, #7153) [@SuperWangKai] +- Backends: OSX: Fixed monitor and window position by correctly transforming Y origin on multi-viewports + multi-monitor setups. (#7028, #7101, #6009, #6432) [@dmirty-kuzmenko, @734vin] +- Backends: OSX: Fixed IME position in multi-monitor multi-viewports setups. (#7028) [@734vin] ----------------------------------------------------------------------- VERSION 1.90.0 (Released 2023-11-15) ----------------------------------------------------------------------- +Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.90 + Breaking changes: - BeginChild(): Upgraded 'bool border = false' parameter to 'ImGuiChildFlags flags = 0'. @@ -182,7 +492,7 @@ Other changes: with ImGuiDragDropFlags_AcceptNoPreviewTooltip and submitting a tooltip manually. - Tables: - Added angled headers support. You need to set ImGuiTableColumnFlags_AngledHeader on selected - columns and call TableAngledHeadersRow(). Added style.TableAngledHeadersAngle style option. + columns and call TableAngledHeadersRow(). Added style.TableAngledHeadersAngle style option. (#6917) - Added ImGuiTableFlags_HighlightHoveredColumn flag, currently highlighting column header. - Fixed an edge-case when no columns are visible + table scrollbar is visible + user code is always testing return value of TableSetColumnIndex() to coarse clip. With an active diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 7d6738dc9260..5cc9cdb53f40 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -58,7 +58,7 @@ Steps: - Be mindful that messages are being sent to the mailbox of "Watching" users. Try to proofread your messages before sending them. Edits are not seen by those users unless they browse the site. **Some unfortunate words of warning** -- If you are involved in cheating schemes (e.g. DLL injection) for competitive online multiplayer games, please don't post here. We won't answer and you will be blocked. It doesn't matter if your question relates to said project. We've had too many of you and need to project our time and sanity. +- If you are involved in cheating schemes (e.g. DLL injection) for competitive online multiplayer games, please don't post here. We won't answer and you will be blocked. It doesn't matter if your question relates to said project. We've had too many of you and need to protect our time and sanity. - Due to frequent abuse of this service from the aforementioned users, if your GitHub account is anonymous and was created five minutes ago please understand that your post will receive more scrutiny and incomplete questions will be harshly dismissed. If you have been using Dear ImGui for a while or have been using C/C++ for several years or have demonstrated good behavior here, it is ok to not fulfill every item to the letter. Those are guidelines and experienced users or members of the community will know which information is useful in a given context. diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index edaddb0554f3..e813489666ea 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -104,8 +104,8 @@ OSX + OpenGL2 example.
(NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends. You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.) -[example_emscripten_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_emscripten_wgpu/)
-Emcripten + GLFW + WebGPU example.
+[example_glfw_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_wgpu/)
+GLFW + WebGPU example. Supports Emscripten (web) or Dawn (desktop)
= main.cpp + imgui_impl_glfw.cpp + imgui_impl_wgpu.cpp Note that the 'example_glfw_opengl3' and 'example_sdl2_opengl3' examples also supports Emscripten! diff --git a/docs/FAQ.md b/docs/FAQ.md index 012d2ce43ff9..65824781e1cc 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -426,7 +426,7 @@ Finally, you may call `ImGui::ShowMetricsWindow()` to explore/visualize/understa ### Q: How can I use maths operators with ImVec2? -We do not export maths operators by default in imgui.h in order to not conflict with the use of your own maths types and maths operators. As a convenience, you may use `#defne IMGUI_DEFINE_MATH_OPERATORS` + `#include "imgui.h"` to access our basic maths operators. +We do not export maths operators by default in imgui.h in order to not conflict with the use of your own maths types and maths operators. As a convenience, you may use `#define IMGUI_DEFINE_MATH_OPERATORS` + `#include "imgui.h"` to access our basic maths operators. ##### [Return to Index](#index) @@ -621,7 +621,7 @@ You may take a look at: - [Quotes](https://github.com/ocornut/imgui/wiki/Quotes) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) -- [Sponsors](https://github.com/ocornut/imgui/wiki/Sponsors) +- [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding) - [Gallery](https://github.com/ocornut/imgui/issues/6897) ##### [Return to Index](#index) @@ -664,7 +664,7 @@ There is an auto-generated [c-api for Dear ImGui (cimgui)](https://github.com/ci # Q&A: Community ### Q: How can I help? -- Businesses: please reach out to `omar AT dearimgui.com` if you work in a place using Dear ImGui! We can discuss ways for your company to fund development via invoiced technical support, maintenance, or sponsoring contacts. This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people to work on this project. +- Businesses: please reach out to `omar AT dearimgui.com` if you work in a place using Dear ImGui! We can discuss ways for your company to fund development via invoiced technical support, maintenance, or sponsoring contacts. This is among the most useful thing you can do for Dear ImGui. With increased funding, we can hire more people to work on this project. Please see [Funding](https://github.com/ocornut/imgui/wiki/Funding) page. - Individuals: you can support continued maintenance and development via PayPal donations. See [README](https://github.com/ocornut/imgui/blob/master/docs/README.md). - If you are experienced with Dear ImGui and C++, look at [GitHub Issues](https://github.com/ocornut/imgui/issues), [GitHub Discussions](https://github.com/ocornut/imgui/discussions), the [Wiki](https://github.com/ocornut/imgui/wiki), read [docs/TODO.txt](https://github.com/ocornut/imgui/blob/master/docs/TODO.txt), and see how you want to help and can help! - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere, etc. diff --git a/docs/FONTS.md b/docs/FONTS.md index 8988fb1122e7..df8b610e5639 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -53,7 +53,7 @@ All loaded fonts glyphs are rendered into a single texture atlas ahead of time. This is often of byproduct of point 3. If you have large number of glyphs or multiple fonts, the texture may become too big for your graphics API. **The typical result of failing to upload a texture is if every glyph or everything appears as empty black or white rectangle.** Mind the fact that some graphics drivers have texture size limitation. If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. Some solutions: -- You may reduce oversampling, e.g. `font_config.OversampleH = 1`, this will half your texture size for a quality looss. +- You may reduce oversampling, e.g. `font_config.OversampleH = 1`, this will half your texture size for a quality loss. Note that while OversampleH = 2 looks visibly very close to 3 in most situations, with OversampleH = 1 the quality drop will be noticeable. Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample). - Reduce glyphs ranges by calculating them from source localization data. You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win! @@ -482,7 +482,7 @@ Some fonts files are available in the `misc/fonts/` folder: #### MONOSPACE FONTS Pixel Perfect: -- Proggy Fonts, by Tristan Grimmer http://www.proggyfonts.net or http://upperbounds.net +- Proggy Fonts, by Tristan Grimmer http://www.proggyfonts.net or http://upperboundsinteractive.com/fonts.php - Sweet16, Sweet16 Mono, by Martin Sedlak (Latin + Supplemental + Extended A) https://github.com/kmar/Sweet16Font (also include an .inl file to use directly in dear imgui.) Regular: diff --git a/docs/README.md b/docs/README.md index cf8921c86e92..37267d39b410 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,12 +11,12 @@ Dear ImGui Businesses: support continued development and maintenance via invoiced sponsoring/support contracts:
  _E-mail: contact @ dearimgui dot com_ -
Individuals: support continued development and maintenance [here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). Also see [Sponsors](https://github.com/ocornut/imgui/wiki/Sponsors) page. +
Individuals: support continued development and maintenance [here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). Also see [Funding](https://github.com/ocornut/imgui/wiki/Funding) page. | [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Releases & Changelogs](#releases--changelogs) - [Demo](#demo) - [Integration](#integration) | :----------------------------------------------------------: | -| [Gallery](#gallery) - [Support, FAQ](#support-frequently-asked-questions-faq) - [How to help](#how-to-help) - [Sponsors](https://github.com/ocornut/imgui/wiki/Sponsors) - [Credits](#credits) - [License](#license) | -| [Wiki](https://github.com/ocornut/imgui/wiki) - [Languages & frameworks backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | +| [Gallery](#gallery) - [Support, FAQ](#support-frequently-asked-questions-faq) - [How to help](#how-to-help) - **[Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding)** - [Credits](#credits) - [License](#license) | +| [Wiki](https://github.com/ocornut/imgui/wiki) - [Extensions](https://github.com/ocornut/imgui/wiki/Useful-Extensions) - [Languages bindings & frameworks backends](https://github.com/ocornut/imgui/wiki/Bindings) - [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) - [User quotes](https://github.com/ocornut/imgui/wiki/Quotes) | ### The Pitch @@ -39,7 +39,7 @@ Dear ImGui is particularly suited to integration in game engines (for tooling), ### Usage -**The core of Dear ImGui is self-contained within a few platform-agnostic files** which you can easily compile in your application/engine. They are all the files in the root folder of the repository (imgui*.cpp, imgui*.h). **No specific build process is required**. You can add the .cpp files into your existing project. +**The core of Dear ImGui is self-contained within a few platform-agnostic files** which you can easily compile in your application/engine. They are all the files in the root folder of the repository (imgui*.cpp, imgui*.h). **No specific build process is required**. You can add the .cpp files into your existing project. **Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui. @@ -110,7 +110,7 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. [Here's how the demo looks](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: -- [imgui-demo-binaries-20230704.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20230704.zip) (Windows, 1.89.7, built 2023/07/04, master) or [older binaries](https://www.dearimgui.com/binaries). +- [imgui-demo-binaries-20240105.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20240105.zip) (Windows, 1.90.1 WIP, built 2024/01/05, master) or [older binaries](https://www.dearimgui.com/binaries). The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). @@ -139,6 +139,8 @@ Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. ### Gallery +Examples projects using Dear ImGui: [Tracy](https://github.com/wolfpld/tracy) (profiler), [ImHex](https://github.com/WerWolv/ImHex) (hex editor/data analysis), [RemedyBG](https://remedybg.itch.io/remedybg) (debugger) and [hundreds of others](https://github.com/ocornut/imgui/wiki/Software-using-Dear-ImGui). + For more user-submitted screenshots of projects using Dear ImGui, check out the [Gallery Threads](https://github.com/ocornut/imgui/issues/6897)! For a list of third-party widgets and extensions, check out the [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page. @@ -160,6 +162,8 @@ See: [Upcoming Changes](https://github.com/ocornut/imgui/wiki/Upcoming-Changes). See: [Dear ImGui Test Engine + Test Suite](https://github.com/ocornut/imgui_test_engine) for Automation & Testing. +For the purposes of getting search engines to crawl the wiki, here's a link to the [Crawable Wiki](https://github-wiki-see.page/m/ocornut/imgui/wiki) (not for humans, [here's why](https://github-wiki-see.page/)). + Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions). For ANY other questions, bug reports, requests, feedback, please post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully. Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_). @@ -170,7 +174,7 @@ We occasionally tag [Releases](https://github.com/ocornut/imgui/releases) (with **Who uses Dear ImGui?** -See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Sponsors](https://github.com/ocornut/imgui/wiki/Sponsors), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues/6897)! +See the [Quotes](https://github.com/ocornut/imgui/wiki/Quotes), [Funding & Sponsors](https://github.com/ocornut/imgui/wiki/Funding), and [Software using Dear ImGui](https://github.com/ocornut/imgui/wiki/Software-using-dear-imgui) Wiki pages for an idea of who is using Dear ImGui. Please add your game/software if you can! Also, see the [Gallery Threads](https://github.com/ocornut/imgui/issues/6897)! How to help ----------- @@ -180,13 +184,13 @@ How to help - See [GitHub Forum/Issues](https://github.com/ocornut/imgui/issues). - You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest of the end-users and also to ease the maintainer into understanding and accepting it. - See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas. -- Be a [sponsor](https://github.com/ocornut/imgui/wiki/Sponsors)! Have your company financially support this project via invoiced sponsors/maintenance or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: omar AT dearimgui DOT com). +- Be a [Funding Supporter](https://github.com/ocornut/imgui/wiki/Funding)! Have your company financially support this project via invoiced sponsors/maintenance or by buying a license for [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine) (please reach out: omar AT dearimgui DOT com). Sponsors -------- Ongoing Dear ImGui development is and has been financially supported by users and private sponsors. -
Please see the **[detailed list of current and past Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors)** for details. +
Please see the **[detailed list of current and past Dear ImGui funding supporters and sponsors](https://github.com/ocornut/imgui/wiki/Funding)** for details.
From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. **THANK YOU to all past and present supporters for helping to keep this project alive and thriving!** @@ -203,11 +207,11 @@ Developed by [Omar Cornut](https://www.miracleworld.net) and every direct or ind Recurring contributors include Rokas Kupstys [@rokups](https://github.com/rokups) (2020-2022): a good portion of work on automation system and regression tests now available in [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). -Sponsoring, maintenance/support contracts and other B2B transactions are hosted and handled by [Disco Hello](https://www.discohello.com). +Maintenance/support contracts, sponsoring invoices and other B2B transactions are hosted and handled by [Disco Hello](https://www.discohello.com). Omar: "I first discovered the IMGUI paradigm at [Q-Games](https://www.q-games.com) where Atman Binstock had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating and improving it." -Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license). +Embeds [ProggyClean.ttf](https://www.proggyfonts.net) font by Tristan Grimmer (MIT license).
Embeds [stb_textedit.h, stb_truetype.h, stb_rect_pack.h](https://github.com/nothings/stb/) by Sean Barrett (public domain). Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. Also thank you to everyone posting feedback, questions and patches on GitHub. diff --git a/examples/example_emscripten_wgpu/main.cpp b/examples/example_emscripten_wgpu/main.cpp deleted file mode 100644 index a2126bcd1519..000000000000 --- a/examples/example_emscripten_wgpu/main.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// Dear ImGui: standalone example application for Emscripten, using GLFW + WebGPU -// (Emscripten is a C++-to-javascript compiler, used to publish executables for the web. See https://emscripten.org/) - -// Learn about Dear ImGui: -// - FAQ https://dearimgui.com/faq -// - Getting Started https://dearimgui.com/getting-started -// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). -// - Introduction, links and more at the top of imgui.cpp - -#include "imgui.h" -#include "imgui_impl_glfw.h" -#include "imgui_impl_wgpu.h" -#include -#include -#include -#include -#include -#include -#include - -// Global WebGPU required states -static WGPUDevice wgpu_device = nullptr; -static WGPUSurface wgpu_surface = nullptr; -static WGPUTextureFormat wgpu_preferred_fmt = WGPUTextureFormat_RGBA8Unorm; -static WGPUSwapChain wgpu_swap_chain = nullptr; -static int wgpu_swap_chain_width = 0; -static int wgpu_swap_chain_height = 0; - -// Forward declarations -static void MainLoopStep(void* window); -static bool InitWGPU(); -static void print_glfw_error(int error, const char* description); -static void print_wgpu_error(WGPUErrorType error_type, const char* message, void*); - -// Main code -int main(int, char**) -{ - glfwSetErrorCallback(print_glfw_error); - if (!glfwInit()) - return 1; - - // Make sure GLFW does not initialize any graphics context. - // This needs to be done explicitly later. - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow* window = glfwCreateWindow(1280, 720, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr); - if (!window) - { - glfwTerminate(); - return 1; - } - - // Initialize the WebGPU environment - if (!InitWGPU()) - { - if (window) - glfwDestroyWindow(window); - glfwTerminate(); - return 1; - } - glfwShowWindow(window); - - // Setup Dear ImGui context - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); (void)io; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls - - // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. - // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. - io.IniFilename = nullptr; - - // Setup Dear ImGui style - ImGui::StyleColorsDark(); - //ImGui::StyleColorsLight(); - - // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOther(window, true); - ImGui_ImplWGPU_Init(wgpu_device, 3, wgpu_preferred_fmt, WGPUTextureFormat_Undefined); - - // Load Fonts - // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. - // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. - // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). - // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. - // - Read 'docs/FONTS.md' for more instructions and details. - // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! - // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. - //io.Fonts->AddFontDefault(); -#ifndef IMGUI_DISABLE_FILE_FUNCTIONS - //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf", 18.0f); - io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); - //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); - //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); - //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); - //IM_ASSERT(font != nullptr); -#endif - - // This function will directly return and exit the main function. - // Make sure that no required objects get cleaned up. - // This way we can use the browsers 'requestAnimationFrame' to control the rendering. - emscripten_set_main_loop_arg(MainLoopStep, window, 0, false); - - return 0; -} - -static bool InitWGPU() -{ - wgpu_device = emscripten_webgpu_get_device(); - if (!wgpu_device) - return false; - - wgpuDeviceSetUncapturedErrorCallback(wgpu_device, print_wgpu_error, nullptr); - - // Use C++ wrapper due to misbehavior in Emscripten. - // Some offset computation for wgpuInstanceCreateSurface in JavaScript - // seem to be inline with struct alignments in the C++ structure - wgpu::SurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; - html_surface_desc.selector = "#canvas"; - - wgpu::SurfaceDescriptor surface_desc = {}; - surface_desc.nextInChain = &html_surface_desc; - - wgpu::Instance instance = wgpuCreateInstance(nullptr); - wgpu::Surface surface = instance.CreateSurface(&surface_desc); - wgpu::Adapter adapter = {}; - wgpu_preferred_fmt = (WGPUTextureFormat)surface.GetPreferredFormat(adapter); - wgpu_surface = surface.Release(); - - return true; -} - -static void MainLoopStep(void* window) -{ - ImGuiIO& io = ImGui::GetIO(); - - glfwPollEvents(); - - int width, height; - glfwGetFramebufferSize((GLFWwindow*)window, &width, &height); - - // React to changes in screen size - if (width != wgpu_swap_chain_width && height != wgpu_swap_chain_height) - { - ImGui_ImplWGPU_InvalidateDeviceObjects(); - if (wgpu_swap_chain) - wgpuSwapChainRelease(wgpu_swap_chain); - wgpu_swap_chain_width = width; - wgpu_swap_chain_height = height; - WGPUSwapChainDescriptor swap_chain_desc = {}; - swap_chain_desc.usage = WGPUTextureUsage_RenderAttachment; - swap_chain_desc.format = wgpu_preferred_fmt; - swap_chain_desc.width = width; - swap_chain_desc.height = height; - swap_chain_desc.presentMode = WGPUPresentMode_Fifo; - wgpu_swap_chain = wgpuDeviceCreateSwapChain(wgpu_device, wgpu_surface, &swap_chain_desc); - ImGui_ImplWGPU_CreateDeviceObjects(); - } - - // Start the Dear ImGui frame - ImGui_ImplWGPU_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - // Our state - // (we use static, which essentially makes the variable globals, as a convenience to keep the example code easy to follow) - static bool show_demo_window = true; - static bool show_another_window = false; - static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); - - // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). - if (show_demo_window) - ImGui::ShowDemoWindow(&show_demo_window); - - // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. - { - static float f = 0.0f; - static int counter = 0; - - ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. - - ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) - ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state - ImGui::Checkbox("Another Window", &show_another_window); - - ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f - ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color - - if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) - counter++; - ImGui::SameLine(); - ImGui::Text("counter = %d", counter); - - ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); - ImGui::End(); - } - - // 3. Show another simple window. - if (show_another_window) - { - ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) - ImGui::Text("Hello from another window!"); - if (ImGui::Button("Close Me")) - show_another_window = false; - ImGui::End(); - } - - // Rendering - ImGui::Render(); - - WGPURenderPassColorAttachment color_attachments = {}; - color_attachments.loadOp = WGPULoadOp_Clear; - color_attachments.storeOp = WGPUStoreOp_Store; - color_attachments.clearValue = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; - color_attachments.view = wgpuSwapChainGetCurrentTextureView(wgpu_swap_chain); - WGPURenderPassDescriptor render_pass_desc = {}; - render_pass_desc.colorAttachmentCount = 1; - render_pass_desc.colorAttachments = &color_attachments; - render_pass_desc.depthStencilAttachment = nullptr; - - WGPUCommandEncoderDescriptor enc_desc = {}; - WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(wgpu_device, &enc_desc); - - WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_pass_desc); - ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass); - wgpuRenderPassEncoderEnd(pass); - - WGPUCommandBufferDescriptor cmd_buffer_desc = {}; - WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc); - WGPUQueue queue = wgpuDeviceGetQueue(wgpu_device); - wgpuQueueSubmit(queue, 1, &cmd_buffer); -} - -static void print_glfw_error(int error, const char* description) -{ - printf("GLFW Error %d: %s\n", error, description); -} - -static void print_wgpu_error(WGPUErrorType error_type, const char* message, void*) -{ - const char* error_type_lbl = ""; - switch (error_type) - { - case WGPUErrorType_Validation: error_type_lbl = "Validation"; break; - case WGPUErrorType_OutOfMemory: error_type_lbl = "Out of memory"; break; - case WGPUErrorType_Unknown: error_type_lbl = "Unknown"; break; - case WGPUErrorType_DeviceLost: error_type_lbl = "Device lost"; break; - default: error_type_lbl = "Unknown"; - } - printf("%s error: %s\n", error_type_lbl, message); -} diff --git a/examples/example_glfw_metal/Makefile b/examples/example_glfw_metal/Makefile index 82d5ac962b9c..32a7aeca2395 100644 --- a/examples/example_glfw_metal/Makefile +++ b/examples/example_glfw_metal/Makefile @@ -14,10 +14,10 @@ SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) LIBS = -framework Metal -framework MetalKit -framework Cocoa -framework IOKit -framework CoreVideo -framework QuartzCore -LIBS += -L/usr/local/lib -L/opt/homebrew/lib +LIBS += -L/usr/local/lib -L/opt/homebrew/lib -L/opt/local/lib LIBS += -lglfw -CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I/usr/local/include -I/opt/homebrew/include +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -I/usr/local/include -I/opt/homebrew/include -I/opt/local/include CXXFLAGS += -Wall -Wformat CFLAGS = $(CXXFLAGS) diff --git a/examples/example_glfw_opengl3/Makefile.emscripten b/examples/example_glfw_opengl3/Makefile.emscripten index 8ea4eacfc4c1..bd972abffc85 100644 --- a/examples/example_glfw_opengl3/Makefile.emscripten +++ b/examples/example_glfw_opengl3/Makefile.emscripten @@ -59,7 +59,7 @@ endif CPPFLAGS += -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends #CPPFLAGS += -g CPPFLAGS += -Wall -Wformat -Os $(EMS) -# LDFLAGS += --shell-file ../libs/emscripten/shell_minimal.html +LDFLAGS += --shell-file ../libs/emscripten/shell_minimal.html LDFLAGS += $(EMS) ##--------------------------------------------------------------------- diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 2e369fbfe9af..4aaf40646dec 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -96,6 +96,9 @@ int main(int, char**) // Setup Platform/Renderer backends ImGui_ImplGlfw_InitForOpenGL(window, true); +#ifdef __EMSCRIPTEN__ + ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas"); +#endif ImGui_ImplOpenGL3_Init(glsl_version); // Load Fonts diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 5fb86739c4fa..c852e5f4d4f3 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -31,9 +31,9 @@ #pragma comment(lib, "legacy_stdio_definitions") #endif -//#define IMGUI_UNLIMITED_FRAME_RATE +//#define APP_USE_UNLIMITED_FRAME_RATE #ifdef _DEBUG -#define IMGUI_VULKAN_DEBUG_REPORT +#define APP_USE_VULKAN_DEBUG_REPORT #endif // Data @@ -64,14 +64,14 @@ static void check_vk_result(VkResult err) abort(); } -#ifdef IMGUI_VULKAN_DEBUG_REPORT +#ifdef APP_USE_VULKAN_DEBUG_REPORT static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData) { (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage); return VK_FALSE; } -#endif // IMGUI_VULKAN_DEBUG_REPORT +#endif // APP_USE_VULKAN_DEBUG_REPORT static bool IsExtensionAvailable(const ImVector& properties, const char* extension) { @@ -139,7 +139,7 @@ static void SetupVulkan(ImVector instance_extensions) #endif // Enabling validation layers -#ifdef IMGUI_VULKAN_DEBUG_REPORT +#ifdef APP_USE_VULKAN_DEBUG_REPORT const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; create_info.enabledLayerCount = 1; create_info.ppEnabledLayerNames = layers; @@ -153,7 +153,7 @@ static void SetupVulkan(ImVector instance_extensions) check_vk_result(err); // Setup the debug report callback -#ifdef IMGUI_VULKAN_DEBUG_REPORT +#ifdef APP_USE_VULKAN_DEBUG_REPORT auto vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT"); IM_ASSERT(vkCreateDebugReportCallbackEXT != nullptr); VkDebugReportCallbackCreateInfoEXT debug_report_ci = {}; @@ -258,7 +258,7 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_ARRAYSIZE(requestSurfaceImageFormat), requestSurfaceColorSpace); // Select Present Mode -#ifdef IMGUI_UNLIMITED_FRAME_RATE +#ifdef APP_USE_UNLIMITED_FRAME_RATE VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR }; #else VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR }; @@ -275,11 +275,11 @@ static void CleanupVulkan() { vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator); -#ifdef IMGUI_VULKAN_DEBUG_REPORT +#ifdef APP_USE_VULKAN_DEBUG_REPORT // Remove the debug report callback auto vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT"); vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator); -#endif // IMGUI_VULKAN_DEBUG_REPORT +#endif // APP_USE_VULKAN_DEBUG_REPORT vkDestroyDevice(g_Device, g_Allocator); vkDestroyInstance(g_Instance, g_Allocator); @@ -376,7 +376,7 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd) return; } check_vk_result(err); - wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->ImageCount; // Now we can use the next set of semaphores + wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores } // Main code @@ -446,13 +446,14 @@ int main(int, char**) init_info.Queue = g_Queue; init_info.PipelineCache = g_PipelineCache; init_info.DescriptorPool = g_DescriptorPool; + init_info.RenderPass = wd->RenderPass; init_info.Subpass = 0; init_info.MinImageCount = g_MinImageCount; init_info.ImageCount = wd->ImageCount; init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; init_info.Allocator = g_Allocator; init_info.CheckVkResultFn = check_vk_result; - ImGui_ImplVulkan_Init(&init_info, wd->RenderPass); + ImGui_ImplVulkan_Init(&init_info); // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt new file mode 100644 index 000000000000..e682836ddb58 --- /dev/null +++ b/examples/example_glfw_wgpu/CMakeLists.txt @@ -0,0 +1,100 @@ +# Building for desktop (WebGPU-native) with Dawn: +# 1. git clone https://github.com/google/dawn dawn +# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn +# 3. cmake --build build +# The resulting binary will be found at one of the following locations: +# * build/Debug/example_glfw_wgpu[.exe] +# * build/example_glfw_wgpu[.exe] + +# Building for Emscripten: +# 1. Install Emscripten SDK following the instructions: https://emscripten.org/docs/getting_started/downloads.html +# 2. Install Ninja build system +# 3. emcmake cmake -G Ninja -B build +# 3. cmake --build build +# 4. emrun build/index.html + +cmake_minimum_required(VERSION 3.10.2) +project(imgui_example_glfw_wgpu C CXX) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) +endif() + +set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 + +# Dear ImGui +set(IMGUI_DIR ../../) + +# Libraries +if(EMSCRIPTEN) + set(LIBRARIES glfw) + add_compile_options(-sDISABLE_EXCEPTION_CATCHING=1 -DIMGUI_DISABLE_FILE_FUNCTIONS=1) +else() + # Dawn wgpu desktop + set(DAWN_FETCH_DEPENDENCIES ON) + set(IMGUI_DAWN_DIR CACHE PATH "Path to Dawn repository") + if (NOT IMGUI_DAWN_DIR) + message(FATAL_ERROR "Please specify the Dawn repository by setting IMGUI_DAWN_DIR") + endif() + + option(DAWN_FETCH_DEPENDENCIES "Use fetch_dawn_dependencies.py as an alternative to using depot_tools" ON) + + # Dawn builds many things by default - disable things we don't need + option(DAWN_BUILD_SAMPLES "Enables building Dawn's samples" OFF) + option(TINT_BUILD_CMD_TOOLS "Build the Tint command line tools" OFF) + option(TINT_BUILD_DOCS "Build documentation" OFF) + option(TINT_BUILD_TESTS "Build tests" OFF) + if (NOT APPLE) + option(TINT_BUILD_MSL_WRITER "Build the MSL output writer" OFF) + endif() + if(WIN32) + option(TINT_BUILD_SPV_READER "Build the SPIR-V input reader" OFF) + option(TINT_BUILD_WGSL_READER "Build the WGSL input reader" ON) + option(TINT_BUILD_GLSL_WRITER "Build the GLSL output writer" OFF) + option(TINT_BUILD_GLSL_VALIDATOR "Build the GLSL output validator" OFF) + option(TINT_BUILD_SPV_WRITER "Build the SPIR-V output writer" OFF) + option(TINT_BUILD_WGSL_WRITER "Build the WGSL output writer" ON) + endif() + + add_subdirectory("${IMGUI_DAWN_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/dawn" EXCLUDE_FROM_ALL) + + set(LIBRARIES webgpu_dawn webgpu_cpp webgpu_glfw glfw) +endif() + +add_executable(example_glfw_wgpu + main.cpp + # backend files + ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp + ${IMGUI_DIR}/backends/imgui_impl_wgpu.cpp + # Dear ImGui files + ${IMGUI_DIR}/imgui.cpp + ${IMGUI_DIR}/imgui_draw.cpp + ${IMGUI_DIR}/imgui_demo.cpp + ${IMGUI_DIR}/imgui_tables.cpp + ${IMGUI_DIR}/imgui_widgets.cpp +) +target_include_directories(example_glfw_wgpu PUBLIC + ${IMGUI_DIR} + ${IMGUI_DIR}/backends +) + +target_link_libraries(example_glfw_wgpu PUBLIC ${LIBRARIES}) + +# Emscripten settings +if(EMSCRIPTEN) + target_link_options(example_glfw_wgpu PRIVATE + "-sUSE_WEBGPU=1" + "-sUSE_GLFW=3" + "-sWASM=1" + "-sALLOW_MEMORY_GROWTH=1" + "-sNO_EXIT_RUNTIME=0" + "-sASSERTIONS=1" + "-sDISABLE_EXCEPTION_CATCHING=1" + "-sNO_FILESYSTEM=1" + ) + set_target_properties(example_glfw_wgpu PROPERTIES OUTPUT_NAME "index") + # copy our custom index.html to build directory + add_custom_command(TARGET example_glfw_wgpu POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_LIST_DIR}/web/index.html" $ + ) +endif() diff --git a/examples/example_emscripten_wgpu/Makefile b/examples/example_glfw_wgpu/Makefile.emscripten similarity index 100% rename from examples/example_emscripten_wgpu/Makefile rename to examples/example_glfw_wgpu/Makefile.emscripten diff --git a/examples/example_emscripten_wgpu/README.md b/examples/example_glfw_wgpu/README.md similarity index 87% rename from examples/example_emscripten_wgpu/README.md rename to examples/example_glfw_wgpu/README.md index c4c4dec76fa3..399d431ffaa1 100644 --- a/examples/example_emscripten_wgpu/README.md +++ b/examples/example_glfw_wgpu/README.md @@ -6,7 +6,7 @@ - You may also refer to our [Continuous Integration setup](https://github.com/ocornut/imgui/tree/master/.github/workflows) for Emscripten setup. -- Then build using `make` while in the `example_emscripten_wgpu/` directory. +- Then build using `make -f Makefile.emscripten` while in the `example_glfw_wgpu/` directory. - Requires recent Emscripten as WGPU is still a work-in-progress API. @@ -18,7 +18,7 @@ To run on a local machine: - Otherwise, generally you will need a local webserver: - Quoting [https://emscripten.org/docs/getting_started](https://emscripten.org/docs/getting_started/Tutorial.html#generating-html):
_"Unfortunately several browsers (including Chrome, Safari, and Internet Explorer) do not support file:// [XHR](https://emscripten.org/docs/site/glossary.html#term-xhr) requests, and can’t load extra files needed by the HTML (like a .wasm file, or packaged file data as mentioned lower down). For these browsers you’ll need to serve the files using a [local webserver](https://emscripten.org/docs/getting_started/FAQ.html#faq-local-webserver) and then open http://localhost:8000/hello.html."_ - - Emscripten SDK has a handy `emrun` command: `emrun web/example_emscripten_opengl3.html --browser firefox` which will spawn a temporary local webserver (in Firefox). See https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html for details. + - Emscripten SDK has a handy `emrun` command: `emrun web/example_glfw_wgpu.html --browser firefox` which will spawn a temporary local webserver (in Firefox). See https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html for details. - You may use Python 3 builtin webserver: `python -m http.server -d web` (this is what `make serve` uses). - You may use Python 2 builtin webserver: `cd web && python -m SimpleHTTPServer`. - If you are accessing the files over a network, certain browsers, such as Firefox, will restrict Gamepad API access to secure contexts only (e.g. https only). diff --git a/examples/example_glfw_wgpu/main.cpp b/examples/example_glfw_wgpu/main.cpp new file mode 100644 index 000000000000..4e47b8323bd6 --- /dev/null +++ b/examples/example_glfw_wgpu/main.cpp @@ -0,0 +1,345 @@ +// Dear ImGui: standalone example application for using GLFW + WebGPU +// - Emscripten is supported for publishing on web. See https://emscripten.org. +// - Dawn is used as a WebGPU implementation on desktop. + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +#include "imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_wgpu.h" +#include + +#ifdef __EMSCRIPTEN__ +#include +#include +#include +#else +#include +#endif + +#include +#include +#include + +// This example can also compile and run with Emscripten! See 'Makefile.emscripten' for details. +#ifdef __EMSCRIPTEN__ +#include "../libs/emscripten/emscripten_mainloop_stub.h" +#endif + +// Global WebGPU required states +static WGPUInstance wgpu_instance = nullptr; +static WGPUDevice wgpu_device = nullptr; +static WGPUSurface wgpu_surface = nullptr; +static WGPUTextureFormat wgpu_preferred_fmt = WGPUTextureFormat_RGBA8Unorm; +static WGPUSwapChain wgpu_swap_chain = nullptr; +static int wgpu_swap_chain_width = 1280; +static int wgpu_swap_chain_height = 720; + +// Forward declarations +static bool InitWGPU(GLFWwindow* window); +static void CreateSwapChain(int width, int height); + +static void glfw_error_callback(int error, const char* description) +{ + printf("GLFW Error %d: %s\n", error, description); +} + +static void wgpu_error_callback(WGPUErrorType error_type, const char* message, void*) +{ + const char* error_type_lbl = ""; + switch (error_type) + { + case WGPUErrorType_Validation: error_type_lbl = "Validation"; break; + case WGPUErrorType_OutOfMemory: error_type_lbl = "Out of memory"; break; + case WGPUErrorType_Unknown: error_type_lbl = "Unknown"; break; + case WGPUErrorType_DeviceLost: error_type_lbl = "Device lost"; break; + default: error_type_lbl = "Unknown"; + } + printf("%s error: %s\n", error_type_lbl, message); +} + +// Main code +int main(int, char**) +{ + glfwSetErrorCallback(glfw_error_callback); + if (!glfwInit()) + return 1; + + // Make sure GLFW does not initialize any graphics context. + // This needs to be done explicitly later. + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + GLFWwindow* window = glfwCreateWindow(wgpu_swap_chain_width, wgpu_swap_chain_height, "Dear ImGui GLFW+WebGPU example", nullptr, nullptr); + if (window == nullptr) + return 1; + + // Initialize the WebGPU environment + if (!InitWGPU(window)) + { + if (window) + glfwDestroyWindow(window); + glfwTerminate(); + return 1; + } + CreateSwapChain(wgpu_swap_chain_width, wgpu_swap_chain_height); + glfwShowWindow(window); + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplGlfw_InitForOther(window, true); +#ifdef __EMSCRIPTEN__ + ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback("#canvas"); +#endif + ImGui_ImplWGPU_InitInfo init_info; + init_info.Device = wgpu_device; + init_info.NumFramesInFlight = 3; + init_info.RenderTargetFormat = wgpu_preferred_fmt; + init_info.DepthStencilFormat = WGPUTextureFormat_Undefined; + ImGui_ImplWGPU_Init(&init_info); + + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. + // - Read 'docs/FONTS.md' for more instructions and details. + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. + //io.Fonts->AddFontDefault(); +#ifndef IMGUI_DISABLE_FILE_FUNCTIONS + //io.Fonts->AddFontFromFileTTF("fonts/segoeui.ttf", 18.0f); + //io.Fonts->AddFontFromFileTTF("fonts/DroidSans.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0f); + //io.Fonts->AddFontFromFileTTF("fonts/Cousine-Regular.ttf", 15.0f); + //io.Fonts->AddFontFromFileTTF("fonts/ProggyTiny.ttf", 10.0f); + //ImFont* font = io.Fonts->AddFontFromFileTTF("fonts/ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); + //IM_ASSERT(font != nullptr); +#endif + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop +#ifdef __EMSCRIPTEN__ + // For an Emscripten build we are disabling file-system access, so let's not attempt to do a fopen() of the imgui.ini file. + // You may manually call LoadIniSettingsFromMemory() to load settings from your own storage. + io.IniFilename = nullptr; + EMSCRIPTEN_MAINLOOP_BEGIN +#else + while (!glfwWindowShouldClose(window)) +#endif + { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. + // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + glfwPollEvents(); + + // React to changes in screen size + int width, height; + glfwGetFramebufferSize((GLFWwindow*)window, &width, &height); + if (width != wgpu_swap_chain_width || height != wgpu_swap_chain_height) + { + ImGui_ImplWGPU_InvalidateDeviceObjects(); + CreateSwapChain(width, height); + ImGui_ImplWGPU_CreateDeviceObjects(); + } + + // Start the Dear ImGui frame + ImGui_ImplWGPU_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + +#ifndef __EMSCRIPTEN__ + // Tick needs to be called in Dawn to display validation errors + wgpuDeviceTick(wgpu_device); +#endif + + WGPURenderPassColorAttachment color_attachments = {}; + color_attachments.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; + color_attachments.loadOp = WGPULoadOp_Clear; + color_attachments.storeOp = WGPUStoreOp_Store; + color_attachments.clearValue = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; + color_attachments.view = wgpuSwapChainGetCurrentTextureView(wgpu_swap_chain); + + WGPURenderPassDescriptor render_pass_desc = {}; + render_pass_desc.colorAttachmentCount = 1; + render_pass_desc.colorAttachments = &color_attachments; + render_pass_desc.depthStencilAttachment = nullptr; + + WGPUCommandEncoderDescriptor enc_desc = {}; + WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(wgpu_device, &enc_desc); + + WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_pass_desc); + ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass); + wgpuRenderPassEncoderEnd(pass); + + WGPUCommandBufferDescriptor cmd_buffer_desc = {}; + WGPUCommandBuffer cmd_buffer = wgpuCommandEncoderFinish(encoder, &cmd_buffer_desc); + WGPUQueue queue = wgpuDeviceGetQueue(wgpu_device); + wgpuQueueSubmit(queue, 1, &cmd_buffer); + +#ifndef __EMSCRIPTEN__ + wgpuSwapChainPresent(wgpu_swap_chain); +#endif + + wgpuTextureViewRelease(color_attachments.view); + wgpuRenderPassEncoderRelease(pass); + wgpuCommandEncoderRelease(encoder); + wgpuCommandBufferRelease(cmd_buffer); + } +#ifdef __EMSCRIPTEN__ + EMSCRIPTEN_MAINLOOP_END; +#endif + + // Cleanup + ImGui_ImplWGPU_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window); + glfwTerminate(); + + return 0; +} + +#ifndef __EMSCRIPTEN__ +static WGPUAdapter RequestAdapter(WGPUInstance instance) +{ + auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, const char* message, void* pUserData) + { + if (status == WGPURequestAdapterStatus_Success) + *(WGPUAdapter*)(pUserData) = adapter; + else + printf("Could not get WebGPU adapter: %s\n", message); +}; + WGPUAdapter adapter; + wgpuInstanceRequestAdapter(instance, nullptr, onAdapterRequestEnded, (void*)&adapter); + return adapter; +} + +static WGPUDevice RequestDevice(WGPUAdapter& adapter) +{ + auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, const char* message, void* pUserData) + { + if (status == WGPURequestDeviceStatus_Success) + *(WGPUDevice*)(pUserData) = device; + else + printf("Could not get WebGPU device: %s\n", message); + }; + WGPUDevice device; + wgpuAdapterRequestDevice(adapter, nullptr, onDeviceRequestEnded, (void*)&device); + return device; +} +#endif + +static bool InitWGPU(GLFWwindow* window) +{ + wgpu::Instance instance = wgpuCreateInstance(nullptr); + +#ifdef __EMSCRIPTEN__ + wgpu_device = emscripten_webgpu_get_device(); + if (!wgpu_device) + return false; +#else + WGPUAdapter adapter = RequestAdapter(instance.Get()); + if (!adapter) + return false; + wgpu_device = RequestDevice(adapter); +#endif + +#ifdef __EMSCRIPTEN__ + wgpu::SurfaceDescriptorFromCanvasHTMLSelector html_surface_desc = {}; + html_surface_desc.selector = "#canvas"; + wgpu::SurfaceDescriptor surface_desc = {}; + surface_desc.nextInChain = &html_surface_desc; + wgpu::Surface surface = instance.CreateSurface(&surface_desc); + + wgpu::Adapter adapter = {}; + wgpu_preferred_fmt = (WGPUTextureFormat)surface.GetPreferredFormat(adapter); +#else + wgpu::Surface surface = wgpu::glfw::CreateSurfaceForWindow(instance, window); + if (!surface) + return false; + wgpu_preferred_fmt = WGPUTextureFormat_BGRA8Unorm; +#endif + + wgpu_instance = instance.MoveToCHandle(); + wgpu_surface = surface.MoveToCHandle(); + + wgpuDeviceSetUncapturedErrorCallback(wgpu_device, wgpu_error_callback, nullptr); + + return true; +} + +static void CreateSwapChain(int width, int height) +{ + if (wgpu_swap_chain) + wgpuSwapChainRelease(wgpu_swap_chain); + wgpu_swap_chain_width = width; + wgpu_swap_chain_height = height; + WGPUSwapChainDescriptor swap_chain_desc = {}; + swap_chain_desc.usage = WGPUTextureUsage_RenderAttachment; + swap_chain_desc.format = wgpu_preferred_fmt; + swap_chain_desc.width = width; + swap_chain_desc.height = height; + swap_chain_desc.presentMode = WGPUPresentMode_Fifo; + wgpu_swap_chain = wgpuDeviceCreateSwapChain(wgpu_device, wgpu_surface, &swap_chain_desc); +} diff --git a/examples/example_emscripten_wgpu/web/index.html b/examples/example_glfw_wgpu/web/index.html similarity index 94% rename from examples/example_emscripten_wgpu/web/index.html rename to examples/example_glfw_wgpu/web/index.html index 82b1c422151f..a2a91c4a75f8 100644 --- a/examples/example_emscripten_wgpu/web/index.html +++ b/examples/example_glfw_wgpu/web/index.html @@ -3,7 +3,7 @@ - Dear ImGui Emscripten+WebGPU example + Dear ImGui Emscripten+GLFW+WebGPU example