From 7ada6fe232fd635b024838165cf8c9b69dd90e45 Mon Sep 17 00:00:00 2001
From: ApfelTeeSaft <91074565+ApfelTeeSaft@users.noreply.github.com>
Date: Tue, 6 Jan 2026 17:14:56 +0100
Subject: [PATCH] Code
---
Alphanium.sln | 21 +
Alphanium/Alphanium.filters | 108 +
Alphanium/Alphanium.vcxproj | 123 +
Alphanium/Source/Features.cpp | 526 +
Alphanium/Source/Features.h | 57 +
Alphanium/Source/Hooking.cpp | 138 +
Alphanium/Source/Hooking.h | 5 +
Alphanium/Source/ImGuiLayer.cpp | 105 +
Alphanium/Source/ImGuiLayer.h | 24 +
Alphanium/Source/Logger.cpp | 33 +
Alphanium/Source/Logger.h | 4 +
Alphanium/Source/Memory.cpp | 107 +
Alphanium/Source/Memory.h | 18 +
.../Source/MinHook/dll_resources/MinHook.def | 14 +
.../Source/MinHook/dll_resources/MinHook.rc | 32 +
Alphanium/Source/MinHook/include/MinHook.h | 186 +
Alphanium/Source/MinHook/src/buffer.c | 312 +
Alphanium/Source/MinHook/src/buffer.h | 42 +
Alphanium/Source/MinHook/src/hde/hde32.c | 326 +
Alphanium/Source/MinHook/src/hde/hde32.h | 105 +
Alphanium/Source/MinHook/src/hde/hde64.c | 337 +
Alphanium/Source/MinHook/src/hde/hde64.h | 112 +
Alphanium/Source/MinHook/src/hde/pstdint.h | 39 +
Alphanium/Source/MinHook/src/hde/table32.h | 73 +
Alphanium/Source/MinHook/src/hde/table64.h | 74 +
Alphanium/Source/MinHook/src/hook.c | 889 +
Alphanium/Source/MinHook/src/trampoline.c | 316 +
Alphanium/Source/MinHook/src/trampoline.h | 105 +
Alphanium/Source/Resolver.cpp | 344 +
Alphanium/Source/Resolver.h | 4 +
Alphanium/Source/StandaloneWindow.cpp | 177 +
Alphanium/Source/StandaloneWindow.h | 5 +
Alphanium/Source/Strings.cpp | 35 +
Alphanium/Source/Strings.h | 9 +
Alphanium/Source/UE4Globals.h | 23 +
Alphanium/Source/UE4Helpers.cpp | 291 +
Alphanium/Source/UE4Helpers.h | 13 +
Alphanium/Source/UE4Types.h | 137 +
Alphanium/Source/dllmain.cpp | 30 +
Alphanium/Source/imgui/.editorconfig | 28 +
Alphanium/Source/imgui/.gitattributes | 30 +
Alphanium/Source/imgui/.github/FUNDING.yml | 1 +
.../imgui/.github/ISSUE_TEMPLATE/config.yml | 1 +
.../.github/ISSUE_TEMPLATE/issue_template.yml | 92 +
.../imgui/.github/pull_request_template.md | 10 +
.../Source/imgui/.github/workflows/build.yml | 774 +
.../workflows/build_windows_vulkan_libs.ps1 | 38 +
.../Source/imgui/.github/workflows/manual.yml | 12 +
.../imgui/.github/workflows/scheduled.yml | 15 +
.../.github/workflows/static-analysis.yml | 46 +
Alphanium/Source/imgui/.gitignore | 79 +
Alphanium/Source/imgui/LICENSE.txt | 21 +
.../imgui/backends/imgui_impl_allegro5.cpp | 698 +
.../imgui/backends/imgui_impl_allegro5.h | 44 +
.../imgui/backends/imgui_impl_android.cpp | 308 +
.../imgui/backends/imgui_impl_android.h | 37 +
.../Source/imgui/backends/imgui_impl_dx10.cpp | 659 +
.../Source/imgui/backends/imgui_impl_dx10.h | 48 +
.../Source/imgui/backends/imgui_impl_dx11.cpp | 679 +
.../Source/imgui/backends/imgui_impl_dx11.h | 51 +
.../Source/imgui/backends/imgui_impl_dx12.cpp | 971 +
.../Source/imgui/backends/imgui_impl_dx12.h | 79 +
.../Source/imgui/backends/imgui_impl_dx9.cpp | 480 +
.../Source/imgui/backends/imgui_impl_dx9.h | 37 +
.../Source/imgui/backends/imgui_impl_glfw.cpp | 1067 +
.../Source/imgui/backends/imgui_impl_glfw.h | 70 +
.../Source/imgui/backends/imgui_impl_glut.cpp | 309 +
.../Source/imgui/backends/imgui_impl_glut.h | 47 +
.../Source/imgui/backends/imgui_impl_metal.h | 78 +
.../Source/imgui/backends/imgui_impl_metal.mm | 654 +
.../Source/imgui/backends/imgui_impl_null.cpp | 102 +
.../Source/imgui/backends/imgui_impl_null.h | 34 +
.../imgui/backends/imgui_impl_opengl2.cpp | 352 +
.../imgui/backends/imgui_impl_opengl2.h | 43 +
.../imgui/backends/imgui_impl_opengl3.cpp | 1058 +
.../imgui/backends/imgui_impl_opengl3.h | 68 +
.../backends/imgui_impl_opengl3_loader.h | 949 +
.../Source/imgui/backends/imgui_impl_osx.h | 54 +
.../Source/imgui/backends/imgui_impl_osx.mm | 836 +
.../Source/imgui/backends/imgui_impl_sdl2.cpp | 908 +
.../Source/imgui/backends/imgui_impl_sdl2.h | 50 +
.../Source/imgui/backends/imgui_impl_sdl3.cpp | 871 +
.../Source/imgui/backends/imgui_impl_sdl3.h | 47 +
.../imgui/backends/imgui_impl_sdlgpu3.cpp | 664 +
.../imgui/backends/imgui_impl_sdlgpu3.h | 64 +
.../backends/imgui_impl_sdlgpu3_shaders.h | 372 +
.../backends/imgui_impl_sdlrenderer2.cpp | 300 +
.../imgui/backends/imgui_impl_sdlrenderer2.h | 53 +
.../backends/imgui_impl_sdlrenderer3.cpp | 316 +
.../imgui/backends/imgui_impl_sdlrenderer3.h | 53 +
.../imgui/backends/imgui_impl_vulkan.cpp | 1891 ++
.../Source/imgui/backends/imgui_impl_vulkan.h | 252 +
.../Source/imgui/backends/imgui_impl_wgpu.cpp | 1086 +
.../Source/imgui/backends/imgui_impl_wgpu.h | 121 +
.../imgui/backends/imgui_impl_win32.cpp | 974 +
.../Source/imgui/backends/imgui_impl_win32.h | 53 +
.../backends/sdlgpu3/build_instructions.txt | 40 +
.../Source/imgui/backends/sdlgpu3/shader.frag | 15 +
.../Source/imgui/backends/sdlgpu3/shader.vert | 24 +
.../backends/vulkan/build_instructions.txt | 4 +
.../imgui/backends/vulkan/generate_spv.sh | 6 +
.../imgui/backends/vulkan/glsl_shader.frag | 14 +
.../imgui/backends/vulkan/glsl_shader.vert | 25 +
Alphanium/Source/imgui/docs/BACKENDS.md | 378 +
Alphanium/Source/imgui/docs/CHANGELOG.txt | 8034 +++++++
Alphanium/Source/imgui/docs/CONTRIBUTING.md | 81 +
Alphanium/Source/imgui/docs/EXAMPLES.md | 256 +
Alphanium/Source/imgui/docs/FAQ.md | 847 +
Alphanium/Source/imgui/docs/FONTS.md | 607 +
Alphanium/Source/imgui/docs/README.md | 226 +
Alphanium/Source/imgui/docs/TODO.txt | 328 +
Alphanium/Source/imgui/examples/README.txt | 12 +
.../imgui/examples/example_allegro5/README.md | 36 +
.../example_allegro5/example_allegro5.vcxproj | 185 +
.../example_allegro5.vcxproj.filters | 61 +
.../example_allegro5/imconfig_allegro5.h | 11 +
.../imgui/examples/example_allegro5/main.cpp | 149 +
.../example_android_opengl3/CMakeLists.txt | 40 +
.../android/.gitignore | 14 +
.../android/app/build.gradle | 37 +
.../android/app/src/main/AndroidManifest.xml | 25 +
.../android/app/src/main/java/MainActivity.kt | 40 +
.../android/build.gradle | 5 +
.../android/settings.gradle | 22 +
.../examples/example_android_opengl3/main.cpp | 382 +
.../examples/example_apple_metal/Makefile | 21 +
.../examples/example_apple_metal/README.md | 10 +
.../project.pbxproj | 522 +
.../example_apple_metal/iOS/Info-iOS.plist | 49 +
.../iOS/LaunchScreen.storyboard | 27 +
.../macOS/Info-macOS.plist | 30 +
.../macOS/MainMenu.storyboard | 93 +
.../examples/example_apple_metal/main.mm | 348 +
.../examples/example_apple_opengl2/Makefile | 21 +
.../project.pbxproj | 332 +
.../examples/example_apple_opengl2/main.mm | 256 +
.../examples/example_glfw_metal/Makefile | 46 +
.../imgui/examples/example_glfw_metal/main.mm | 182 +
.../examples/example_glfw_opengl2/Makefile | 81 +
.../example_glfw_opengl2/build_win32.bat | 8 +
.../example_glfw_opengl2.vcxproj | 186 +
.../example_glfw_opengl2.vcxproj.filters | 64 +
.../examples/example_glfw_opengl2/main.cpp | 177 +
.../examples/example_glfw_opengl3/Makefile | 89 +
.../example_glfw_opengl3/Makefile.emscripten | 95 +
.../example_glfw_opengl3/build_win32.bat | 8 +
.../example_glfw_opengl3.vcxproj | 187 +
.../example_glfw_opengl3.vcxproj.filters | 67 +
.../examples/example_glfw_opengl3/main.cpp | 214 +
.../example_glfw_vulkan/CMakeLists.txt | 47 +
.../examples/example_glfw_vulkan/Makefile | 83 +
.../example_glfw_vulkan/build_win32.bat | 14 +
.../example_glfw_vulkan/build_win64.bat | 14 +
.../example_glfw_vulkan.vcxproj | 190 +
.../example_glfw_vulkan.vcxproj.filters | 64 +
.../examples/example_glfw_vulkan/main.cpp | 540 +
.../examples/example_glfw_wgpu/CMakeLists.txt | 215 +
.../example_glfw_wgpu/Makefile.emscripten | 103 +
.../examples/example_glfw_wgpu/README.md | 167 +
.../imgui/examples/example_glfw_wgpu/main.cpp | 576 +
.../examples/example_glut_opengl2/Makefile | 75 +
.../example_glut_opengl2.vcxproj | 186 +
.../example_glut_opengl2.vcxproj.filters | 64 +
.../examples/example_glut_opengl2/main.cpp | 164 +
.../imgui/examples/example_null/Makefile | 92 +
.../examples/example_null/build_win32.bat | 3 +
.../example_null/example_null.vcxproj | 178 +
.../example_null/example_null.vcxproj.filters | 57 +
.../imgui/examples/example_null/main.cpp | 43 +
.../example_sdl2_directx11/build_win32.bat | 8 +
.../example_sdl2_directx11.vcxproj | 187 +
.../example_sdl2_directx11.vcxproj.filters | 63 +
.../examples/example_sdl2_directx11/main.cpp | 263 +
.../examples/example_sdl2_metal/Makefile | 47 +
.../imgui/examples/example_sdl2_metal/main.mm | 189 +
.../examples/example_sdl2_opengl2/Makefile | 79 +
.../examples/example_sdl2_opengl2/README.md | 29 +
.../example_sdl2_opengl2/build_win32.bat | 8 +
.../example_sdl2_opengl2.vcxproj | 186 +
.../example_sdl2_opengl2.vcxproj.filters | 64 +
.../examples/example_sdl2_opengl2/main.cpp | 188 +
.../examples/example_sdl2_opengl3/Makefile | 91 +
.../example_sdl2_opengl3/Makefile.emscripten | 95 +
.../examples/example_sdl2_opengl3/README.md | 57 +
.../example_sdl2_opengl3/build_win32.bat | 8 +
.../example_sdl2_opengl3.vcxproj | 187 +
.../example_sdl2_opengl3.vcxproj.filters | 67 +
.../examples/example_sdl2_opengl3/main.cpp | 238 +
.../example_sdl2_sdlrenderer2/Makefile | 79 +
.../example_sdl2_sdlrenderer2/README.md | 25 +
.../example_sdl2_sdlrenderer2/build_win32.bat | 8 +
.../example_sdl2_sdlrenderer2.vcxproj | 187 +
.../example_sdl2_sdlrenderer2.vcxproj.filters | 64 +
.../example_sdl2_sdlrenderer2/main.cpp | 189 +
.../examples/example_sdl2_vulkan/Makefile | 80 +
.../example_sdl2_vulkan/build_win32.bat | 14 +
.../example_sdl2_vulkan/build_win64.bat | 14 +
.../example_sdl2_vulkan.vcxproj | 190 +
.../example_sdl2_vulkan.vcxproj.filters | 64 +
.../examples/example_sdl2_vulkan/main.cpp | 555 +
.../examples/example_sdl2_wgpu/CMakeLists.txt | 205 +
.../example_sdl2_wgpu/Makefile.emscripten | 103 +
.../examples/example_sdl2_wgpu/README.md | 167 +
.../imgui/examples/example_sdl2_wgpu/main.cpp | 541 +
.../example_sdl3_directx11/build_win32.bat | 8 +
.../example_sdl3_directx11.vcxproj | 187 +
.../example_sdl3_directx11.vcxproj.filters | 63 +
.../examples/example_sdl3_directx11/main.cpp | 258 +
.../examples/example_sdl3_metal/Makefile | 48 +
.../imgui/examples/example_sdl3_metal/main.mm | 208 +
.../examples/example_sdl3_opengl3/Makefile | 85 +
.../example_sdl3_opengl3/Makefile.emscripten | 99 +
.../examples/example_sdl3_opengl3/README.md | 40 +
.../example_sdl3_opengl3/build_win32.bat | 14 +
.../example_sdl3_opengl3/build_win64.bat | 14 +
.../example_sdl3_opengl3.vcxproj | 187 +
.../example_sdl3_opengl3.vcxproj.filters | 67 +
.../examples/example_sdl3_opengl3/main.cpp | 232 +
.../examples/example_sdl3_sdlgpu3/Makefile | 73 +
.../example_sdl3_sdlgpu3/build_win64.bat | 14 +
.../example_sdl3_sdlgpu3.vcxproj | 189 +
.../example_sdl3_sdlgpu3.vcxproj.filters | 60 +
.../examples/example_sdl3_sdlgpu3/main.cpp | 230 +
.../example_sdl3_sdlrenderer3/Makefile | 74 +
.../example_sdl3_sdlrenderer3/build_win32.bat | 8 +
.../example_sdl3_sdlrenderer3.vcxproj | 186 +
.../example_sdl3_sdlrenderer3.vcxproj.filters | 64 +
.../example_sdl3_sdlrenderer3/main.cpp | 194 +
.../examples/example_sdl3_vulkan/Makefile | 77 +
.../example_sdl3_vulkan/build_win32.bat | 14 +
.../example_sdl3_vulkan/build_win64.bat | 14 +
.../example_sdl3_vulkan.vcxproj | 190 +
.../example_sdl3_vulkan.vcxproj.filters | 64 +
.../examples/example_sdl3_vulkan/main.cpp | 558 +
.../examples/example_sdl3_wgpu/CMakeLists.txt | 207 +
.../example_sdl3_wgpu/Makefile.emscripten | 103 +
.../examples/example_sdl3_wgpu/README.md | 167 +
.../imgui/examples/example_sdl3_wgpu/main.cpp | 553 +
.../example_win32_directx10/build_win32.bat | 8 +
.../example_win32_directx10.vcxproj | 176 +
.../example_win32_directx10.vcxproj.filters | 63 +
.../examples/example_win32_directx10/main.cpp | 280 +
.../example_win32_directx11/build_win32.bat | 9 +
.../example_win32_directx11.vcxproj | 175 +
.../example_win32_directx11.vcxproj.filters | 63 +
.../examples/example_win32_directx11/main.cpp | 283 +
.../example_win32_directx12/build_win32.bat | 8 +
.../example_win32_directx12.vcxproj | 180 +
.../example_win32_directx12.vcxproj.filters | 65 +
.../examples/example_win32_directx12/main.cpp | 542 +
.../example_win32_directx9/build_win32.bat | 8 +
.../example_win32_directx9.vcxproj | 176 +
.../example_win32_directx9.vcxproj.filters | 64 +
.../examples/example_win32_directx9/main.cpp | 272 +
.../example_win32_opengl3/build_mingw.bat | 8 +
.../example_win32_opengl3/build_win32.bat | 8 +
.../example_win32_opengl3.vcxproj | 176 +
.../example_win32_opengl3.vcxproj.filters | 64 +
.../examples/example_win32_opengl3/main.cpp | 251 +
.../example_win32_vulkan/build_win32.bat | 9 +
.../example_win32_vulkan/build_win64.bat | 9 +
.../example_win32_vulkan.vcxproj | 178 +
.../example_win32_vulkan.vcxproj.filters | 63 +
.../examples/example_win32_vulkan/main.cpp | 567 +
.../Source/imgui/examples/imgui_examples.sln | 221 +
.../emscripten/emscripten_mainloop_stub.h | 38 +
.../libs/emscripten/shell_minimal.html | 65 +
.../imgui/examples/libs/glfw/COPYING.txt | 22 +
.../examples/libs/glfw/include/GLFW/glfw3.h | 4227 ++++
.../libs/glfw/include/GLFW/glfw3native.h | 456 +
.../libs/glfw/lib-vc2010-32/glfw3.lib | Bin 0 -> 187376 bytes
.../libs/glfw/lib-vc2010-64/glfw3.lib | Bin 0 -> 291120 bytes
.../imgui/examples/libs/usynergy/README.txt | 8 +
.../imgui/examples/libs/usynergy/uSynergy.c | 636 +
.../imgui/examples/libs/usynergy/uSynergy.h | 420 +
Alphanium/Source/imgui/imconfig.h | 147 +
Alphanium/Source/imgui/imgui.cpp | 18102 ++++++++++++++++
Alphanium/Source/imgui/imgui.h | 4178 ++++
Alphanium/Source/imgui/imgui_demo.cpp | 10886 ++++++++++
Alphanium/Source/imgui/imgui_draw.cpp | 6353 ++++++
Alphanium/Source/imgui/imgui_internal.h | 3961 ++++
Alphanium/Source/imgui/imgui_tables.cpp | 4569 ++++
Alphanium/Source/imgui/imgui_widgets.cpp | 10787 +++++++++
Alphanium/Source/imgui/imstb_rectpack.h | 627 +
Alphanium/Source/imgui/imstb_textedit.h | 1527 ++
Alphanium/Source/imgui/imstb_truetype.h | 5085 +++++
Alphanium/Source/imgui/misc/README.txt | 23 +
Alphanium/Source/imgui/misc/cpp/README.txt | 17 +
.../Source/imgui/misc/cpp/imgui_stdlib.cpp | 100 +
.../Source/imgui/misc/cpp/imgui_stdlib.h | 37 +
.../Source/imgui/misc/debuggers/README.txt | 21 +
.../Source/imgui/misc/debuggers/imgui.gdb | 12 +
.../imgui/misc/debuggers/imgui.natstepfilter | 31 +
.../Source/imgui/misc/debuggers/imgui.natvis | 58 +
.../Source/imgui/misc/debuggers/imgui_lldb.py | 189 +
.../imgui/misc/fonts/Cousine-Regular.ttf | Bin 0 -> 43912 bytes
.../Source/imgui/misc/fonts/DroidSans.ttf | Bin 0 -> 190044 bytes
.../Source/imgui/misc/fonts/Karla-Regular.ttf | Bin 0 -> 16848 bytes
.../Source/imgui/misc/fonts/ProggyClean.ttf | Bin 0 -> 41208 bytes
.../Source/imgui/misc/fonts/ProggyTiny.ttf | Bin 0 -> 35656 bytes
.../Source/imgui/misc/fonts/Roboto-Medium.ttf | Bin 0 -> 162588 bytes
.../misc/fonts/binary_to_compressed_c.cpp | 424 +
.../Source/imgui/misc/freetype/README.md | 54 +
.../imgui/misc/freetype/imgui_freetype.cpp | 751 +
.../imgui/misc/freetype/imgui_freetype.h | 83 +
.../misc/single_file/imgui_single_file.h | 29 +
306 files changed, 129162 insertions(+)
create mode 100644 Alphanium.sln
create mode 100644 Alphanium/Alphanium.filters
create mode 100644 Alphanium/Alphanium.vcxproj
create mode 100644 Alphanium/Source/Features.cpp
create mode 100644 Alphanium/Source/Features.h
create mode 100644 Alphanium/Source/Hooking.cpp
create mode 100644 Alphanium/Source/Hooking.h
create mode 100644 Alphanium/Source/ImGuiLayer.cpp
create mode 100644 Alphanium/Source/ImGuiLayer.h
create mode 100644 Alphanium/Source/Logger.cpp
create mode 100644 Alphanium/Source/Logger.h
create mode 100644 Alphanium/Source/Memory.cpp
create mode 100644 Alphanium/Source/Memory.h
create mode 100644 Alphanium/Source/MinHook/dll_resources/MinHook.def
create mode 100644 Alphanium/Source/MinHook/dll_resources/MinHook.rc
create mode 100644 Alphanium/Source/MinHook/include/MinHook.h
create mode 100644 Alphanium/Source/MinHook/src/buffer.c
create mode 100644 Alphanium/Source/MinHook/src/buffer.h
create mode 100644 Alphanium/Source/MinHook/src/hde/hde32.c
create mode 100644 Alphanium/Source/MinHook/src/hde/hde32.h
create mode 100644 Alphanium/Source/MinHook/src/hde/hde64.c
create mode 100644 Alphanium/Source/MinHook/src/hde/hde64.h
create mode 100644 Alphanium/Source/MinHook/src/hde/pstdint.h
create mode 100644 Alphanium/Source/MinHook/src/hde/table32.h
create mode 100644 Alphanium/Source/MinHook/src/hde/table64.h
create mode 100644 Alphanium/Source/MinHook/src/hook.c
create mode 100644 Alphanium/Source/MinHook/src/trampoline.c
create mode 100644 Alphanium/Source/MinHook/src/trampoline.h
create mode 100644 Alphanium/Source/Resolver.cpp
create mode 100644 Alphanium/Source/Resolver.h
create mode 100644 Alphanium/Source/StandaloneWindow.cpp
create mode 100644 Alphanium/Source/StandaloneWindow.h
create mode 100644 Alphanium/Source/Strings.cpp
create mode 100644 Alphanium/Source/Strings.h
create mode 100644 Alphanium/Source/UE4Globals.h
create mode 100644 Alphanium/Source/UE4Helpers.cpp
create mode 100644 Alphanium/Source/UE4Helpers.h
create mode 100644 Alphanium/Source/UE4Types.h
create mode 100644 Alphanium/Source/dllmain.cpp
create mode 100644 Alphanium/Source/imgui/.editorconfig
create mode 100644 Alphanium/Source/imgui/.gitattributes
create mode 100644 Alphanium/Source/imgui/.github/FUNDING.yml
create mode 100644 Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/config.yml
create mode 100644 Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/issue_template.yml
create mode 100644 Alphanium/Source/imgui/.github/pull_request_template.md
create mode 100644 Alphanium/Source/imgui/.github/workflows/build.yml
create mode 100644 Alphanium/Source/imgui/.github/workflows/build_windows_vulkan_libs.ps1
create mode 100644 Alphanium/Source/imgui/.github/workflows/manual.yml
create mode 100644 Alphanium/Source/imgui/.github/workflows/scheduled.yml
create mode 100644 Alphanium/Source/imgui/.github/workflows/static-analysis.yml
create mode 100644 Alphanium/Source/imgui/.gitignore
create mode 100644 Alphanium/Source/imgui/LICENSE.txt
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_allegro5.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_allegro5.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_android.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_android.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx10.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx10.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx11.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx11.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx12.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx12.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx9.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_dx9.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_glfw.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_glfw.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_glut.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_glut.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_metal.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_metal.mm
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_null.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_null.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_opengl2.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_opengl2.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_opengl3.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_opengl3.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_opengl3_loader.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_osx.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_osx.mm
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdl2.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdl2.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdl3.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdl3.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlgpu3.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlgpu3.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlgpu3_shaders.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlrenderer2.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlrenderer2.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlrenderer3.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_sdlrenderer3.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_vulkan.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_vulkan.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_wgpu.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_wgpu.h
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_win32.cpp
create mode 100644 Alphanium/Source/imgui/backends/imgui_impl_win32.h
create mode 100644 Alphanium/Source/imgui/backends/sdlgpu3/build_instructions.txt
create mode 100644 Alphanium/Source/imgui/backends/sdlgpu3/shader.frag
create mode 100644 Alphanium/Source/imgui/backends/sdlgpu3/shader.vert
create mode 100644 Alphanium/Source/imgui/backends/vulkan/build_instructions.txt
create mode 100644 Alphanium/Source/imgui/backends/vulkan/generate_spv.sh
create mode 100644 Alphanium/Source/imgui/backends/vulkan/glsl_shader.frag
create mode 100644 Alphanium/Source/imgui/backends/vulkan/glsl_shader.vert
create mode 100644 Alphanium/Source/imgui/docs/BACKENDS.md
create mode 100644 Alphanium/Source/imgui/docs/CHANGELOG.txt
create mode 100644 Alphanium/Source/imgui/docs/CONTRIBUTING.md
create mode 100644 Alphanium/Source/imgui/docs/EXAMPLES.md
create mode 100644 Alphanium/Source/imgui/docs/FAQ.md
create mode 100644 Alphanium/Source/imgui/docs/FONTS.md
create mode 100644 Alphanium/Source/imgui/docs/README.md
create mode 100644 Alphanium/Source/imgui/docs/TODO.txt
create mode 100644 Alphanium/Source/imgui/examples/README.txt
create mode 100644 Alphanium/Source/imgui/examples/example_allegro5/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_allegro5/example_allegro5.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_allegro5/example_allegro5.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_allegro5/imconfig_allegro5.h
create mode 100644 Alphanium/Source/imgui/examples/example_allegro5/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/CMakeLists.txt
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/android/.gitignore
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/android/app/build.gradle
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/android/app/src/main/AndroidManifest.xml
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/android/app/src/main/java/MainActivity.kt
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/android/build.gradle
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/android/settings.gradle
create mode 100644 Alphanium/Source/imgui/examples/example_android_opengl3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/example_apple_metal.xcodeproj/project.pbxproj
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/iOS/Info-iOS.plist
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/iOS/LaunchScreen.storyboard
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/macOS/Info-macOS.plist
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/macOS/MainMenu.storyboard
create mode 100644 Alphanium/Source/imgui/examples/example_apple_metal/main.mm
create mode 100644 Alphanium/Source/imgui/examples/example_apple_opengl2/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_apple_opengl2/example_apple_opengl2.xcodeproj/project.pbxproj
create mode 100644 Alphanium/Source/imgui/examples/example_apple_opengl2/main.mm
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_metal/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_metal/main.mm
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl2/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl2/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl2/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl3/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl3/Makefile.emscripten
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl3/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_opengl3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/CMakeLists.txt
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/build_win64.bat
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_vulkan/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_wgpu/CMakeLists.txt
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_wgpu/Makefile.emscripten
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_wgpu/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_glfw_wgpu/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_glut_opengl2/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_glut_opengl2/example_glut_opengl2.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_glut_opengl2/example_glut_opengl2.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_glut_opengl2/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_null/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_null/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_null/example_null.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_null/example_null.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_null/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_directx11/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_directx11/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_metal/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_metal/main.mm
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl2/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl2/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl2/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl2/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/Makefile.emscripten
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_opengl3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_sdlrenderer2/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_sdlrenderer2/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_sdlrenderer2/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_sdlrenderer2/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_vulkan/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_vulkan/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_vulkan/build_win64.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_vulkan/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_wgpu/CMakeLists.txt
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_wgpu/Makefile.emscripten
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_wgpu/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_sdl2_wgpu/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_directx11/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_directx11/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_metal/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_metal/main.mm
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/Makefile.emscripten
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/build_win64.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_opengl3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlgpu3/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlgpu3/build_win64.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlgpu3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlrenderer3/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlrenderer3/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_sdlrenderer3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_vulkan/Makefile
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_vulkan/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_vulkan/build_win64.bat
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_vulkan/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_wgpu/CMakeLists.txt
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_wgpu/Makefile.emscripten
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_wgpu/README.md
create mode 100644 Alphanium/Source/imgui/examples/example_sdl3_wgpu/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx10/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx10/example_win32_directx10.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx10/example_win32_directx10.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx10/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx11/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx11/example_win32_directx11.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx11/example_win32_directx11.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx11/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx12/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx12/example_win32_directx12.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx12/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx9/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx9/example_win32_directx9.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx9/example_win32_directx9.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_win32_directx9/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_win32_opengl3/build_mingw.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_opengl3/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_opengl3/example_win32_opengl3.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_win32_opengl3/example_win32_opengl3.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_win32_opengl3/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/example_win32_vulkan/build_win32.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_vulkan/build_win64.bat
create mode 100644 Alphanium/Source/imgui/examples/example_win32_vulkan/example_win32_vulkan.vcxproj
create mode 100644 Alphanium/Source/imgui/examples/example_win32_vulkan/example_win32_vulkan.vcxproj.filters
create mode 100644 Alphanium/Source/imgui/examples/example_win32_vulkan/main.cpp
create mode 100644 Alphanium/Source/imgui/examples/imgui_examples.sln
create mode 100644 Alphanium/Source/imgui/examples/libs/emscripten/emscripten_mainloop_stub.h
create mode 100644 Alphanium/Source/imgui/examples/libs/emscripten/shell_minimal.html
create mode 100644 Alphanium/Source/imgui/examples/libs/glfw/COPYING.txt
create mode 100644 Alphanium/Source/imgui/examples/libs/glfw/include/GLFW/glfw3.h
create mode 100644 Alphanium/Source/imgui/examples/libs/glfw/include/GLFW/glfw3native.h
create mode 100644 Alphanium/Source/imgui/examples/libs/glfw/lib-vc2010-32/glfw3.lib
create mode 100644 Alphanium/Source/imgui/examples/libs/glfw/lib-vc2010-64/glfw3.lib
create mode 100644 Alphanium/Source/imgui/examples/libs/usynergy/README.txt
create mode 100644 Alphanium/Source/imgui/examples/libs/usynergy/uSynergy.c
create mode 100644 Alphanium/Source/imgui/examples/libs/usynergy/uSynergy.h
create mode 100644 Alphanium/Source/imgui/imconfig.h
create mode 100644 Alphanium/Source/imgui/imgui.cpp
create mode 100644 Alphanium/Source/imgui/imgui.h
create mode 100644 Alphanium/Source/imgui/imgui_demo.cpp
create mode 100644 Alphanium/Source/imgui/imgui_draw.cpp
create mode 100644 Alphanium/Source/imgui/imgui_internal.h
create mode 100644 Alphanium/Source/imgui/imgui_tables.cpp
create mode 100644 Alphanium/Source/imgui/imgui_widgets.cpp
create mode 100644 Alphanium/Source/imgui/imstb_rectpack.h
create mode 100644 Alphanium/Source/imgui/imstb_textedit.h
create mode 100644 Alphanium/Source/imgui/imstb_truetype.h
create mode 100644 Alphanium/Source/imgui/misc/README.txt
create mode 100644 Alphanium/Source/imgui/misc/cpp/README.txt
create mode 100644 Alphanium/Source/imgui/misc/cpp/imgui_stdlib.cpp
create mode 100644 Alphanium/Source/imgui/misc/cpp/imgui_stdlib.h
create mode 100644 Alphanium/Source/imgui/misc/debuggers/README.txt
create mode 100644 Alphanium/Source/imgui/misc/debuggers/imgui.gdb
create mode 100644 Alphanium/Source/imgui/misc/debuggers/imgui.natstepfilter
create mode 100644 Alphanium/Source/imgui/misc/debuggers/imgui.natvis
create mode 100644 Alphanium/Source/imgui/misc/debuggers/imgui_lldb.py
create mode 100644 Alphanium/Source/imgui/misc/fonts/Cousine-Regular.ttf
create mode 100644 Alphanium/Source/imgui/misc/fonts/DroidSans.ttf
create mode 100644 Alphanium/Source/imgui/misc/fonts/Karla-Regular.ttf
create mode 100644 Alphanium/Source/imgui/misc/fonts/ProggyClean.ttf
create mode 100644 Alphanium/Source/imgui/misc/fonts/ProggyTiny.ttf
create mode 100644 Alphanium/Source/imgui/misc/fonts/Roboto-Medium.ttf
create mode 100644 Alphanium/Source/imgui/misc/fonts/binary_to_compressed_c.cpp
create mode 100644 Alphanium/Source/imgui/misc/freetype/README.md
create mode 100644 Alphanium/Source/imgui/misc/freetype/imgui_freetype.cpp
create mode 100644 Alphanium/Source/imgui/misc/freetype/imgui_freetype.h
create mode 100644 Alphanium/Source/imgui/misc/single_file/imgui_single_file.h
diff --git a/Alphanium.sln b/Alphanium.sln
new file mode 100644
index 0000000..4cc65ee
--- /dev/null
+++ b/Alphanium.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Alphanium", "Alphanium\\Alphanium.vcxproj", "{E05FB1D7-9BF3-4D61-AFEB-2AEF6285EF81}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E05FB1D7-9BF3-4D61-AFEB-2AEF6285EF81}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E05FB1D7-9BF3-4D61-AFEB-2AEF6285EF81}.Debug|Win32.Build.0 = Debug|Win32
+ {E05FB1D7-9BF3-4D61-AFEB-2AEF6285EF81}.Release|Win32.ActiveCfg = Release|Win32
+ {E05FB1D7-9BF3-4D61-AFEB-2AEF6285EF81}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Alphanium/Alphanium.filters b/Alphanium/Alphanium.filters
new file mode 100644
index 0000000..0dc5dce
--- /dev/null
+++ b/Alphanium/Alphanium.filters
@@ -0,0 +1,108 @@
+
+
+
+
+ {C5537E4F-E681-4036-98D8-5AEC30C061FF}
+
+
+ {f3321c91-480c-46f8-b100-b833bc1e8ea3}
+
+
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ Source
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+ external
+
+
+
\ No newline at end of file
diff --git a/Alphanium/Alphanium.vcxproj b/Alphanium/Alphanium.vcxproj
new file mode 100644
index 0000000..11b11c2
--- /dev/null
+++ b/Alphanium/Alphanium.vcxproj
@@ -0,0 +1,123 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+
+ {E05FB1D7-9BF3-4D61-AFEB-2AEF6285EF81}
+ Win32Proj
+ Alphanium
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ MultiByte
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ Disabled
+ true
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;Alphanium_EXPORTS;%(PreprocessorDefinitions)
+ $(ProjectDir)Source;%(AdditionalIncludeDirectories)
+ stdcpp17
+
+
+ Windows
+ true
+ d3d9.lib;gdi32.lib;user32.lib;kernel32.lib;psapi.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;Alphanium_EXPORTS;%(PreprocessorDefinitions)
+ $(ProjectDir)Source;%(AdditionalIncludeDirectories)
+ stdcpp17
+
+
+ Windows
+ true
+ true
+ true
+ d3d9.lib;gdi32.lib;user32.lib;kernel32.lib;psapi.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Alphanium/Source/Features.cpp b/Alphanium/Source/Features.cpp
new file mode 100644
index 0000000..4621e79
--- /dev/null
+++ b/Alphanium/Source/Features.cpp
@@ -0,0 +1,526 @@
+#include "Features.h"
+#include "UE4Globals.h"
+#include "UE4Helpers.h"
+#include "Strings.h"
+#include "imgui/imgui.h"
+#include "Logger.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace {
+Features g_features;
+
+int32_t FindNameIndexByString(const std::string& name) {
+ auto* names = reinterpret_cast(g_ue4.GNames);
+ if (!names || !names->Entries) {
+ return -1;
+ }
+ for (int32_t i = 0; i < 1024 * 1024; ++i) {
+ auto* entry = names->Entries[i];
+ if (!entry) {
+ continue;
+ }
+ if (name == entry->AnsiName) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void ConsoleCommand(APlayerController* controller, const std::string& command) {
+ if (!controller) {
+ return;
+ }
+ auto func = FindFunction(L"Function Engine.PlayerController.ConsoleCommand");
+ if (!func) {
+ return;
+ }
+ struct FString {
+ wchar_t* Data;
+ int32_t Count;
+ int32_t Max;
+ } cmd{};
+ std::wstring wide(command.begin(), command.end());
+ cmd.Data = const_cast(wide.c_str());
+ cmd.Count = static_cast(wide.size() + 1);
+ cmd.Max = cmd.Count;
+ struct Params {
+ FString Command;
+ bool bWriteToLog;
+ FString ReturnValue;
+ } params{};
+ params.Command = cmd;
+ params.bWriteToLog = false;
+
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(controller), func, ¶ms);
+ }
+}
+}
+
+Features& GetFeatures() {
+ return g_features;
+}
+
+void Features::Initialize() {
+ StartContentScan();
+}
+
+void Features::Tick() {
+ ApplyMovementCheats();
+ ProcessScanResults();
+}
+
+void Features::RenderUI() {
+ if (!showMenu_) {
+ return;
+ }
+
+ ImGui::SetNextWindowSize({700.0f, 500.0f});
+ if (!ImGui::Begin("Alphanium")) {
+ ImGui::End();
+ return;
+ }
+
+ if (ImGui::BeginTabBar("MainTabs")) {
+ if (ImGui::BeginTabItem("Maps")) {
+ RenderMapsTab();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("GameObjects")) {
+ RenderObjectsTab();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Spawning")) {
+ RenderSpawningTab();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Cheats / Utilities")) {
+ RenderCheatsTab();
+ ImGui::EndTabItem();
+ }
+ if (ImGui::BeginTabItem("Gameplay Reconstruction")) {
+ RenderGameplayTab();
+ ImGui::EndTabItem();
+ }
+ ImGui::EndTabBar();
+ }
+
+ ImGui::End();
+}
+
+void Features::RenderMapsTab() {
+ ImGui::Text("Discovered Maps:");
+ ImGui::BeginChild("MapList", ImVec2(0.0f, 220.0f), true);
+ for (const auto& map : stringDump_.maps) {
+ bool selected = (selectedMap_ == map);
+ if (ImGui::Selectable(map.c_str(), selected)) {
+ selectedMap_ = map;
+ }
+ }
+ for (const auto& map : scannedMaps_) {
+ bool selected = (selectedMap_ == map);
+ if (ImGui::Selectable(map.c_str(), selected)) {
+ selectedMap_ = map;
+ }
+ }
+ ImGui::EndChild();
+ if (!selectedMap_.empty()) {
+ ImGui::Text("Selected: %s", selectedMap_.c_str());
+ }
+ if (ImGui::Button("Quick Load (Sandbox)")) {
+ QuickLoadMap(selectedMap_);
+ }
+ if (ImGui::Button("Full Load (Gameplay)")) {
+ FullLoadMap(selectedMap_);
+ }
+ if (ImGui::Button("Unload")) {
+ UnloadMap();
+ }
+ if (ImGui::Button("Reload")) {
+ ReloadMap();
+ }
+}
+
+void Features::RenderObjectsTab() {
+ std::vector foundActors;
+ std::unordered_set seen;
+
+ if (UWorld* world = GetWorld()) {
+ if (world->PersistentLevel) {
+ auto& actors = world->PersistentLevel->Actors;
+ for (int32_t i = 0; i < actors.Count; ++i) {
+ AActor* actor = actors[i];
+ if (actor && seen.insert(reinterpret_cast(actor)).second) {
+ foundActors.push_back(actor);
+ }
+ }
+ }
+ for (int32_t l = 0; l < world->Levels.Count; ++l) {
+ ULevel* level = world->Levels[l];
+ if (!level) {
+ continue;
+ }
+ auto& actors = level->Actors;
+ for (int32_t i = 0; i < actors.Count; ++i) {
+ AActor* actor = actors[i];
+ if (actor && seen.insert(reinterpret_cast(actor)).second) {
+ foundActors.push_back(actor);
+ }
+ }
+ }
+ }
+
+ UClass* actorClass = reinterpret_cast(FindObjectByName(L"Class Engine.Actor"));
+ if (auto* objects = GetGUObjectArray()) {
+ for (int32_t i = 0; i < objects->NumElements; ++i) {
+ auto& item = objects->Objects[i];
+ if (!item.Object) {
+ continue;
+ }
+ UObject* obj = item.Object;
+ if (actorClass && !obj->IsA(actorClass)) {
+ continue;
+ }
+ AActor* actor = reinterpret_cast(obj);
+ if (seen.insert(reinterpret_cast(actor)).second) {
+ foundActors.push_back(actor);
+ }
+ }
+ }
+
+ ImGui::Text("Actors: %d", static_cast(foundActors.size()));
+ for (auto* actor : foundActors) {
+ if (!actor) {
+ continue;
+ }
+ std::string label = actor->GetName();
+ if (ImGui::Button(label.c_str())) {
+ selectedActor_.Actor = actor;
+ selectedActor_.Location = actor->GetActorLocation();
+ }
+ }
+
+ if (selectedActor_.Actor) {
+ ImGui::Text("Selected: %s", selectedActor_.Actor->GetFullName().c_str());
+ float loc[3] = {selectedActor_.Location.X, selectedActor_.Location.Y, selectedActor_.Location.Z};
+ ImGui::InputFloat3("Location", loc);
+ if (ImGui::Button("Apply Transform")) {
+ selectedActor_.Location = {loc[0], loc[1], loc[2]};
+ SetActorLocation(selectedActor_.Actor, selectedActor_.Location);
+ }
+ if (ImGui::Button("Destroy")) {
+ DestroyActor(selectedActor_.Actor);
+ selectedActor_.Actor = nullptr;
+ }
+ }
+}
+
+void Features::RenderSpawningTab() {
+ ImGui::Text("Husk Spawning:");
+ if (ImGui::Button("Spawn Husk (No AI / T-Pose)")) {
+ SpawnHusk(false);
+ }
+ if (ImGui::Button("Spawn Husk (With AI)")) {
+ SpawnHusk(true);
+ }
+}
+
+void Features::RenderCheatsTab() {
+ ImGui::Checkbox("Fly", &fly_);
+ ImGui::Checkbox("Noclip", &noclip_);
+ ImGui::Checkbox("Gravity", &gravity_);
+ ImGui::SliderFloat("Walk Speed", &walkSpeedMultiplier_, 0.1f, 5.0f);
+ float tp[3] = {teleportTarget_.X, teleportTarget_.Y, teleportTarget_.Z};
+ ImGui::InputFloat3("Teleport Target", tp);
+ teleportTarget_ = {tp[0], tp[1], tp[2]};
+ if (ImGui::Button("Teleport")) {
+ if (auto controller = GetLocalPlayerController()) {
+ auto pawn = controller->AcknowledgedPawn;
+ if (pawn) {
+ SetActorLocation(reinterpret_cast(pawn), teleportTarget_);
+ }
+ }
+ }
+}
+
+void Features::RenderGameplayTab() {
+ ImGui::Text("Reconstruct offline gameplay systems.");
+ if (ImGui::Button("Load / Setup Gameplay")) {
+ SetupGameplay();
+ }
+}
+
+void Features::QuickLoadMap(const std::string& mapName) {
+ if (mapName.empty()) {
+ return;
+ }
+ UObject* world = reinterpret_cast(GetWorld());
+ if (!world) {
+ LogMessage("QuickLoadMap: world is null");
+ return;
+ }
+ std::string command = BuildMapCommand(mapName);
+ LogMessage("QuickLoadMap: executing '%s'", command.c_str());
+ ExecuteConsoleCommand(world, command);
+
+ auto controller = GetLocalPlayerController();
+ if (!controller) {
+ LogMessage("QuickLoadMap: PlayerController not found");
+ return;
+ }
+ FVector spawnLoc{0.0f, 0.0f, 300.0f};
+ auto character = SpawnDefaultCharacter(spawnLoc);
+ if (character) {
+ PossessPawn(controller, reinterpret_cast(character));
+ } else {
+ LogMessage("QuickLoadMap: failed to spawn default character");
+ }
+}
+
+void Features::FullLoadMap(const std::string& mapName) {
+ QuickLoadMap(mapName);
+ UWorld* world = GetWorld();
+ if (!world) {
+ return;
+ }
+ auto gameModeClass = FindObjectByName(L"Class Engine.GameMode");
+ auto gameStateClass = FindObjectByName(L"Class Engine.GameState");
+ if (gameModeClass) {
+ FVector loc{0.0f, 0.0f, 0.0f};
+ auto gm = SpawnDefaultCharacter(loc);
+ world->AuthorityGameMode = reinterpret_cast(gm);
+ }
+ if (gameStateClass) {
+ FVector loc{0.0f, 0.0f, 0.0f};
+ auto gs = SpawnDefaultCharacter(loc);
+ world->GameState = reinterpret_cast(gs);
+ }
+}
+
+void Features::UnloadMap() {
+ UObject* world = reinterpret_cast(GetWorld());
+ if (world) {
+ LogMessage("UnloadMap: executing open /Engine/Maps/Entry");
+ ExecuteConsoleCommand(world, "open /Engine/Maps/Entry");
+ } else {
+ LogMessage("UnloadMap: world is null");
+ }
+}
+
+void Features::ReloadMap() {
+ if (!selectedMap_.empty()) {
+ QuickLoadMap(selectedMap_);
+ }
+}
+
+void Features::ApplyMovementCheats() {
+ auto controller = GetLocalPlayerController();
+ if (!controller) {
+ return;
+ }
+ UObject* world = reinterpret_cast(GetWorld());
+ if (!world) {
+ LogMessage("ApplyMovementCheats: world is null");
+ return;
+ }
+ if (fly_) {
+ ExecuteConsoleCommand(world, "fly");
+ }
+ if (noclip_) {
+ ExecuteConsoleCommand(world, "ghost");
+ }
+ if (!gravity_) {
+ ExecuteConsoleCommand(world, "setgravity 0");
+ } else {
+ ExecuteConsoleCommand(world, "setgravity 1");
+ }
+ if (walkSpeedMultiplier_ != 1.0f) {
+ std::string cmd = "slomo " + std::to_string(walkSpeedMultiplier_);
+ ExecuteConsoleCommand(world, cmd);
+ }
+}
+
+void Features::SpawnHusk(bool withAI) {
+ auto controller = GetLocalPlayerController();
+ if (!controller) {
+ return;
+ }
+ UObject* huskClass = FindObjectByName(L"Class FortniteGame.FortAIPawn_Husk");
+ if (!huskClass) {
+ huskClass = FindObjectByName(L"Husk");
+ }
+ if (!huskClass) {
+ return;
+ }
+ UWorld* world = GetWorld();
+ if (!world) {
+ return;
+ }
+ auto spawnFunc = FindFunction(L"Function Engine.World.SpawnActor");
+ if (!spawnFunc) {
+ return;
+ }
+ FVector spawnLoc{0.0f, 0.0f, 300.0f};
+ if (controller->AcknowledgedPawn) {
+ spawnLoc = controller->AcknowledgedPawn->GetActorLocation();
+ spawnLoc.X += 200.0f;
+ }
+ struct SpawnParams {
+ UClass* Class;
+ FVector Location;
+ FRotator Rotation;
+ AActor* Owner;
+ APawn* Instigator;
+ bool bNoCollisionFail;
+ bool bRemoteOwned;
+ AActor* ReturnValue;
+ } params{};
+ params.Class = reinterpret_cast(huskClass);
+ params.Location = spawnLoc;
+ params.Rotation = {0.0f, 0.0f, 0.0f};
+ params.bNoCollisionFail = true;
+
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(world), spawnFunc, ¶ms);
+ }
+ AActor* husk = params.ReturnValue;
+ if (!husk || !withAI) {
+ return;
+ }
+
+ UObject* aiClass = FindObjectByName(L"Class Engine.AIController");
+ if (!aiClass) {
+ return;
+ }
+ SpawnParams aiParams{};
+ aiParams.Class = reinterpret_cast(aiClass);
+ aiParams.Location = spawnLoc;
+ aiParams.Rotation = {0.0f, 0.0f, 0.0f};
+ aiParams.bNoCollisionFail = true;
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(world), spawnFunc, &aiParams);
+ }
+ AActor* ai = aiParams.ReturnValue;
+ if (!ai) {
+ return;
+ }
+ auto possessFunc = FindFunction(L"Function Engine.Controller.Possess");
+ if (possessFunc) {
+ struct PossessParams { APawn* Pawn; } possess{reinterpret_cast(husk)};
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(ai), possessFunc, &possess);
+ }
+ }
+}
+
+void Features::SetupGameplay() {
+ auto controller = GetLocalPlayerController();
+ if (!controller) {
+ return;
+ }
+ auto giveItemFunc = FindFunction(L"Function FortniteGame.FortPlayerController.GiveItem");
+ for (const auto& weapon : stringDump_.weapon_defs) {
+ if (!giveItemFunc) {
+ break;
+ }
+ UObject* itemDef = FindObjectByName(std::wstring(weapon.begin(), weapon.end()));
+ if (!itemDef) {
+ continue;
+ }
+ struct Params {
+ UObject* ItemDef;
+ int32_t Count;
+ int32_t Level;
+ bool bSilent;
+ } params{};
+ params.ItemDef = itemDef;
+ params.Count = 1;
+ params.Level = 1;
+ params.bSilent = true;
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(controller), giveItemFunc, ¶ms);
+ }
+ }
+
+ auto buildFunc = FindFunction(L"Function FortniteGame.FortPlayerController.ToggleBuildMode");
+ if (buildFunc) {
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(controller), buildFunc, nullptr);
+ }
+ }
+}
+
+std::string Features::BuildMapCommand(const std::string& mapName) const {
+ if (mapName.find("/Game/") == 0 || mapName.find("/Engine/") == 0) {
+ return "open " + mapName;
+ }
+ std::string name = mapName;
+ const std::string ext = ".umap";
+ if (name.size() > ext.size() && name.substr(name.size() - ext.size()) == ext) {
+ name = name.substr(0, name.size() - ext.size());
+ }
+ if (name.find("Content/") == 0) {
+ name = name.substr(strlen("Content/"));
+ }
+ return "open /Game/" + name;
+}
+
+void Features::StartContentScan() {
+ if (scanning_) {
+ return;
+ }
+ scanning_ = true;
+ scanThread_ = std::thread([this]() {
+ char modulePath[MAX_PATH] = {};
+ GetModuleFileNameA(nullptr, modulePath, MAX_PATH);
+ std::filesystem::path exePath(modulePath);
+ auto root = exePath.parent_path().parent_path().parent_path();
+ auto content = root / "Content";
+ LogMessage("Alphanium: scanning content at %s", content.string().c_str());
+ if (!std::filesystem::exists(content)) {
+ LogMessage("Alphanium: Content folder not found");
+ scanning_ = false;
+ return;
+ }
+ std::vector found;
+ for (auto& entry : std::filesystem::recursive_directory_iterator(content)) {
+ if (!entry.is_regular_file()) {
+ continue;
+ }
+ auto path = entry.path();
+ if (path.extension() == ".umap") {
+ auto rel = std::filesystem::relative(path, content);
+ std::string name = rel.string();
+ std::replace(name.begin(), name.end(), '\\', '/');
+ found.push_back(name);
+ }
+ }
+ {
+ std::lock_guard lock(scanMutex_);
+ pendingMaps_.swap(found);
+ }
+ scanning_ = false;
+ });
+ scanThread_.detach();
+}
+
+void Features::ProcessScanResults() {
+ std::vector pending;
+ {
+ std::lock_guard lock(scanMutex_);
+ pending.swap(pendingMaps_);
+ }
+ if (pending.empty()) {
+ return;
+ }
+ LogMessage("Alphanium: content scan found %zu maps", pending.size());
+ scannedMaps_ = std::move(pending);
+ if (selectedMap_.empty() && !scannedMaps_.empty()) {
+ selectedMap_ = scannedMaps_.front();
+ }
+}
diff --git a/Alphanium/Source/Features.h b/Alphanium/Source/Features.h
new file mode 100644
index 0000000..96ec909
--- /dev/null
+++ b/Alphanium/Source/Features.h
@@ -0,0 +1,57 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include "UE4Types.h"
+#include "Strings.h"
+
+struct SelectedActorInfo {
+ AActor* Actor = nullptr;
+ FVector Location{0.0f, 0.0f, 0.0f};
+};
+
+class Features {
+public:
+ void Initialize();
+ void Tick();
+ void RenderUI();
+
+private:
+ void RenderMapsTab();
+ void RenderObjectsTab();
+ void RenderSpawningTab();
+ void RenderCheatsTab();
+ void RenderGameplayTab();
+
+ void QuickLoadMap(const std::string& mapName);
+ void FullLoadMap(const std::string& mapName);
+ void UnloadMap();
+ void ReloadMap();
+
+ void ApplyMovementCheats();
+ void SpawnHusk(bool withAI);
+ void SetupGameplay();
+ void StartContentScan();
+ void ProcessScanResults();
+ std::string BuildMapCommand(const std::string& mapName) const;
+
+ StringDump stringDump_;
+ std::string selectedMap_;
+ SelectedActorInfo selectedActor_;
+ std::vector scannedMaps_;
+ std::vector pendingMaps_;
+ std::thread scanThread_;
+ std::mutex scanMutex_;
+ std::atomic scanning_{false};
+
+ bool showMenu_ = true;
+ bool fly_ = false;
+ bool noclip_ = false;
+ bool gravity_ = true;
+ float walkSpeedMultiplier_ = 1.0f;
+ FVector teleportTarget_{0.0f, 0.0f, 0.0f};
+};
+
+Features& GetFeatures();
diff --git a/Alphanium/Source/Hooking.cpp b/Alphanium/Source/Hooking.cpp
new file mode 100644
index 0000000..665ccd6
--- /dev/null
+++ b/Alphanium/Source/Hooking.cpp
@@ -0,0 +1,138 @@
+#include "Hooking.h"
+#include "MinHook/include/MinHook.h"
+#include "ImGuiLayer.h"
+#include "UE4Globals.h"
+#include "Features.h"
+#include "Logger.h"
+#include
+#include
+
+namespace {
+using PresentFn = HRESULT(WINAPI*)(IDirect3DDevice9*, const RECT*, const RECT*, HWND, const RGNDATA*);
+using EndSceneFn = HRESULT(WINAPI*)(IDirect3DDevice9*);
+PresentFn g_originalPresent = nullptr;
+EndSceneFn g_originalEndScene = nullptr;
+void* g_presentTarget = nullptr;
+void* g_endSceneTarget = nullptr;
+using ProcessEventFnT = void(__thiscall*)(UObject*, UFunction*, void*);
+ProcessEventFnT g_originalProcessEvent = nullptr;
+
+LRESULT CALLBACK DummyWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+HWND CreateDummyWindow() {
+ WNDCLASSEXA wc{};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = DummyWndProc;
+ wc.hInstance = GetModuleHandleA(nullptr);
+ wc.lpszClassName = "AlphaniumDummyWindow";
+ RegisterClassExA(&wc);
+ return CreateWindowA(wc.lpszClassName, "Alphanium", WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, nullptr, nullptr, wc.hInstance, nullptr);
+}
+
+HRESULT WINAPI PresentHook(IDirect3DDevice9* device, const RECT* src, const RECT* dst, HWND hwnd, const RGNDATA* dirty) {
+ static bool initialized = false;
+ if (!initialized) {
+ GetImGuiLayer().Initialize(device);
+ GetFeatures().Initialize();
+ initialized = true;
+ }
+ GetFeatures().Tick();
+ GetImGuiLayer().Render();
+ return g_originalPresent(device, src, dst, hwnd, dirty);
+}
+
+HRESULT WINAPI EndSceneHook(IDirect3DDevice9* device) {
+ static bool initialized = false;
+ if (!initialized) {
+ GetImGuiLayer().Initialize(device);
+ GetFeatures().Initialize();
+ initialized = true;
+ }
+ GetFeatures().Tick();
+ GetImGuiLayer().Render();
+ return g_originalEndScene(device);
+}
+
+void __fastcall ProcessEventHook(UObject* obj, void*, UFunction* func, void* params) {
+ if (func) {
+ std::string name = func->GetFullName();
+ if (name.find("SpawnActor") != std::string::npos) {
+ LogMessage("ProcessEvent: %s", name.c_str());
+ }
+ }
+ if (g_originalProcessEvent) {
+ g_originalProcessEvent(obj, func, params);
+ }
+}
+}
+
+bool InitializeHooks() {
+ if (MH_Initialize() != MH_OK) {
+ return false;
+ }
+
+ IDirect3D9* d3d = Direct3DCreate9(D3D_SDK_VERSION);
+ if (!d3d) {
+ return false;
+ }
+ HWND hwnd = CreateDummyWindow();
+ D3DPRESENT_PARAMETERS params{};
+ params.Windowed = TRUE;
+ params.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ params.hDeviceWindow = hwnd;
+
+ IDirect3DDevice9* device = nullptr;
+ HRESULT hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
+ D3DCREATE_SOFTWARE_VERTEXPROCESSING,
+ ¶ms, &device);
+ if (FAILED(hr)) {
+ d3d->Release();
+ DestroyWindow(hwnd);
+ return false;
+ }
+
+ void** vtable = *reinterpret_cast(device);
+ g_presentTarget = vtable[17];
+ g_originalPresent = reinterpret_cast(g_presentTarget);
+ g_endSceneTarget = vtable[42];
+ g_originalEndScene = reinterpret_cast(g_endSceneTarget);
+
+ if (MH_CreateHook(g_presentTarget, reinterpret_cast(&PresentHook), reinterpret_cast(&g_originalPresent)) == MH_OK) {
+ MH_EnableHook(g_presentTarget);
+ LogMessage("Hooked Present at %p", g_presentTarget);
+ } else if (g_endSceneTarget) {
+ if (MH_CreateHook(g_endSceneTarget, reinterpret_cast(&EndSceneHook), reinterpret_cast(&g_originalEndScene)) == MH_OK) {
+ MH_EnableHook(g_endSceneTarget);
+ LogMessage("Hooked EndScene at %p", g_endSceneTarget);
+ } else {
+ LogMessage("Failed to hook Present or EndScene");
+ }
+ }
+
+ device->Release();
+ d3d->Release();
+ DestroyWindow(hwnd);
+
+ if (g_ue4.ProcessEvent) {
+ g_originalProcessEvent = reinterpret_cast(g_ue4.ProcessEvent);
+ MH_CreateHook(reinterpret_cast(g_ue4.ProcessEvent), reinterpret_cast(&ProcessEventHook), reinterpret_cast(&g_originalProcessEvent));
+ MH_EnableHook(reinterpret_cast(g_ue4.ProcessEvent));
+ }
+
+ return true;
+}
+
+void ShutdownHooks() {
+ if (g_ue4.ProcessEvent) {
+ MH_DisableHook(reinterpret_cast(g_ue4.ProcessEvent));
+ }
+ if (g_endSceneTarget) {
+ MH_DisableHook(g_endSceneTarget);
+ }
+ if (g_presentTarget) {
+ MH_DisableHook(g_presentTarget);
+ }
+ MH_Uninitialize();
+}
diff --git a/Alphanium/Source/Hooking.h b/Alphanium/Source/Hooking.h
new file mode 100644
index 0000000..31baef8
--- /dev/null
+++ b/Alphanium/Source/Hooking.h
@@ -0,0 +1,5 @@
+#pragma once
+#include
+
+bool InitializeHooks();
+void ShutdownHooks();
diff --git a/Alphanium/Source/ImGuiLayer.cpp b/Alphanium/Source/ImGuiLayer.cpp
new file mode 100644
index 0000000..9bfcb13
--- /dev/null
+++ b/Alphanium/Source/ImGuiLayer.cpp
@@ -0,0 +1,105 @@
+#include "ImGuiLayer.h"
+#include "imgui/imgui.h"
+#include "imgui/backends/imgui_impl_dx9.h"
+#include "imgui/backends/imgui_impl_win32.h"
+#include "Features.h"
+
+namespace {
+ImGuiLayer g_layer;
+}
+
+ImGuiLayer& GetImGuiLayer() {
+ return g_layer;
+}
+
+bool ImGuiLayer::Initialize(IDirect3DDevice9* device) {
+ if (!device) {
+ return false;
+ }
+ device_ = device;
+ D3DDEVICE_CREATION_PARAMETERS params{};
+ if (FAILED(device_->GetCreationParameters(¶ms))) {
+ return false;
+ }
+ hwnd_ = params.hFocusWindow;
+ if (!contextInitialized_) {
+ ImGui::CreateContext();
+ contextInitialized_ = true;
+ }
+ if (!backendInitialized_) {
+ ImGui_ImplWin32_Init(hwnd_);
+ ImGui_ImplDX9_Init(device_);
+ backendInitialized_ = true;
+ }
+ return true;
+}
+
+bool ImGuiLayer::InitializeStandalone(HWND hwnd) {
+ if (!hwnd) {
+ return false;
+ }
+ hwnd_ = hwnd;
+ if (!contextInitialized_) {
+ ImGui::CreateContext();
+ contextInitialized_ = true;
+ }
+ return true;
+}
+
+bool ImGuiLayer::InitializeStandaloneDevice(HWND hwnd, IDirect3DDevice9* device) {
+ if (!hwnd || !device) {
+ return false;
+ }
+ hwnd_ = hwnd;
+ device_ = device;
+ if (!contextInitialized_) {
+ ImGui::CreateContext();
+ contextInitialized_ = true;
+ }
+ if (!backendInitialized_) {
+ ImGui_ImplWin32_Init(hwnd_);
+ ImGui_ImplDX9_Init(device_);
+ backendInitialized_ = true;
+ }
+ return true;
+}
+
+void ImGuiLayer::Shutdown() {
+ if (backendInitialized_) {
+ ImGui_ImplDX9_Shutdown();
+ ImGui_ImplWin32_Shutdown();
+ backendInitialized_ = false;
+ }
+ if (contextInitialized_) {
+ ImGui::DestroyContext();
+ contextInitialized_ = false;
+ }
+ device_ = nullptr;
+ hwnd_ = nullptr;
+}
+
+void ImGuiLayer::Render() {
+ if (!device_ || !hwnd_) {
+ return;
+ }
+ std::lock_guard lock(renderMutex_);
+ ImGui_ImplDX9_NewFrame();
+ ImGui_ImplWin32_NewFrame();
+ ImGui::NewFrame();
+ GetFeatures().RenderUI();
+ ImGui::Render();
+ ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
+}
+
+void ImGuiLayer::RenderStandalone() {
+ if (!device_ || !hwnd_) {
+ return;
+ }
+ std::lock_guard lock(renderMutex_);
+ ImGui_ImplDX9_NewFrame();
+ ImGui_ImplWin32_NewFrame();
+ ImGui::NewFrame();
+ GetFeatures().RenderUI();
+ ImGui::Render();
+ ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
+}
diff --git a/Alphanium/Source/ImGuiLayer.h b/Alphanium/Source/ImGuiLayer.h
new file mode 100644
index 0000000..0b71ca4
--- /dev/null
+++ b/Alphanium/Source/ImGuiLayer.h
@@ -0,0 +1,24 @@
+#pragma once
+#include
+#include
+#include
+
+class ImGuiLayer {
+public:
+ bool Initialize(IDirect3DDevice9* device);
+ bool InitializeStandalone(HWND hwnd);
+ bool InitializeStandaloneDevice(HWND hwnd, IDirect3DDevice9* device);
+ void Shutdown();
+ void Render();
+ void RenderStandalone();
+ bool IsInitialized() const { return contextInitialized_; }
+
+private:
+ IDirect3DDevice9* device_ = nullptr;
+ HWND hwnd_ = nullptr;
+ bool contextInitialized_ = false;
+ bool backendInitialized_ = false;
+ std::mutex renderMutex_;
+};
+
+ImGuiLayer& GetImGuiLayer();
diff --git a/Alphanium/Source/Logger.cpp b/Alphanium/Source/Logger.cpp
new file mode 100644
index 0000000..a2c6263
--- /dev/null
+++ b/Alphanium/Source/Logger.cpp
@@ -0,0 +1,33 @@
+#include "Logger.h"
+#include
+#include
+#include
+
+namespace {
+bool g_consoleReady = false;
+}
+
+void InitializeConsole() {
+ if (g_consoleReady) {
+ return;
+ }
+ if (AllocConsole()) {
+ FILE* out = nullptr;
+ freopen_s(&out, "CONOUT$", "w", stdout);
+ FILE* err = nullptr;
+ freopen_s(&err, "CONOUT$", "w", stderr);
+ g_consoleReady = true;
+ }
+}
+
+void LogMessage(const char* fmt, ...) {
+ if (!g_consoleReady) {
+ return;
+ }
+ char buffer[1024];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+ printf("%s\n", buffer);
+}
diff --git a/Alphanium/Source/Logger.h b/Alphanium/Source/Logger.h
new file mode 100644
index 0000000..251dfb3
--- /dev/null
+++ b/Alphanium/Source/Logger.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void InitializeConsole();
+void LogMessage(const char* fmt, ...);
diff --git a/Alphanium/Source/Memory.cpp b/Alphanium/Source/Memory.cpp
new file mode 100644
index 0000000..70ca124
--- /dev/null
+++ b/Alphanium/Source/Memory.cpp
@@ -0,0 +1,107 @@
+#include "Memory.h"
+#include
+#include
+
+ModuleInfo GetMainModuleInfo() {
+ HMODULE module = GetModuleHandleA(nullptr);
+ MODULEINFO info{};
+ if (!GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(info))) {
+ return {};
+ }
+ ModuleInfo result;
+ result.base = reinterpret_cast(info.lpBaseOfDll);
+ result.size = info.SizeOfImage;
+ return result;
+}
+
+uintptr_t AlignDown(uintptr_t value, size_t alignment) {
+ return value & ~(alignment - 1);
+}
+
+uintptr_t FindPattern(const ModuleInfo& module, const std::vector& pattern, const std::string& mask) {
+ if (pattern.empty() || pattern.size() != mask.size()) {
+ return 0;
+ }
+ const uint8_t* start = reinterpret_cast(module.base);
+ size_t size = module.size;
+ for (size_t i = 0; i + pattern.size() <= size; ++i) {
+ bool matched = true;
+ for (size_t j = 0; j < pattern.size(); ++j) {
+ if (mask[j] == 'x' && start[i + j] != pattern[j]) {
+ matched = false;
+ break;
+ }
+ }
+ if (matched) {
+ return module.base + i;
+ }
+ }
+ return 0;
+}
+
+std::vector FindAllReferences(const ModuleInfo& module, const void* target, size_t max_results) {
+ std::vector results;
+ uintptr_t value = reinterpret_cast(target);
+ const uint8_t* start = reinterpret_cast(module.base);
+ size_t size = module.size;
+ for (size_t i = 0; i + sizeof(uintptr_t) <= size; i += 1) {
+ uintptr_t current = *reinterpret_cast(start + i);
+ if (current == value) {
+ results.push_back(module.base + i);
+ if (results.size() >= max_results) {
+ break;
+ }
+ }
+ }
+ return results;
+}
+
+uintptr_t FindStringInModule(const ModuleInfo& module, const std::string& str) {
+ if (str.empty()) {
+ return 0;
+ }
+ const uint8_t* start = reinterpret_cast(module.base);
+ size_t size = module.size;
+ for (size_t i = 0; i + str.size() <= size; ++i) {
+ if (memcmp(start + i, str.data(), str.size()) == 0) {
+ return module.base + i;
+ }
+ }
+ return 0;
+}
+
+uintptr_t FindWideStringInModule(const ModuleInfo& module, const std::wstring& str) {
+ if (str.empty()) {
+ return 0;
+ }
+ const uint8_t* start = reinterpret_cast(module.base);
+ size_t size = module.size;
+ const uint8_t* needle = reinterpret_cast(str.data());
+ size_t bytes = str.size() * sizeof(wchar_t);
+ for (size_t i = 0; i + bytes <= size; ++i) {
+ if (memcmp(start + i, needle, bytes) == 0) {
+ return module.base + i;
+ }
+ }
+ return 0;
+}
+
+bool IsReadableAddress(const void* address, size_t size) {
+ if (!address) {
+ return false;
+ }
+ MEMORY_BASIC_INFORMATION mbi{};
+ if (!VirtualQuery(address, &mbi, sizeof(mbi))) {
+ return false;
+ }
+ if (mbi.State != MEM_COMMIT) {
+ return false;
+ }
+ if (mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD)) {
+ return false;
+ }
+ uintptr_t start = reinterpret_cast(address);
+ uintptr_t end = start + size;
+ uintptr_t regionEnd = reinterpret_cast(mbi.BaseAddress) + mbi.RegionSize;
+ return end <= regionEnd;
+}
diff --git a/Alphanium/Source/Memory.h b/Alphanium/Source/Memory.h
new file mode 100644
index 0000000..a3c974f
--- /dev/null
+++ b/Alphanium/Source/Memory.h
@@ -0,0 +1,18 @@
+#pragma once
+#include
+#include
+#include
+#include
+
+struct ModuleInfo {
+ uintptr_t base = 0;
+ size_t size = 0;
+};
+
+ModuleInfo GetMainModuleInfo();
+uintptr_t FindPattern(const ModuleInfo& module, const std::vector& pattern, const std::string& mask);
+std::vector FindAllReferences(const ModuleInfo& module, const void* target, size_t max_results = 32);
+uintptr_t FindStringInModule(const ModuleInfo& module, const std::string& str);
+uintptr_t FindWideStringInModule(const ModuleInfo& module, const std::wstring& str);
+bool IsReadableAddress(const void* address, size_t size = 1);
+uintptr_t AlignDown(uintptr_t value, size_t alignment);
diff --git a/Alphanium/Source/MinHook/dll_resources/MinHook.def b/Alphanium/Source/MinHook/dll_resources/MinHook.def
new file mode 100644
index 0000000..c6af698
--- /dev/null
+++ b/Alphanium/Source/MinHook/dll_resources/MinHook.def
@@ -0,0 +1,14 @@
+EXPORTS
+ MH_Initialize
+ MH_Uninitialize
+
+ MH_CreateHook
+ MH_CreateHookApi
+ MH_CreateHookApiEx
+ MH_RemoveHook
+ MH_EnableHook
+ MH_DisableHook
+ MH_QueueEnableHook
+ MH_QueueDisableHook
+ MH_ApplyQueued
+ MH_StatusToString
diff --git a/Alphanium/Source/MinHook/dll_resources/MinHook.rc b/Alphanium/Source/MinHook/dll_resources/MinHook.rc
new file mode 100644
index 0000000..7cbacb7
--- /dev/null
+++ b/Alphanium/Source/MinHook/dll_resources/MinHook.rc
@@ -0,0 +1,32 @@
+1 VERSIONINFO
+ FILEVERSION 1,3,3,0
+ PRODUCTVERSION 1,3,3,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Tsuda Kageyu"
+ VALUE "FileDescription", "MinHook - The Minimalistic API Hook Library for x64/x86"
+ VALUE "FileVersion", "1.3.3.0"
+ VALUE "InternalName", "MinHookD"
+ VALUE "LegalCopyright", "Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved."
+ VALUE "LegalTrademarks", "Tsuda Kageyu"
+ VALUE "ProductName", "MinHook DLL"
+ VALUE "ProductVersion", "1.3.3.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Alphanium/Source/MinHook/include/MinHook.h b/Alphanium/Source/MinHook/include/MinHook.h
new file mode 100644
index 0000000..15c0a87
--- /dev/null
+++ b/Alphanium/Source/MinHook/include/MinHook.h
@@ -0,0 +1,186 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
+ #error MinHook supports only x86 and x64 systems.
+#endif
+
+#include
+
+// MinHook Error Codes.
+typedef enum MH_STATUS
+{
+ // Unknown error. Should not be returned.
+ MH_UNKNOWN = -1,
+
+ // Successful.
+ MH_OK = 0,
+
+ // MinHook is already initialized.
+ MH_ERROR_ALREADY_INITIALIZED,
+
+ // MinHook is not initialized yet, or already uninitialized.
+ MH_ERROR_NOT_INITIALIZED,
+
+ // The hook for the specified target function is already created.
+ MH_ERROR_ALREADY_CREATED,
+
+ // The hook for the specified target function is not created yet.
+ MH_ERROR_NOT_CREATED,
+
+ // The hook for the specified target function is already enabled.
+ MH_ERROR_ENABLED,
+
+ // The hook for the specified target function is not enabled yet, or already
+ // disabled.
+ MH_ERROR_DISABLED,
+
+ // The specified pointer is invalid. It points the address of non-allocated
+ // and/or non-executable region.
+ MH_ERROR_NOT_EXECUTABLE,
+
+ // The specified target function cannot be hooked.
+ MH_ERROR_UNSUPPORTED_FUNCTION,
+
+ // Failed to allocate memory.
+ MH_ERROR_MEMORY_ALLOC,
+
+ // Failed to change the memory protection.
+ MH_ERROR_MEMORY_PROTECT,
+
+ // The specified module is not loaded.
+ MH_ERROR_MODULE_NOT_FOUND,
+
+ // The specified function is not found.
+ MH_ERROR_FUNCTION_NOT_FOUND
+}
+MH_STATUS;
+
+// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
+// MH_QueueEnableHook or MH_QueueDisableHook.
+#define MH_ALL_HOOKS NULL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Initialize the MinHook library. You must call this function EXACTLY ONCE
+ // at the beginning of your program.
+ MH_STATUS WINAPI MH_Initialize(VOID);
+
+ // Uninitialize the MinHook library. You must call this function EXACTLY
+ // ONCE at the end of your program.
+ MH_STATUS WINAPI MH_Uninitialize(VOID);
+
+ // Creates a Hook for the specified target function, in disabled state.
+ // Parameters:
+ // pTarget [in] A pointer to the target function, which will be
+ // overridden by the detour function.
+ // pDetour [in] A pointer to the detour function, which will override
+ // the target function.
+ // ppOriginal [out] A pointer to the trampoline function, which will be
+ // used to call the original target function.
+ // This parameter can be NULL.
+ MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
+
+ // Creates a Hook for the specified API function, in disabled state.
+ // Parameters:
+ // pszModule [in] A pointer to the loaded module name which contains the
+ // target function.
+ // pszTarget [in] A pointer to the target function name, which will be
+ // overridden by the detour function.
+ // pDetour [in] A pointer to the detour function, which will override
+ // the target function.
+ // ppOriginal [out] A pointer to the trampoline function, which will be
+ // used to call the original target function.
+ // This parameter can be NULL.
+ MH_STATUS WINAPI MH_CreateHookApi(
+ LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
+
+ // Creates a Hook for the specified API function, in disabled state.
+ // Parameters:
+ // pszModule [in] A pointer to the loaded module name which contains the
+ // target function.
+ // pszTarget [in] A pointer to the target function name, which will be
+ // overridden by the detour function.
+ // pDetour [in] A pointer to the detour function, which will override
+ // the target function.
+ // ppOriginal [out] A pointer to the trampoline function, which will be
+ // used to call the original target function.
+ // This parameter can be NULL.
+ // ppTarget [out] A pointer to the target function, which will be used
+ // with other functions.
+ // This parameter can be NULL.
+ MH_STATUS WINAPI MH_CreateHookApiEx(
+ LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
+
+ // Removes an already created hook.
+ // Parameters:
+ // pTarget [in] A pointer to the target function.
+ MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
+
+ // Enables an already created hook.
+ // Parameters:
+ // pTarget [in] A pointer to the target function.
+ // If this parameter is MH_ALL_HOOKS, all created hooks are
+ // enabled in one go.
+ MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
+
+ // Disables an already created hook.
+ // Parameters:
+ // pTarget [in] A pointer to the target function.
+ // If this parameter is MH_ALL_HOOKS, all created hooks are
+ // disabled in one go.
+ MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
+
+ // Queues to enable an already created hook.
+ // Parameters:
+ // pTarget [in] A pointer to the target function.
+ // If this parameter is MH_ALL_HOOKS, all created hooks are
+ // queued to be enabled.
+ MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
+
+ // Queues to disable an already created hook.
+ // Parameters:
+ // pTarget [in] A pointer to the target function.
+ // If this parameter is MH_ALL_HOOKS, all created hooks are
+ // queued to be disabled.
+ MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
+
+ // Applies all queued changes in one go.
+ MH_STATUS WINAPI MH_ApplyQueued(VOID);
+
+ // Translates the MH_STATUS to its name as a string.
+ const char * WINAPI MH_StatusToString(MH_STATUS status);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/Alphanium/Source/MinHook/src/buffer.c b/Alphanium/Source/MinHook/src/buffer.c
new file mode 100644
index 0000000..8f9fbce
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/buffer.c
@@ -0,0 +1,312 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include "buffer.h"
+
+// Size of each memory block. (= page size of VirtualAlloc)
+#define MEMORY_BLOCK_SIZE 0x1000
+
+// Max range for seeking a memory block. (= 1024MB)
+#define MAX_MEMORY_RANGE 0x40000000
+
+// Memory protection flags to check the executable address.
+#define PAGE_EXECUTE_FLAGS \
+ (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
+
+// Memory slot.
+typedef struct _MEMORY_SLOT
+{
+ union
+ {
+ struct _MEMORY_SLOT *pNext;
+ UINT8 buffer[MEMORY_SLOT_SIZE];
+ };
+} MEMORY_SLOT, *PMEMORY_SLOT;
+
+// Memory block info. Placed at the head of each block.
+typedef struct _MEMORY_BLOCK
+{
+ struct _MEMORY_BLOCK *pNext;
+ PMEMORY_SLOT pFree; // First element of the free slot list.
+ UINT usedCount;
+} MEMORY_BLOCK, *PMEMORY_BLOCK;
+
+//-------------------------------------------------------------------------
+// Global Variables:
+//-------------------------------------------------------------------------
+
+// First element of the memory block list.
+PMEMORY_BLOCK g_pMemoryBlocks;
+
+//-------------------------------------------------------------------------
+VOID InitializeBuffer(VOID)
+{
+ // Nothing to do for now.
+}
+
+//-------------------------------------------------------------------------
+VOID UninitializeBuffer(VOID)
+{
+ PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
+ g_pMemoryBlocks = NULL;
+
+ while (pBlock)
+ {
+ PMEMORY_BLOCK pNext = pBlock->pNext;
+ VirtualFree(pBlock, 0, MEM_RELEASE);
+ pBlock = pNext;
+ }
+}
+
+//-------------------------------------------------------------------------
+#if defined(_M_X64) || defined(__x86_64__)
+static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
+{
+ ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
+
+ // Round down to the allocation granularity.
+ tryAddr -= tryAddr % dwAllocationGranularity;
+
+ // Start from the previous allocation granularity multiply.
+ tryAddr -= dwAllocationGranularity;
+
+ while (tryAddr >= (ULONG_PTR)pMinAddr)
+ {
+ MEMORY_BASIC_INFORMATION mbi;
+ if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
+ break;
+
+ if (mbi.State == MEM_FREE)
+ return (LPVOID)tryAddr;
+
+ if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
+ break;
+
+ tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
+ }
+
+ return NULL;
+}
+#endif
+
+//-------------------------------------------------------------------------
+#if defined(_M_X64) || defined(__x86_64__)
+static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
+{
+ ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
+
+ // Round down to the allocation granularity.
+ tryAddr -= tryAddr % dwAllocationGranularity;
+
+ // Start from the next allocation granularity multiply.
+ tryAddr += dwAllocationGranularity;
+
+ while (tryAddr <= (ULONG_PTR)pMaxAddr)
+ {
+ MEMORY_BASIC_INFORMATION mbi;
+ if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
+ break;
+
+ if (mbi.State == MEM_FREE)
+ return (LPVOID)tryAddr;
+
+ tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
+
+ // Round up to the next allocation granularity.
+ tryAddr += dwAllocationGranularity - 1;
+ tryAddr -= tryAddr % dwAllocationGranularity;
+ }
+
+ return NULL;
+}
+#endif
+
+//-------------------------------------------------------------------------
+static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
+{
+ PMEMORY_BLOCK pBlock;
+#if defined(_M_X64) || defined(__x86_64__)
+ ULONG_PTR minAddr;
+ ULONG_PTR maxAddr;
+
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
+ maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
+
+ // pOrigin ± 512MB
+ if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
+ minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
+
+ if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
+ maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
+
+ // Make room for MEMORY_BLOCK_SIZE bytes.
+ maxAddr -= MEMORY_BLOCK_SIZE - 1;
+#endif
+
+ // Look the registered blocks for a reachable one.
+ for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
+ {
+#if defined(_M_X64) || defined(__x86_64__)
+ // Ignore the blocks too far.
+ if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
+ continue;
+#endif
+ // The block has at least one unused slot.
+ if (pBlock->pFree != NULL)
+ return pBlock;
+ }
+
+#if defined(_M_X64) || defined(__x86_64__)
+ // Alloc a new block above if not found.
+ {
+ LPVOID pAlloc = pOrigin;
+ while ((ULONG_PTR)pAlloc >= minAddr)
+ {
+ pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
+ if (pAlloc == NULL)
+ break;
+
+ pBlock = (PMEMORY_BLOCK)VirtualAlloc(
+ pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (pBlock != NULL)
+ break;
+ }
+ }
+
+ // Alloc a new block below if not found.
+ if (pBlock == NULL)
+ {
+ LPVOID pAlloc = pOrigin;
+ while ((ULONG_PTR)pAlloc <= maxAddr)
+ {
+ pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
+ if (pAlloc == NULL)
+ break;
+
+ pBlock = (PMEMORY_BLOCK)VirtualAlloc(
+ pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if (pBlock != NULL)
+ break;
+ }
+ }
+#else
+ // In x86 mode, a memory block can be placed anywhere.
+ pBlock = (PMEMORY_BLOCK)VirtualAlloc(
+ NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+#endif
+
+ if (pBlock != NULL)
+ {
+ // Build a linked list of all the slots.
+ PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
+ pBlock->pFree = NULL;
+ pBlock->usedCount = 0;
+ do
+ {
+ pSlot->pNext = pBlock->pFree;
+ pBlock->pFree = pSlot;
+ pSlot++;
+ } while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
+
+ pBlock->pNext = g_pMemoryBlocks;
+ g_pMemoryBlocks = pBlock;
+ }
+
+ return pBlock;
+}
+
+//-------------------------------------------------------------------------
+LPVOID AllocateBuffer(LPVOID pOrigin)
+{
+ PMEMORY_SLOT pSlot;
+ PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
+ if (pBlock == NULL)
+ return NULL;
+
+ // Remove an unused slot from the list.
+ pSlot = pBlock->pFree;
+ pBlock->pFree = pSlot->pNext;
+ pBlock->usedCount++;
+#ifdef _DEBUG
+ // Fill the slot with INT3 for debugging.
+ memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
+#endif
+ return pSlot;
+}
+
+//-------------------------------------------------------------------------
+VOID FreeBuffer(LPVOID pBuffer)
+{
+ PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
+ PMEMORY_BLOCK pPrev = NULL;
+ ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
+
+ while (pBlock != NULL)
+ {
+ if ((ULONG_PTR)pBlock == pTargetBlock)
+ {
+ PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
+#ifdef _DEBUG
+ // Clear the released slot for debugging.
+ memset(pSlot, 0x00, sizeof(*pSlot));
+#endif
+ // Restore the released slot to the list.
+ pSlot->pNext = pBlock->pFree;
+ pBlock->pFree = pSlot;
+ pBlock->usedCount--;
+
+ // Free if unused.
+ if (pBlock->usedCount == 0)
+ {
+ if (pPrev)
+ pPrev->pNext = pBlock->pNext;
+ else
+ g_pMemoryBlocks = pBlock->pNext;
+
+ VirtualFree(pBlock, 0, MEM_RELEASE);
+ }
+
+ break;
+ }
+
+ pPrev = pBlock;
+ pBlock = pBlock->pNext;
+ }
+}
+
+//-------------------------------------------------------------------------
+BOOL IsExecutableAddress(LPVOID pAddress)
+{
+ MEMORY_BASIC_INFORMATION mi;
+ VirtualQuery(pAddress, &mi, sizeof(mi));
+
+ return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
+}
diff --git a/Alphanium/Source/MinHook/src/buffer.h b/Alphanium/Source/MinHook/src/buffer.h
new file mode 100644
index 0000000..204d551
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/buffer.h
@@ -0,0 +1,42 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+// Size of each memory slot.
+#if defined(_M_X64) || defined(__x86_64__)
+ #define MEMORY_SLOT_SIZE 64
+#else
+ #define MEMORY_SLOT_SIZE 32
+#endif
+
+VOID InitializeBuffer(VOID);
+VOID UninitializeBuffer(VOID);
+LPVOID AllocateBuffer(LPVOID pOrigin);
+VOID FreeBuffer(LPVOID pBuffer);
+BOOL IsExecutableAddress(LPVOID pAddress);
diff --git a/Alphanium/Source/MinHook/src/hde/hde32.c b/Alphanium/Source/MinHook/src/hde/hde32.c
new file mode 100644
index 0000000..08fa25b
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/hde32.c
@@ -0,0 +1,326 @@
+/*
+ * Hacker Disassembler Engine 32 C
+ * Copyright (c) 2008-2009, Vyacheslav Patkov.
+ * All rights reserved.
+ *
+ */
+
+#if defined(_M_IX86) || defined(__i386__)
+
+#include "hde32.h"
+#include "table32.h"
+
+unsigned int hde32_disasm(const void *code, hde32s *hs)
+{
+ uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
+ uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0;
+
+ // Avoid using memset to reduce the footprint.
+#ifndef _MSC_VER
+ memset((LPBYTE)hs, 0, sizeof(hde32s));
+#else
+ __stosb((LPBYTE)hs, 0, sizeof(hde32s));
+#endif
+
+ for (x = 16; x; x--)
+ switch (c = *p++) {
+ case 0xf3:
+ hs->p_rep = c;
+ pref |= PRE_F3;
+ break;
+ case 0xf2:
+ hs->p_rep = c;
+ pref |= PRE_F2;
+ break;
+ case 0xf0:
+ hs->p_lock = c;
+ pref |= PRE_LOCK;
+ break;
+ case 0x26: case 0x2e: case 0x36:
+ case 0x3e: case 0x64: case 0x65:
+ hs->p_seg = c;
+ pref |= PRE_SEG;
+ break;
+ case 0x66:
+ hs->p_66 = c;
+ pref |= PRE_66;
+ break;
+ case 0x67:
+ hs->p_67 = c;
+ pref |= PRE_67;
+ break;
+ default:
+ goto pref_done;
+ }
+ pref_done:
+
+ hs->flags = (uint32_t)pref << 23;
+
+ if (!pref)
+ pref |= PRE_NONE;
+
+ if ((hs->opcode = c) == 0x0f) {
+ hs->opcode2 = c = *p++;
+ ht += DELTA_OPCODES;
+ } else if (c >= 0xa0 && c <= 0xa3) {
+ if (pref & PRE_67)
+ pref |= PRE_66;
+ else
+ pref &= ~PRE_66;
+ }
+
+ opcode = c;
+ cflags = ht[ht[opcode / 4] + (opcode % 4)];
+
+ if (cflags == C_ERROR) {
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+ cflags = 0;
+ if ((opcode & -3) == 0x24)
+ cflags++;
+ }
+
+ x = 0;
+ if (cflags & C_GROUP) {
+ uint16_t t;
+ t = *(uint16_t *)(ht + (cflags & 0x7f));
+ cflags = (uint8_t)t;
+ x = (uint8_t)(t >> 8);
+ }
+
+ if (hs->opcode2) {
+ ht = hde32_table + DELTA_PREFIXES;
+ if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+ }
+
+ if (cflags & C_MODRM) {
+ hs->flags |= F_MODRM;
+ hs->modrm = c = *p++;
+ hs->modrm_mod = m_mod = c >> 6;
+ hs->modrm_rm = m_rm = c & 7;
+ hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
+
+ if (x && ((x << m_reg) & 0x80))
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+
+ if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
+ uint8_t t = opcode - 0xd9;
+ if (m_mod == 3) {
+ ht = hde32_table + DELTA_FPU_MODRM + t*8;
+ t = ht[m_reg] << m_rm;
+ } else {
+ ht = hde32_table + DELTA_FPU_REG;
+ t = ht[t] << m_reg;
+ }
+ if (t & 0x80)
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+ }
+
+ if (pref & PRE_LOCK) {
+ if (m_mod == 3) {
+ hs->flags |= F_ERROR | F_ERROR_LOCK;
+ } else {
+ uint8_t *table_end, op = opcode;
+ if (hs->opcode2) {
+ ht = hde32_table + DELTA_OP2_LOCK_OK;
+ table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
+ } else {
+ ht = hde32_table + DELTA_OP_LOCK_OK;
+ table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
+ op &= -2;
+ }
+ for (; ht != table_end; ht++)
+ if (*ht++ == op) {
+ if (!((*ht << m_reg) & 0x80))
+ goto no_lock_error;
+ else
+ break;
+ }
+ hs->flags |= F_ERROR | F_ERROR_LOCK;
+ no_lock_error:
+ ;
+ }
+ }
+
+ if (hs->opcode2) {
+ switch (opcode) {
+ case 0x20: case 0x22:
+ m_mod = 3;
+ if (m_reg > 4 || m_reg == 1)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ case 0x21: case 0x23:
+ m_mod = 3;
+ if (m_reg == 4 || m_reg == 5)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ }
+ } else {
+ switch (opcode) {
+ case 0x8c:
+ if (m_reg > 5)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ case 0x8e:
+ if (m_reg == 1 || m_reg > 5)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ }
+ }
+
+ if (m_mod == 3) {
+ uint8_t *table_end;
+ if (hs->opcode2) {
+ ht = hde32_table + DELTA_OP2_ONLY_MEM;
+ table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM;
+ } else {
+ ht = hde32_table + DELTA_OP_ONLY_MEM;
+ table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
+ }
+ for (; ht != table_end; ht += 2)
+ if (*ht++ == opcode) {
+ if (*ht++ & pref && !((*ht << m_reg) & 0x80))
+ goto error_operand;
+ else
+ break;
+ }
+ goto no_error_operand;
+ } else if (hs->opcode2) {
+ switch (opcode) {
+ case 0x50: case 0xd7: case 0xf7:
+ if (pref & (PRE_NONE | PRE_66))
+ goto error_operand;
+ break;
+ case 0xd6:
+ if (pref & (PRE_F2 | PRE_F3))
+ goto error_operand;
+ break;
+ case 0xc5:
+ goto error_operand;
+ }
+ goto no_error_operand;
+ } else
+ goto no_error_operand;
+
+ error_operand:
+ hs->flags |= F_ERROR | F_ERROR_OPERAND;
+ no_error_operand:
+
+ c = *p++;
+ if (m_reg <= 1) {
+ if (opcode == 0xf6)
+ cflags |= C_IMM8;
+ else if (opcode == 0xf7)
+ cflags |= C_IMM_P66;
+ }
+
+ switch (m_mod) {
+ case 0:
+ if (pref & PRE_67) {
+ if (m_rm == 6)
+ disp_size = 2;
+ } else
+ if (m_rm == 5)
+ disp_size = 4;
+ break;
+ case 1:
+ disp_size = 1;
+ break;
+ case 2:
+ disp_size = 2;
+ if (!(pref & PRE_67))
+ disp_size <<= 1;
+ }
+
+ if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) {
+ hs->flags |= F_SIB;
+ p++;
+ hs->sib = c;
+ hs->sib_scale = c >> 6;
+ hs->sib_index = (c & 0x3f) >> 3;
+ if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
+ disp_size = 4;
+ }
+
+ p--;
+ switch (disp_size) {
+ case 1:
+ hs->flags |= F_DISP8;
+ hs->disp.disp8 = *p;
+ break;
+ case 2:
+ hs->flags |= F_DISP16;
+ hs->disp.disp16 = *(uint16_t *)p;
+ break;
+ case 4:
+ hs->flags |= F_DISP32;
+ hs->disp.disp32 = *(uint32_t *)p;
+ }
+ p += disp_size;
+ } else if (pref & PRE_LOCK)
+ hs->flags |= F_ERROR | F_ERROR_LOCK;
+
+ if (cflags & C_IMM_P66) {
+ if (cflags & C_REL32) {
+ if (pref & PRE_66) {
+ hs->flags |= F_IMM16 | F_RELATIVE;
+ hs->imm.imm16 = *(uint16_t *)p;
+ p += 2;
+ goto disasm_done;
+ }
+ goto rel32_ok;
+ }
+ if (pref & PRE_66) {
+ hs->flags |= F_IMM16;
+ hs->imm.imm16 = *(uint16_t *)p;
+ p += 2;
+ } else {
+ hs->flags |= F_IMM32;
+ hs->imm.imm32 = *(uint32_t *)p;
+ p += 4;
+ }
+ }
+
+ if (cflags & C_IMM16) {
+ if (hs->flags & F_IMM32) {
+ hs->flags |= F_IMM16;
+ hs->disp.disp16 = *(uint16_t *)p;
+ } else if (hs->flags & F_IMM16) {
+ hs->flags |= F_2IMM16;
+ hs->disp.disp16 = *(uint16_t *)p;
+ } else {
+ hs->flags |= F_IMM16;
+ hs->imm.imm16 = *(uint16_t *)p;
+ }
+ p += 2;
+ }
+ if (cflags & C_IMM8) {
+ hs->flags |= F_IMM8;
+ hs->imm.imm8 = *p++;
+ }
+
+ if (cflags & C_REL32) {
+ rel32_ok:
+ hs->flags |= F_IMM32 | F_RELATIVE;
+ hs->imm.imm32 = *(uint32_t *)p;
+ p += 4;
+ } else if (cflags & C_REL8) {
+ hs->flags |= F_IMM8 | F_RELATIVE;
+ hs->imm.imm8 = *p++;
+ }
+
+ disasm_done:
+
+ if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
+ hs->flags |= F_ERROR | F_ERROR_LENGTH;
+ hs->len = 15;
+ }
+
+ return (unsigned int)hs->len;
+}
+
+#endif // defined(_M_IX86) || defined(__i386__)
diff --git a/Alphanium/Source/MinHook/src/hde/hde32.h b/Alphanium/Source/MinHook/src/hde/hde32.h
new file mode 100644
index 0000000..1112450
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/hde32.h
@@ -0,0 +1,105 @@
+/*
+ * Hacker Disassembler Engine 32
+ * Copyright (c) 2006-2009, Vyacheslav Patkov.
+ * All rights reserved.
+ *
+ * hde32.h: C/C++ header file
+ *
+ */
+
+#ifndef _HDE32_H_
+#define _HDE32_H_
+
+/* stdint.h - C99 standard header
+ * http://en.wikipedia.org/wiki/stdint.h
+ *
+ * if your compiler doesn't contain "stdint.h" header (for
+ * example, Microsoft Visual C++), you can download file:
+ * http://www.azillionmonkeys.com/qed/pstdint.h
+ * and change next line to:
+ * #include "pstdint.h"
+ */
+#include "pstdint.h"
+
+#define F_MODRM 0x00000001
+#define F_SIB 0x00000002
+#define F_IMM8 0x00000004
+#define F_IMM16 0x00000008
+#define F_IMM32 0x00000010
+#define F_DISP8 0x00000020
+#define F_DISP16 0x00000040
+#define F_DISP32 0x00000080
+#define F_RELATIVE 0x00000100
+#define F_2IMM16 0x00000800
+#define F_ERROR 0x00001000
+#define F_ERROR_OPCODE 0x00002000
+#define F_ERROR_LENGTH 0x00004000
+#define F_ERROR_LOCK 0x00008000
+#define F_ERROR_OPERAND 0x00010000
+#define F_PREFIX_REPNZ 0x01000000
+#define F_PREFIX_REPX 0x02000000
+#define F_PREFIX_REP 0x03000000
+#define F_PREFIX_66 0x04000000
+#define F_PREFIX_67 0x08000000
+#define F_PREFIX_LOCK 0x10000000
+#define F_PREFIX_SEG 0x20000000
+#define F_PREFIX_ANY 0x3f000000
+
+#define PREFIX_SEGMENT_CS 0x2e
+#define PREFIX_SEGMENT_SS 0x36
+#define PREFIX_SEGMENT_DS 0x3e
+#define PREFIX_SEGMENT_ES 0x26
+#define PREFIX_SEGMENT_FS 0x64
+#define PREFIX_SEGMENT_GS 0x65
+#define PREFIX_LOCK 0xf0
+#define PREFIX_REPNZ 0xf2
+#define PREFIX_REPX 0xf3
+#define PREFIX_OPERAND_SIZE 0x66
+#define PREFIX_ADDRESS_SIZE 0x67
+
+#pragma pack(push,1)
+
+typedef struct {
+ uint8_t len;
+ uint8_t p_rep;
+ uint8_t p_lock;
+ uint8_t p_seg;
+ uint8_t p_66;
+ uint8_t p_67;
+ uint8_t opcode;
+ uint8_t opcode2;
+ uint8_t modrm;
+ uint8_t modrm_mod;
+ uint8_t modrm_reg;
+ uint8_t modrm_rm;
+ uint8_t sib;
+ uint8_t sib_scale;
+ uint8_t sib_index;
+ uint8_t sib_base;
+ union {
+ uint8_t imm8;
+ uint16_t imm16;
+ uint32_t imm32;
+ } imm;
+ union {
+ uint8_t disp8;
+ uint16_t disp16;
+ uint32_t disp32;
+ } disp;
+ uint32_t flags;
+} hde32s;
+
+#pragma pack(pop)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* __cdecl */
+unsigned int hde32_disasm(const void *code, hde32s *hs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HDE32_H_ */
diff --git a/Alphanium/Source/MinHook/src/hde/hde64.c b/Alphanium/Source/MinHook/src/hde/hde64.c
new file mode 100644
index 0000000..c23e2fc
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/hde64.c
@@ -0,0 +1,337 @@
+/*
+ * Hacker Disassembler Engine 64 C
+ * Copyright (c) 2008-2009, Vyacheslav Patkov.
+ * All rights reserved.
+ *
+ */
+
+#if defined(_M_X64) || defined(__x86_64__)
+
+#include "hde64.h"
+#include "table64.h"
+
+unsigned int hde64_disasm(const void *code, hde64s *hs)
+{
+ uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
+ uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
+ uint8_t op64 = 0;
+
+ // Avoid using memset to reduce the footprint.
+#ifndef _MSC_VER
+ memset((LPBYTE)hs, 0, sizeof(hde64s));
+#else
+ __stosb((LPBYTE)hs, 0, sizeof(hde64s));
+#endif
+
+ for (x = 16; x; x--)
+ switch (c = *p++) {
+ case 0xf3:
+ hs->p_rep = c;
+ pref |= PRE_F3;
+ break;
+ case 0xf2:
+ hs->p_rep = c;
+ pref |= PRE_F2;
+ break;
+ case 0xf0:
+ hs->p_lock = c;
+ pref |= PRE_LOCK;
+ break;
+ case 0x26: case 0x2e: case 0x36:
+ case 0x3e: case 0x64: case 0x65:
+ hs->p_seg = c;
+ pref |= PRE_SEG;
+ break;
+ case 0x66:
+ hs->p_66 = c;
+ pref |= PRE_66;
+ break;
+ case 0x67:
+ hs->p_67 = c;
+ pref |= PRE_67;
+ break;
+ default:
+ goto pref_done;
+ }
+ pref_done:
+
+ hs->flags = (uint32_t)pref << 23;
+
+ if (!pref)
+ pref |= PRE_NONE;
+
+ if ((c & 0xf0) == 0x40) {
+ hs->flags |= F_PREFIX_REX;
+ if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
+ op64++;
+ hs->rex_r = (c & 7) >> 2;
+ hs->rex_x = (c & 3) >> 1;
+ hs->rex_b = c & 1;
+ if (((c = *p++) & 0xf0) == 0x40) {
+ opcode = c;
+ goto error_opcode;
+ }
+ }
+
+ if ((hs->opcode = c) == 0x0f) {
+ hs->opcode2 = c = *p++;
+ ht += DELTA_OPCODES;
+ } else if (c >= 0xa0 && c <= 0xa3) {
+ op64++;
+ if (pref & PRE_67)
+ pref |= PRE_66;
+ else
+ pref &= ~PRE_66;
+ }
+
+ opcode = c;
+ cflags = ht[ht[opcode / 4] + (opcode % 4)];
+
+ if (cflags == C_ERROR) {
+ error_opcode:
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+ cflags = 0;
+ if ((opcode & -3) == 0x24)
+ cflags++;
+ }
+
+ x = 0;
+ if (cflags & C_GROUP) {
+ uint16_t t;
+ t = *(uint16_t *)(ht + (cflags & 0x7f));
+ cflags = (uint8_t)t;
+ x = (uint8_t)(t >> 8);
+ }
+
+ if (hs->opcode2) {
+ ht = hde64_table + DELTA_PREFIXES;
+ if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+ }
+
+ if (cflags & C_MODRM) {
+ hs->flags |= F_MODRM;
+ hs->modrm = c = *p++;
+ hs->modrm_mod = m_mod = c >> 6;
+ hs->modrm_rm = m_rm = c & 7;
+ hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
+
+ if (x && ((x << m_reg) & 0x80))
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+
+ if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
+ uint8_t t = opcode - 0xd9;
+ if (m_mod == 3) {
+ ht = hde64_table + DELTA_FPU_MODRM + t*8;
+ t = ht[m_reg] << m_rm;
+ } else {
+ ht = hde64_table + DELTA_FPU_REG;
+ t = ht[t] << m_reg;
+ }
+ if (t & 0x80)
+ hs->flags |= F_ERROR | F_ERROR_OPCODE;
+ }
+
+ if (pref & PRE_LOCK) {
+ if (m_mod == 3) {
+ hs->flags |= F_ERROR | F_ERROR_LOCK;
+ } else {
+ uint8_t *table_end, op = opcode;
+ if (hs->opcode2) {
+ ht = hde64_table + DELTA_OP2_LOCK_OK;
+ table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
+ } else {
+ ht = hde64_table + DELTA_OP_LOCK_OK;
+ table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
+ op &= -2;
+ }
+ for (; ht != table_end; ht++)
+ if (*ht++ == op) {
+ if (!((*ht << m_reg) & 0x80))
+ goto no_lock_error;
+ else
+ break;
+ }
+ hs->flags |= F_ERROR | F_ERROR_LOCK;
+ no_lock_error:
+ ;
+ }
+ }
+
+ if (hs->opcode2) {
+ switch (opcode) {
+ case 0x20: case 0x22:
+ m_mod = 3;
+ if (m_reg > 4 || m_reg == 1)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ case 0x21: case 0x23:
+ m_mod = 3;
+ if (m_reg == 4 || m_reg == 5)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ }
+ } else {
+ switch (opcode) {
+ case 0x8c:
+ if (m_reg > 5)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ case 0x8e:
+ if (m_reg == 1 || m_reg > 5)
+ goto error_operand;
+ else
+ goto no_error_operand;
+ }
+ }
+
+ if (m_mod == 3) {
+ uint8_t *table_end;
+ if (hs->opcode2) {
+ ht = hde64_table + DELTA_OP2_ONLY_MEM;
+ table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
+ } else {
+ ht = hde64_table + DELTA_OP_ONLY_MEM;
+ table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
+ }
+ for (; ht != table_end; ht += 2)
+ if (*ht++ == opcode) {
+ if (*ht++ & pref && !((*ht << m_reg) & 0x80))
+ goto error_operand;
+ else
+ break;
+ }
+ goto no_error_operand;
+ } else if (hs->opcode2) {
+ switch (opcode) {
+ case 0x50: case 0xd7: case 0xf7:
+ if (pref & (PRE_NONE | PRE_66))
+ goto error_operand;
+ break;
+ case 0xd6:
+ if (pref & (PRE_F2 | PRE_F3))
+ goto error_operand;
+ break;
+ case 0xc5:
+ goto error_operand;
+ }
+ goto no_error_operand;
+ } else
+ goto no_error_operand;
+
+ error_operand:
+ hs->flags |= F_ERROR | F_ERROR_OPERAND;
+ no_error_operand:
+
+ c = *p++;
+ if (m_reg <= 1) {
+ if (opcode == 0xf6)
+ cflags |= C_IMM8;
+ else if (opcode == 0xf7)
+ cflags |= C_IMM_P66;
+ }
+
+ switch (m_mod) {
+ case 0:
+ if (pref & PRE_67) {
+ if (m_rm == 6)
+ disp_size = 2;
+ } else
+ if (m_rm == 5)
+ disp_size = 4;
+ break;
+ case 1:
+ disp_size = 1;
+ break;
+ case 2:
+ disp_size = 2;
+ if (!(pref & PRE_67))
+ disp_size <<= 1;
+ }
+
+ if (m_mod != 3 && m_rm == 4) {
+ hs->flags |= F_SIB;
+ p++;
+ hs->sib = c;
+ hs->sib_scale = c >> 6;
+ hs->sib_index = (c & 0x3f) >> 3;
+ if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
+ disp_size = 4;
+ }
+
+ p--;
+ switch (disp_size) {
+ case 1:
+ hs->flags |= F_DISP8;
+ hs->disp.disp8 = *p;
+ break;
+ case 2:
+ hs->flags |= F_DISP16;
+ hs->disp.disp16 = *(uint16_t *)p;
+ break;
+ case 4:
+ hs->flags |= F_DISP32;
+ hs->disp.disp32 = *(uint32_t *)p;
+ }
+ p += disp_size;
+ } else if (pref & PRE_LOCK)
+ hs->flags |= F_ERROR | F_ERROR_LOCK;
+
+ if (cflags & C_IMM_P66) {
+ if (cflags & C_REL32) {
+ if (pref & PRE_66) {
+ hs->flags |= F_IMM16 | F_RELATIVE;
+ hs->imm.imm16 = *(uint16_t *)p;
+ p += 2;
+ goto disasm_done;
+ }
+ goto rel32_ok;
+ }
+ if (op64) {
+ hs->flags |= F_IMM64;
+ hs->imm.imm64 = *(uint64_t *)p;
+ p += 8;
+ } else if (!(pref & PRE_66)) {
+ hs->flags |= F_IMM32;
+ hs->imm.imm32 = *(uint32_t *)p;
+ p += 4;
+ } else
+ goto imm16_ok;
+ }
+
+
+ if (cflags & C_IMM16) {
+ imm16_ok:
+ hs->flags |= F_IMM16;
+ hs->imm.imm16 = *(uint16_t *)p;
+ p += 2;
+ }
+ if (cflags & C_IMM8) {
+ hs->flags |= F_IMM8;
+ hs->imm.imm8 = *p++;
+ }
+
+ if (cflags & C_REL32) {
+ rel32_ok:
+ hs->flags |= F_IMM32 | F_RELATIVE;
+ hs->imm.imm32 = *(uint32_t *)p;
+ p += 4;
+ } else if (cflags & C_REL8) {
+ hs->flags |= F_IMM8 | F_RELATIVE;
+ hs->imm.imm8 = *p++;
+ }
+
+ disasm_done:
+
+ if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
+ hs->flags |= F_ERROR | F_ERROR_LENGTH;
+ hs->len = 15;
+ }
+
+ return (unsigned int)hs->len;
+}
+
+#endif // defined(_M_X64) || defined(__x86_64__)
diff --git a/Alphanium/Source/MinHook/src/hde/hde64.h b/Alphanium/Source/MinHook/src/hde/hde64.h
new file mode 100644
index 0000000..ecbf4df
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/hde64.h
@@ -0,0 +1,112 @@
+/*
+ * Hacker Disassembler Engine 64
+ * Copyright (c) 2008-2009, Vyacheslav Patkov.
+ * All rights reserved.
+ *
+ * hde64.h: C/C++ header file
+ *
+ */
+
+#ifndef _HDE64_H_
+#define _HDE64_H_
+
+/* stdint.h - C99 standard header
+ * http://en.wikipedia.org/wiki/stdint.h
+ *
+ * if your compiler doesn't contain "stdint.h" header (for
+ * example, Microsoft Visual C++), you can download file:
+ * http://www.azillionmonkeys.com/qed/pstdint.h
+ * and change next line to:
+ * #include "pstdint.h"
+ */
+#include "pstdint.h"
+
+#define F_MODRM 0x00000001
+#define F_SIB 0x00000002
+#define F_IMM8 0x00000004
+#define F_IMM16 0x00000008
+#define F_IMM32 0x00000010
+#define F_IMM64 0x00000020
+#define F_DISP8 0x00000040
+#define F_DISP16 0x00000080
+#define F_DISP32 0x00000100
+#define F_RELATIVE 0x00000200
+#define F_ERROR 0x00001000
+#define F_ERROR_OPCODE 0x00002000
+#define F_ERROR_LENGTH 0x00004000
+#define F_ERROR_LOCK 0x00008000
+#define F_ERROR_OPERAND 0x00010000
+#define F_PREFIX_REPNZ 0x01000000
+#define F_PREFIX_REPX 0x02000000
+#define F_PREFIX_REP 0x03000000
+#define F_PREFIX_66 0x04000000
+#define F_PREFIX_67 0x08000000
+#define F_PREFIX_LOCK 0x10000000
+#define F_PREFIX_SEG 0x20000000
+#define F_PREFIX_REX 0x40000000
+#define F_PREFIX_ANY 0x7f000000
+
+#define PREFIX_SEGMENT_CS 0x2e
+#define PREFIX_SEGMENT_SS 0x36
+#define PREFIX_SEGMENT_DS 0x3e
+#define PREFIX_SEGMENT_ES 0x26
+#define PREFIX_SEGMENT_FS 0x64
+#define PREFIX_SEGMENT_GS 0x65
+#define PREFIX_LOCK 0xf0
+#define PREFIX_REPNZ 0xf2
+#define PREFIX_REPX 0xf3
+#define PREFIX_OPERAND_SIZE 0x66
+#define PREFIX_ADDRESS_SIZE 0x67
+
+#pragma pack(push,1)
+
+typedef struct {
+ uint8_t len;
+ uint8_t p_rep;
+ uint8_t p_lock;
+ uint8_t p_seg;
+ uint8_t p_66;
+ uint8_t p_67;
+ uint8_t rex;
+ uint8_t rex_w;
+ uint8_t rex_r;
+ uint8_t rex_x;
+ uint8_t rex_b;
+ uint8_t opcode;
+ uint8_t opcode2;
+ uint8_t modrm;
+ uint8_t modrm_mod;
+ uint8_t modrm_reg;
+ uint8_t modrm_rm;
+ uint8_t sib;
+ uint8_t sib_scale;
+ uint8_t sib_index;
+ uint8_t sib_base;
+ union {
+ uint8_t imm8;
+ uint16_t imm16;
+ uint32_t imm32;
+ uint64_t imm64;
+ } imm;
+ union {
+ uint8_t disp8;
+ uint16_t disp16;
+ uint32_t disp32;
+ } disp;
+ uint32_t flags;
+} hde64s;
+
+#pragma pack(pop)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* __cdecl */
+unsigned int hde64_disasm(const void *code, hde64s *hs);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HDE64_H_ */
diff --git a/Alphanium/Source/MinHook/src/hde/pstdint.h b/Alphanium/Source/MinHook/src/hde/pstdint.h
new file mode 100644
index 0000000..84d82a0
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/pstdint.h
@@ -0,0 +1,39 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include
+
+// Integer types for HDE.
+typedef INT8 int8_t;
+typedef INT16 int16_t;
+typedef INT32 int32_t;
+typedef INT64 int64_t;
+typedef UINT8 uint8_t;
+typedef UINT16 uint16_t;
+typedef UINT32 uint32_t;
+typedef UINT64 uint64_t;
diff --git a/Alphanium/Source/MinHook/src/hde/table32.h b/Alphanium/Source/MinHook/src/hde/table32.h
new file mode 100644
index 0000000..7b3e12e
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/table32.h
@@ -0,0 +1,73 @@
+/*
+ * Hacker Disassembler Engine 32 C
+ * Copyright (c) 2008-2009, Vyacheslav Patkov.
+ * All rights reserved.
+ *
+ */
+
+#define C_NONE 0x00
+#define C_MODRM 0x01
+#define C_IMM8 0x02
+#define C_IMM16 0x04
+#define C_IMM_P66 0x10
+#define C_REL8 0x20
+#define C_REL32 0x40
+#define C_GROUP 0x80
+#define C_ERROR 0xff
+
+#define PRE_ANY 0x00
+#define PRE_NONE 0x01
+#define PRE_F2 0x02
+#define PRE_F3 0x04
+#define PRE_66 0x08
+#define PRE_67 0x10
+#define PRE_LOCK 0x20
+#define PRE_SEG 0x40
+#define PRE_ALL 0xff
+
+#define DELTA_OPCODES 0x4a
+#define DELTA_FPU_REG 0xf1
+#define DELTA_FPU_MODRM 0xf8
+#define DELTA_PREFIXES 0x130
+#define DELTA_OP_LOCK_OK 0x1a1
+#define DELTA_OP2_LOCK_OK 0x1b9
+#define DELTA_OP_ONLY_MEM 0x1cb
+#define DELTA_OP2_ONLY_MEM 0x1da
+
+unsigned char hde32_table[] = {
+ 0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,0xa8,0xa3,
+ 0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xac,0xaa,0xb2,0xaa,0x9f,0x9f,
+ 0x9f,0x9f,0xb5,0xa3,0xa3,0xa4,0xaa,0xaa,0xba,0xaa,0x96,0xaa,0xa8,0xaa,0xc3,
+ 0xc3,0x96,0x96,0xb7,0xae,0xd6,0xbd,0xa3,0xc5,0xa3,0xa3,0x9f,0xc3,0x9c,0xaa,
+ 0xaa,0xac,0xaa,0xbf,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0x90,
+ 0x82,0x7d,0x97,0x59,0x59,0x59,0x59,0x59,0x7f,0x59,0x59,0x60,0x7d,0x7f,0x7f,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x9a,0x88,0x7d,
+ 0x59,0x50,0x50,0x50,0x50,0x59,0x59,0x59,0x59,0x61,0x94,0x61,0x9e,0x59,0x59,
+ 0x85,0x59,0x92,0xa3,0x60,0x60,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,
+ 0x59,0x59,0x9f,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xcc,0x01,0xbc,0x03,0xf0,
+ 0x10,0x10,0x10,0x10,0x50,0x50,0x50,0x50,0x14,0x20,0x20,0x20,0x20,0x01,0x01,
+ 0x01,0x01,0xc4,0x02,0x10,0x00,0x00,0x00,0x00,0x01,0x01,0xc0,0xc2,0x10,0x11,
+ 0x02,0x03,0x11,0x03,0x03,0x04,0x00,0x00,0x14,0x00,0x02,0x00,0x00,0xc6,0xc8,
+ 0x02,0x02,0x02,0x02,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xca,
+ 0x01,0x01,0x01,0x00,0x06,0x00,0x04,0x00,0xc0,0xc2,0x01,0x01,0x03,0x01,0xff,
+ 0xff,0x01,0x00,0x03,0xc4,0xc4,0xc6,0x03,0x01,0x01,0x01,0xff,0x03,0x03,0x03,
+ 0xc8,0x40,0x00,0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,
+ 0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xff,0xff,0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x7f,0x00,0x00,0xff,0x4a,0x4a,0x4a,0x4a,0x4b,0x52,0x4a,0x4a,0x4a,0x4a,0x4f,
+ 0x4c,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x55,0x45,0x40,0x4a,0x4a,0x4a,
+ 0x45,0x59,0x4d,0x46,0x4a,0x5d,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,0x4a,
+ 0x4a,0x4a,0x4a,0x4a,0x4a,0x61,0x63,0x67,0x4e,0x4a,0x4a,0x6b,0x6d,0x4a,0x4a,
+ 0x45,0x6d,0x4a,0x4a,0x44,0x45,0x4a,0x4a,0x00,0x00,0x00,0x02,0x0d,0x06,0x06,
+ 0x06,0x06,0x0e,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x00,0x06,0x06,0x02,0x06,
+ 0x00,0x0a,0x0a,0x07,0x07,0x06,0x02,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
+ 0x04,0x04,0x00,0x00,0x00,0x0e,0x05,0x06,0x06,0x06,0x01,0x06,0x00,0x00,0x08,
+ 0x00,0x10,0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,
+ 0x86,0x00,0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,
+ 0xf8,0xbb,0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,
+ 0xc4,0xff,0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,
+ 0x13,0x09,0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,
+ 0xb2,0xff,0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,
+ 0xe7,0x08,0x00,0xf0,0x02,0x00
+};
diff --git a/Alphanium/Source/MinHook/src/hde/table64.h b/Alphanium/Source/MinHook/src/hde/table64.h
new file mode 100644
index 0000000..01d4541
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hde/table64.h
@@ -0,0 +1,74 @@
+/*
+ * Hacker Disassembler Engine 64 C
+ * Copyright (c) 2008-2009, Vyacheslav Patkov.
+ * All rights reserved.
+ *
+ */
+
+#define C_NONE 0x00
+#define C_MODRM 0x01
+#define C_IMM8 0x02
+#define C_IMM16 0x04
+#define C_IMM_P66 0x10
+#define C_REL8 0x20
+#define C_REL32 0x40
+#define C_GROUP 0x80
+#define C_ERROR 0xff
+
+#define PRE_ANY 0x00
+#define PRE_NONE 0x01
+#define PRE_F2 0x02
+#define PRE_F3 0x04
+#define PRE_66 0x08
+#define PRE_67 0x10
+#define PRE_LOCK 0x20
+#define PRE_SEG 0x40
+#define PRE_ALL 0xff
+
+#define DELTA_OPCODES 0x4a
+#define DELTA_FPU_REG 0xfd
+#define DELTA_FPU_MODRM 0x104
+#define DELTA_PREFIXES 0x13c
+#define DELTA_OP_LOCK_OK 0x1ae
+#define DELTA_OP2_LOCK_OK 0x1c6
+#define DELTA_OP_ONLY_MEM 0x1d8
+#define DELTA_OP2_ONLY_MEM 0x1e7
+
+unsigned char hde64_table[] = {
+ 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
+ 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
+ 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
+ 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
+ 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
+ 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
+ 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
+ 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
+ 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
+ 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
+ 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
+ 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
+ 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
+ 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
+ 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
+ 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
+ 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
+ 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
+ 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
+ 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
+ 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
+ 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+ 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
+ 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
+ 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
+ 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
+ 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
+ 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
+ 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
+ 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
+ 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
+ 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
+ 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
+ 0x00,0xf0,0x02,0x00
+};
diff --git a/Alphanium/Source/MinHook/src/hook.c b/Alphanium/Source/MinHook/src/hook.c
new file mode 100644
index 0000000..ce65e57
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/hook.c
@@ -0,0 +1,889 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+#include
+#include
+
+#include "../include/MinHook.h"
+#include "buffer.h"
+#include "trampoline.h"
+
+#ifndef ARRAYSIZE
+ #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+// Initial capacity of the HOOK_ENTRY buffer.
+#define INITIAL_HOOK_CAPACITY 32
+
+// Initial capacity of the thread IDs buffer.
+#define INITIAL_THREAD_CAPACITY 128
+
+// Special hook position values.
+#define INVALID_HOOK_POS UINT_MAX
+#define ALL_HOOKS_POS UINT_MAX
+
+// Freeze() action argument defines.
+#define ACTION_DISABLE 0
+#define ACTION_ENABLE 1
+#define ACTION_APPLY_QUEUED 2
+
+// Thread access rights for suspending/resuming threads.
+#define THREAD_ACCESS \
+ (THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
+
+// Hook information.
+typedef struct _HOOK_ENTRY
+{
+ LPVOID pTarget; // Address of the target function.
+ LPVOID pDetour; // Address of the detour or relay function.
+ LPVOID pTrampoline; // Address of the trampoline function.
+ UINT8 backup[8]; // Original prologue of the target function.
+
+ UINT8 patchAbove : 1; // Uses the hot patch area.
+ UINT8 isEnabled : 1; // Enabled.
+ UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
+
+ UINT nIP : 4; // Count of the instruction boundaries.
+ UINT8 oldIPs[8]; // Instruction boundaries of the target function.
+ UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
+} HOOK_ENTRY, *PHOOK_ENTRY;
+
+// Suspended threads for Freeze()/Unfreeze().
+typedef struct _FROZEN_THREADS
+{
+ LPDWORD pItems; // Data heap
+ UINT capacity; // Size of allocated data heap, items
+ UINT size; // Actual number of data items
+} FROZEN_THREADS, *PFROZEN_THREADS;
+
+//-------------------------------------------------------------------------
+// Global Variables:
+//-------------------------------------------------------------------------
+
+// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
+volatile LONG g_isLocked = FALSE;
+
+// Private heap handle. If not NULL, this library is initialized.
+HANDLE g_hHeap = NULL;
+
+// Hook entries.
+struct
+{
+ PHOOK_ENTRY pItems; // Data heap
+ UINT capacity; // Size of allocated data heap, items
+ UINT size; // Actual number of data items
+} g_hooks;
+
+//-------------------------------------------------------------------------
+// Returns INVALID_HOOK_POS if not found.
+static UINT FindHookEntry(LPVOID pTarget)
+{
+ UINT i;
+ for (i = 0; i < g_hooks.size; ++i)
+ {
+ if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
+ return i;
+ }
+
+ return INVALID_HOOK_POS;
+}
+
+//-------------------------------------------------------------------------
+static PHOOK_ENTRY AddHookEntry()
+{
+ if (g_hooks.pItems == NULL)
+ {
+ g_hooks.capacity = INITIAL_HOOK_CAPACITY;
+ g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
+ g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
+ if (g_hooks.pItems == NULL)
+ return NULL;
+ }
+ else if (g_hooks.size >= g_hooks.capacity)
+ {
+ PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
+ g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
+ if (p == NULL)
+ return NULL;
+
+ g_hooks.capacity *= 2;
+ g_hooks.pItems = p;
+ }
+
+ return &g_hooks.pItems[g_hooks.size++];
+}
+
+//-------------------------------------------------------------------------
+static void DeleteHookEntry(UINT pos)
+{
+ if (pos < g_hooks.size - 1)
+ g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
+
+ g_hooks.size--;
+
+ if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
+ {
+ PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
+ g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
+ if (p == NULL)
+ return;
+
+ g_hooks.capacity /= 2;
+ g_hooks.pItems = p;
+ }
+}
+
+//-------------------------------------------------------------------------
+static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
+{
+ UINT i;
+
+ if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
+ return (DWORD_PTR)pHook->pTarget;
+
+ for (i = 0; i < pHook->nIP; ++i)
+ {
+ if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
+ return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
+ }
+
+#if defined(_M_X64) || defined(__x86_64__)
+ // Check relay function.
+ if (ip == (DWORD_PTR)pHook->pDetour)
+ return (DWORD_PTR)pHook->pTarget;
+#endif
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
+{
+ UINT i;
+ for (i = 0; i < pHook->nIP; ++i)
+ {
+ if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
+ return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
+ }
+
+ return 0;
+}
+
+//-------------------------------------------------------------------------
+static void ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
+{
+ // If the thread suspended in the overwritten area,
+ // move IP to the proper address.
+
+ CONTEXT c;
+#if defined(_M_X64) || defined(__x86_64__)
+ DWORD64 *pIP = &c.Rip;
+#else
+ DWORD *pIP = &c.Eip;
+#endif
+ UINT count;
+
+ c.ContextFlags = CONTEXT_CONTROL;
+ if (!GetThreadContext(hThread, &c))
+ return;
+
+ if (pos == ALL_HOOKS_POS)
+ {
+ pos = 0;
+ count = g_hooks.size;
+ }
+ else
+ {
+ count = pos + 1;
+ }
+
+ for (; pos < count; ++pos)
+ {
+ PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
+ BOOL enable;
+ DWORD_PTR ip;
+
+ switch (action)
+ {
+ case ACTION_DISABLE:
+ enable = FALSE;
+ break;
+
+ case ACTION_ENABLE:
+ enable = TRUE;
+ break;
+
+ default: // ACTION_APPLY_QUEUED
+ enable = pHook->queueEnable;
+ break;
+ }
+ if (pHook->isEnabled == enable)
+ continue;
+
+ if (enable)
+ ip = FindNewIP(pHook, *pIP);
+ else
+ ip = FindOldIP(pHook, *pIP);
+
+ if (ip != 0)
+ {
+ *pIP = ip;
+ SetThreadContext(hThread, &c);
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+static VOID EnumerateThreads(PFROZEN_THREADS pThreads)
+{
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (hSnapshot != INVALID_HANDLE_VALUE)
+ {
+ THREADENTRY32 te;
+ te.dwSize = sizeof(THREADENTRY32);
+ if (Thread32First(hSnapshot, &te))
+ {
+ do
+ {
+ if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
+ && te.th32OwnerProcessID == GetCurrentProcessId()
+ && te.th32ThreadID != GetCurrentThreadId())
+ {
+ if (pThreads->pItems == NULL)
+ {
+ pThreads->capacity = INITIAL_THREAD_CAPACITY;
+ pThreads->pItems
+ = (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
+ if (pThreads->pItems == NULL)
+ break;
+ }
+ else if (pThreads->size >= pThreads->capacity)
+ {
+ LPDWORD p = (LPDWORD)HeapReAlloc(
+ g_hHeap, 0, pThreads->pItems, (pThreads->capacity * 2) * sizeof(DWORD));
+ if (p == NULL)
+ break;
+
+ pThreads->capacity *= 2;
+ pThreads->pItems = p;
+ }
+ pThreads->pItems[pThreads->size++] = te.th32ThreadID;
+ }
+
+ te.dwSize = sizeof(THREADENTRY32);
+ } while (Thread32Next(hSnapshot, &te));
+ }
+ CloseHandle(hSnapshot);
+ }
+}
+
+//-------------------------------------------------------------------------
+static VOID Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
+{
+ pThreads->pItems = NULL;
+ pThreads->capacity = 0;
+ pThreads->size = 0;
+ EnumerateThreads(pThreads);
+
+ if (pThreads->pItems != NULL)
+ {
+ UINT i;
+ for (i = 0; i < pThreads->size; ++i)
+ {
+ HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
+ if (hThread != NULL)
+ {
+ SuspendThread(hThread);
+ ProcessThreadIPs(hThread, pos, action);
+ CloseHandle(hThread);
+ }
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+static VOID Unfreeze(PFROZEN_THREADS pThreads)
+{
+ if (pThreads->pItems != NULL)
+ {
+ UINT i;
+ for (i = 0; i < pThreads->size; ++i)
+ {
+ HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
+ if (hThread != NULL)
+ {
+ ResumeThread(hThread);
+ CloseHandle(hThread);
+ }
+ }
+
+ HeapFree(g_hHeap, 0, pThreads->pItems);
+ }
+}
+
+//-------------------------------------------------------------------------
+static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
+{
+ PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
+ DWORD oldProtect;
+ SIZE_T patchSize = sizeof(JMP_REL);
+ LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
+
+ if (pHook->patchAbove)
+ {
+ pPatchTarget -= sizeof(JMP_REL);
+ patchSize += sizeof(JMP_REL_SHORT);
+ }
+
+ if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
+ return MH_ERROR_MEMORY_PROTECT;
+
+ if (enable)
+ {
+ PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
+ pJmp->opcode = 0xE9;
+ pJmp->operand = (UINT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
+
+ if (pHook->patchAbove)
+ {
+ PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
+ pShortJmp->opcode = 0xEB;
+ pShortJmp->operand = (UINT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
+ }
+ }
+ else
+ {
+ if (pHook->patchAbove)
+ memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
+ else
+ memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
+ }
+
+ VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
+
+ // Just-in-case measure.
+ FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
+
+ pHook->isEnabled = enable;
+ pHook->queueEnable = enable;
+
+ return MH_OK;
+}
+
+//-------------------------------------------------------------------------
+static MH_STATUS EnableAllHooksLL(BOOL enable)
+{
+ MH_STATUS status = MH_OK;
+ UINT i, first = INVALID_HOOK_POS;
+
+ for (i = 0; i < g_hooks.size; ++i)
+ {
+ if (g_hooks.pItems[i].isEnabled != enable)
+ {
+ first = i;
+ break;
+ }
+ }
+
+ if (first != INVALID_HOOK_POS)
+ {
+ FROZEN_THREADS threads;
+ Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
+
+ for (i = first; i < g_hooks.size; ++i)
+ {
+ if (g_hooks.pItems[i].isEnabled != enable)
+ {
+ status = EnableHookLL(i, enable);
+ if (status != MH_OK)
+ break;
+ }
+ }
+
+ Unfreeze(&threads);
+ }
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+static VOID EnterSpinLock(VOID)
+{
+ SIZE_T spinCount = 0;
+
+ // Wait until the flag is FALSE.
+ while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
+ {
+ // No need to generate a memory barrier here, since InterlockedCompareExchange()
+ // generates a full memory barrier itself.
+
+ // Prevent the loop from being too busy.
+ if (spinCount < 32)
+ Sleep(0);
+ else
+ Sleep(1);
+
+ spinCount++;
+ }
+}
+
+//-------------------------------------------------------------------------
+static VOID LeaveSpinLock(VOID)
+{
+ // No need to generate a memory barrier here, since InterlockedExchange()
+ // generates a full memory barrier itself.
+
+ InterlockedExchange(&g_isLocked, FALSE);
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_Initialize(VOID)
+{
+ MH_STATUS status = MH_OK;
+
+ EnterSpinLock();
+
+ if (g_hHeap == NULL)
+ {
+ g_hHeap = HeapCreate(0, 0, 0);
+ if (g_hHeap != NULL)
+ {
+ // Initialize the internal function buffer.
+ InitializeBuffer();
+ }
+ else
+ {
+ status = MH_ERROR_MEMORY_ALLOC;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_ALREADY_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_Uninitialize(VOID)
+{
+ MH_STATUS status = MH_OK;
+
+ EnterSpinLock();
+
+ if (g_hHeap != NULL)
+ {
+ status = EnableAllHooksLL(FALSE);
+ if (status == MH_OK)
+ {
+ // Free the internal function buffer.
+
+ // HeapFree is actually not required, but some tools detect a false
+ // memory leak without HeapFree.
+
+ UninitializeBuffer();
+
+ HeapFree(g_hHeap, 0, g_hooks.pItems);
+ HeapDestroy(g_hHeap);
+
+ g_hHeap = NULL;
+
+ g_hooks.pItems = NULL;
+ g_hooks.capacity = 0;
+ g_hooks.size = 0;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
+{
+ MH_STATUS status = MH_OK;
+
+ EnterSpinLock();
+
+ if (g_hHeap != NULL)
+ {
+ if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
+ {
+ UINT pos = FindHookEntry(pTarget);
+ if (pos == INVALID_HOOK_POS)
+ {
+ LPVOID pBuffer = AllocateBuffer(pTarget);
+ if (pBuffer != NULL)
+ {
+ TRAMPOLINE ct;
+
+ ct.pTarget = pTarget;
+ ct.pDetour = pDetour;
+ ct.pTrampoline = pBuffer;
+ if (CreateTrampolineFunction(&ct))
+ {
+ PHOOK_ENTRY pHook = AddHookEntry();
+ if (pHook != NULL)
+ {
+ pHook->pTarget = ct.pTarget;
+#if defined(_M_X64) || defined(__x86_64__)
+ pHook->pDetour = ct.pRelay;
+#else
+ pHook->pDetour = ct.pDetour;
+#endif
+ pHook->pTrampoline = ct.pTrampoline;
+ pHook->patchAbove = ct.patchAbove;
+ pHook->isEnabled = FALSE;
+ pHook->queueEnable = FALSE;
+ pHook->nIP = ct.nIP;
+ memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
+ memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
+
+ // Back up the target function.
+
+ if (ct.patchAbove)
+ {
+ memcpy(
+ pHook->backup,
+ (LPBYTE)pTarget - sizeof(JMP_REL),
+ sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
+ }
+ else
+ {
+ memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
+ }
+
+ if (ppOriginal != NULL)
+ *ppOriginal = pHook->pTrampoline;
+ }
+ else
+ {
+ status = MH_ERROR_MEMORY_ALLOC;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_UNSUPPORTED_FUNCTION;
+ }
+
+ if (status != MH_OK)
+ {
+ FreeBuffer(pBuffer);
+ }
+ }
+ else
+ {
+ status = MH_ERROR_MEMORY_ALLOC;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_ALREADY_CREATED;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_EXECUTABLE;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
+{
+ MH_STATUS status = MH_OK;
+
+ EnterSpinLock();
+
+ if (g_hHeap != NULL)
+ {
+ UINT pos = FindHookEntry(pTarget);
+ if (pos != INVALID_HOOK_POS)
+ {
+ if (g_hooks.pItems[pos].isEnabled)
+ {
+ FROZEN_THREADS threads;
+ Freeze(&threads, pos, ACTION_DISABLE);
+
+ status = EnableHookLL(pos, FALSE);
+
+ Unfreeze(&threads);
+ }
+
+ if (status == MH_OK)
+ {
+ FreeBuffer(g_hooks.pItems[pos].pTrampoline);
+ DeleteHookEntry(pos);
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_CREATED;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
+{
+ MH_STATUS status = MH_OK;
+
+ EnterSpinLock();
+
+ if (g_hHeap != NULL)
+ {
+ if (pTarget == MH_ALL_HOOKS)
+ {
+ status = EnableAllHooksLL(enable);
+ }
+ else
+ {
+ FROZEN_THREADS threads;
+ UINT pos = FindHookEntry(pTarget);
+ if (pos != INVALID_HOOK_POS)
+ {
+ if (g_hooks.pItems[pos].isEnabled != enable)
+ {
+ Freeze(&threads, pos, ACTION_ENABLE);
+
+ status = EnableHookLL(pos, enable);
+
+ Unfreeze(&threads);
+ }
+ else
+ {
+ status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_CREATED;
+ }
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
+{
+ return EnableHook(pTarget, TRUE);
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
+{
+ return EnableHook(pTarget, FALSE);
+}
+
+//-------------------------------------------------------------------------
+static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
+{
+ MH_STATUS status = MH_OK;
+
+ EnterSpinLock();
+
+ if (g_hHeap != NULL)
+ {
+ if (pTarget == MH_ALL_HOOKS)
+ {
+ UINT i;
+ for (i = 0; i < g_hooks.size; ++i)
+ g_hooks.pItems[i].queueEnable = queueEnable;
+ }
+ else
+ {
+ UINT pos = FindHookEntry(pTarget);
+ if (pos != INVALID_HOOK_POS)
+ {
+ g_hooks.pItems[pos].queueEnable = queueEnable;
+ }
+ else
+ {
+ status = MH_ERROR_NOT_CREATED;
+ }
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
+{
+ return QueueHook(pTarget, TRUE);
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
+{
+ return QueueHook(pTarget, FALSE);
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_ApplyQueued(VOID)
+{
+ MH_STATUS status = MH_OK;
+ UINT i, first = INVALID_HOOK_POS;
+
+ EnterSpinLock();
+
+ if (g_hHeap != NULL)
+ {
+ for (i = 0; i < g_hooks.size; ++i)
+ {
+ if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
+ {
+ first = i;
+ break;
+ }
+ }
+
+ if (first != INVALID_HOOK_POS)
+ {
+ FROZEN_THREADS threads;
+ Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
+
+ for (i = first; i < g_hooks.size; ++i)
+ {
+ PHOOK_ENTRY pHook = &g_hooks.pItems[i];
+ if (pHook->isEnabled != pHook->queueEnable)
+ {
+ status = EnableHookLL(i, pHook->queueEnable);
+ if (status != MH_OK)
+ break;
+ }
+ }
+
+ Unfreeze(&threads);
+ }
+ }
+ else
+ {
+ status = MH_ERROR_NOT_INITIALIZED;
+ }
+
+ LeaveSpinLock();
+
+ return status;
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_CreateHookApiEx(
+ LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
+ LPVOID *ppOriginal, LPVOID *ppTarget)
+{
+ HMODULE hModule;
+ LPVOID pTarget;
+
+ hModule = GetModuleHandleW(pszModule);
+ if (hModule == NULL)
+ return MH_ERROR_MODULE_NOT_FOUND;
+
+ pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
+ if (pTarget == NULL)
+ return MH_ERROR_FUNCTION_NOT_FOUND;
+
+ if(ppTarget != NULL)
+ *ppTarget = pTarget;
+
+ return MH_CreateHook(pTarget, pDetour, ppOriginal);
+}
+
+//-------------------------------------------------------------------------
+MH_STATUS WINAPI MH_CreateHookApi(
+ LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
+{
+ return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
+}
+
+//-------------------------------------------------------------------------
+const char * WINAPI MH_StatusToString(MH_STATUS status)
+{
+#define MH_ST2STR(x) \
+ case x: \
+ return #x;
+
+ switch (status) {
+ MH_ST2STR(MH_UNKNOWN)
+ MH_ST2STR(MH_OK)
+ MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
+ MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
+ MH_ST2STR(MH_ERROR_ALREADY_CREATED)
+ MH_ST2STR(MH_ERROR_NOT_CREATED)
+ MH_ST2STR(MH_ERROR_ENABLED)
+ MH_ST2STR(MH_ERROR_DISABLED)
+ MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
+ MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
+ MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
+ MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
+ MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
+ MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
+ }
+
+#undef MH_ST2STR
+
+ return "(unknown)";
+}
diff --git a/Alphanium/Source/MinHook/src/trampoline.c b/Alphanium/Source/MinHook/src/trampoline.c
new file mode 100644
index 0000000..ac37f0f
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/trampoline.c
@@ -0,0 +1,316 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include
+
+#ifndef ARRAYSIZE
+ #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
+#if defined(_M_X64) || defined(__x86_64__)
+ #include "./hde/hde64.h"
+ typedef hde64s HDE;
+ #define HDE_DISASM(code, hs) hde64_disasm(code, hs)
+#else
+ #include "./hde/hde32.h"
+ typedef hde32s HDE;
+ #define HDE_DISASM(code, hs) hde32_disasm(code, hs)
+#endif
+
+#include "trampoline.h"
+#include "buffer.h"
+
+// Maximum size of a trampoline function.
+#if defined(_M_X64) || defined(__x86_64__)
+ #define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
+#else
+ #define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
+#endif
+
+//-------------------------------------------------------------------------
+static BOOL IsCodePadding(LPBYTE pInst, UINT size)
+{
+ UINT i;
+
+ if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
+ return FALSE;
+
+ for (i = 1; i < size; ++i)
+ {
+ if (pInst[i] != pInst[0])
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//-------------------------------------------------------------------------
+BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
+{
+#if defined(_M_X64) || defined(__x86_64__)
+ CALL_ABS call = {
+ 0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
+ 0xEB, 0x08, // EB 08: JMP +10
+ 0x0000000000000000ULL // Absolute destination address
+ };
+ JMP_ABS jmp = {
+ 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
+ 0x0000000000000000ULL // Absolute destination address
+ };
+ JCC_ABS jcc = {
+ 0x70, 0x0E, // 7* 0E: J** +16
+ 0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
+ 0x0000000000000000ULL // Absolute destination address
+ };
+#else
+ CALL_REL call = {
+ 0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
+ 0x00000000 // Relative destination address
+ };
+ JMP_REL jmp = {
+ 0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
+ 0x00000000 // Relative destination address
+ };
+ JCC_REL jcc = {
+ 0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
+ 0x00000000 // Relative destination address
+ };
+#endif
+
+ UINT8 oldPos = 0;
+ UINT8 newPos = 0;
+ ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
+ BOOL finished = FALSE; // Is the function completed?
+#if defined(_M_X64) || defined(__x86_64__)
+ UINT8 instBuf[16];
+#endif
+
+ ct->patchAbove = FALSE;
+ ct->nIP = 0;
+
+ do
+ {
+ HDE hs;
+ UINT copySize;
+ LPVOID pCopySrc;
+ ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
+ ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
+
+ copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
+ if (hs.flags & F_ERROR)
+ return FALSE;
+
+ pCopySrc = (LPVOID)pOldInst;
+ if (oldPos >= sizeof(JMP_REL))
+ {
+ // The trampoline function is long enough.
+ // Complete the function with the jump to the target function.
+#if defined(_M_X64) || defined(__x86_64__)
+ jmp.address = pOldInst;
+#else
+ jmp.operand = (UINT32)(pOldInst - (pNewInst + sizeof(jmp)));
+#endif
+ pCopySrc = &jmp;
+ copySize = sizeof(jmp);
+
+ finished = TRUE;
+ }
+#if defined(_M_X64) || defined(__x86_64__)
+ else if ((hs.modrm & 0xC7) == 0x05)
+ {
+ // Instructions using RIP relative addressing. (ModR/M = 00???101B)
+
+ // Modify the RIP relative address.
+ PUINT32 pRelAddr;
+
+ // Avoid using memcpy to reduce the footprint.
+#ifndef _MSC_VER
+ memcpy(instBuf, (LPBYTE)pOldInst, copySize);
+#else
+ __movsb(instBuf, (LPBYTE)pOldInst, copySize);
+#endif
+ pCopySrc = instBuf;
+
+ // Relative address is stored at (instruction length - immediate value length - 4).
+ pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
+ *pRelAddr
+ = (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
+
+ // Complete the function if JMP (FF /4).
+ if (hs.opcode == 0xFF && hs.modrm_reg == 4)
+ finished = TRUE;
+ }
+#endif
+ else if (hs.opcode == 0xE8)
+ {
+ // Direct relative CALL
+ ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
+#if defined(_M_X64) || defined(__x86_64__)
+ call.address = dest;
+#else
+ call.operand = (UINT32)(dest - (pNewInst + sizeof(call)));
+#endif
+ pCopySrc = &call;
+ copySize = sizeof(call);
+ }
+ else if ((hs.opcode & 0xFD) == 0xE9)
+ {
+ // Direct relative JMP (EB or E9)
+ ULONG_PTR dest = pOldInst + hs.len;
+
+ if (hs.opcode == 0xEB) // isShort jmp
+ dest += (INT8)hs.imm.imm8;
+ else
+ dest += (INT32)hs.imm.imm32;
+
+ // Simply copy an internal jump.
+ if ((ULONG_PTR)ct->pTarget <= dest
+ && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
+ {
+ if (jmpDest < dest)
+ jmpDest = dest;
+ }
+ else
+ {
+#if defined(_M_X64) || defined(__x86_64__)
+ jmp.address = dest;
+#else
+ jmp.operand = (UINT32)(dest - (pNewInst + sizeof(jmp)));
+#endif
+ pCopySrc = &jmp;
+ copySize = sizeof(jmp);
+
+ // Exit the function If it is not in the branch
+ finished = (pOldInst >= jmpDest);
+ }
+ }
+ else if ((hs.opcode & 0xF0) == 0x70
+ || (hs.opcode & 0xFC) == 0xE0
+ || (hs.opcode2 & 0xF0) == 0x80)
+ {
+ // Direct relative Jcc
+ ULONG_PTR dest = pOldInst + hs.len;
+
+ if ((hs.opcode & 0xF0) == 0x70 // Jcc
+ || (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
+ dest += (INT8)hs.imm.imm8;
+ else
+ dest += (INT32)hs.imm.imm32;
+
+ // Simply copy an internal jump.
+ if ((ULONG_PTR)ct->pTarget <= dest
+ && dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
+ {
+ if (jmpDest < dest)
+ jmpDest = dest;
+ }
+ else if ((hs.opcode & 0xFC) == 0xE0)
+ {
+ // LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
+ return FALSE;
+ }
+ else
+ {
+ UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
+#if defined(_M_X64) || defined(__x86_64__)
+ // Invert the condition in x64 mode to simplify the conditional jump logic.
+ jcc.opcode = 0x71 ^ cond;
+ jcc.address = dest;
+#else
+ jcc.opcode1 = 0x80 | cond;
+ jcc.operand = (UINT32)(dest - (pNewInst + sizeof(jcc)));
+#endif
+ pCopySrc = &jcc;
+ copySize = sizeof(jcc);
+ }
+ }
+ else if ((hs.opcode & 0xFE) == 0xC2)
+ {
+ // RET (C2 or C3)
+
+ // Complete the function if not in a branch.
+ finished = (pOldInst >= jmpDest);
+ }
+
+ // Can't alter the instruction length in a branch.
+ if (pOldInst < jmpDest && copySize != hs.len)
+ return FALSE;
+
+ // Trampoline function is too large.
+ if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
+ return FALSE;
+
+ // Trampoline function has too many instructions.
+ if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
+ return FALSE;
+
+ ct->oldIPs[ct->nIP] = oldPos;
+ ct->newIPs[ct->nIP] = newPos;
+ ct->nIP++;
+
+ // Avoid using memcpy to reduce the footprint.
+#ifndef _MSC_VER
+ memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
+#else
+ __movsb((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
+#endif
+ newPos += copySize;
+ oldPos += hs.len;
+ }
+ while (!finished);
+
+ // Is there enough place for a long jump?
+ if (oldPos < sizeof(JMP_REL)
+ && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
+ {
+ // Is there enough place for a short jump?
+ if (oldPos < sizeof(JMP_REL_SHORT)
+ && !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
+ {
+ return FALSE;
+ }
+
+ // Can we place the long jump above the function?
+ if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
+ return FALSE;
+
+ if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
+ return FALSE;
+
+ ct->patchAbove = TRUE;
+ }
+
+#if defined(_M_X64) || defined(__x86_64__)
+ // Create a relay function.
+ jmp.address = (ULONG_PTR)ct->pDetour;
+
+ ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
+ memcpy(ct->pRelay, &jmp, sizeof(jmp));
+#endif
+
+ return TRUE;
+}
diff --git a/Alphanium/Source/MinHook/src/trampoline.h b/Alphanium/Source/MinHook/src/trampoline.h
new file mode 100644
index 0000000..bdffdac
--- /dev/null
+++ b/Alphanium/Source/MinHook/src/trampoline.h
@@ -0,0 +1,105 @@
+/*
+ * MinHook - The Minimalistic API Hooking Library for x64/x86
+ * Copyright (C) 2009-2017 Tsuda Kageyu.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#pragma pack(push, 1)
+
+// Structs for writing x86/x64 instructions.
+
+// 8-bit relative jump.
+typedef struct _JMP_REL_SHORT
+{
+ UINT8 opcode; // EB xx: JMP +2+xx
+ UINT8 operand;
+} JMP_REL_SHORT, *PJMP_REL_SHORT;
+
+// 32-bit direct relative jump/call.
+typedef struct _JMP_REL
+{
+ UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
+ UINT32 operand; // Relative destination address
+} JMP_REL, *PJMP_REL, CALL_REL;
+
+// 64-bit indirect absolute jump.
+typedef struct _JMP_ABS
+{
+ UINT8 opcode0; // FF25 00000000: JMP [+6]
+ UINT8 opcode1;
+ UINT32 dummy;
+ UINT64 address; // Absolute destination address
+} JMP_ABS, *PJMP_ABS;
+
+// 64-bit indirect absolute call.
+typedef struct _CALL_ABS
+{
+ UINT8 opcode0; // FF15 00000002: CALL [+6]
+ UINT8 opcode1;
+ UINT32 dummy0;
+ UINT8 dummy1; // EB 08: JMP +10
+ UINT8 dummy2;
+ UINT64 address; // Absolute destination address
+} CALL_ABS;
+
+// 32-bit direct relative conditional jumps.
+typedef struct _JCC_REL
+{
+ UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
+ UINT8 opcode1;
+ UINT32 operand; // Relative destination address
+} JCC_REL;
+
+// 64bit indirect absolute conditional jumps that x64 lacks.
+typedef struct _JCC_ABS
+{
+ UINT8 opcode; // 7* 0E: J** +16
+ UINT8 dummy0;
+ UINT8 dummy1; // FF25 00000000: JMP [+6]
+ UINT8 dummy2;
+ UINT32 dummy3;
+ UINT64 address; // Absolute destination address
+} JCC_ABS;
+
+#pragma pack(pop)
+
+typedef struct _TRAMPOLINE
+{
+ LPVOID pTarget; // [In] Address of the target function.
+ LPVOID pDetour; // [In] Address of the detour function.
+ LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
+
+#if defined(_M_X64) || defined(__x86_64__)
+ LPVOID pRelay; // [Out] Address of the relay function.
+#endif
+ BOOL patchAbove; // [Out] Should use the hot patch area?
+ UINT nIP; // [Out] Number of the instruction boundaries.
+ UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
+ UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
+} TRAMPOLINE, *PTRAMPOLINE;
+
+BOOL CreateTrampolineFunction(PTRAMPOLINE ct);
diff --git a/Alphanium/Source/Resolver.cpp b/Alphanium/Source/Resolver.cpp
new file mode 100644
index 0000000..aa273af
--- /dev/null
+++ b/Alphanium/Source/Resolver.cpp
@@ -0,0 +1,344 @@
+#include "Resolver.h"
+#include "Memory.h"
+#include "UE4Globals.h"
+#include
+#include
+
+namespace {
+uintptr_t FindFunctionByStringXref(const ModuleInfo& module, const std::string& name) {
+ uintptr_t strAddr = FindStringInModule(module, name);
+ if (!strAddr) {
+ return 0;
+ }
+ auto refs = FindAllReferences(module, reinterpret_cast(strAddr));
+ for (auto ref : refs) {
+ // Search for a function prolog before the reference.
+ for (int back = 0; back < 0x200; ++back) {
+ uintptr_t candidate = ref - back;
+ if (candidate < module.base) {
+ break;
+ }
+ uint8_t* bytes = reinterpret_cast(candidate);
+ if (bytes[0] == 0x55 && bytes[1] == 0x8B && bytes[2] == 0xEC) {
+ return candidate;
+ }
+ }
+ }
+ return 0;
+}
+
+uintptr_t FindFunctionByWideStringXref(const ModuleInfo& module, const std::wstring& name) {
+ uintptr_t strAddr = FindWideStringInModule(module, name);
+ if (!strAddr) {
+ return 0;
+ }
+ auto refs = FindAllReferences(module, reinterpret_cast(strAddr));
+ for (auto ref : refs) {
+ for (int back = 0; back < 0x200; ++back) {
+ uintptr_t candidate = ref - back;
+ if (candidate < module.base) {
+ break;
+ }
+ uint8_t* bytes = reinterpret_cast(candidate);
+ if (bytes[0] == 0x55 && bytes[1] == 0x8B && bytes[2] == 0xEC) {
+ return candidate;
+ }
+ }
+ }
+ return 0;
+}
+
+uintptr_t ResolveByPattern(const ModuleInfo& module, const std::vector& pattern, const std::string& mask, int offset) {
+ uintptr_t addr = FindPattern(module, pattern, mask);
+ if (!addr) {
+ return 0;
+ }
+ return *reinterpret_cast(addr + offset);
+}
+
+bool IsInModule(uintptr_t value, const ModuleInfo& module) {
+ return value >= module.base && value < (module.base + module.size);
+}
+
+bool IsLikelyUObject(uintptr_t candidate, const ModuleInfo& module) {
+ if (!IsReadableAddress(reinterpret_cast(candidate), sizeof(void*) * 2)) {
+ return false;
+ }
+ uintptr_t vtable = *reinterpret_cast(candidate);
+ return IsInModule(vtable, module);
+}
+
+uintptr_t FindGWorldHeuristic(const ModuleInfo& module, DWORD maxMs) {
+ uintptr_t start = module.base;
+ uintptr_t end = module.base + module.size;
+ MEMORY_BASIC_INFORMATION mbi{};
+ DWORD startTick = GetTickCount();
+ for (uintptr_t addr = start; addr < end; addr += mbi.RegionSize) {
+ if (GetTickCount() - startTick > maxMs) {
+ break;
+ }
+ if (!VirtualQuery(reinterpret_cast(addr), &mbi, sizeof(mbi))) {
+ break;
+ }
+ if (mbi.AllocationBase != reinterpret_cast(module.base)) {
+ continue;
+ }
+ if (!(mbi.Protect & (PAGE_READWRITE | PAGE_READONLY)) || (mbi.Protect & PAGE_GUARD)) {
+ continue;
+ }
+ auto regionStart = reinterpret_cast(mbi.BaseAddress);
+ auto regionEnd = regionStart + mbi.RegionSize;
+ for (uintptr_t ptrAddr = regionStart; ptrAddr + sizeof(uintptr_t) <= regionEnd; ptrAddr += sizeof(uintptr_t)) {
+ if (GetTickCount() - startTick > maxMs) {
+ break;
+ }
+ uintptr_t candidate = *reinterpret_cast(ptrAddr);
+ if (!IsLikelyUObject(candidate, module)) {
+ continue;
+ }
+ auto persistentLevelOffset = offsetof(UWorld, PersistentLevel);
+ auto levelsOffset = offsetof(UWorld, Levels);
+ if (!IsReadableAddress(reinterpret_cast(candidate + persistentLevelOffset), sizeof(uintptr_t))) {
+ continue;
+ }
+ uintptr_t levelPtr = *reinterpret_cast(candidate + persistentLevelOffset);
+ if (!IsLikelyUObject(levelPtr, module)) {
+ continue;
+ }
+ auto levels = reinterpret_cast*>(candidate + levelsOffset);
+ if (!IsReadableAddress(levels, sizeof(TArray))) {
+ continue;
+ }
+ if (levels->Count < 0 || levels->Count > 256 || levels->Max < levels->Count) {
+ continue;
+ }
+ return ptrAddr;
+ }
+ }
+ return 0;
+}
+
+uintptr_t FindGUObjectArrayHeuristic(const ModuleInfo& module, DWORD maxMs) {
+ uintptr_t start = module.base;
+ uintptr_t end = module.base + module.size;
+ MEMORY_BASIC_INFORMATION mbi{};
+ DWORD startTick = GetTickCount();
+ for (uintptr_t addr = start; addr < end; addr += mbi.RegionSize) {
+ if (GetTickCount() - startTick > maxMs) {
+ break;
+ }
+ if (!VirtualQuery(reinterpret_cast(addr), &mbi, sizeof(mbi))) {
+ break;
+ }
+ if (mbi.AllocationBase != reinterpret_cast(module.base)) {
+ continue;
+ }
+ if (!(mbi.Protect & (PAGE_READWRITE | PAGE_READONLY)) || (mbi.Protect & PAGE_GUARD)) {
+ continue;
+ }
+ auto regionStart = reinterpret_cast(mbi.BaseAddress);
+ auto regionEnd = regionStart + mbi.RegionSize;
+ for (uintptr_t ptrAddr = regionStart; ptrAddr + sizeof(FUObjectArray) <= regionEnd; ptrAddr += sizeof(uintptr_t)) {
+ if (GetTickCount() - startTick > maxMs) {
+ break;
+ }
+ auto* arr = reinterpret_cast(ptrAddr);
+ if (!IsReadableAddress(arr, sizeof(FUObjectArray))) {
+ continue;
+ }
+ if (arr->NumElements <= 0 || arr->NumElements > 5000000 || arr->MaxElements < arr->NumElements) {
+ continue;
+ }
+ if (!IsReadableAddress(arr->Objects, sizeof(FUObjectItem) * 4)) {
+ continue;
+ }
+ if (!IsReadableAddress(&arr->Objects[0], sizeof(FUObjectItem))) {
+ continue;
+ }
+ if (!arr->Objects[0].Object) {
+ continue;
+ }
+ if (!IsLikelyUObject(reinterpret_cast(arr->Objects[0].Object), module)) {
+ continue;
+ }
+ return ptrAddr;
+ }
+ }
+ return 0;
+}
+
+uintptr_t FindGNamesHeuristic(const ModuleInfo& module, DWORD maxMs) {
+ const char* needle = "None";
+ uintptr_t start = module.base;
+ uintptr_t end = module.base + module.size;
+ MEMORY_BASIC_INFORMATION mbi{};
+ DWORD startTick = GetTickCount();
+ for (uintptr_t addr = start; addr < end; addr += mbi.RegionSize) {
+ if (GetTickCount() - startTick > maxMs) {
+ break;
+ }
+ if (!VirtualQuery(reinterpret_cast(addr), &mbi, sizeof(mbi))) {
+ break;
+ }
+ if (!(mbi.Protect & (PAGE_READWRITE | PAGE_READONLY)) || (mbi.Protect & PAGE_GUARD)) {
+ continue;
+ }
+ auto regionStart = reinterpret_cast(mbi.BaseAddress);
+ auto regionEnd = regionStart + mbi.RegionSize;
+ for (uintptr_t ptrAddr = regionStart; ptrAddr + sizeof(uintptr_t) <= regionEnd; ptrAddr += sizeof(uintptr_t)) {
+ if (GetTickCount() - startTick > maxMs) {
+ break;
+ }
+ auto entryPtr = *reinterpret_cast(ptrAddr);
+ if (!IsReadableAddress(reinterpret_cast(entryPtr), 32)) {
+ continue;
+ }
+ const char* name0 = reinterpret_cast(entryPtr);
+ const char* name10 = reinterpret_cast(entryPtr + 0x10);
+ if (IsReadableAddress(name0, 8) && memcmp(name0, needle, 4) == 0) {
+ return ptrAddr;
+ }
+ if (IsReadableAddress(name10, 8) && memcmp(name10, needle, 4) == 0) {
+ return ptrAddr;
+ }
+ }
+ }
+ return 0;
+}
+}
+
+bool ResolveAllAddresses(std::string& log) {
+ std::ostringstream oss;
+ ModuleInfo module = GetMainModuleInfo();
+ if (!module.base) {
+ oss << "Failed to read module info.\n";
+ log = oss.str();
+ return false;
+ }
+ oss << "Module base: 0x" << std::hex << module.base << " size: 0x" << module.size << "\n";
+
+ g_ue4.ProcessEvent = FindFunctionByStringXref(module, "ProcessEvent");
+ if (!g_ue4.ProcessEvent) {
+ g_ue4.ProcessEvent = FindFunctionByWideStringXref(module, L"ProcessEvent");
+ }
+ if (!g_ue4.ProcessEvent) {
+ oss << "ProcessEvent not found via string xref.\n";
+ } else {
+ oss << "ProcessEvent resolved at 0x" << std::hex << g_ue4.ProcessEvent << " (string xref).\n";
+ }
+
+ g_ue4.StaticFindObject = FindFunctionByStringXref(module, "StaticFindObject");
+ if (!g_ue4.StaticFindObject) {
+ g_ue4.StaticFindObject = FindFunctionByWideStringXref(module, L"StaticFindObject");
+ }
+ if (!g_ue4.StaticFindObject) {
+ oss << "StaticFindObject not found via string xref.\n";
+ } else {
+ oss << "StaticFindObject resolved at 0x" << std::hex << g_ue4.StaticFindObject << " (string xref).\n";
+ }
+
+ // GNames resolver: multiple UE4.12 x86 patterns. all don't work tho?
+ // Signature A: A1 ?? ?? ?? ?? 8B 0C 85 ?? ?? ?? ?? 85 C9 74 0C
+ {
+ std::vector pattern = {0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x0C, 0x85, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC9, 0x74, 0x0C};
+ std::string mask = "x????xxx????xxxx";
+ g_ue4.GNames = ResolveByPattern(module, pattern, mask, 1);
+ if (!g_ue4.GNames) {
+ // Signature B: 8B 0D ?? ?? ?? ?? 8B 04 85 ?? ?? ?? ?? 85 C0
+ std::vector pattern2 = {0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x04, 0x85, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC0};
+ std::string mask2 = "xx????xxx????xx";
+ g_ue4.GNames = ResolveByPattern(module, pattern2, mask2, 2);
+ }
+ if (!g_ue4.GNames) {
+ // Signature C: A1 ?? ?? ?? ?? 8B 04 85 ?? ?? ?? ?? 85 C0 74 0B
+ std::vector pattern3 = {0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x04, 0x85, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x74, 0x0B};
+ std::string mask3 = "x????xxx????xxxx";
+ g_ue4.GNames = ResolveByPattern(module, pattern3, mask3, 1);
+ }
+ if (g_ue4.GNames) {
+ oss << "GNames resolved at 0x" << std::hex << g_ue4.GNames << " (pattern).\n";
+ } else {
+ oss << "GNames pattern failed.\n";
+ }
+ }
+ if (!g_ue4.GNames) {
+ oss << "GNames heuristic scan start.\n";
+ g_ue4.GNames = FindGNamesHeuristic(module, 3000);
+ if (g_ue4.GNames) {
+ oss << "GNames resolved at 0x" << std::hex << g_ue4.GNames << " (heuristic).\n";
+ } else {
+ oss << "GNames heuristic failed or timed out.\n";
+ }
+ }
+
+ // GUObjectArray resolver: multiple UE4.12 x86 patterns. all don't work here too lol
+ // Signature A: A1 ?? ?? ?? ?? 8B 0C 85 ?? ?? ?? ?? 8B 04 8D
+ {
+ std::vector pattern = {0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x0C, 0x85, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x04, 0x8D};
+ std::string mask = "x????xxx????xxx";
+ g_ue4.GUObjectArray = ResolveByPattern(module, pattern, mask, 1);
+ if (!g_ue4.GUObjectArray) {
+ // Signature B: 8B 0D ?? ?? ?? ?? 8B 04 8D ?? ?? ?? ?? 8B 40 08
+ std::vector pattern2 = {0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x04, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x08};
+ std::string mask2 = "xx????xxx????xxx";
+ g_ue4.GUObjectArray = ResolveByPattern(module, pattern2, mask2, 2);
+ }
+ if (!g_ue4.GUObjectArray) {
+ // Signature C: A1 ?? ?? ?? ?? 8B 04 85 ?? ?? ?? ?? 8B 40 10 8B 0D
+ std::vector pattern3 = {0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x04, 0x85, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x10, 0x8B, 0x0D};
+ std::string mask3 = "x????xxx????xxxx";
+ g_ue4.GUObjectArray = ResolveByPattern(module, pattern3, mask3, 1);
+ }
+ if (g_ue4.GUObjectArray) {
+ oss << "GUObjectArray resolved at 0x" << std::hex << g_ue4.GUObjectArray << " (pattern).\n";
+ } else {
+ oss << "GUObjectArray pattern failed.\n";
+ }
+ }
+ if (!g_ue4.GUObjectArray) {
+ oss << "GUObjectArray heuristic scan start.\n";
+ g_ue4.GUObjectArray = FindGUObjectArrayHeuristic(module, 3000);
+ if (g_ue4.GUObjectArray) {
+ oss << "GUObjectArray resolved at 0x" << std::hex << g_ue4.GUObjectArray << " (heuristic).\n";
+ } else {
+ oss << "GUObjectArray heuristic failed or timed out.\n";
+ }
+ }
+
+ // GWorld resolver: signature based on UE4.12 x86 global world pointer usage. still brokeeeen
+ // Signature A: A1 ?? ?? ?? ?? 8B 40 30 85 C0 74 10
+ {
+ std::vector pattern = {0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x40, 0x30, 0x85, 0xC0, 0x74, 0x10};
+ std::string mask = "x????xxxxxxx";
+ g_ue4.GWorld = ResolveByPattern(module, pattern, mask, 1);
+ if (!g_ue4.GWorld) {
+ // Signature B: 8B 0D ?? ?? ?? ?? 8B 81 ?? ?? ?? ?? 85 C0
+ std::vector pattern2 = {0x8B, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x81, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC0};
+ std::string mask2 = "xx????xx????xx";
+ g_ue4.GWorld = ResolveByPattern(module, pattern2, mask2, 2);
+ }
+ if (!g_ue4.GWorld) {
+ // Signature C: A1 ?? ?? ?? ?? 8B 80 ?? ?? ?? ?? 85 C0 74 0C
+ std::vector pattern3 = {0xA1, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x80, 0x00, 0x00, 0x00, 0x00, 0x85, 0xC0, 0x74, 0x0C};
+ std::string mask3 = "x????xx????xxxx";
+ g_ue4.GWorld = ResolveByPattern(module, pattern3, mask3, 1);
+ }
+ if (g_ue4.GWorld) {
+ oss << "GWorld resolved at 0x" << std::hex << g_ue4.GWorld << " (pattern).\n";
+ } else {
+ oss << "GWorld pattern failed.\n";
+ }
+ }
+ if (!g_ue4.GWorld) {
+ oss << "GWorld heuristic scan start.\n";
+ g_ue4.GWorld = FindGWorldHeuristic(module, 3000);
+ if (g_ue4.GWorld) {
+ oss << "GWorld resolved at 0x" << std::hex << g_ue4.GWorld << " (heuristic).\n";
+ } else {
+ oss << "GWorld heuristic failed or timed out.\n";
+ }
+ }
+
+ log = oss.str();
+ return g_ue4.ProcessEvent && g_ue4.GWorld;
+}
diff --git a/Alphanium/Source/Resolver.h b/Alphanium/Source/Resolver.h
new file mode 100644
index 0000000..f7e894a
--- /dev/null
+++ b/Alphanium/Source/Resolver.h
@@ -0,0 +1,4 @@
+#pragma once
+#include
+
+bool ResolveAllAddresses(std::string& log);
diff --git a/Alphanium/Source/StandaloneWindow.cpp b/Alphanium/Source/StandaloneWindow.cpp
new file mode 100644
index 0000000..6691bd1
--- /dev/null
+++ b/Alphanium/Source/StandaloneWindow.cpp
@@ -0,0 +1,177 @@
+#include "StandaloneWindow.h"
+#include "ImGuiLayer.h"
+#include "Features.h"
+#include "Logger.h"
+#include
+#include
+#include "imgui/imgui.h"
+extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(
+ HWND hWnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam
+);
+#include "imgui/backends/imgui_impl_win32.h"
+#include "imgui/backends/imgui_impl_dx9.h"
+
+namespace {
+std::atomic g_running{false};
+HWND g_hwnd = nullptr;
+HANDLE g_thread = nullptr;
+IDirect3D9* g_d3d = nullptr;
+IDirect3DDevice9* g_device = nullptr;
+D3DPRESENT_PARAMETERS g_d3dpp = {};
+
+LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ if (ImGui_ImplWin32_WndProcHandler(hwnd, msg, wparam, lparam)) {
+ return true;
+ }
+ switch (msg) {
+ case WM_SIZE:
+ if (g_device && wparam != SIZE_MINIMIZED) {
+ g_d3dpp.BackBufferWidth = LOWORD(lparam);
+ g_d3dpp.BackBufferHeight = HIWORD(lparam);
+ ImGui_ImplDX9_InvalidateDeviceObjects();
+ if (SUCCEEDED(g_device->Reset(&g_d3dpp))) {
+ ImGui_ImplDX9_CreateDeviceObjects();
+ }
+ }
+ return 0;
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ return 0;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ default:
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+ }
+}
+
+bool CreateDevice(HWND hwnd) {
+ g_d3d = Direct3DCreate9(D3D_SDK_VERSION);
+ if (!g_d3d) {
+ return false;
+ }
+ ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
+ g_d3dpp.Windowed = TRUE;
+ g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ g_d3dpp.hDeviceWindow = hwnd;
+ g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
+ RECT rect{};
+ GetClientRect(hwnd, &rect);
+ g_d3dpp.BackBufferWidth = rect.right - rect.left;
+ g_d3dpp.BackBufferHeight = rect.bottom - rect.top;
+ g_d3dpp.EnableAutoDepthStencil = TRUE;
+ g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
+ return SUCCEEDED(g_d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
+ D3DCREATE_HARDWARE_VERTEXPROCESSING,
+ &g_d3dpp, &g_device));
+}
+
+void CleanupDevice() {
+ if (g_device) {
+ g_device->Release();
+ g_device = nullptr;
+ }
+ if (g_d3d) {
+ g_d3d->Release();
+ g_d3d = nullptr;
+ }
+}
+
+DWORD WINAPI OverlayThread(LPVOID) {
+ WNDCLASSEXA wc{};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = OverlayWndProc;
+ wc.hInstance = GetModuleHandleA(nullptr);
+ wc.lpszClassName = "AlphaniumOverlayWindow";
+ wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ RegisterClassExA(&wc);
+
+ g_hwnd = CreateWindowExA(
+ 0,
+ wc.lpszClassName,
+ "Alphanium",
+ WS_OVERLAPPEDWINDOW,
+ 100,
+ 100,
+ 720,
+ 540,
+ nullptr,
+ nullptr,
+ wc.hInstance,
+ nullptr);
+
+ if (!g_hwnd) {
+ g_running = false;
+ return 0;
+ }
+
+ ShowWindow(g_hwnd, SW_SHOW);
+
+ GetFeatures().Initialize();
+ if (!CreateDevice(g_hwnd)) {
+ LogMessage("Alphanium: failed to create D3D9 device for standalone window");
+ g_running = false;
+ CleanupDevice();
+ return 0;
+ }
+ GetImGuiLayer().InitializeStandaloneDevice(g_hwnd, g_device);
+
+ MSG msg{};
+ while (g_running) {
+ while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT) {
+ g_running = false;
+ break;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ GetFeatures().Tick();
+ if (g_device) {
+ g_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(20, 20, 20), 1.0f, 0);
+ if (SUCCEEDED(g_device->BeginScene())) {
+ GetImGuiLayer().RenderStandalone();
+ g_device->EndScene();
+ }
+ HRESULT result = g_device->Present(nullptr, nullptr, nullptr, nullptr);
+ if (result == D3DERR_DEVICELOST && g_device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET) {
+ ImGui_ImplDX9_InvalidateDeviceObjects();
+ if (SUCCEEDED(g_device->Reset(&g_d3dpp))) {
+ ImGui_ImplDX9_CreateDeviceObjects();
+ }
+ }
+ }
+ Sleep(16);
+ }
+
+ GetImGuiLayer().Shutdown();
+ if (g_hwnd) {
+ DestroyWindow(g_hwnd);
+ g_hwnd = nullptr;
+ }
+ CleanupDevice();
+ return 0;
+}
+}
+
+bool StartStandaloneOverlay() {
+ if (g_running) {
+ return true;
+ }
+ g_running = true;
+ g_thread = CreateThread(nullptr, 0, OverlayThread, nullptr, 0, nullptr);
+ return g_thread != nullptr;
+}
+
+void StopStandaloneOverlay() {
+ g_running = false;
+ if (g_thread) {
+ WaitForSingleObject(g_thread, 2000);
+ CloseHandle(g_thread);
+ g_thread = nullptr;
+ }
+}
diff --git a/Alphanium/Source/StandaloneWindow.h b/Alphanium/Source/StandaloneWindow.h
new file mode 100644
index 0000000..c246f92
--- /dev/null
+++ b/Alphanium/Source/StandaloneWindow.h
@@ -0,0 +1,5 @@
+#pragma once
+#include
+
+bool StartStandaloneOverlay();
+void StopStandaloneOverlay();
diff --git a/Alphanium/Source/Strings.cpp b/Alphanium/Source/Strings.cpp
new file mode 100644
index 0000000..d40491c
--- /dev/null
+++ b/Alphanium/Source/Strings.cpp
@@ -0,0 +1,35 @@
+#include "Strings.h"
+#include
+#include
+#include
+#include "Logger.h"
+
+namespace {
+std::string GetModuleDir() {
+ char buffer[MAX_PATH] = {};
+ GetModuleFileNameA(reinterpret_cast(&GetModuleDir), buffer, MAX_PATH);
+ std::string path = buffer;
+ size_t pos = path.find_last_of("\\/");
+ if (pos == std::string::npos) {
+ return ".";
+ }
+ return path.substr(0, pos);
+}
+
+std::string GetCurrentDir() {
+ char buffer[MAX_PATH] = {};
+ GetCurrentDirectoryA(MAX_PATH, buffer);
+ return buffer;
+}
+
+std::string NormalizeName(const std::string& name) {
+ std::string result;
+ for (char c : name) {
+ if (c == '\r' || c == '\n' || c == '\t') {
+ continue;
+ }
+ result.push_back(c);
+ }
+ return result;
+}
+}
diff --git a/Alphanium/Source/Strings.h b/Alphanium/Source/Strings.h
new file mode 100644
index 0000000..9ff0efc
--- /dev/null
+++ b/Alphanium/Source/Strings.h
@@ -0,0 +1,9 @@
+#pragma once
+#include
+#include
+
+struct StringDump {
+ std::vector maps;
+ std::vector function_names;
+ std::vector weapon_defs;
+};
\ No newline at end of file
diff --git a/Alphanium/Source/UE4Globals.h b/Alphanium/Source/UE4Globals.h
new file mode 100644
index 0000000..60dfd34
--- /dev/null
+++ b/Alphanium/Source/UE4Globals.h
@@ -0,0 +1,23 @@
+#pragma once
+#include
+#include "UE4Types.h"
+
+struct UE4Globals {
+ uintptr_t GNames = 0;
+ uintptr_t GUObjectArray = 0;
+ uintptr_t GWorld = 0;
+ uintptr_t ProcessEvent = 0;
+ uintptr_t StaticFindObject = 0;
+};
+
+extern UE4Globals g_ue4;
+
+FNameEntry* GetNameEntry(int32_t index);
+FUObjectArray* GetGUObjectArray();
+UWorld* GetWorld();
+
+using ProcessEventFn = void(__thiscall*)(UObject* obj, UFunction* function, void* params);
+using StaticFindObjectFn = UObject* (__cdecl*)(UClass* cls, UObject* outer, const wchar_t* name, bool exact);
+
+ProcessEventFn GetProcessEvent();
+StaticFindObjectFn GetStaticFindObject();
diff --git a/Alphanium/Source/UE4Helpers.cpp b/Alphanium/Source/UE4Helpers.cpp
new file mode 100644
index 0000000..68dc36a
--- /dev/null
+++ b/Alphanium/Source/UE4Helpers.cpp
@@ -0,0 +1,291 @@
+#include "UE4Helpers.h"
+#include "UE4Globals.h"
+#include "Memory.h"
+#include "Logger.h"
+#include
+#include
+
+UE4Globals g_ue4{};
+
+namespace {
+bool IsLikelyNameEntry(const FNameEntry* entry) {
+ if (!IsReadableAddress(entry, sizeof(FNameEntry))) {
+ return false;
+ }
+ const char* name = entry->AnsiName;
+ if (!IsReadableAddress(name, 4)) {
+ return false;
+ }
+ return name[0] != '\0';
+}
+}
+
+FNameEntry* GetNameEntry(int32_t index) {
+ if (!g_ue4.GNames) {
+ return nullptr;
+ }
+ auto names = reinterpret_cast(g_ue4.GNames);
+ if (names && IsReadableAddress(names, sizeof(FNameEntryArray)) && names->Entries) {
+ return names->Entries[index];
+ }
+ auto direct = reinterpret_cast(g_ue4.GNames);
+ if (IsReadableAddress(direct, sizeof(void*) * (index + 1))) {
+ auto entry = direct[index];
+ if (IsLikelyNameEntry(entry)) {
+ return entry;
+ }
+ }
+ return nullptr;
+}
+
+FUObjectArray* GetGUObjectArray() {
+ if (!g_ue4.GUObjectArray) {
+ return nullptr;
+ }
+ auto arr = reinterpret_cast(g_ue4.GUObjectArray);
+ if (IsReadableAddress(arr, sizeof(FUObjectArray))) {
+ return arr;
+ }
+ return nullptr;
+}
+
+UWorld* GetWorld() {
+ return g_ue4.GWorld ? *reinterpret_cast(g_ue4.GWorld) : nullptr;
+}
+
+ProcessEventFn GetProcessEvent() {
+ return g_ue4.ProcessEvent ? reinterpret_cast(g_ue4.ProcessEvent) : nullptr;
+}
+
+StaticFindObjectFn GetStaticFindObject() {
+ return g_ue4.StaticFindObject ? reinterpret_cast(g_ue4.StaticFindObject) : nullptr;
+}
+
+std::string UObject::GetName() const {
+ FNameEntry* entry = GetNameEntry(NamePrivate.ComparisonIndex);
+ if (!entry) {
+ return "None";
+ }
+ return entry->AnsiName;
+}
+
+std::string UObject::GetFullName() const {
+ if (!ClassPrivate) {
+ return GetName();
+ }
+ std::string result = ClassPrivate->GetName();
+ result += " ";
+ const UObject* current = this;
+ std::string outerName;
+ while (current) {
+ outerName = current->GetName();
+ if (current->OuterPrivate) {
+ outerName = current->OuterPrivate->GetName() + "." + outerName;
+ }
+ break;
+ }
+ result += outerName;
+ return result;
+}
+
+bool UObject::IsA(const UClass* cls) const {
+ if (!cls) {
+ return false;
+ }
+ const UClass* current = ClassPrivate;
+ while (current) {
+ if (current == cls) {
+ return true;
+ }
+ current = current->SuperStruct ? reinterpret_cast(current->SuperStruct) : nullptr;
+ }
+ return false;
+}
+
+FVector AActor::GetActorLocation() const {
+ auto* root = reinterpret_cast(RootComponent);
+ if (!root) {
+ return {0.0f, 0.0f, 0.0f};
+ }
+ return *root;
+}
+
+UObject* FindObjectByName(const std::wstring& name) {
+ if (auto fn = GetStaticFindObject()) {
+ return fn(nullptr, nullptr, name.c_str(), false);
+ }
+ auto* objects = GetGUObjectArray();
+ if (!objects || !objects->Objects) {
+ return nullptr;
+ }
+ for (int32_t i = 0; i < objects->NumElements; ++i) {
+ auto& item = objects->Objects[i];
+ if (!item.Object) {
+ continue;
+ }
+ std::string full = item.Object->GetFullName();
+ std::wstring full_w(full.begin(), full.end());
+ if (full_w.find(name) != std::wstring::npos) {
+ return item.Object;
+ }
+ }
+ return nullptr;
+}
+
+UFunction* FindFunction(const std::wstring& name) {
+ auto obj = FindObjectByName(name);
+ return obj ? reinterpret_cast(obj) : nullptr;
+}
+
+APlayerController* GetLocalPlayerController() {
+ auto* objects = GetGUObjectArray();
+ if (!objects || !objects->Objects) {
+ return nullptr;
+ }
+ for (int32_t i = 0; i < objects->NumElements; ++i) {
+ auto& item = objects->Objects[i];
+ if (!item.Object) {
+ continue;
+ }
+ std::string name = item.Object->GetFullName();
+ if (name.find("PlayerController") != std::string::npos) {
+ return reinterpret_cast(item.Object);
+ }
+ }
+ return nullptr;
+}
+
+ACharacter* SpawnDefaultCharacter(const FVector& location) {
+ UWorld* world = GetWorld();
+ if (!world) {
+ return nullptr;
+ }
+ auto spawnFunc = FindFunction(L"Function Engine.World.SpawnActor");
+ if (!spawnFunc) {
+ return nullptr;
+ }
+ UObject* characterClassObj = FindObjectByName(L"Class Engine.Character");
+ if (!characterClassObj) {
+ characterClassObj = FindObjectByName(L"Class Engine.DefaultPawn");
+ }
+ if (!characterClassObj) {
+ return nullptr;
+ }
+ struct SpawnParams {
+ UClass* Class;
+ FVector Location;
+ FRotator Rotation;
+ AActor* Owner;
+ APawn* Instigator;
+ bool bNoCollisionFail;
+ bool bRemoteOwned;
+ AActor* ReturnValue;
+ } params{};
+ params.Class = reinterpret_cast(characterClassObj);
+ params.Location = location;
+ params.Rotation = {0.0f, 0.0f, 0.0f};
+ params.Owner = nullptr;
+ params.Instigator = nullptr;
+ params.bNoCollisionFail = true;
+ params.bRemoteOwned = false;
+ params.ReturnValue = nullptr;
+
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(world), spawnFunc, ¶ms);
+ return reinterpret_cast(params.ReturnValue);
+ }
+ return nullptr;
+}
+
+void PossessPawn(APlayerController* controller, APawn* pawn) {
+ if (!controller || !pawn) {
+ return;
+ }
+ auto possessFunc = FindFunction(L"Function Engine.Controller.Possess");
+ if (!possessFunc) {
+ return;
+ }
+ struct Params { APawn* Pawn; } params{pawn};
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(controller), possessFunc, ¶ms);
+ }
+}
+
+void SetActorLocation(AActor* actor, const FVector& location) {
+ if (!actor) {
+ return;
+ }
+ auto func = FindFunction(L"Function Engine.Actor.SetActorLocation");
+ if (!func) {
+ return;
+ }
+ struct Params {
+ FVector NewLocation;
+ bool bSweep;
+ void* SweepHitResult;
+ bool bTeleport;
+ bool ReturnValue;
+ } params{};
+ params.NewLocation = location;
+ params.bSweep = false;
+ params.bTeleport = true;
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(actor), func, ¶ms);
+ }
+}
+
+void DestroyActor(AActor* actor) {
+ if (!actor) {
+ return;
+ }
+ auto func = FindFunction(L"Function Engine.Actor.K2_DestroyActor");
+ if (!func) {
+ return;
+ }
+ if (auto process = GetProcessEvent()) {
+ process(reinterpret_cast(actor), func, nullptr);
+ }
+}
+
+void ExecuteConsoleCommand(UObject* worldContext, const std::string& command) {
+ if (!worldContext) {
+ LogMessage("ExecuteConsoleCommand: world context null for command '%s'", command.c_str());
+ return;
+ }
+ auto func = FindFunction(L"Function Engine.KismetSystemLibrary.ExecuteConsoleCommand");
+ if (!func) {
+ LogMessage("ExecuteConsoleCommand: KismetSystemLibrary.ExecuteConsoleCommand not found");
+ return;
+ }
+ UObject* kismetObj = FindObjectByName(L"Default__KismetSystemLibrary");
+ if (!kismetObj) {
+ kismetObj = FindObjectByName(L"Class Engine.KismetSystemLibrary");
+ }
+ if (!kismetObj) {
+ LogMessage("ExecuteConsoleCommand: KismetSystemLibrary object not found");
+ return;
+ }
+ struct FString {
+ wchar_t* Data;
+ int32_t Count;
+ int32_t Max;
+ } cmd{};
+ std::wstring wide(command.begin(), command.end());
+ cmd.Data = const_cast(wide.c_str());
+ cmd.Count = static_cast(wide.size() + 1);
+ cmd.Max = cmd.Count;
+ struct Params {
+ UObject* WorldContext;
+ FString Command;
+ APlayerController* SpecificPlayer;
+ } params{};
+ params.WorldContext = worldContext;
+ params.Command = cmd;
+ params.SpecificPlayer = nullptr;
+ if (auto process = GetProcessEvent()) {
+ LogMessage("ExecuteConsoleCommand: '%s' (Kismet=%p Function=%p)", command.c_str(), kismetObj, func);
+ process(kismetObj, func, ¶ms);
+ } else {
+ LogMessage("ExecuteConsoleCommand: ProcessEvent not resolved");
+ }
+}
diff --git a/Alphanium/Source/UE4Helpers.h b/Alphanium/Source/UE4Helpers.h
new file mode 100644
index 0000000..6f6d9f9
--- /dev/null
+++ b/Alphanium/Source/UE4Helpers.h
@@ -0,0 +1,13 @@
+#pragma once
+#include "UE4Types.h"
+
+UObject* FindObjectByName(const std::wstring& name);
+UFunction* FindFunction(const std::wstring& name);
+
+APlayerController* GetLocalPlayerController();
+ACharacter* SpawnDefaultCharacter(const FVector& location);
+void PossessPawn(APlayerController* controller, APawn* pawn);
+
+void SetActorLocation(AActor* actor, const FVector& location);
+void DestroyActor(AActor* actor);
+void ExecuteConsoleCommand(UObject* worldContext, const std::string& command);
diff --git a/Alphanium/Source/UE4Types.h b/Alphanium/Source/UE4Types.h
new file mode 100644
index 0000000..72586ec
--- /dev/null
+++ b/Alphanium/Source/UE4Types.h
@@ -0,0 +1,137 @@
+#pragma once
+#include
+#include
+
+struct FNameEntry {
+ int32_t Index;
+ char AnsiName[1024];
+};
+
+struct FName {
+ int32_t ComparisonIndex;
+ int32_t Number;
+};
+
+template
+struct TArray {
+ T* Data;
+ int32_t Count;
+ int32_t Max;
+
+ T& operator[](int32_t idx) { return Data[idx]; }
+ const T& operator[](int32_t idx) const { return Data[idx]; }
+};
+
+struct UObject;
+struct UClass;
+struct UFunction;
+
+struct UObject {
+ void** VTable;
+ int32_t ObjectFlags;
+ int32_t InternalIndex;
+ UClass* ClassPrivate;
+ FName NamePrivate;
+ UObject* OuterPrivate;
+
+ std::string GetName() const;
+ std::string GetFullName() const;
+ bool IsA(const UClass* cls) const;
+};
+
+struct UField : UObject {
+ UField* Next;
+};
+
+struct UStruct : UField {
+ UStruct* SuperStruct;
+ UField* Children;
+ int32_t PropertySize;
+ int32_t MinAlignment;
+};
+
+struct UFunction : UStruct {
+ int32_t FunctionFlags;
+ int16_t RepOffset;
+ int16_t NumParms;
+ int16_t ParmsSize;
+ int16_t ReturnValueOffset;
+};
+
+struct UClass : UStruct {
+ void* ClassConstructor;
+ void* ClassVTableHelperCtorCaller;
+ void* ClassAddReferencedObjects;
+ int32_t ClassFlags;
+};
+
+struct FVector {
+ float X;
+ float Y;
+ float Z;
+};
+
+struct FRotator {
+ float Pitch;
+ float Yaw;
+ float Roll;
+};
+
+struct FTransform {
+ FVector Translation;
+ FRotator Rotation;
+ FVector Scale3D;
+};
+
+struct AActor;
+struct UWorld;
+struct ULevel;
+struct APlayerController;
+struct APawn;
+struct ACharacter;
+struct AGameModeBase;
+struct AGameStateBase;
+
+struct AActor : UObject {
+ void* RootComponent;
+ FVector GetActorLocation() const;
+};
+
+struct APlayerController : AActor {
+ APawn* AcknowledgedPawn;
+};
+
+struct APawn : AActor {};
+struct ACharacter : APawn {};
+
+struct ULevel : UObject {
+ TArray Actors;
+};
+
+struct UWorld : UObject {
+ ULevel* PersistentLevel;
+ AGameModeBase* AuthorityGameMode;
+ AGameStateBase* GameState;
+ TArray Levels;
+};
+
+struct AGameModeBase : AActor {};
+struct AGameStateBase : AActor {};
+
+struct FNameEntryArray {
+ FNameEntry** Entries;
+};
+
+struct FUObjectItem {
+ UObject* Object;
+ int32_t Flags;
+ int32_t ClusterIndex;
+ int32_t SerialNumber;
+};
+
+struct FUObjectArray {
+ FUObjectItem* Objects;
+ int32_t MaxElements;
+ int32_t NumElements;
+};
+
diff --git a/Alphanium/Source/dllmain.cpp b/Alphanium/Source/dllmain.cpp
new file mode 100644
index 0000000..86eee2c
--- /dev/null
+++ b/Alphanium/Source/dllmain.cpp
@@ -0,0 +1,30 @@
+#include
+#include
+#include "Resolver.h"
+#include "Hooking.h"
+#include "StandaloneWindow.h"
+#include "Logger.h"
+
+DWORD WINAPI MainThread(LPVOID) {
+ InitializeConsole();
+ LogMessage("Alphanium: initializing");
+ std::string log;
+ ResolveAllAddresses(log);
+ LogMessage("%s", log.c_str());
+ InitializeHooks();
+ LogMessage("Alphanium: hooks initialized");
+ StartStandaloneOverlay();
+ LogMessage("Alphanium: standalone window started");
+ return 0;
+}
+
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) {
+ if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
+ DisableThreadLibraryCalls(hModule);
+ CreateThread(nullptr, 0, MainThread, nullptr, 0, nullptr);
+ } else if (ul_reason_for_call == DLL_PROCESS_DETACH) {
+ StopStandaloneOverlay();
+ ShutdownHooks();
+ }
+ return TRUE;
+}
diff --git a/Alphanium/Source/imgui/.editorconfig b/Alphanium/Source/imgui/.editorconfig
new file mode 100644
index 0000000..5adfefa
--- /dev/null
+++ b/Alphanium/Source/imgui/.editorconfig
@@ -0,0 +1,28 @@
+# See http://editorconfig.org to read about the EditorConfig format.
+# - In theory automatically supported by VS2017+ and most common IDE or text editors.
+# - In practice VS2019-VS2022 stills don't trim trailing whitespaces correctly :(
+# - Suggest installing this to trim whitespaces:
+# GitHub https://github.com/madskristensen/TrailingWhitespace
+# VS2019 https://marketplace.visualstudio.com/items?itemName=MadsKristensen.TrailingWhitespaceVisualizer
+# VS2022 https://marketplace.visualstudio.com/items?itemName=MadsKristensen.TrailingWhitespace64
+# (in spite of its name doesn't only visualize but also trims)
+# - Alternative for older VS2010 to VS2015: https://marketplace.visualstudio.com/items?itemName=EditorConfigTeam.EditorConfig
+
+# top-most EditorConfig file
+root = true
+
+# Default settings:
+# Use 4 spaces as indentation
+[*]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[imstb_*]
+indent_size = 3
+trim_trailing_whitespace = false
+
+[Makefile]
+indent_style = tab
+indent_size = 4
diff --git a/Alphanium/Source/imgui/.gitattributes b/Alphanium/Source/imgui/.gitattributes
new file mode 100644
index 0000000..d48470e
--- /dev/null
+++ b/Alphanium/Source/imgui/.gitattributes
@@ -0,0 +1,30 @@
+* text=auto
+
+*.c text
+*.cpp text
+*.h text
+*.m text
+*.mm text
+*.md text
+*.txt text
+*.html text
+*.bat text
+*.frag text
+*.vert text
+*.mkb text
+*.icf text
+
+*.sln text eol=crlf
+*.vcxproj text eol=crlf
+*.vcxproj.filters text eol=crlf
+*.natvis text eol=crlf
+
+Makefile text eol=lf
+*.sh text eol=lf
+*.pbxproj text eol=lf
+*.storyboard text eol=lf
+*.plist text eol=lf
+
+*.png binary
+*.ttf binary
+*.lib binary
diff --git a/Alphanium/Source/imgui/.github/FUNDING.yml b/Alphanium/Source/imgui/.github/FUNDING.yml
new file mode 100644
index 0000000..df7d709
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: ['https://github.com/ocornut/imgui/wiki/Funding']
diff --git a/Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/config.yml b/Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..3ba13e0
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: false
diff --git a/Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/issue_template.yml b/Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/issue_template.yml
new file mode 100644
index 0000000..6ed6249
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/ISSUE_TEMPLATE/issue_template.yml
@@ -0,0 +1,92 @@
+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, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions)
+ For anything else: **we are happy to use 'GitHub Issues' for many types of open-ended questions**. We are encouraging 'Issues' becoming a large, centralized, tagged, cross-referenced database of Dear ImGui contents.
+
+ Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.
+
+ **If you are using Dear ImGui as part of a job that you are being well-paid for** and your company is not a sponsor. Please be mindful that this is a Free Software and you might be about to ask volunteers to help you doing your job. Please put extra effort describing your issue or question properly. If your company is wealthy, please read [Funding](https://github.com/ocornut/imgui/wiki/Funding) and consider getting in touch.
+ - type: markdown
+ attributes:
+ value: |
+ **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/Alphanium/Source/imgui/.github/pull_request_template.md b/Alphanium/Source/imgui/.github/pull_request_template.md
new file mode 100644
index 0000000..d40b14c
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/pull_request_template.md
@@ -0,0 +1,10 @@
+(Click "Preview" to turn any http URL into a clickable link)
+
+1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md)
+
+2. **Make sure you're using a special branch just for this pull request**. (In git, 1 PR = 1 branch. If you update the branch the PR will be updated.)
+
+3. Consider running the [imgui_test_suite](https://github.com/ocornut/imgui_test_engine) or adding new tests to test for expected behaviors.
+
+4. Clear this template before submitting your PR.
+
diff --git a/Alphanium/Source/imgui/.github/workflows/build.yml b/Alphanium/Source/imgui/.github/workflows/build.yml
new file mode 100644
index 0000000..3ee7297
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/workflows/build.yml
@@ -0,0 +1,774 @@
+name: build
+
+on:
+ push:
+ pull_request:
+ workflow_run:
+ # Use a workflow as a trigger of scheduled builds. Forked repositories can disable scheduled builds by disabling
+ # "scheduled" workflow, while maintaining ability to perform local CI builds.
+ workflows:
+ - scheduled
+ - manual
+ branches:
+ - master
+ - docking
+ types:
+ - requested
+
+jobs:
+ Build-Windows:
+ runs-on: windows-2025
+ name: Build - Windows
+
+ defaults:
+ run:
+ working-directory: ${{ github.workspace }}/imgui
+
+ env:
+ VS_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\
+ MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: ${{ github.workspace }}/imgui
+
+ # The VulkanSDK libs for Windows is manually generated using build_windows_vulkan_libs.ps1 + attached to issue #8925.
+ # (we have a .yml workflow in commit history if it becomes ever useful to create this on CI too)
+ - name: Install Dependencies
+ shell: powershell
+ run: |
+ Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL2-devel-2.32.8-VC.zip" -OutFile "SDL2-devel-2.32.8-VC.zip"
+ Expand-Archive -Path SDL2-devel-2.32.8-VC.zip
+ echo "SDL2_DIR=$(pwd)\SDL2-devel-2.32.8-VC\SDL2-2.32.8\" >>${env:GITHUB_ENV}
+
+ Invoke-WebRequest -Uri "https://www.libsdl.org/release/SDL3-devel-3.2.18-VC.zip" -OutFile "SDL3-devel-3.2.18-VC.zip"
+ Expand-Archive -Path SDL3-devel-3.2.18-VC.zip
+ echo "SDL3_DIR=$(pwd)\SDL3-devel-3.2.18-VC\SDL3-3.2.18\" >>${env:GITHUB_ENV}
+
+ Invoke-WebRequest -Uri "https://github.com/user-attachments/files/22464296/vulkan_windows_libs_1.4.326.zip" -OutFile vulkan_windows_libs_1.4.326.zip
+ Expand-Archive -Path vulkan_windows_libs_1.4.326.zip
+ echo "VULKAN_SDK=$(pwd)\vulkan_windows_libs_1.4.326\" >>${env:GITHUB_ENV}
+
+ - name: Fix Projects
+ shell: powershell
+ run: |
+ # CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version.
+ gci -recurse -filter "*.vcxproj" | ForEach-Object {
+ (Get-Content $_.FullName) -Replace "v\d{3}","v143" | Set-Content -Path $_.FullName
+ (Get-Content $_.FullName) -Replace "[\d\.]+",'$(LatestTargetPlatformVersion)' | Set-Content -Path $_.FullName
+ }
+
+ # Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long.
+ - name: Build example_null (extra warnings, mingw 64-bit)
+ run: mingw32-make -C examples/example_null WITH_EXTRA_WARNINGS=1
+
+ - name: Build example_null (mingw 64-bit, as DLL)
+ shell: bash
+ run: |
+ echo '#define IMGUI_API __declspec(dllexport)' > example_single_file.cpp
+ echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
+ echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
+ g++ -I. -Wall -Wformat -shared -o libimgui.dll -Wl,--out-implib,libimgui.a example_single_file.cpp -limm32
+ g++ -I. -Wall -Wformat -DIMGUI_API='__declspec(dllimport)' -DIMGUI_IMPL_API= -o example_null.exe examples/example_null/main.cpp -L. -limgui
+ rm -f example_null.exe libimgui.* example_single_file.*
+
+ - name: Build example_null (extra warnings, msvc 64-bit)
+ shell: cmd
+ run: |
+ cd examples\example_null
+ call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat"
+ .\build_win32.bat /W4
+
+ - name: Build example_null (single file build)
+ shell: bash
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp -limm32
+
+ - name: Build example_null (with IMGUI_DISABLE_WIN32_FUNCTIONS)
+ shell: bash
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_DISABLE_WIN32_FUNCTIONS
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -Wall -Wformat -o example_single_file.exe example_single_file.cpp -limm32
+
+ - name: Build example_null (as DLL)
+ shell: cmd
+ run: |
+ call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat"
+
+ echo #define IMGUI_API __declspec(dllexport) > example_single_file.cpp
+ echo #define IMGUI_IMPLEMENTATION >> example_single_file.cpp
+ echo #include "misc/single_file/imgui_single_file.h" >> example_single_file.cpp
+
+ cl.exe /D_USRDLL /D_WINDLL /I. example_single_file.cpp /LD /FeImGui.dll /link
+ cl.exe /DIMGUI_API=__declspec(dllimport) -DIMGUI_IMPL_API= /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp
+
+ # Win64 examples are more frequently compilted than the Win32 examples.
+ # More of the Win32 examples requires 'workflow_run' to reduce waste.
+ - name: Build Win32 example_glfw_opengl2
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_glfw_opengl3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_glfw_vulkan
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl2_sdlrenderer2
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl2_vulkan
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl2_opengl2
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl2_opengl3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+
+ - name: Build Win32 example_sdl2_directx11
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl3_opengl3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+
+ - name: Build Win32 example_sdl3_sdlgpu3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl3_sdlrenderer3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_sdl3_vulkan
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_win32_directx9
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_win32_directx10
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win32 example_win32_directx11
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=Win32 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ # Windows 64-bits
+ - name: Build Win64 example_glfw_opengl2
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl2/example_glfw_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_glfw_opengl3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ - name: Build Win64 example_glfw_vulkan
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_vulkan/example_glfw_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ - name: Build Win64 example_sdl2_sdlrenderer2
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_sdl2_vulkan
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_vulkan/example_sdl2_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_sdl2_opengl2
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl2/example_sdl2_opengl2.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_sdl2_opengl3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_opengl3/example_sdl2_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_sdl2_directx11
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ - name: Build Win64 example_sdl3_opengl3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_sdl3_sdlgpu3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ - name: Build Win64 example_sdl3_sdlrenderer3
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ - name: Build Win64 example_sdl3_vulkan
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_vulkan/example_sdl3_vulkan.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_win32_directx9
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx9/example_win32_directx9.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_win32_directx10
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx10/example_win32_directx10.vcxproj /p:Platform=x64 /p:Configuration=Release'
+ if: github.event_name == 'workflow_run'
+
+ - name: Build Win64 example_win32_directx11
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx11/example_win32_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ - name: Build Win64 example_win32_directx12
+ shell: cmd
+ run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_win32_directx12/example_win32_directx12.vcxproj /p:Platform=x64 /p:Configuration=Release'
+
+ Build-Linux:
+ runs-on: ubuntu-latest
+ name: Build - Linux
+
+ defaults:
+ run:
+ working-directory: ${{ github.workspace }}/imgui
+
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: ${{ github.workspace }}/imgui
+
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y libglfw3-dev libsdl2-dev gcc-multilib g++-multilib libfreetype6-dev libvulkan-dev
+
+ - name: Build example_null (extra warnings, gcc 32-bit)
+ run: |
+ make -C examples/example_null clean
+ CXXFLAGS="$CXXFLAGS -m32 -Werror" make -C examples/example_null WITH_EXTRA_WARNINGS=1
+
+ - name: Build example_null (extra warnings, gcc 64-bit)
+ run: |
+ make -C examples/example_null clean
+ CXXFLAGS="$CXXFLAGS -m64 -Werror" make -C examples/example_null WITH_EXTRA_WARNINGS=1
+
+ - name: Build example_null (extra warnings, clang 32-bit)
+ run: |
+ make -C examples/example_null clean
+ CXXFLAGS="$CXXFLAGS -m32 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1
+
+ - name: Build example_null (extra warnings, clang 64-bit)
+ run: |
+ make -C examples/example_null clean
+ CXXFLAGS="$CXXFLAGS -m64 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1
+
+ - name: Build example_null (extra warnings, empty IM_ASSERT)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IM_ASSERT(x)
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -Wextra -Werror -Wno-zero-as-null-pointer-constant -Wno-double-promotion -Wno-variadic-macros -Wno-empty-body -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (freetype)
+ run: |
+ make -C examples/example_null clean
+ make -C examples/example_null WITH_FREETYPE=1
+
+ - name: Build example_null (single file build)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with ImWchar32)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_USE_WCHAR32
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with large ImDrawIdx + pointer ImTextureID)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define ImTextureID void*
+ #define ImDrawIdx unsigned int
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with IMGUI_DISABLE_OBSOLETE_FUNCTIONS)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with IMGUI_DISABLE_OBSOLETE_KEYIO)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_DISABLE_OBSOLETE_KEYIO
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with C++20)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_DISABLE_OBSOLETE_KEYIO
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++20 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with IMGUI_DISABLE_DEMO_WINDOWS and IMGUI_DISABLE_DEBUG_TOOLS)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_DISABLE_DEMO_WINDOWS
+ #define IMGUI_DISABLE_DEBUG_TOOLS
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with IMGUI_DISABLE_FILE_FUNCTIONS)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_DISABLE_FILE_FUNCTIONS
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with IMGUI_USE_BGRA_PACKED_COLOR)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_USE_BGRA_PACKED_COLOR
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (with IM_VEC2_CLASS_EXTRA and IM_VEC4_CLASS_EXTRA)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ struct MyVec2 { float x; float y; MyVec2(float x, float y) : x(x), y(y) { } };
+ struct MyVec4 { float x; float y; float z; float w;
+ MyVec4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) { } };
+ #define IM_VEC2_CLASS_EXTRA \
+ ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
+ operator MyVec2() const { return MyVec2(x, y); }
+ #define IM_VEC4_CLASS_EXTRA \
+ ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
+ operator MyVec4() const { return MyVec4(x, y, z, w); }
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ g++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (C++26, Clang)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #define IMGUI_DISABLE_DEMO_WINDOWS
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ clang++ -I. -std=c++26 -Wall -Wformat -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (without c++ runtime, Clang)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #define IMGUI_DISABLE_DEMO_WINDOWS
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ clang++ -I. -std=c++11 -Wall -Wformat -nodefaultlibs -fno-rtti -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
+
+ - name: Build example_glfw_opengl2
+ run: make -C examples/example_glfw_opengl2
+
+ - name: Build example_glfw_opengl3
+ run: make -C examples/example_glfw_opengl3
+ if: github.event_name == 'workflow_run'
+
+ - name: Build example_sdl2_opengl2
+ run: make -C examples/example_sdl2_opengl2
+ if: github.event_name == 'workflow_run'
+
+ - name: Build example_sdl2_opengl3
+ run: make -C examples/example_sdl2_opengl3
+
+ - name: Build with IMGUI_IMPL_VULKAN_NO_PROTOTYPES
+ run: g++ -c -I. -std=c++11 -DIMGUI_IMPL_VULKAN_NO_PROTOTYPES=1 backends/imgui_impl_vulkan.cpp
+
+ Build-MacOS:
+ runs-on: macos-latest
+ name: Build - MacOS
+
+ defaults:
+ run:
+ working-directory: ${{ github.workspace }}/imgui
+
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: ${{ github.workspace }}/imgui
+
+ - name: Install Dependencies
+ run: |
+ brew install glfw3 sdl2 sdl3
+
+ - name: Build example_null (extra warnings, clang 64-bit)
+ run: make -C examples/example_null WITH_EXTRA_WARNINGS=1
+
+ - name: Build example_null (single file build)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ clang++ -I. -std=c++11 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (single file build, c++20)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ clang++ -I. -std=c++20 -Wall -Wformat -o example_single_file example_single_file.cpp
+
+ - name: Build example_null (without c++ runtime)
+ run: |
+ cat > example_single_file.cpp <<'EOF'
+
+ #define IMGUI_IMPLEMENTATION
+ #include "misc/single_file/imgui_single_file.h"
+ #include "examples/example_null/main.cpp"
+
+ EOF
+ clang++ -I. -std=c++11 -Wall -Wformat -nodefaultlibs -fno-rtti -fno-exceptions -fno-threadsafe-statics -lc -lm -o example_single_file example_single_file.cpp
+
+ - name: Build example_glfw_opengl2
+ run: make -C examples/example_glfw_opengl2
+
+ - name: Build example_glfw_opengl3
+ run: make -C examples/example_glfw_opengl3
+ if: github.event_name == 'workflow_run'
+
+ - name: Build example_glfw_metal
+ run: make -C examples/example_glfw_metal
+
+ - name: Build example_sdl2_metal
+ run: make -C examples/example_sdl2_metal
+
+ - name: Build example_sdl2_opengl2
+ run: make -C examples/example_sdl2_opengl2
+ if: github.event_name == 'workflow_run'
+
+ - name: Build example_sdl2_opengl3
+ run: make -C examples/example_sdl2_opengl3
+
+ - name: Build example_sdl3_opengl3
+ run: make -C examples/example_sdl3_opengl3
+
+ - name: Build example_apple_metal
+ run: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_macos
+
+ - name: Build example_apple_opengl2
+ run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2
+
+ Build-iOS:
+ runs-on: macos-14
+ name: Build - iOS
+
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Build example_apple_metal
+ run: |
+ # Code signing is required, but we disable it because it is irrelevant for CI builds.
+ xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_ios CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
+
+ Build-Emscripten:
+ runs-on: ubuntu-latest
+ name: Build - Emscripten
+
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Install Dependencies
+ run: |
+ wget -q https://github.com/emscripten-core/emsdk/archive/master.tar.gz
+ tar -xvf master.tar.gz
+ emsdk-master/emsdk update
+ emsdk-master/emsdk install latest
+ emsdk-master/emsdk activate latest
+ sudo apt-get install build-essential
+
+ - name: Build example_sdl2_opengl3 with Emscripten
+ run: |
+ pushd emsdk-master
+ source ./emsdk_env.sh
+ popd
+ make -C examples/example_sdl2_opengl3 -f Makefile.emscripten
+
+ # This build compiles example_glfw_wgpu using Makefile.emscripten and Emscripten GLFW built-in implementation (-sUSE_GLFW=3)
+ # This ensures 2 things: the make build works, and the GLFW built-in implementation is tested
+ - name: Build example_glfw_wgpu with Emscripten/Makefile
+ run: |
+ pushd emsdk-master
+ source ./emsdk_env.sh
+ popd
+ make -C examples/example_glfw_wgpu -f Makefile.emscripten
+
+ # This build compiles example_glfw_wgpu using CMakeLists.txt and Emscripten GLFW contrib port (--use-port=contrib.glfw3)
+ # This ensures 2 things: the CMake build works, and the GLFW contrib port is tested
+ - name: Build example_glfw_wgpu with Emscripten/CMake
+ run: |
+ pushd emsdk-master
+ source ./emsdk_env.sh
+ popd
+ emcc -v
+ emcmake cmake -B build -DCMAKE_BUILD_TYPE=Release examples/example_glfw_wgpu
+ cmake --build build
+
+ Build-Android:
+ runs-on: ubuntu-latest
+ name: Build - Android
+
+ steps:
+ - uses: actions/checkout@v5
+
+ - name: Build example_android_opengl3
+ run: |
+ cd examples/example_android_opengl3/android
+ gradle assembleDebug --stacktrace
+
+ Test-Windows:
+ runs-on: windows-2025
+ name: Test - Windows
+
+ defaults:
+ run:
+ working-directory: ${{ github.workspace }}/imgui
+
+ env:
+ MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\
+
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: ${{ github.workspace }}/imgui
+
+ - uses: actions/checkout@v5
+ continue-on-error: true
+ with:
+ fetch-depth: 1
+ repository: ocornut/imgui_test_engine
+ path: ${{ github.workspace }}/imgui_test_engine
+ submodules: true
+
+ - name: Fix Tests Projects
+ shell: powershell
+ working-directory: ${{ github.workspace }}/imgui_test_engine
+ run: |
+ # WARNING: This will need updating if toolset/sdk change in project files!
+ gci -recurse -filter "*.vcxproj" | ForEach-Object {
+ # Fix SDK and toolset for most samples.
+ (Get-Content $_.FullName) -Replace "v110","v142" | Set-Content -Path $_.FullName
+ (Get-Content $_.FullName) -Replace "8.1","10.0.20348.0" | Set-Content -Path $_.FullName
+ # Fix SDK and toolset for samples that require newer SDK/toolset. At the moment it is only dx12.
+ (Get-Content $_.FullName) -Replace "v140","v142" | Set-Content -Path $_.FullName
+ (Get-Content $_.FullName) -Replace "10.0.14393.0","10.0.20348.0" | Set-Content -Path $_.FullName
+ }
+
+ - name: Build Tests
+ shell: cmd
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: '"%MSBUILD_PATH%\MSBuild.exe" imgui_test_suite.vcxproj /p:Platform=x64 /p:Configuration=Release /p:ClFlags=/WX -maxcpucount:%NUMBER_OF_PROCESSORS%'
+
+ - name: Run Tests
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: Release/imgui_test_suite.exe -nogui -nopause -v2 -ve4 tests
+
+ - name: Check for Docking
+ id: check_docking
+ shell: bash
+ working-directory: ${{ github.workspace }}/imgui
+ run: echo "has_dock=$(grep -q "#define IMGUI_HAS_DOCK" imgui.h && echo true || echo false)" >> $GITHUB_OUTPUT
+
+ - name: Run Viewport Tests
+ if: steps.check_docking.outputs.has_dock == 'true'
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: Release/imgui_test_suite.exe -nogui -nopause -v2 -ve4 -viewport-mock viewport
+
+ Test-Linux:
+ runs-on: ubuntu-latest
+ name: Test - Linux
+
+ defaults:
+ run:
+ working-directory: ${{ github.workspace }}/imgui
+
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: ${{ github.workspace }}/imgui
+
+ - uses: actions/checkout@v5
+ with:
+ fetch-depth: 1
+ repository: ocornut/imgui_test_engine
+ path: ${{ github.workspace }}/imgui_test_engine
+ submodules: true
+
+ - name: Build Tests
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: make -j$(nproc)
+
+ - name: Run Tests
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: ./imgui_test_suite -nogui -nopause -v2 -ve4 tests
+
+ - name: Check for Docking
+ id: check_docking
+ working-directory: ${{ github.workspace }}/imgui
+ run: echo "has_dock=$(grep -q "#define IMGUI_HAS_DOCK" imgui.h && echo true || echo false)" >> $GITHUB_OUTPUT
+
+ - name: Run Viewport Tests
+ if: steps.check_docking.outputs.has_dock == 'true'
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: ./imgui_test_suite -nogui -nopause -v2 -ve4 -viewport-mock viewport
+
+ Test-MacOS:
+ runs-on: macos-latest
+ name: Test - MacOS
+
+ defaults:
+ run:
+ working-directory: ${{ github.workspace }}/imgui
+
+ steps:
+ - uses: actions/checkout@v5
+ with:
+ path: ${{ github.workspace }}/imgui
+
+ - uses: actions/checkout@v5
+ with:
+ fetch-depth: 1
+ repository: ocornut/imgui_test_engine
+ path: ${{ github.workspace }}/imgui_test_engine
+ submodules: true
+
+ - name: Build Tests
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: make -j$(nproc)
+
+ - name: Run Tests
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: ./imgui_test_suite -nogui -nopause -v2 -ve4 tests
+
+ - name: Check for Docking
+ id: check_docking
+ working-directory: ${{ github.workspace }}/imgui
+ run: echo "has_dock=$(grep -q "#define IMGUI_HAS_DOCK" imgui.h && echo true || echo false)" >> $GITHUB_OUTPUT
+
+ - name: Run Viewport Tests
+ if: steps.check_docking.outputs.has_dock == 'true'
+ working-directory: ${{ github.workspace }}/imgui_test_engine/imgui_test_suite
+ run: ./imgui_test_suite -nogui -nopause -v2 -ve4 -viewport-mock viewport
diff --git a/Alphanium/Source/imgui/.github/workflows/build_windows_vulkan_libs.ps1 b/Alphanium/Source/imgui/.github/workflows/build_windows_vulkan_libs.ps1
new file mode 100644
index 0000000..6658f5b
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/workflows/build_windows_vulkan_libs.ps1
@@ -0,0 +1,38 @@
+# This is current meant to be run manually, occasionally:
+# - Run then zip the contents of vulkanArtifact/ into e.g. vulkan_windows_libs_1.4.326
+# - Upload as an attachment to https://github.com/ocornut/imgui/pull/8925 then change filename in build.yml
+# - There is a build_windows_vulkan_libs.yml in commit history that we removed thinking this is run so rarely we don't need to pollute CI UI with it.
+
+# Set default vulkan version if none provided
+if (-not $env:VULKAN_TAG) { $env:VULKAN_TAG = "1.4.326" }
+
+# Create output folder
+mkdir vulkanArtifact
+
+# Download Vulkan Headers
+
+Invoke-WebRequest -Uri "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v$($env:VULKAN_TAG).zip" -OutFile Vulkan-Headers-$($env:VULKAN_TAG).zip
+Expand-Archive -Path Vulkan-Headers-$($env:VULKAN_TAG).zip
+
+# Copy Vulkan Headers to artifact folder
+
+cp -R Vulkan-Headers-$($env:VULKAN_TAG)\Vulkan-Headers-$($env:VULKAN_TAG)\include vulkanArtifact\Include
+
+# Download Vulkan Loader
+
+Invoke-WebRequest -Uri "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/v$($env:VULKAN_TAG).zip" -OutFile Vulkan-Loader-$($env:VULKAN_TAG).zip
+Expand-Archive -Path Vulkan-Loader-$($env:VULKAN_TAG).zip
+
+# Build Vulkan Loader x64
+
+cmake -S Vulkan-Loader-$($env:VULKAN_TAG)\Vulkan-Loader-$($env:VULKAN_TAG) -B VulkanLoader-build64 -D UPDATE_DEPS=On -A x64
+cmake --build VulkanLoader-build64
+mkdir vulkanArtifact\Lib
+copy VulkanLoader-build64\loader\Debug\vulkan-1.lib vulkanArtifact\Lib
+
+# Build Vulkan Loader win32
+
+cmake -S Vulkan-Loader-$($env:VULKAN_TAG)\Vulkan-Loader-$($env:VULKAN_TAG) -B VulkanLoader-build32 -D UPDATE_DEPS=On -A Win32
+cmake --build VulkanLoader-build32
+mkdir vulkanArtifact\Lib32
+copy VulkanLoader-build32\loader\Debug\vulkan-1.lib vulkanArtifact\Lib32
diff --git a/Alphanium/Source/imgui/.github/workflows/manual.yml b/Alphanium/Source/imgui/.github/workflows/manual.yml
new file mode 100644
index 0000000..3c472f1
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/workflows/manual.yml
@@ -0,0 +1,12 @@
+#
+# This is a dummy workflow used to trigger full builds manually.
+#
+name: manual
+
+on: workflow_dispatch
+
+jobs:
+ manual:
+ runs-on: ubuntu-latest
+ steps:
+ - run: exit 0
diff --git a/Alphanium/Source/imgui/.github/workflows/scheduled.yml b/Alphanium/Source/imgui/.github/workflows/scheduled.yml
new file mode 100644
index 0000000..2a08578
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/workflows/scheduled.yml
@@ -0,0 +1,15 @@
+#
+# This is a dummy workflow used to trigger scheduled builds. Forked repositories most likely should disable this
+# workflow to avoid daily builds of inactive repositories.
+#
+name: scheduled
+
+on:
+ schedule:
+ - cron: '0 9 * * *'
+
+jobs:
+ scheduled:
+ runs-on: ubuntu-latest
+ steps:
+ - run: exit 0
diff --git a/Alphanium/Source/imgui/.github/workflows/static-analysis.yml b/Alphanium/Source/imgui/.github/workflows/static-analysis.yml
new file mode 100644
index 0000000..53db047
--- /dev/null
+++ b/Alphanium/Source/imgui/.github/workflows/static-analysis.yml
@@ -0,0 +1,46 @@
+name: static-analysis
+
+on:
+ workflow_run:
+ # Perform static analysis together with build workflow. Build triggers of "build" workflow do not need to be repeated here.
+ workflows:
+ - build
+ types:
+ - requested
+
+jobs:
+ PVS-Studio:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+
+ - name: Install Dependencies
+ env:
+ # The Secret variable setup in GitHub must be in format: "name_or_email key", on a single line
+ PVS_STUDIO_LICENSE: ${{ secrets.PVS_STUDIO_LICENSE }}
+ run: |
+ if [[ "$PVS_STUDIO_LICENSE" != "" ]];
+ then
+ wget -q https://files.viva64.com/etc/pubkey.txt
+ sudo apt-key add pubkey.txt
+ sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list
+ sudo apt-get update
+ sudo apt-get install -y pvs-studio
+ pvs-studio-analyzer credentials -o pvs-studio.lic $PVS_STUDIO_LICENSE
+ fi
+
+ - name: PVS-Studio static analysis
+ run: |
+ if [[ ! -f pvs-studio.lic ]];
+ then
+ echo "PVS Studio license is missing. No analysis will be performed."
+ echo "If you have a PVS Studio license please create a project secret named PVS_STUDIO_LICENSE with your license."
+ echo "You may use a free license. More information at https://www.viva64.com/en/b/0457/"
+ exit 0
+ fi
+ cd examples/example_null
+ pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
+ pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
+ plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log
diff --git a/Alphanium/Source/imgui/.gitignore b/Alphanium/Source/imgui/.gitignore
new file mode 100644
index 0000000..1aedcf7
--- /dev/null
+++ b/Alphanium/Source/imgui/.gitignore
@@ -0,0 +1,79 @@
+## OSX artifacts
+.DS_Store
+
+## Dear ImGui artifacts
+imgui.ini
+imgui*.ini
+
+## General build artifacts
+*.o
+*.obj
+*.exe
+examples/*/Debug/*
+examples/*/Release/*
+examples/*/x64/*
+examples/*.tmp
+
+## Visual Studio artifacts
+.vs
+ipch
+*.opensdf
+*.log
+*.pdb
+*.ilk
+*.user
+*.sdf
+*.suo
+*.VC.db
+*.VC.VC.opendb
+
+## Getting files created in JSON/Schemas/Catalog/ from a VS2022 update
+JSON/
+
+## Commonly used CMake directories & CMake CPM cache
+build*/
+.cache
+
+## Xcode & macOS artifacts
+project.xcworkspace
+xcuserdata
+examples/*/*.dSYM
+
+## Emscripten artifacts
+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_sdl2_wgpu/web/*
+examples/example_sdl3_opengl3/web/*
+examples/example_sdl3_wgpu/web/*
+
+## JetBrains IDE artifacts
+.idea
+cmake-build-*
+
+## VS code artifacts
+.vscode
+
+## Unix executables from our example Makefiles
+examples/example_apple_metal/example_apple_metal
+examples/example_apple_opengl2/example_apple_opengl2
+examples/example_glfw_metal/example_glfw_metal
+examples/example_glfw_opengl2/example_glfw_opengl2
+examples/example_glfw_opengl3/example_glfw_opengl3
+examples/example_glfw_vulkan/example_glfw_vulkan
+examples/example_glut_opengl2/example_glut_opengl2
+examples/example_null/example_null
+examples/example_sdl2_metal/example_sdl2_metal
+examples/example_sdl2_opengl2/example_sdl2_opengl2
+examples/example_sdl2_opengl3/example_sdl2_opengl3
+examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2
+examples/example_sdl2_vulkan/example_sdl2_vulkan
+examples/example_sdl3_metal/example_sdl3_metal
+examples/example_sdl3_opengl3/example_sdl3_opengl3
+examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3
+examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3
+examples/example_sdl3_vulkan/example_sdl3_vulkan
diff --git a/Alphanium/Source/imgui/LICENSE.txt b/Alphanium/Source/imgui/LICENSE.txt
new file mode 100644
index 0000000..00ae473
--- /dev/null
+++ b/Alphanium/Source/imgui/LICENSE.txt
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014-2025 Omar Cornut
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_allegro5.cpp b/Alphanium/Source/imgui/backends/imgui_impl_allegro5.cpp
new file mode 100644
index 0000000..bb6660d
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_allegro5.cpp
@@ -0,0 +1,698 @@
+// dear imgui: Renderer + Platform Backend for Allegro 5
+// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Clipboard support (from Allegro 5.1.12).
+// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
+// Missing features or Issues:
+// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
+// [ ] Platform: Missing gamepad support.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-09-18: Call platform_io.ClearRendererHandlers() and platform_io.ClearPlatformHandlers() on shutdown.
+// 2025-08-12: Inputs: fixed missing support for ImGuiKey_PrintScreen under Windows, as raw Allegro 5 does not receive it.
+// 2025-08-12: Added ImGui_ImplAllegro5_SetDisplay() function to change current ALLEGRO_DISPLAY, as Allegro applications often need to do that.
+// 2025-07-07: Fixed texture update broken on some platforms where ALLEGRO_LOCK_WRITEONLY needed all texels to be rewritten.
+// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLGPU3_CreateFontsTexture() and ImGui_ImplSDLGPU3_DestroyFontsTexture().
+// 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support.
+// 2025-01-06: Avoid calling al_set_mouse_cursor() repeatedly since it appears to leak on on X11 (#8256).
+// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
+// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
+// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
+// 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5.
+// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
+// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
+// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
+// 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 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)
+// 2021-02-18: Change blending equation to preserve alpha in output buffer.
+// 2020-08-10: Inputs: Fixed horizontal mouse wheel direction.
+// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
+// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
+// 2019-05-11: Inputs: Don't filter character value from ALLEGRO_EVENT_KEY_CHAR before calling AddInputCharacter().
+// 2019-04-30: Renderer: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2018-11-30: Platform: Added touchscreen support.
+// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
+// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
+// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-06-13: Renderer: Stopped using al_draw_indexed_prim() as it is buggy in Allegro's DX9 backend.
+// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
+// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
+// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
+// 2018-04-18: Misc: Added support for 32-bit vertex indices to avoid conversion at runtime. Added imconfig_allegro5.h to enforce 32-bit indices when included from imgui.h.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplAllegro5_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_allegro5.h"
+#include // uint64_t
+#include // memcpy
+
+// Allegro
+#include
+#include
+#ifdef _WIN32
+#include
+#endif
+#define ALLEGRO_HAS_CLIPBOARD ((ALLEGRO_VERSION_INT & ~ALLEGRO_UNSTABLE_BIT) >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
+#define ALLEGRO_HAS_DRAW_INDEXED_PRIM ((ALLEGRO_VERSION_INT & ~ALLEGRO_UNSTABLE_BIT) >= ((5 << 24) | (2 << 16) | ( 5 << 8))) // DX9 implementation of al_draw_indexed_prim() got fixed in Allegro 5.2.5
+
+// Visual Studio warnings
+#ifdef _MSC_VER
+#pragma warning (disable: 4127) // condition expression is constant
+#endif
+
+struct ImDrawVertAllegro
+{
+ ImVec2 pos;
+ ImVec2 uv;
+ ALLEGRO_COLOR col;
+};
+
+// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
+// FIXME-OPT: Consider inlining al_map_rgba()?
+// see https://github.com/liballeg/allegro5/blob/master/src/pixels.c#L554
+// and https://github.com/liballeg/allegro5/blob/master/include/allegro5/internal/aintern_pixels.h
+#define DRAW_VERT_IMGUI_TO_ALLEGRO(DST, SRC) { (DST)->pos = (SRC)->pos; (DST)->uv = (SRC)->uv; unsigned char* c = (unsigned char*)&(SRC)->col; (DST)->col = al_map_rgba(c[0], c[1], c[2], c[3]); }
+
+// Allegro Data
+struct ImGui_ImplAllegro5_Data
+{
+ ALLEGRO_DISPLAY* Display;
+ ALLEGRO_BITMAP* Texture;
+ double Time;
+ ALLEGRO_MOUSE_CURSOR* MouseCursorInvisible;
+ ALLEGRO_VERTEX_DECL* VertexDecl;
+ char* ClipboardTextData;
+ ImGuiMouseCursor LastCursor;
+
+ ImVector BufVertices;
+ ImVector BufIndices;
+
+ ImGui_ImplAllegro5_Data() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
+static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; }
+
+static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
+{
+ // Setup blending
+ al_set_separate_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA, ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA);
+
+ // Setup orthographic projection matrix
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
+ {
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ ALLEGRO_TRANSFORM transform;
+ al_identity_transform(&transform);
+ al_use_transform(&transform);
+ al_orthographic_transform(&transform, L, T, 1.0f, R, B, -1.0f);
+ al_use_projection_transform(&transform);
+ }
+}
+
+// Render function.
+void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
+ // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
+ if (draw_data->Textures != nullptr)
+ for (ImTextureData* tex : *draw_data->Textures)
+ if (tex->Status != ImTextureStatus_OK)
+ ImGui_ImplAllegro5_UpdateTexture(tex);
+
+ // Backup Allegro state that will be modified
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
+ ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
+ int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
+ al_get_clipping_rectangle(&last_clip_x, &last_clip_y, &last_clip_w, &last_clip_h);
+ int last_blender_op, last_blender_src, last_blender_dst;
+ al_get_blender(&last_blender_op, &last_blender_src, &last_blender_dst);
+
+ // Setup desired render state
+ ImGui_ImplAllegro5_SetupRenderState(draw_data);
+
+ // Render command lists
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ ImVector& vertices = bd->BufVertices;
+#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
+ vertices.resize(draw_list->VtxBuffer.Size);
+ for (int i = 0; i < draw_list->VtxBuffer.Size; i++)
+ {
+ const ImDrawVert* src_v = &draw_list->VtxBuffer[i];
+ ImDrawVertAllegro* dst_v = &vertices[i];
+ DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
+ }
+ const int* indices = nullptr;
+ if (sizeof(ImDrawIdx) == 2)
+ {
+ // FIXME-OPT: Allegro doesn't support 16-bit indices.
+ // You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
+ // Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
+ bd->BufIndices.resize(draw_list->IdxBuffer.Size);
+ for (int i = 0; i < draw_list->IdxBuffer.Size; ++i)
+ bd->BufIndices[i] = (int)draw_list->IdxBuffer.Data[i];
+ indices = bd->BufIndices.Data;
+ }
+ else if (sizeof(ImDrawIdx) == 4)
+ {
+ indices = (const int*)draw_list->IdxBuffer.Data;
+ }
+#else
+ // Allegro's implementation of al_draw_indexed_prim() for DX9 was broken until 5.2.5. Unindex buffers ourselves while converting vertex format.
+ vertices.resize(draw_list->IdxBuffer.Size);
+ for (int i = 0; i < draw_list->IdxBuffer.Size; i++)
+ {
+ const ImDrawVert* src_v = &draw_list->VtxBuffer[draw_list->IdxBuffer[i]];
+ ImDrawVertAllegro* dst_v = &vertices[i];
+ DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
+ }
+#endif
+
+ // Render command lists
+ ImVec2 clip_off = draw_data->DisplayPos;
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplAllegro5_SetupRenderState(draw_data);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
+ ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply scissor/clipping rectangle, Draw
+ ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
+ al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
+#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
+ al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
+#else
+ al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
+#endif
+ }
+ }
+ }
+
+ // Restore modified Allegro state
+ al_set_blender(last_blender_op, last_blender_src, last_blender_dst);
+ al_set_clipping_rectangle(last_clip_x, last_clip_y, last_clip_w, last_clip_h);
+ al_use_transform(&last_transform);
+ al_use_projection_transform(&last_projection_transform);
+}
+
+bool ImGui_ImplAllegro5_CreateDeviceObjects()
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+
+ // Create an invisible mouse cursor
+ // Because al_hide_mouse_cursor() seems to mess up with the actual inputs..
+ ALLEGRO_BITMAP* mouse_cursor = al_create_bitmap(8, 8);
+ bd->MouseCursorInvisible = al_create_mouse_cursor(mouse_cursor, 0, 0);
+ al_destroy_bitmap(mouse_cursor);
+
+ return true;
+}
+
+void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex)
+{
+ if (tex->Status == ImTextureStatus_WantCreate)
+ {
+ // Create and upload new texture to graphics system
+ //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+
+ // Create texture
+ // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
+ const int new_bitmap_flags = al_get_new_bitmap_flags();
+ int new_bitmap_format = al_get_new_bitmap_format();
+ al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
+ al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE);
+ ALLEGRO_BITMAP* cpu_bitmap = al_create_bitmap(tex->Width, tex->Height);
+ IM_ASSERT(cpu_bitmap != nullptr && "Backend failed to create texture!");
+
+ // Upload pixels
+ ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap(cpu_bitmap, al_get_bitmap_format(cpu_bitmap), ALLEGRO_LOCK_WRITEONLY);
+ IM_ASSERT(locked_region != nullptr && "Backend failed to create texture!");
+ memcpy(locked_region->data, tex->GetPixels(), tex->GetSizeInBytes());
+ al_unlock_bitmap(cpu_bitmap);
+
+ // Convert software texture to hardware texture.
+ al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP);
+ al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA);
+ ALLEGRO_BITMAP* gpu_bitmap = al_clone_bitmap(cpu_bitmap);
+ al_destroy_bitmap(cpu_bitmap);
+ IM_ASSERT(gpu_bitmap != nullptr && "Backend failed to create texture!");
+
+ al_set_new_bitmap_flags(new_bitmap_flags);
+ al_set_new_bitmap_format(new_bitmap_format);
+
+ // Store identifiers
+ tex->SetTexID((ImTextureID)(intptr_t)gpu_bitmap);
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ else if (tex->Status == ImTextureStatus_WantUpdates)
+ {
+ // Update selected blocks. We only ever write to textures regions which have never been used before!
+ // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
+ ImTextureRect r = tex->UpdateRect; // Bounding box encompassing all individual updates
+ ALLEGRO_BITMAP* gpu_bitmap = (ALLEGRO_BITMAP*)(intptr_t)tex->TexID;
+ ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap_region(gpu_bitmap, r.x, r.y, r.w, r.h, al_get_bitmap_format(gpu_bitmap), ALLEGRO_LOCK_WRITEONLY);
+ IM_ASSERT(locked_region && "Backend failed to update texture!");
+ for (int y = 0; y < r.h; y++)
+ memcpy((unsigned char*)locked_region->data + locked_region->pitch * y, tex->GetPixelsAt(r.x, r.y + y), r.w * tex->BytesPerPixel); // dst, src, block pitch
+ al_unlock_bitmap(gpu_bitmap);
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ else if (tex->Status == ImTextureStatus_WantDestroy)
+ {
+ ALLEGRO_BITMAP* backend_tex = (ALLEGRO_BITMAP*)(intptr_t)tex->TexID;
+ if (backend_tex)
+ al_destroy_bitmap(backend_tex);
+
+ // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
+ tex->SetTexID(ImTextureID_Invalid);
+ tex->SetStatus(ImTextureStatus_Destroyed);
+ }
+}
+
+void ImGui_ImplAllegro5_InvalidateDeviceObjects()
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+
+ // Destroy all textures
+ for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
+ if (tex->RefCount == 1)
+ {
+ tex->SetStatus(ImTextureStatus_WantDestroy);
+ ImGui_ImplAllegro5_UpdateTexture(tex);
+ }
+
+ // Destroy mouse cursor
+ if (bd->MouseCursorInvisible)
+ {
+ al_destroy_mouse_cursor(bd->MouseCursorInvisible);
+ bd->MouseCursorInvisible = nullptr;
+ }
+}
+
+#if ALLEGRO_HAS_CLIPBOARD
+static const char* ImGui_ImplAllegro5_GetClipboardText(ImGuiContext*)
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ if (bd->ClipboardTextData)
+ al_free(bd->ClipboardTextData);
+ bd->ClipboardTextData = al_get_clipboard_text(bd->Display);
+ return bd->ClipboardTextData;
+}
+
+static void ImGui_ImplAllegro5_SetClipboardText(ImGuiContext*, const char* text)
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ al_set_clipboard_text(bd->Display, text);
+}
+#endif
+
+// Not static to allow third-party code to use that if they want to (but undocumented)
+ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code);
+ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code)
+{
+ switch (key_code)
+ {
+ case ALLEGRO_KEY_TAB: return ImGuiKey_Tab;
+ case ALLEGRO_KEY_LEFT: return ImGuiKey_LeftArrow;
+ case ALLEGRO_KEY_RIGHT: return ImGuiKey_RightArrow;
+ case ALLEGRO_KEY_UP: return ImGuiKey_UpArrow;
+ case ALLEGRO_KEY_DOWN: return ImGuiKey_DownArrow;
+ case ALLEGRO_KEY_PGUP: return ImGuiKey_PageUp;
+ case ALLEGRO_KEY_PGDN: return ImGuiKey_PageDown;
+ case ALLEGRO_KEY_HOME: return ImGuiKey_Home;
+ case ALLEGRO_KEY_END: return ImGuiKey_End;
+ case ALLEGRO_KEY_INSERT: return ImGuiKey_Insert;
+ case ALLEGRO_KEY_DELETE: return ImGuiKey_Delete;
+ case ALLEGRO_KEY_BACKSPACE: return ImGuiKey_Backspace;
+ case ALLEGRO_KEY_SPACE: return ImGuiKey_Space;
+ case ALLEGRO_KEY_ENTER: return ImGuiKey_Enter;
+ case ALLEGRO_KEY_ESCAPE: return ImGuiKey_Escape;
+ case ALLEGRO_KEY_QUOTE: return ImGuiKey_Apostrophe;
+ case ALLEGRO_KEY_COMMA: return ImGuiKey_Comma;
+ case ALLEGRO_KEY_MINUS: return ImGuiKey_Minus;
+ case ALLEGRO_KEY_FULLSTOP: return ImGuiKey_Period;
+ case ALLEGRO_KEY_SLASH: return ImGuiKey_Slash;
+ case ALLEGRO_KEY_SEMICOLON: return ImGuiKey_Semicolon;
+ case ALLEGRO_KEY_EQUALS: return ImGuiKey_Equal;
+ case ALLEGRO_KEY_OPENBRACE: return ImGuiKey_LeftBracket;
+ case ALLEGRO_KEY_BACKSLASH: return ImGuiKey_Backslash;
+ case ALLEGRO_KEY_CLOSEBRACE: return ImGuiKey_RightBracket;
+ case ALLEGRO_KEY_TILDE: return ImGuiKey_GraveAccent;
+ case ALLEGRO_KEY_CAPSLOCK: return ImGuiKey_CapsLock;
+ case ALLEGRO_KEY_SCROLLLOCK: return ImGuiKey_ScrollLock;
+ case ALLEGRO_KEY_NUMLOCK: return ImGuiKey_NumLock;
+ case ALLEGRO_KEY_PRINTSCREEN: return ImGuiKey_PrintScreen;
+ case ALLEGRO_KEY_PAUSE: return ImGuiKey_Pause;
+ case ALLEGRO_KEY_PAD_0: return ImGuiKey_Keypad0;
+ case ALLEGRO_KEY_PAD_1: return ImGuiKey_Keypad1;
+ case ALLEGRO_KEY_PAD_2: return ImGuiKey_Keypad2;
+ case ALLEGRO_KEY_PAD_3: return ImGuiKey_Keypad3;
+ case ALLEGRO_KEY_PAD_4: return ImGuiKey_Keypad4;
+ case ALLEGRO_KEY_PAD_5: return ImGuiKey_Keypad5;
+ case ALLEGRO_KEY_PAD_6: return ImGuiKey_Keypad6;
+ case ALLEGRO_KEY_PAD_7: return ImGuiKey_Keypad7;
+ case ALLEGRO_KEY_PAD_8: return ImGuiKey_Keypad8;
+ case ALLEGRO_KEY_PAD_9: return ImGuiKey_Keypad9;
+ case ALLEGRO_KEY_PAD_DELETE: return ImGuiKey_KeypadDecimal;
+ case ALLEGRO_KEY_PAD_SLASH: return ImGuiKey_KeypadDivide;
+ case ALLEGRO_KEY_PAD_ASTERISK: return ImGuiKey_KeypadMultiply;
+ case ALLEGRO_KEY_PAD_MINUS: return ImGuiKey_KeypadSubtract;
+ case ALLEGRO_KEY_PAD_PLUS: return ImGuiKey_KeypadAdd;
+ case ALLEGRO_KEY_PAD_ENTER: return ImGuiKey_KeypadEnter;
+ case ALLEGRO_KEY_PAD_EQUALS: return ImGuiKey_KeypadEqual;
+ case ALLEGRO_KEY_LCTRL: return ImGuiKey_LeftCtrl;
+ case ALLEGRO_KEY_LSHIFT: return ImGuiKey_LeftShift;
+ case ALLEGRO_KEY_ALT: return ImGuiKey_LeftAlt;
+ case ALLEGRO_KEY_LWIN: return ImGuiKey_LeftSuper;
+ case ALLEGRO_KEY_RCTRL: return ImGuiKey_RightCtrl;
+ case ALLEGRO_KEY_RSHIFT: return ImGuiKey_RightShift;
+ case ALLEGRO_KEY_ALTGR: return ImGuiKey_RightAlt;
+ case ALLEGRO_KEY_RWIN: return ImGuiKey_RightSuper;
+ case ALLEGRO_KEY_MENU: return ImGuiKey_Menu;
+ case ALLEGRO_KEY_0: return ImGuiKey_0;
+ case ALLEGRO_KEY_1: return ImGuiKey_1;
+ case ALLEGRO_KEY_2: return ImGuiKey_2;
+ case ALLEGRO_KEY_3: return ImGuiKey_3;
+ case ALLEGRO_KEY_4: return ImGuiKey_4;
+ case ALLEGRO_KEY_5: return ImGuiKey_5;
+ case ALLEGRO_KEY_6: return ImGuiKey_6;
+ case ALLEGRO_KEY_7: return ImGuiKey_7;
+ case ALLEGRO_KEY_8: return ImGuiKey_8;
+ case ALLEGRO_KEY_9: return ImGuiKey_9;
+ case ALLEGRO_KEY_A: return ImGuiKey_A;
+ case ALLEGRO_KEY_B: return ImGuiKey_B;
+ case ALLEGRO_KEY_C: return ImGuiKey_C;
+ case ALLEGRO_KEY_D: return ImGuiKey_D;
+ case ALLEGRO_KEY_E: return ImGuiKey_E;
+ case ALLEGRO_KEY_F: return ImGuiKey_F;
+ case ALLEGRO_KEY_G: return ImGuiKey_G;
+ case ALLEGRO_KEY_H: return ImGuiKey_H;
+ case ALLEGRO_KEY_I: return ImGuiKey_I;
+ case ALLEGRO_KEY_J: return ImGuiKey_J;
+ case ALLEGRO_KEY_K: return ImGuiKey_K;
+ case ALLEGRO_KEY_L: return ImGuiKey_L;
+ case ALLEGRO_KEY_M: return ImGuiKey_M;
+ case ALLEGRO_KEY_N: return ImGuiKey_N;
+ case ALLEGRO_KEY_O: return ImGuiKey_O;
+ case ALLEGRO_KEY_P: return ImGuiKey_P;
+ case ALLEGRO_KEY_Q: return ImGuiKey_Q;
+ case ALLEGRO_KEY_R: return ImGuiKey_R;
+ case ALLEGRO_KEY_S: return ImGuiKey_S;
+ case ALLEGRO_KEY_T: return ImGuiKey_T;
+ case ALLEGRO_KEY_U: return ImGuiKey_U;
+ case ALLEGRO_KEY_V: return ImGuiKey_V;
+ case ALLEGRO_KEY_W: return ImGuiKey_W;
+ case ALLEGRO_KEY_X: return ImGuiKey_X;
+ case ALLEGRO_KEY_Y: return ImGuiKey_Y;
+ case ALLEGRO_KEY_Z: return ImGuiKey_Z;
+ case ALLEGRO_KEY_F1: return ImGuiKey_F1;
+ case ALLEGRO_KEY_F2: return ImGuiKey_F2;
+ case ALLEGRO_KEY_F3: return ImGuiKey_F3;
+ case ALLEGRO_KEY_F4: return ImGuiKey_F4;
+ case ALLEGRO_KEY_F5: return ImGuiKey_F5;
+ case ALLEGRO_KEY_F6: return ImGuiKey_F6;
+ case ALLEGRO_KEY_F7: return ImGuiKey_F7;
+ case ALLEGRO_KEY_F8: return ImGuiKey_F8;
+ case ALLEGRO_KEY_F9: return ImGuiKey_F9;
+ case ALLEGRO_KEY_F10: return ImGuiKey_F10;
+ case ALLEGRO_KEY_F11: return ImGuiKey_F11;
+ case ALLEGRO_KEY_F12: return ImGuiKey_F12;
+ default: return ImGuiKey_None;
+ }
+}
+
+bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplAllegro5_Data* bd = IM_NEW(ImGui_ImplAllegro5_Data)();
+ io.BackendPlatformUserData = (void*)bd;
+ io.BackendPlatformName = io.BackendRendererName = "imgui_impl_allegro5";
+ io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
+
+ bd->LastCursor = ALLEGRO_SYSTEM_MOUSE_CURSOR_NONE;
+
+ ImGui_ImplAllegro5_SetDisplay(display);
+
+#if ALLEGRO_HAS_CLIPBOARD
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ platform_io.Platform_SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
+ platform_io.Platform_GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
+#endif
+
+ return true;
+}
+
+void ImGui_ImplAllegro5_Shutdown()
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ ImGui_ImplAllegro5_InvalidateDeviceObjects();
+ if (bd->VertexDecl)
+ al_destroy_vertex_decl(bd->VertexDecl);
+ if (bd->ClipboardTextData)
+ al_free(bd->ClipboardTextData);
+
+ io.BackendPlatformName = io.BackendRendererName = nullptr;
+ io.BackendPlatformUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_RendererHasTextures);
+ platform_io.ClearRendererHandlers();
+ platform_io.ClearPlatformHandlers();
+ IM_DELETE(bd);
+}
+
+void ImGui_ImplAllegro5_SetDisplay(ALLEGRO_DISPLAY* display)
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ bd->Display = display;
+
+ if (bd->VertexDecl)
+ {
+ al_destroy_vertex_decl(bd->VertexDecl);
+ bd->VertexDecl = NULL;
+ }
+
+ if (bd->Display && !bd->VertexDecl)
+ {
+ // Create custom vertex declaration.
+ // Unfortunately Allegro doesn't support 32-bits packed colors so we have to convert them to 4 floats.
+ // We still use a custom declaration to use 'ALLEGRO_PRIM_TEX_COORD' instead of 'ALLEGRO_PRIM_TEX_COORD_PIXEL' else we can't do a reliable conversion.
+ ALLEGRO_VERTEX_ELEMENT elems[] =
+ {
+ { ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(ImDrawVertAllegro, pos) },
+ { ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(ImDrawVertAllegro, uv) },
+ { ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(ImDrawVertAllegro, col) },
+ { 0, 0, 0 }
+ };
+ bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
+ }
+}
+
+// ev->keyboard.modifiers seems always zero so using that...
+static void ImGui_ImplAllegro5_UpdateKeyModifiers()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ALLEGRO_KEYBOARD_STATE keys;
+ al_get_keyboard_state(&keys);
+ io.AddKeyEvent(ImGuiMod_Ctrl, al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL));
+ io.AddKeyEvent(ImGuiMod_Shift, al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT));
+ io.AddKeyEvent(ImGuiMod_Alt, al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR));
+ io.AddKeyEvent(ImGuiMod_Super, al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN));
+}
+
+// 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.
+bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplAllegro5_Init()?");
+ ImGuiIO& io = ImGui::GetIO();
+
+ switch (ev->type)
+ {
+ case ALLEGRO_EVENT_MOUSE_AXES:
+ if (ev->mouse.display == bd->Display)
+ {
+ io.AddMousePosEvent(ev->mouse.x, ev->mouse.y);
+ io.AddMouseWheelEvent(-ev->mouse.dw, ev->mouse.dz);
+ }
+ return true;
+ case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
+ case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
+ if (ev->mouse.display == bd->Display && ev->mouse.button > 0 && ev->mouse.button <= 5)
+ io.AddMouseButtonEvent(ev->mouse.button - 1, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
+ return true;
+ case ALLEGRO_EVENT_TOUCH_MOVE:
+ if (ev->touch.display == bd->Display)
+ io.AddMousePosEvent(ev->touch.x, ev->touch.y);
+ return true;
+ case ALLEGRO_EVENT_TOUCH_BEGIN:
+ case ALLEGRO_EVENT_TOUCH_END:
+ case ALLEGRO_EVENT_TOUCH_CANCEL:
+ if (ev->touch.display == bd->Display && ev->touch.primary)
+ io.AddMouseButtonEvent(0, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
+ return true;
+ case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
+ if (ev->mouse.display == bd->Display)
+ io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
+ return true;
+ case ALLEGRO_EVENT_KEY_CHAR:
+ if (ev->keyboard.display == bd->Display)
+ if (ev->keyboard.unichar != 0)
+ io.AddInputCharacter((unsigned int)ev->keyboard.unichar);
+ return true;
+ case ALLEGRO_EVENT_KEY_DOWN:
+ case ALLEGRO_EVENT_KEY_UP:
+ if (ev->keyboard.display == bd->Display)
+ {
+ ImGui_ImplAllegro5_UpdateKeyModifiers();
+ ImGuiKey key = ImGui_ImplAllegro5_KeyCodeToImGuiKey(ev->keyboard.keycode);
+ io.AddKeyEvent(key, (ev->type == ALLEGRO_EVENT_KEY_DOWN));
+ io.SetKeyEventNativeData(key, ev->keyboard.keycode, -1); // To support legacy indexing (<1.87 user code)
+ }
+ return true;
+ case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
+ if (ev->display.source == bd->Display)
+ io.AddFocusEvent(false);
+ return true;
+ case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
+ if (ev->display.source == bd->Display)
+ {
+ io.AddFocusEvent(true);
+#if defined(ALLEGRO_UNSTABLE)
+ al_clear_keyboard_state(bd->Display);
+#endif
+ }
+ return true;
+ }
+ return false;
+}
+
+static void ImGui_ImplAllegro5_UpdateMouseCursor()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
+ return;
+
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
+
+ // Hide OS mouse cursor if imgui is drawing it
+ if (io.MouseDrawCursor)
+ imgui_cursor = ImGuiMouseCursor_None;
+
+ if (bd->LastCursor == imgui_cursor)
+ return;
+ bd->LastCursor = imgui_cursor;
+ if (imgui_cursor == ImGuiMouseCursor_None)
+ {
+ al_set_mouse_cursor(bd->Display, bd->MouseCursorInvisible);
+ }
+ else
+ {
+ ALLEGRO_SYSTEM_MOUSE_CURSOR cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_DEFAULT;
+ switch (imgui_cursor)
+ {
+ case ImGuiMouseCursor_TextInput: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_EDIT; break;
+ case ImGuiMouseCursor_ResizeAll: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_MOVE; break;
+ case ImGuiMouseCursor_ResizeNS: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_N; break;
+ case ImGuiMouseCursor_ResizeEW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_E; break;
+ case ImGuiMouseCursor_ResizeNESW: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NE; break;
+ case ImGuiMouseCursor_ResizeNWSE: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_RESIZE_NW; break;
+ case ImGuiMouseCursor_Wait: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_BUSY; break;
+ case ImGuiMouseCursor_Progress: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_PROGRESS; break;
+ case ImGuiMouseCursor_NotAllowed: cursor_id = ALLEGRO_SYSTEM_MOUSE_CURSOR_UNAVAILABLE; break;
+ }
+ al_set_system_mouse_cursor(bd->Display, cursor_id);
+ }
+}
+
+void ImGui_ImplAllegro5_NewFrame()
+{
+ ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplAllegro5_Init()?");
+
+ if (!bd->MouseCursorInvisible)
+ ImGui_ImplAllegro5_CreateDeviceObjects();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ ImGuiIO& io = ImGui::GetIO();
+ int w, h;
+ w = al_get_display_width(bd->Display);
+ h = al_get_display_height(bd->Display);
+ io.DisplaySize = ImVec2((float)w, (float)h);
+
+ // Setup time step
+ double current_time = al_get_time();
+ io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
+ bd->Time = current_time;
+
+ // Allegro 5 doesn't receive PrintScreen under Windows
+#ifdef _WIN32
+ io.AddKeyEvent(ImGuiKey_PrintScreen, (::GetAsyncKeyState(VK_SNAPSHOT) & 0x8000) != 0);
+#endif
+
+ // Setup mouse cursor shape
+ ImGui_ImplAllegro5_UpdateMouseCursor();
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_allegro5.h b/Alphanium/Source/imgui/backends/imgui_impl_allegro5.h
new file mode 100644
index 0000000..6224304
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_allegro5.h
@@ -0,0 +1,44 @@
+// dear imgui: Renderer + Platform Backend for Allegro 5
+// (Info: Allegro 5 is a cross-platform general purpose library for handling windows, inputs, graphics, etc.)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Clipboard support (from Allegro 5.1.12).
+// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
+// Missing features or Issues:
+// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
+// [ ] Platform: Missing gamepad support.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct ALLEGRO_DISPLAY;
+union ALLEGRO_EVENT;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display);
+IMGUI_IMPL_API void ImGui_ImplAllegro5_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplAllegro5_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data);
+IMGUI_IMPL_API bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* event);
+IMGUI_IMPL_API void ImGui_ImplAllegro5_SetDisplay(ALLEGRO_DISPLAY* display);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API bool ImGui_ImplAllegro5_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplAllegro5_InvalidateDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex);
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_android.cpp b/Alphanium/Source/imgui/backends/imgui_impl_android.cpp
new file mode 100644
index 0000000..a76de1c
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_android.cpp
@@ -0,0 +1,308 @@
+// dear imgui: Platform Binding for Android native app
+// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
+
+// Implemented features:
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
+// Missing features or Issues:
+// [ ] Platform: Clipboard support.
+// [ ] Platform: Gamepad support.
+// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
+// Important:
+// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
+// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
+// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
+// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
+// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
+// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
+// 2021-03-04: Initial version.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_android.h"
+#include
+#include
+#include
+#include
+#include
+
+// Android data
+static double g_Time = 0.0;
+static ANativeWindow* g_Window;
+static char g_LogTag[] = "ImGuiExample";
+
+static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code)
+{
+ switch (key_code)
+ {
+ case AKEYCODE_TAB: return ImGuiKey_Tab;
+ case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow;
+ case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow;
+ case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow;
+ case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow;
+ case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp;
+ case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown;
+ case AKEYCODE_MOVE_HOME: return ImGuiKey_Home;
+ case AKEYCODE_MOVE_END: return ImGuiKey_End;
+ case AKEYCODE_INSERT: return ImGuiKey_Insert;
+ case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete;
+ case AKEYCODE_DEL: return ImGuiKey_Backspace;
+ case AKEYCODE_SPACE: return ImGuiKey_Space;
+ case AKEYCODE_ENTER: return ImGuiKey_Enter;
+ case AKEYCODE_ESCAPE: return ImGuiKey_Escape;
+ case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
+ case AKEYCODE_COMMA: return ImGuiKey_Comma;
+ case AKEYCODE_MINUS: return ImGuiKey_Minus;
+ case AKEYCODE_PERIOD: return ImGuiKey_Period;
+ case AKEYCODE_SLASH: return ImGuiKey_Slash;
+ case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon;
+ case AKEYCODE_EQUALS: return ImGuiKey_Equal;
+ case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
+ case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash;
+ case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
+ case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent;
+ case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
+ case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
+ case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock;
+ case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen;
+ case AKEYCODE_BREAK: return ImGuiKey_Pause;
+ case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0;
+ case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1;
+ case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2;
+ case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3;
+ case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4;
+ case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5;
+ case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6;
+ case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7;
+ case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8;
+ case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9;
+ case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal;
+ case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide;
+ case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply;
+ case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract;
+ case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd;
+ case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter;
+ case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual;
+ case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl;
+ case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift;
+ case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt;
+ case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper;
+ case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl;
+ case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift;
+ case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt;
+ case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper;
+ case AKEYCODE_MENU: return ImGuiKey_Menu;
+ case AKEYCODE_0: return ImGuiKey_0;
+ case AKEYCODE_1: return ImGuiKey_1;
+ case AKEYCODE_2: return ImGuiKey_2;
+ case AKEYCODE_3: return ImGuiKey_3;
+ case AKEYCODE_4: return ImGuiKey_4;
+ case AKEYCODE_5: return ImGuiKey_5;
+ case AKEYCODE_6: return ImGuiKey_6;
+ case AKEYCODE_7: return ImGuiKey_7;
+ case AKEYCODE_8: return ImGuiKey_8;
+ case AKEYCODE_9: return ImGuiKey_9;
+ case AKEYCODE_A: return ImGuiKey_A;
+ case AKEYCODE_B: return ImGuiKey_B;
+ case AKEYCODE_C: return ImGuiKey_C;
+ case AKEYCODE_D: return ImGuiKey_D;
+ case AKEYCODE_E: return ImGuiKey_E;
+ case AKEYCODE_F: return ImGuiKey_F;
+ case AKEYCODE_G: return ImGuiKey_G;
+ case AKEYCODE_H: return ImGuiKey_H;
+ case AKEYCODE_I: return ImGuiKey_I;
+ case AKEYCODE_J: return ImGuiKey_J;
+ case AKEYCODE_K: return ImGuiKey_K;
+ case AKEYCODE_L: return ImGuiKey_L;
+ case AKEYCODE_M: return ImGuiKey_M;
+ case AKEYCODE_N: return ImGuiKey_N;
+ case AKEYCODE_O: return ImGuiKey_O;
+ case AKEYCODE_P: return ImGuiKey_P;
+ case AKEYCODE_Q: return ImGuiKey_Q;
+ case AKEYCODE_R: return ImGuiKey_R;
+ case AKEYCODE_S: return ImGuiKey_S;
+ case AKEYCODE_T: return ImGuiKey_T;
+ case AKEYCODE_U: return ImGuiKey_U;
+ case AKEYCODE_V: return ImGuiKey_V;
+ case AKEYCODE_W: return ImGuiKey_W;
+ case AKEYCODE_X: return ImGuiKey_X;
+ case AKEYCODE_Y: return ImGuiKey_Y;
+ case AKEYCODE_Z: return ImGuiKey_Z;
+ case AKEYCODE_F1: return ImGuiKey_F1;
+ case AKEYCODE_F2: return ImGuiKey_F2;
+ case AKEYCODE_F3: return ImGuiKey_F3;
+ case AKEYCODE_F4: return ImGuiKey_F4;
+ case AKEYCODE_F5: return ImGuiKey_F5;
+ case AKEYCODE_F6: return ImGuiKey_F6;
+ case AKEYCODE_F7: return ImGuiKey_F7;
+ case AKEYCODE_F8: return ImGuiKey_F8;
+ case AKEYCODE_F9: return ImGuiKey_F9;
+ case AKEYCODE_F10: return ImGuiKey_F10;
+ case AKEYCODE_F11: return ImGuiKey_F11;
+ case AKEYCODE_F12: return ImGuiKey_F12;
+ default: return ImGuiKey_None;
+ }
+}
+
+int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ int32_t event_type = AInputEvent_getType(input_event);
+ switch (event_type)
+ {
+ case AINPUT_EVENT_TYPE_KEY:
+ {
+ int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
+ int32_t event_scan_code = AKeyEvent_getScanCode(input_event);
+ int32_t event_action = AKeyEvent_getAction(input_event);
+ int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
+
+ io.AddKeyEvent(ImGuiMod_Ctrl, (event_meta_state & AMETA_CTRL_ON) != 0);
+ io.AddKeyEvent(ImGuiMod_Shift, (event_meta_state & AMETA_SHIFT_ON) != 0);
+ io.AddKeyEvent(ImGuiMod_Alt, (event_meta_state & AMETA_ALT_ON) != 0);
+ io.AddKeyEvent(ImGuiMod_Super, (event_meta_state & AMETA_META_ON) != 0);
+
+ switch (event_action)
+ {
+ // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
+ // goes up from a key. We use a simple key event queue/ and process one event per key per frame in
+ // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
+ case AKEY_EVENT_ACTION_DOWN:
+ case AKEY_EVENT_ACTION_UP:
+ {
+ ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code);
+ if (key != ImGuiKey_None)
+ {
+ io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN);
+ io.SetKeyEventNativeData(key, event_key_code, event_scan_code);
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case AINPUT_EVENT_TYPE_MOTION:
+ {
+ int32_t event_action = AMotionEvent_getAction(input_event);
+ int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+ event_action &= AMOTION_EVENT_ACTION_MASK;
+
+ switch (AMotionEvent_getToolType(input_event, event_pointer_index))
+ {
+ case AMOTION_EVENT_TOOL_TYPE_MOUSE:
+ io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
+ break;
+ case AMOTION_EVENT_TOOL_TYPE_STYLUS:
+ case AMOTION_EVENT_TOOL_TYPE_ERASER:
+ io.AddMouseSourceEvent(ImGuiMouseSource_Pen);
+ break;
+ case AMOTION_EVENT_TOOL_TYPE_FINGER:
+ default:
+ io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
+ break;
+ }
+
+ switch (event_action)
+ {
+ case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_UP:
+ {
+ // Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
+ // but we have to process them separately to identify the actual button pressed. This is done below via
+ // AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
+ int tool_type = AMotionEvent_getToolType(input_event, event_pointer_index);
+ if (tool_type == AMOTION_EVENT_TOOL_TYPE_FINGER || tool_type == AMOTION_EVENT_TOOL_TYPE_UNKNOWN)
+ {
+ io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
+ io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN);
+ }
+ break;
+ }
+ case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+ case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+ {
+ int32_t button_state = AMotionEvent_getButtonState(input_event);
+ io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
+ io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
+ io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
+ break;
+ }
+ case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
+ case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
+ io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
+ break;
+ case AMOTION_EVENT_ACTION_SCROLL:
+ io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index));
+ break;
+ default:
+ break;
+ }
+ }
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool ImGui_ImplAndroid_Init(ANativeWindow* window)
+{
+ IMGUI_CHECKVERSION();
+
+ g_Window = window;
+ g_Time = 0.0;
+
+ // Setup backend capabilities flags
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendPlatformName = "imgui_impl_android";
+
+ return true;
+}
+
+void ImGui_ImplAndroid_Shutdown()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendPlatformName = nullptr;
+}
+
+void ImGui_ImplAndroid_NewFrame()
+{
+ ImGuiIO& io = ImGui::GetIO();
+
+ // Setup display size (every frame to accommodate for window resizing)
+ int32_t window_width = ANativeWindow_getWidth(g_Window);
+ int32_t window_height = ANativeWindow_getHeight(g_Window);
+ int display_width = window_width;
+ int display_height = window_height;
+
+ io.DisplaySize = ImVec2((float)window_width, (float)window_height);
+ if (window_width > 0 && window_height > 0)
+ io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
+
+ // Setup time step
+ struct timespec current_timespec;
+ clock_gettime(CLOCK_MONOTONIC, ¤t_timespec);
+ double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
+ io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
+ g_Time = current_time;
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_android.h b/Alphanium/Source/imgui/backends/imgui_impl_android.h
new file mode 100644
index 0000000..f6e4103
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_android.h
@@ -0,0 +1,37 @@
+// dear imgui: Platform Binding for Android native app
+// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
+
+// Implemented features:
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
+// Missing features or Issues:
+// [ ] Platform: Clipboard support.
+// [ ] Platform: Gamepad support.
+// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
+// Important:
+// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
+// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
+// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct ANativeWindow;
+struct AInputEvent;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
+IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event);
+IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx10.cpp b/Alphanium/Source/imgui/backends/imgui_impl_dx10.cpp
new file mode 100644
index 0000000..5650a3c
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx10.cpp
@@ -0,0 +1,659 @@
+// dear imgui: Renderer Backend for DirectX10
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
+// 2025-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
+// 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
+// 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
+// 2024-10-07: DirectX10: Changed default texture sampler to Clamp instead of Repeat/Wrap.
+// 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)
+// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
+// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
+// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
+// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
+// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2016-05-07: DirectX10: Disabling depth-write.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_dx10.h"
+
+// DirectX
+#include
+#include
+#include
+#include
+#ifdef _MSC_VER
+#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
+#endif
+
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#endif
+
+// DirectX10 data
+struct ImGui_ImplDX10_Texture
+{
+ ID3D10Texture2D* pTexture;
+ ID3D10ShaderResourceView* pTextureView;
+};
+
+struct ImGui_ImplDX10_Data
+{
+ ID3D10Device* pd3dDevice;
+ IDXGIFactory* pFactory;
+ ID3D10Buffer* pVB;
+ ID3D10Buffer* pIB;
+ ID3D10VertexShader* pVertexShader;
+ ID3D10InputLayout* pInputLayout;
+ ID3D10Buffer* pVertexConstantBuffer;
+ ID3D10PixelShader* pPixelShader;
+ ID3D10SamplerState* pTexSamplerLinear;
+ ID3D10RasterizerState* pRasterizerState;
+ ID3D10BlendState* pBlendState;
+ ID3D10DepthStencilState* pDepthStencilState;
+ int VertexBufferSize;
+ int IndexBufferSize;
+
+ ImGui_ImplDX10_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
+};
+
+struct VERTEX_CONSTANT_BUFFER_DX10
+{
+ float mvp[4][4];
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
+}
+
+// Functions
+static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device)
+{
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+
+ // Setup viewport
+ D3D10_VIEWPORT vp = {};
+ vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
+ vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0;
+ device->RSSetViewports(1, &vp);
+
+ // Setup orthographic projection matrix into our constant buffer
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
+ void* mapped_resource;
+ if (bd->pVertexConstantBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &mapped_resource) == S_OK)
+ {
+ VERTEX_CONSTANT_BUFFER_DX10* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX10*)mapped_resource;
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
+ bd->pVertexConstantBuffer->Unmap();
+ }
+
+ // Setup shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ device->IASetInputLayout(bd->pInputLayout);
+ device->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
+ device->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
+ device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ device->VSSetShader(bd->pVertexShader);
+ device->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
+ device->PSSetShader(bd->pPixelShader);
+ device->PSSetSamplers(0, 1, &bd->pTexSamplerLinear);
+ device->GSSetShader(nullptr);
+
+ // Setup render state
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ device->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
+ device->OMSetDepthStencilState(bd->pDepthStencilState, 0);
+ device->RSSetState(bd->pRasterizerState);
+}
+
+// Render function
+void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+ ID3D10Device* device = bd->pd3dDevice;
+
+ // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
+ // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
+ if (draw_data->Textures != nullptr)
+ for (ImTextureData* tex : *draw_data->Textures)
+ if (tex->Status != ImTextureStatus_OK)
+ ImGui_ImplDX10_UpdateTexture(tex);
+
+ // Create and grow vertex/index buffers if needed
+ if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
+ bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D10_BUFFER_DESC desc = {};
+ desc.Usage = D3D10_USAGE_DYNAMIC;
+ desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
+ desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ if (device->CreateBuffer(&desc, nullptr, &bd->pVB) < 0)
+ return;
+ }
+
+ if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
+ bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D10_BUFFER_DESC desc = {};
+ desc.Usage = D3D10_USAGE_DYNAMIC;
+ desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
+ desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
+ if (device->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
+ return;
+ }
+
+ // Copy and convert all vertices into a single contiguous buffer
+ ImDrawVert* vtx_dst = nullptr;
+ ImDrawIdx* idx_dst = nullptr;
+ bd->pVB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&vtx_dst);
+ bd->pIB->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&idx_dst);
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += draw_list->VtxBuffer.Size;
+ idx_dst += draw_list->IdxBuffer.Size;
+ }
+ bd->pVB->Unmap();
+ bd->pIB->Unmap();
+
+ // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
+ struct BACKUP_DX10_STATE
+ {
+ UINT ScissorRectsCount, ViewportsCount;
+ D3D10_RECT ScissorRects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ D3D10_VIEWPORT Viewports[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ ID3D10RasterizerState* RS;
+ ID3D10BlendState* BlendState;
+ FLOAT BlendFactor[4];
+ UINT SampleMask;
+ UINT StencilRef;
+ ID3D10DepthStencilState* DepthStencilState;
+ ID3D10ShaderResourceView* PSShaderResource;
+ ID3D10SamplerState* PSSampler;
+ ID3D10PixelShader* PS;
+ ID3D10VertexShader* VS;
+ ID3D10GeometryShader* GS;
+ D3D10_PRIMITIVE_TOPOLOGY PrimitiveTopology;
+ ID3D10Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
+ UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
+ DXGI_FORMAT IndexBufferFormat;
+ ID3D10InputLayout* InputLayout;
+ };
+ BACKUP_DX10_STATE old = {};
+ old.ScissorRectsCount = old.ViewportsCount = D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ device->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
+ device->RSGetViewports(&old.ViewportsCount, old.Viewports);
+ device->RSGetState(&old.RS);
+ device->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
+ device->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
+ device->PSGetShaderResources(0, 1, &old.PSShaderResource);
+ device->PSGetSamplers(0, 1, &old.PSSampler);
+ device->PSGetShader(&old.PS);
+ device->VSGetShader(&old.VS);
+ device->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
+ device->GSGetShader(&old.GS);
+ device->IAGetPrimitiveTopology(&old.PrimitiveTopology);
+ device->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
+ device->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
+ device->IAGetInputLayout(&old.InputLayout);
+
+ // Setup desired DX state
+ ImGui_ImplDX10_SetupRenderState(draw_data, device);
+ // Setup render state structure (for callbacks and custom texture bindings)
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ ImGui_ImplDX10_RenderState render_state;
+ render_state.Device = bd->pd3dDevice;
+ render_state.SamplerDefault = bd->pTexSamplerLinear;
+ render_state.VertexConstantBuffer = bd->pVertexConstantBuffer;
+ platform_io.Renderer_RenderState = &render_state;
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_vtx_offset = 0;
+ int global_idx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ ImVec2 clip_scale = draw_data->FramebufferScale;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != nullptr)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX10_SetupRenderState(draw_data, device);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply scissor/clipping rectangle
+ const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
+ device->RSSetScissorRects(1, &r);
+
+ // Bind texture, Draw
+ ID3D10ShaderResourceView* texture_srv = (ID3D10ShaderResourceView*)pcmd->GetTexID();
+ device->PSSetShaderResources(0, 1, &texture_srv);
+ device->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
+ }
+ }
+ global_idx_offset += draw_list->IdxBuffer.Size;
+ global_vtx_offset += draw_list->VtxBuffer.Size;
+ }
+ platform_io.Renderer_RenderState = nullptr;
+
+ // Restore modified DX state
+ device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
+ device->RSSetViewports(old.ViewportsCount, old.Viewports);
+ device->RSSetState(old.RS); if (old.RS) old.RS->Release();
+ device->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
+ device->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
+ device->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
+ device->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
+ device->PSSetShader(old.PS); if (old.PS) old.PS->Release();
+ device->VSSetShader(old.VS); if (old.VS) old.VS->Release();
+ device->GSSetShader(old.GS); if (old.GS) old.GS->Release();
+ device->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
+ device->IASetPrimitiveTopology(old.PrimitiveTopology);
+ device->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
+ device->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
+ device->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
+}
+
+static void ImGui_ImplDX10_DestroyTexture(ImTextureData* tex)
+{
+ if (ImGui_ImplDX10_Texture* backend_tex = (ImGui_ImplDX10_Texture*)tex->BackendUserData)
+ {
+ IM_ASSERT(backend_tex->pTextureView == (ID3D10ShaderResourceView*)(intptr_t)tex->TexID);
+ backend_tex->pTextureView->Release();
+ backend_tex->pTexture->Release();
+ IM_DELETE(backend_tex);
+
+ // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
+ tex->SetTexID(ImTextureID_Invalid);
+ tex->BackendUserData = nullptr;
+ }
+ tex->SetStatus(ImTextureStatus_Destroyed);
+}
+
+void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex)
+{
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+ if (tex->Status == ImTextureStatus_WantCreate)
+ {
+ // Create and upload new texture to graphics system
+ //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+ unsigned int* pixels = (unsigned int*)tex->GetPixels();
+ ImGui_ImplDX10_Texture* backend_tex = IM_NEW(ImGui_ImplDX10_Texture)();
+
+ // Create texture
+ D3D10_TEXTURE2D_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Width = (UINT)tex->Width;
+ desc.Height = (UINT)tex->Height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.Usage = D3D10_USAGE_DEFAULT;
+ desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+
+ D3D10_SUBRESOURCE_DATA subResource;
+ subResource.pSysMem = pixels;
+ subResource.SysMemPitch = desc.Width * 4;
+ subResource.SysMemSlicePitch = 0;
+ bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &backend_tex->pTexture);
+ IM_ASSERT(backend_tex->pTexture != nullptr && "Backend failed to create texture!");
+
+ // Create texture view
+ D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ ZeroMemory(&srv_desc, sizeof(srv_desc));
+ srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srv_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = desc.MipLevels;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+ bd->pd3dDevice->CreateShaderResourceView(backend_tex->pTexture, &srv_desc, &backend_tex->pTextureView);
+ IM_ASSERT(backend_tex->pTextureView != nullptr && "Backend failed to create texture!");
+
+ // Store identifiers
+ tex->SetTexID((ImTextureID)(intptr_t)backend_tex->pTextureView);
+ tex->SetStatus(ImTextureStatus_OK);
+ tex->BackendUserData = backend_tex;
+ }
+ else if (tex->Status == ImTextureStatus_WantUpdates)
+ {
+ // Update selected blocks. We only ever write to textures regions which have never been used before!
+ // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
+ ImGui_ImplDX10_Texture* backend_tex = (ImGui_ImplDX10_Texture*)tex->BackendUserData;
+ IM_ASSERT(backend_tex->pTextureView == (ID3D10ShaderResourceView*)(intptr_t)tex->TexID);
+ for (ImTextureRect& r : tex->Updates)
+ {
+ D3D10_BOX box = { (UINT)r.x, (UINT)r.y, (UINT)0, (UINT)(r.x + r.w), (UINT)(r.y + r.h), (UINT)1 };
+ bd->pd3dDevice->UpdateSubresource(backend_tex->pTexture, 0, &box, tex->GetPixelsAt(r.x, r.y), (UINT)tex->GetPitch(), 0);
+ }
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
+ ImGui_ImplDX10_DestroyTexture(tex);
+}
+
+bool ImGui_ImplDX10_CreateDeviceObjects()
+{
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+ if (!bd->pd3dDevice)
+ return false;
+ ImGui_ImplDX10_InvalidateDeviceObjects();
+
+ // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX10 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ ID3DBlob* vertexShaderBlob;
+ if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pVertexShader) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+
+ // Create the input layout
+ D3D10_INPUT_ELEMENT_DESC local_layout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, pos), D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, uv), D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)offsetof(ImDrawVert, col), D3D10_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+ vertexShaderBlob->Release();
+
+ // Create the constant buffer
+ {
+ D3D10_BUFFER_DESC desc = {};
+ desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX10);
+ desc.Usage = D3D10_USAGE_DYNAMIC;
+ desc.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer);
+ }
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ sampler sampler0;\
+ Texture2D texture0;\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ ID3DBlob* pixelShaderBlob;
+ if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), &bd->pPixelShader) != S_OK)
+ {
+ pixelShaderBlob->Release();
+ return false;
+ }
+ pixelShaderBlob->Release();
+ }
+
+ // Create the blending setup
+ {
+ D3D10_BLEND_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.AlphaToCoverageEnable = false;
+ desc.BlendEnable[0] = true;
+ desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
+ desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
+ desc.BlendOp = D3D10_BLEND_OP_ADD;
+ desc.SrcBlendAlpha = D3D10_BLEND_ONE;
+ desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
+ desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
+ desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
+ bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
+ }
+
+ // Create the rasterizer state
+ {
+ D3D10_RASTERIZER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.FillMode = D3D10_FILL_SOLID;
+ desc.CullMode = D3D10_CULL_NONE;
+ desc.ScissorEnable = true;
+ desc.DepthClipEnable = true;
+ bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
+ }
+
+ // Create depth-stencil State
+ {
+ D3D10_DEPTH_STENCIL_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D10_COMPARISON_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
+ }
+
+ // Create texture sampler
+ // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
+ {
+ D3D10_SAMPLER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
+ desc.MipLODBias = 0.f;
+ desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.f;
+ desc.MaxLOD = 0.f;
+ bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerLinear);
+ }
+
+ return true;
+}
+
+void ImGui_ImplDX10_InvalidateDeviceObjects()
+{
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+ if (!bd->pd3dDevice)
+ return;
+
+ // Destroy all textures
+ for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
+ if (tex->RefCount == 1)
+ ImGui_ImplDX10_DestroyTexture(tex);
+ if (bd->pTexSamplerLinear) { bd->pTexSamplerLinear->Release(); bd->pTexSamplerLinear = nullptr; }
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
+ if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }
+ if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; }
+ if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; }
+ if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; }
+ if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; }
+ if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; }
+ if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }
+}
+
+bool ImGui_ImplDX10_Init(ID3D10Device* device)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX10_Data* bd = IM_NEW(ImGui_ImplDX10_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_dx10";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
+
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+
+ // Get factory from device
+ IDXGIDevice* pDXGIDevice = nullptr;
+ IDXGIAdapter* pDXGIAdapter = nullptr;
+ IDXGIFactory* pFactory = nullptr;
+ if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
+ if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
+ if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
+ {
+ bd->pd3dDevice = device;
+ bd->pFactory = pFactory;
+ }
+ if (pDXGIDevice) pDXGIDevice->Release();
+ if (pDXGIAdapter) pDXGIAdapter->Release();
+ bd->pd3dDevice->AddRef();
+
+ return true;
+}
+
+void ImGui_ImplDX10_Shutdown()
+{
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ ImGui_ImplDX10_InvalidateDeviceObjects();
+ if (bd->pFactory) { bd->pFactory->Release(); }
+ if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
+
+ io.BackendRendererName = nullptr;
+ io.BackendRendererUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
+ platform_io.ClearRendererHandlers();
+ IM_DELETE(bd);
+}
+
+void ImGui_ImplDX10_NewFrame()
+{
+ ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX10_Init()?");
+
+ if (!bd->pVertexShader)
+ if (!ImGui_ImplDX10_CreateDeviceObjects())
+ IM_ASSERT(0 && "ImGui_ImplDX10_CreateDeviceObjects() failed!");
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx10.h b/Alphanium/Source/imgui/backends/imgui_impl_dx10.h
new file mode 100644
index 0000000..38ecbdf
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx10.h
@@ -0,0 +1,48 @@
+// dear imgui: Renderer Backend for DirectX10
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct ID3D10Device;
+struct ID3D10SamplerState;
+struct ID3D10Buffer;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplDX10_Init(ID3D10Device* device);
+IMGUI_IMPL_API void ImGui_ImplDX10_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX10_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API bool ImGui_ImplDX10_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplDX10_InvalidateDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex);
+
+// [BETA] Selected render state data shared with callbacks.
+// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX10_RenderDrawData() call.
+// (Please open an issue if you feel you need access to more data)
+struct ImGui_ImplDX10_RenderState
+{
+ ID3D10Device* Device;
+ ID3D10SamplerState* SamplerDefault;
+ ID3D10Buffer* VertexConstantBuffer;
+};
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx11.cpp b/Alphanium/Source/imgui/backends/imgui_impl_dx11.cpp
new file mode 100644
index 0000000..8789304
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx11.cpp
@@ -0,0 +1,679 @@
+// dear imgui: Renderer Backend for DirectX11
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
+// 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
+// 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
+// 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler.
+// 2024-10-07: DirectX11: Changed default texture sampler to Clamp instead of Repeat/Wrap.
+// 2024-10-07: DirectX11: Expose selected render state in ImGui_ImplDX11_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
+// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
+// 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)
+// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
+// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
+// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX11_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
+// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility.
+// 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions.
+// 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example.
+// 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2016-05-07: DirectX11: Disabling depth-write.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_dx11.h"
+
+// DirectX
+#include
+#include
+#include
+#ifdef _MSC_VER
+#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
+#endif
+
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#endif
+
+// DirectX11 data
+struct ImGui_ImplDX11_Texture
+{
+ ID3D11Texture2D* pTexture;
+ ID3D11ShaderResourceView* pTextureView;
+};
+
+struct ImGui_ImplDX11_Data
+{
+ ID3D11Device* pd3dDevice;
+ ID3D11DeviceContext* pd3dDeviceContext;
+ IDXGIFactory* pFactory;
+ ID3D11Buffer* pVB;
+ ID3D11Buffer* pIB;
+ ID3D11VertexShader* pVertexShader;
+ ID3D11InputLayout* pInputLayout;
+ ID3D11Buffer* pVertexConstantBuffer;
+ ID3D11PixelShader* pPixelShader;
+ ID3D11SamplerState* pTexSamplerLinear;
+ ID3D11RasterizerState* pRasterizerState;
+ ID3D11BlendState* pBlendState;
+ ID3D11DepthStencilState* pDepthStencilState;
+ int VertexBufferSize;
+ int IndexBufferSize;
+
+ ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
+};
+
+struct VERTEX_CONSTANT_BUFFER_DX11
+{
+ float mvp[4][4];
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
+}
+
+// Functions
+static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11DeviceContext* device_ctx)
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+
+ // Setup viewport
+ D3D11_VIEWPORT vp = {};
+ vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x;
+ vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0;
+ device_ctx->RSSetViewports(1, &vp);
+
+ // Setup orthographic projection matrix into our constant buffer
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if (device_ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) == S_OK)
+ {
+ VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData;
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&constant_buffer->mvp, mvp, sizeof(mvp));
+ device_ctx->Unmap(bd->pVertexConstantBuffer, 0);
+ }
+
+ // Setup shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ device_ctx->IASetInputLayout(bd->pInputLayout);
+ device_ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset);
+ device_ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0);
+ device_ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ device_ctx->VSSetShader(bd->pVertexShader, nullptr, 0);
+ device_ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer);
+ device_ctx->PSSetShader(bd->pPixelShader, nullptr, 0);
+ device_ctx->PSSetSamplers(0, 1, &bd->pTexSamplerLinear);
+ device_ctx->GSSetShader(nullptr, nullptr, 0);
+ device_ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
+ device_ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
+ device_ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
+
+ // Setup render state
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ device_ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
+ device_ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
+ device_ctx->RSSetState(bd->pRasterizerState);
+}
+
+// Render function
+void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ ID3D11DeviceContext* device = bd->pd3dDeviceContext;
+
+ // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
+ // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
+ if (draw_data->Textures != nullptr)
+ for (ImTextureData* tex : *draw_data->Textures)
+ if (tex->Status != ImTextureStatus_OK)
+ ImGui_ImplDX11_UpdateTexture(tex);
+
+ // Create and grow vertex/index buffers if needed
+ if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
+ bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D11_BUFFER_DESC desc = {};
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVB) < 0)
+ return;
+ }
+ if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
+ bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D11_BUFFER_DESC desc = {};
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
+ desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
+ return;
+ }
+
+ // Upload vertex/index data into a single contiguous GPU buffer
+ D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource;
+ if (device->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK)
+ return;
+ if (device->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK)
+ return;
+ ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData;
+ ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += draw_list->VtxBuffer.Size;
+ idx_dst += draw_list->IdxBuffer.Size;
+ }
+ device->Unmap(bd->pVB, 0);
+ device->Unmap(bd->pIB, 0);
+
+ // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!)
+ struct BACKUP_DX11_STATE
+ {
+ UINT ScissorRectsCount, ViewportsCount;
+ D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE];
+ ID3D11RasterizerState* RS;
+ ID3D11BlendState* BlendState;
+ FLOAT BlendFactor[4];
+ UINT SampleMask;
+ UINT StencilRef;
+ ID3D11DepthStencilState* DepthStencilState;
+ ID3D11ShaderResourceView* PSShaderResource;
+ ID3D11SamplerState* PSSampler;
+ ID3D11PixelShader* PS;
+ ID3D11VertexShader* VS;
+ ID3D11GeometryShader* GS;
+ UINT PSInstancesCount, VSInstancesCount, GSInstancesCount;
+ ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation
+ D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology;
+ ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer;
+ UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset;
+ DXGI_FORMAT IndexBufferFormat;
+ ID3D11InputLayout* InputLayout;
+ };
+ BACKUP_DX11_STATE old = {};
+ old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;
+ device->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects);
+ device->RSGetViewports(&old.ViewportsCount, old.Viewports);
+ device->RSGetState(&old.RS);
+ device->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask);
+ device->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef);
+ device->PSGetShaderResources(0, 1, &old.PSShaderResource);
+ device->PSGetSamplers(0, 1, &old.PSSampler);
+ old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256;
+ device->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount);
+ device->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount);
+ device->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer);
+ device->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount);
+
+ device->IAGetPrimitiveTopology(&old.PrimitiveTopology);
+ device->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset);
+ device->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset);
+ device->IAGetInputLayout(&old.InputLayout);
+
+ // Setup desired DX state
+ ImGui_ImplDX11_SetupRenderState(draw_data, device);
+
+ // Setup render state structure (for callbacks and custom texture bindings)
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ ImGui_ImplDX11_RenderState render_state;
+ render_state.Device = bd->pd3dDevice;
+ render_state.DeviceContext = bd->pd3dDeviceContext;
+ render_state.SamplerDefault = bd->pTexSamplerLinear;
+ render_state.VertexConstantBuffer = bd->pVertexConstantBuffer;
+ platform_io.Renderer_RenderState = &render_state;
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_idx_offset = 0;
+ int global_vtx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ ImVec2 clip_scale = draw_data->FramebufferScale;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != nullptr)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX11_SetupRenderState(draw_data, device);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply scissor/clipping rectangle
+ const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
+ device->RSSetScissorRects(1, &r);
+
+ // Bind texture, Draw
+ ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID();
+ device->PSSetShaderResources(0, 1, &texture_srv);
+ device->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset);
+ }
+ }
+ global_idx_offset += draw_list->IdxBuffer.Size;
+ global_vtx_offset += draw_list->VtxBuffer.Size;
+ }
+ platform_io.Renderer_RenderState = nullptr;
+
+ // Restore modified DX state
+ device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
+ device->RSSetViewports(old.ViewportsCount, old.Viewports);
+ device->RSSetState(old.RS); if (old.RS) old.RS->Release();
+ device->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release();
+ device->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release();
+ device->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release();
+ device->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release();
+ device->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release();
+ for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release();
+ device->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release();
+ device->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release();
+ device->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release();
+ for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release();
+ device->IASetPrimitiveTopology(old.PrimitiveTopology);
+ device->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release();
+ device->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release();
+ device->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release();
+}
+
+static void ImGui_ImplDX11_DestroyTexture(ImTextureData* tex)
+{
+ if (ImGui_ImplDX11_Texture* backend_tex = (ImGui_ImplDX11_Texture*)tex->BackendUserData)
+ {
+ IM_ASSERT(backend_tex->pTextureView == (ID3D11ShaderResourceView*)(intptr_t)tex->TexID);
+ backend_tex->pTextureView->Release();
+ backend_tex->pTexture->Release();
+ IM_DELETE(backend_tex);
+
+ // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
+ tex->SetTexID(ImTextureID_Invalid);
+ tex->BackendUserData = nullptr;
+ }
+ tex->SetStatus(ImTextureStatus_Destroyed);
+}
+
+void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex)
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (tex->Status == ImTextureStatus_WantCreate)
+ {
+ // Create and upload new texture to graphics system
+ //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+ unsigned int* pixels = (unsigned int*)tex->GetPixels();
+ ImGui_ImplDX11_Texture* backend_tex = IM_NEW(ImGui_ImplDX11_Texture)();
+
+ // Create texture
+ D3D11_TEXTURE2D_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Width = (UINT)tex->Width;
+ desc.Height = (UINT)tex->Height;
+ desc.MipLevels = 1;
+ desc.ArraySize = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ desc.CPUAccessFlags = 0;
+ D3D11_SUBRESOURCE_DATA subResource;
+ subResource.pSysMem = pixels;
+ subResource.SysMemPitch = desc.Width * 4;
+ subResource.SysMemSlicePitch = 0;
+ bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &backend_tex->pTexture);
+ IM_ASSERT(backend_tex->pTexture != nullptr && "Backend failed to create texture!");
+
+ // Create texture view
+ D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ bd->pd3dDevice->CreateShaderResourceView(backend_tex->pTexture, &srvDesc, &backend_tex->pTextureView);
+ IM_ASSERT(backend_tex->pTextureView != nullptr && "Backend failed to create texture!");
+
+ // Store identifiers
+ tex->SetTexID((ImTextureID)(intptr_t)backend_tex->pTextureView);
+ tex->SetStatus(ImTextureStatus_OK);
+ tex->BackendUserData = backend_tex;
+ }
+ else if (tex->Status == ImTextureStatus_WantUpdates)
+ {
+ // Update selected blocks. We only ever write to textures regions which have never been used before!
+ // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
+ ImGui_ImplDX11_Texture* backend_tex = (ImGui_ImplDX11_Texture*)tex->BackendUserData;
+ IM_ASSERT(backend_tex->pTextureView == (ID3D11ShaderResourceView*)(intptr_t)tex->TexID);
+ for (ImTextureRect& r : tex->Updates)
+ {
+ D3D11_BOX box = { (UINT)r.x, (UINT)r.y, (UINT)0, (UINT)(r.x + r.w), (UINT)(r.y + r .h), (UINT)1 };
+ bd->pd3dDeviceContext->UpdateSubresource(backend_tex->pTexture, 0, &box, tex->GetPixelsAt(r.x, r.y), (UINT)tex->GetPitch(), 0);
+ }
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
+ ImGui_ImplDX11_DestroyTexture(tex);
+}
+
+bool ImGui_ImplDX11_CreateDeviceObjects()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (!bd->pd3dDevice)
+ return false;
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+
+ // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX11 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ ID3DBlob* vertexShaderBlob;
+ if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &bd->pVertexShader) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+
+ // Create the input layout
+ D3D11_INPUT_ELEMENT_DESC local_layout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)offsetof(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+ if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK)
+ {
+ vertexShaderBlob->Release();
+ return false;
+ }
+ vertexShaderBlob->Release();
+
+ // Create the constant buffer
+ {
+ D3D11_BUFFER_DESC desc = {};
+ desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11);
+ desc.Usage = D3D11_USAGE_DYNAMIC;
+ desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ desc.MiscFlags = 0;
+ bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer);
+ }
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ sampler sampler0;\
+ Texture2D texture0;\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ ID3DBlob* pixelShaderBlob;
+ if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK)
+ {
+ pixelShaderBlob->Release();
+ return false;
+ }
+ pixelShaderBlob->Release();
+ }
+
+ // Create the blending setup
+ {
+ D3D11_BLEND_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState);
+ }
+
+ // Create the rasterizer state
+ {
+ D3D11_RASTERIZER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.FillMode = D3D11_FILL_SOLID;
+ desc.CullMode = D3D11_CULL_NONE;
+ desc.ScissorEnable = true;
+ desc.DepthClipEnable = true;
+ bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState);
+ }
+
+ // Create depth-stencil State
+ {
+ D3D11_DEPTH_STENCIL_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
+ }
+
+ // Create texture sampler
+ // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
+ {
+ D3D11_SAMPLER_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.MipLODBias = 0.f;
+ desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ desc.MinLOD = 0.f;
+ desc.MaxLOD = 0.f;
+ bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerLinear);
+ }
+
+ return true;
+}
+
+void ImGui_ImplDX11_InvalidateDeviceObjects()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ if (!bd->pd3dDevice)
+ return;
+
+ // Destroy all textures
+ for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
+ if (tex->RefCount == 1)
+ ImGui_ImplDX11_DestroyTexture(tex);
+
+ if (bd->pTexSamplerLinear) { bd->pTexSamplerLinear->Release(); bd->pTexSamplerLinear = nullptr; }
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
+ if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; }
+ if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; }
+ if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; }
+ if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; }
+ if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; }
+ if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; }
+ if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; }
+}
+
+bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_dx11";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
+
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
+
+ // Get factory from device
+ IDXGIDevice* pDXGIDevice = nullptr;
+ IDXGIAdapter* pDXGIAdapter = nullptr;
+ IDXGIFactory* pFactory = nullptr;
+
+ if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK)
+ if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK)
+ if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK)
+ {
+ bd->pd3dDevice = device;
+ bd->pd3dDeviceContext = device_context;
+ bd->pFactory = pFactory;
+ }
+ if (pDXGIDevice) pDXGIDevice->Release();
+ if (pDXGIAdapter) pDXGIAdapter->Release();
+ bd->pd3dDevice->AddRef();
+ bd->pd3dDeviceContext->AddRef();
+
+ return true;
+}
+
+void ImGui_ImplDX11_Shutdown()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ ImGui_ImplDX11_InvalidateDeviceObjects();
+ if (bd->pFactory) { bd->pFactory->Release(); }
+ if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
+ if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); }
+
+ io.BackendRendererName = nullptr;
+ io.BackendRendererUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
+ platform_io.ClearRendererHandlers();
+ IM_DELETE(bd);
+}
+
+void ImGui_ImplDX11_NewFrame()
+{
+ ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX11_Init()?");
+
+ if (!bd->pVertexShader)
+ if (!ImGui_ImplDX11_CreateDeviceObjects())
+ IM_ASSERT(0 && "ImGui_ImplDX11_CreateDeviceObjects() failed!");
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx11.h b/Alphanium/Source/imgui/backends/imgui_impl_dx11.h
new file mode 100644
index 0000000..c120bf0
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx11.h
@@ -0,0 +1,51 @@
+// dear imgui: Renderer Backend for DirectX11
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct ID3D11Device;
+struct ID3D11DeviceContext;
+struct ID3D11SamplerState;
+struct ID3D11Buffer;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context);
+IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex);
+
+// [BETA] Selected render state data shared with callbacks.
+// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX11_RenderDrawData() call.
+// (Please open an issue if you feel you need access to more data)
+struct ImGui_ImplDX11_RenderState
+{
+ ID3D11Device* Device;
+ ID3D11DeviceContext* DeviceContext;
+ ID3D11SamplerState* SamplerDefault;
+ ID3D11Buffer* VertexConstantBuffer;
+};
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx12.cpp b/Alphanium/Source/imgui/backends/imgui_impl_dx12.cpp
new file mode 100644
index 0000000..d4da6ab
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx12.cpp
@@ -0,0 +1,971 @@
+// dear imgui: Renderer Backend for DirectX12
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
+
+// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
+// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
+// 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
+// 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965)
+// 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963)
+// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
+// 2025-06-19: Fixed build on MinGW. (#8702, #4594)
+// 2025-06-11: DirectX12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
+// 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
+// 2025-02-24: DirectX12: Fixed an issue where ImGui_ImplDX12_Init() signature change from 2024-11-15 combined with change from 2025-01-15 made legacy ImGui_ImplDX12_Init() crash. (#8429)
+// 2025-01-15: DirectX12: Texture upload use the command queue provided in ImGui_ImplDX12_InitInfo instead of creating its own.
+// 2024-12-09: DirectX12: Let user specifies the DepthStencilView format by setting ImGui_ImplDX12_InitInfo::DSVFormat.
+// 2024-11-15: DirectX12: *BREAKING CHANGE* Changed ImGui_ImplDX12_Init() signature to take a ImGui_ImplDX12_InitInfo struct. Legacy ImGui_ImplDX12_Init() signature is still supported (will obsolete).
+// 2024-11-15: DirectX12: *BREAKING CHANGE* User is now required to pass function pointers to allocate/free SRV Descriptors. We provide convenience legacy fields to pass a single descriptor, matching the old API, but upcoming features will want multiple.
+// 2024-10-23: DirectX12: Unmap() call specify written range. The range is informational and may be used by debug tools.
+// 2024-10-07: DirectX12: Changed default texture sampler to Clamp instead of Repeat/Wrap.
+// 2024-10-07: DirectX12: Expose selected render state in ImGui_ImplDX12_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
+// 2024-10-07: DirectX12: Compiling with '#define ImTextureID=ImU64' is unnecessary now that dear imgui defaults ImTextureID to u64 instead of void*.
+// 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)
+// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
+// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
+// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
+// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
+// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
+// 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-03-29: Misc: Various minor tidying up.
+// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData().
+// 2018-06-08: Misc: Extracted imgui_impl_dx12.cpp/.h away from the old combined DX12+Win32 example.
+// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
+// 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_dx12.h"
+
+// DirectX
+#include
+#include
+#include
+#ifdef _MSC_VER
+#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
+#endif
+
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#endif
+
+// MinGW workaround, see #4594
+typedef decltype(D3D12SerializeRootSignature) *_PFN_D3D12_SERIALIZE_ROOT_SIGNATURE;
+
+// DirectX12 data
+struct ImGui_ImplDX12_RenderBuffers;
+
+struct ImGui_ImplDX12_Texture
+{
+ ID3D12Resource* pTextureResource;
+ D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
+ D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
+
+ ImGui_ImplDX12_Texture() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+struct ImGui_ImplDX12_Data
+{
+ ImGui_ImplDX12_InitInfo InitInfo;
+ IDXGIFactory5* pdxgiFactory;
+ ID3D12Device* pd3dDevice;
+ ID3D12RootSignature* pRootSignature;
+ ID3D12PipelineState* pPipelineState;
+ ID3D12CommandQueue* pCommandQueue;
+ bool commandQueueOwned;
+ DXGI_FORMAT RTVFormat;
+ DXGI_FORMAT DSVFormat;
+ ID3D12DescriptorHeap* pd3dSrvDescHeap;
+ ID3D12Fence* Fence;
+ UINT64 FenceLastSignaledValue;
+ HANDLE FenceEvent;
+ UINT numFramesInFlight;
+ bool tearingSupport;
+ bool LegacySingleDescriptorUsed;
+
+ ID3D12CommandAllocator* pTexCmdAllocator;
+ ID3D12GraphicsCommandList* pTexCmdList;
+ ID3D12Resource* pTexUploadBuffer;
+ UINT pTexUploadBufferSize;
+ void* pTexUploadBufferMapped;
+
+ ImGui_ImplDX12_RenderBuffers* pFrameResources;
+ UINT frameIndex;
+
+ ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
+}
+
+// Buffers used during the rendering of a frame
+struct ImGui_ImplDX12_RenderBuffers
+{
+ ID3D12Resource* IndexBuffer;
+ ID3D12Resource* VertexBuffer;
+ int IndexBufferSize;
+ int VertexBufferSize;
+};
+
+struct VERTEX_CONSTANT_BUFFER_DX12
+{
+ float mvp[4][4];
+};
+
+// Functions
+static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list, ImGui_ImplDX12_RenderBuffers* fr)
+{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+
+ // Setup orthographic projection matrix into our constant buffer
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
+ VERTEX_CONSTANT_BUFFER_DX12 vertex_constant_buffer;
+ {
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float mvp[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 0.5f, 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
+ };
+ memcpy(&vertex_constant_buffer.mvp, mvp, sizeof(mvp));
+ }
+
+ // Setup viewport
+ D3D12_VIEWPORT vp = {};
+ vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x;
+ vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = vp.TopLeftY = 0.0f;
+ command_list->RSSetViewports(1, &vp);
+
+ // Bind shader and vertex buffers
+ unsigned int stride = sizeof(ImDrawVert);
+ unsigned int offset = 0;
+ D3D12_VERTEX_BUFFER_VIEW vbv = {};
+ vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset;
+ vbv.SizeInBytes = fr->VertexBufferSize * stride;
+ vbv.StrideInBytes = stride;
+ command_list->IASetVertexBuffers(0, 1, &vbv);
+ D3D12_INDEX_BUFFER_VIEW ibv = {};
+ ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress();
+ ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx);
+ ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
+ command_list->IASetIndexBuffer(&ibv);
+ command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+ command_list->SetPipelineState(bd->pPipelineState);
+ command_list->SetGraphicsRootSignature(bd->pRootSignature);
+ command_list->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
+
+ // Setup blend factor
+ const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
+ command_list->OMSetBlendFactor(blend_factor);
+}
+
+template
+static inline void SafeRelease(T*& res)
+{
+ if (res)
+ res->Release();
+ res = nullptr;
+}
+
+// Render function
+void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
+ // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
+ if (draw_data->Textures != nullptr)
+ for (ImTextureData* tex : *draw_data->Textures)
+ if (tex->Status != ImTextureStatus_OK)
+ ImGui_ImplDX12_UpdateTexture(tex);
+
+ // FIXME: We are assuming that this only gets called once per frame!
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ bd->frameIndex = bd->frameIndex + 1;
+ ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
+
+ // Create and grow vertex/index buffers if needed
+ if (fr->VertexBuffer == nullptr || fr->VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ SafeRelease(fr->VertexBuffer);
+ fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ D3D12_HEAP_PROPERTIES props = {};
+ props.Type = D3D12_HEAP_TYPE_UPLOAD;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ D3D12_RESOURCE_DESC desc = {};
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert);
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+ if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
+ return;
+ }
+ if (fr->IndexBuffer == nullptr || fr->IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ SafeRelease(fr->IndexBuffer);
+ fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ D3D12_HEAP_PROPERTIES props = {};
+ props.Type = D3D12_HEAP_TYPE_UPLOAD;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+ D3D12_RESOURCE_DESC desc = {};
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx);
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+ if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
+ return;
+ }
+
+ // Upload vertex/index data into a single contiguous GPU buffer
+ // During Map() we specify a null read range (as per DX12 API, this is informational and for tooling only)
+ void* vtx_resource, *idx_resource;
+ D3D12_RANGE range = { 0, 0 };
+ if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK)
+ return;
+ if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK)
+ return;
+ ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
+ ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ memcpy(vtx_dst, draw_list->VtxBuffer.Data, draw_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ vtx_dst += draw_list->VtxBuffer.Size;
+ idx_dst += draw_list->IdxBuffer.Size;
+ }
+
+ // During Unmap() we specify the written range (as per DX12 API, this is informational and for tooling only)
+ range.End = (SIZE_T)((intptr_t)vtx_dst - (intptr_t)vtx_resource);
+ IM_ASSERT(range.End == draw_data->TotalVtxCount * sizeof(ImDrawVert));
+ fr->VertexBuffer->Unmap(0, &range);
+ range.End = (SIZE_T)((intptr_t)idx_dst - (intptr_t)idx_resource);
+ IM_ASSERT(range.End == draw_data->TotalIdxCount * sizeof(ImDrawIdx));
+ fr->IndexBuffer->Unmap(0, &range);
+
+ // Setup desired DX state
+ ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr);
+
+ // Setup render state structure (for callbacks and custom texture bindings)
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ ImGui_ImplDX12_RenderState render_state;
+ render_state.Device = bd->pd3dDevice;
+ render_state.CommandList = command_list;
+ platform_io.Renderer_RenderState = &render_state;
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_vtx_offset = 0;
+ int global_idx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ ImVec2 clip_scale = draw_data->FramebufferScale;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != nullptr)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply scissor/clipping rectangle
+ const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
+ command_list->RSSetScissorRects(1, &r);
+
+ // Bind texture, Draw
+ D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
+ texture_handle.ptr = (UINT64)pcmd->GetTexID();
+ command_list->SetGraphicsRootDescriptorTable(1, texture_handle);
+ command_list->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
+ }
+ }
+ global_idx_offset += draw_list->IdxBuffer.Size;
+ global_vtx_offset += draw_list->VtxBuffer.Size;
+ }
+ platform_io.Renderer_RenderState = nullptr;
+}
+
+static void ImGui_ImplDX12_DestroyTexture(ImTextureData* tex)
+{
+ if (ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData)
+ {
+ IM_ASSERT(backend_tex->hFontSrvGpuDescHandle.ptr == (UINT64)tex->TexID);
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, backend_tex->hFontSrvCpuDescHandle, backend_tex->hFontSrvGpuDescHandle);
+ SafeRelease(backend_tex->pTextureResource);
+ backend_tex->hFontSrvCpuDescHandle.ptr = 0;
+ backend_tex->hFontSrvGpuDescHandle.ptr = 0;
+ IM_DELETE(backend_tex);
+
+ // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
+ tex->SetTexID(ImTextureID_Invalid);
+ tex->BackendUserData = nullptr;
+ }
+ tex->SetStatus(ImTextureStatus_Destroyed);
+}
+
+void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex)
+{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ bool need_barrier_before_copy = true; // Do we need a resource barrier before we copy new data in?
+
+ if (tex->Status == ImTextureStatus_WantCreate)
+ {
+ // Create and upload new texture to graphics system
+ //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+ ImGui_ImplDX12_Texture* backend_tex = IM_NEW(ImGui_ImplDX12_Texture)();
+ bd->InitInfo.SrvDescriptorAllocFn(&bd->InitInfo, &backend_tex->hFontSrvCpuDescHandle, &backend_tex->hFontSrvGpuDescHandle); // Allocate a desctriptor handle
+
+ D3D12_HEAP_PROPERTIES props = {};
+ props.Type = D3D12_HEAP_TYPE_DEFAULT;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+
+ D3D12_RESOURCE_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+ desc.Alignment = 0;
+ desc.Width = tex->Width;
+ desc.Height = tex->Height;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ ID3D12Resource* pTexture = nullptr;
+ bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
+ D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pTexture));
+
+ // Create SRV
+ D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
+ ZeroMemory(&srvDesc, sizeof(srvDesc));
+ srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+ srvDesc.Texture2D.MipLevels = desc.MipLevels;
+ srvDesc.Texture2D.MostDetailedMip = 0;
+ srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+ bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, backend_tex->hFontSrvCpuDescHandle);
+ SafeRelease(backend_tex->pTextureResource);
+ backend_tex->pTextureResource = pTexture;
+
+ // Store identifiers
+ tex->SetTexID((ImTextureID)backend_tex->hFontSrvGpuDescHandle.ptr);
+ tex->BackendUserData = backend_tex;
+ need_barrier_before_copy = false; // Because this is a newly-created texture it will be in D3D12_RESOURCE_STATE_COMMON and thus we don't need a barrier
+ // We don't set tex->Status to ImTextureStatus_OK to let the code fallthrough below.
+ }
+
+ if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates)
+ {
+ ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData;
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+
+ // We could use the smaller rect on _WantCreate but using the full rect allows us to clear the texture.
+ // FIXME-OPT: Uploading single box even when using ImTextureStatus_WantUpdates. Could use tex->Updates[]
+ // - Copy all blocks contiguously in upload buffer.
+ // - Barrier before copy, submit all CopyTextureRegion(), barrier after copy.
+ const int upload_x = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.x;
+ const int upload_y = (tex->Status == ImTextureStatus_WantCreate) ? 0 : tex->UpdateRect.y;
+ const int upload_w = (tex->Status == ImTextureStatus_WantCreate) ? tex->Width : tex->UpdateRect.w;
+ const int upload_h = (tex->Status == ImTextureStatus_WantCreate) ? tex->Height : tex->UpdateRect.h;
+
+ // Update full texture or selected blocks. We only ever write to textures regions which have never been used before!
+ // This backend choose to use tex->UpdateRect but you can use tex->Updates[] to upload individual regions.
+ UINT upload_pitch_src = upload_w * tex->BytesPerPixel;
+ UINT upload_pitch_dst = (upload_pitch_src + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
+ UINT upload_size = upload_pitch_dst * upload_h;
+
+ if (bd->pTexUploadBuffer == nullptr || upload_size > bd->pTexUploadBufferSize)
+ {
+ if (bd->pTexUploadBufferMapped)
+ {
+ D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
+ bd->pTexUploadBuffer->Unmap(0, &range);
+ bd->pTexUploadBufferMapped = nullptr;
+ }
+ SafeRelease(bd->pTexUploadBuffer);
+
+ D3D12_RESOURCE_DESC desc;
+ ZeroMemory(&desc, sizeof(desc));
+ desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+ desc.Alignment = 0;
+ desc.Width = upload_size;
+ desc.Height = 1;
+ desc.DepthOrArraySize = 1;
+ desc.MipLevels = 1;
+ desc.Format = DXGI_FORMAT_UNKNOWN;
+ desc.SampleDesc.Count = 1;
+ desc.SampleDesc.Quality = 0;
+ desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+ desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+
+ D3D12_HEAP_PROPERTIES props;
+ memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
+ props.Type = D3D12_HEAP_TYPE_UPLOAD;
+ props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+ props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+
+ HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
+ D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&bd->pTexUploadBuffer));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ D3D12_RANGE range = {0, upload_size};
+ hr = bd->pTexUploadBuffer->Map(0, &range, &bd->pTexUploadBufferMapped);
+ IM_ASSERT(SUCCEEDED(hr));
+ bd->pTexUploadBufferSize = upload_size;
+ }
+
+ bd->pTexCmdAllocator->Reset();
+ bd->pTexCmdList->Reset(bd->pTexCmdAllocator, nullptr);
+ ID3D12GraphicsCommandList* cmdList = bd->pTexCmdList;
+
+ // Copy to upload buffer
+ for (int y = 0; y < upload_h; y++)
+ memcpy((void*)((uintptr_t)bd->pTexUploadBufferMapped + y * upload_pitch_dst), tex->GetPixelsAt(upload_x, upload_y + y), upload_pitch_src);
+
+ if (need_barrier_before_copy)
+ {
+ D3D12_RESOURCE_BARRIER barrier = {};
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrier.Transition.pResource = backend_tex->pTextureResource;
+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+ barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
+ cmdList->ResourceBarrier(1, &barrier);
+ }
+
+ D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
+ D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
+ {
+ srcLocation.pResource = bd->pTexUploadBuffer;
+ srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+ srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ srcLocation.PlacedFootprint.Footprint.Width = upload_w;
+ srcLocation.PlacedFootprint.Footprint.Height = upload_h;
+ srcLocation.PlacedFootprint.Footprint.Depth = 1;
+ srcLocation.PlacedFootprint.Footprint.RowPitch = upload_pitch_dst;
+ dstLocation.pResource = backend_tex->pTextureResource;
+ dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+ dstLocation.SubresourceIndex = 0;
+ }
+ cmdList->CopyTextureRegion(&dstLocation, upload_x, upload_y, 0, &srcLocation, nullptr);
+
+ {
+ D3D12_RESOURCE_BARRIER barrier = {};
+ barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+ barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+ barrier.Transition.pResource = backend_tex->pTextureResource;
+ barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
+ barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
+ barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+ cmdList->ResourceBarrier(1, &barrier);
+ }
+
+ HRESULT hr = cmdList->Close();
+ IM_ASSERT(SUCCEEDED(hr));
+ ID3D12CommandQueue* cmdQueue = bd->pCommandQueue;
+ cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
+ hr = cmdQueue->Signal(bd->Fence, ++bd->FenceLastSignaledValue);
+ IM_ASSERT(SUCCEEDED(hr));
+
+ // FIXME-OPT: Suboptimal?
+ // - To remove this may need to create NumFramesInFlight x ImGui_ImplDX12_FrameContext in backend data (mimick docking version)
+ // - Store per-frame in flight: upload buffer?
+ // - Where do cmdList and cmdAlloc fit?
+ bd->Fence->SetEventOnCompletion(bd->FenceLastSignaledValue, bd->FenceEvent);
+ ::WaitForSingleObject(bd->FenceEvent, INFINITE);
+
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+
+ if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames >= (int)bd->numFramesInFlight)
+ ImGui_ImplDX12_DestroyTexture(tex);
+}
+
+bool ImGui_ImplDX12_CreateDeviceObjects()
+{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ if (!bd || !bd->pd3dDevice)
+ return false;
+ if (bd->pPipelineState)
+ ImGui_ImplDX12_InvalidateDeviceObjects();
+
+ HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&bd->pdxgiFactory));
+ IM_ASSERT(hr == S_OK);
+
+ BOOL allow_tearing = FALSE;
+ bd->pdxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing));
+ bd->tearingSupport = (allow_tearing == TRUE);
+
+ // Create the root signature
+ {
+ D3D12_DESCRIPTOR_RANGE descRange = {};
+ descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ descRange.NumDescriptors = 1;
+ descRange.BaseShaderRegister = 0;
+ descRange.RegisterSpace = 0;
+ descRange.OffsetInDescriptorsFromTableStart = 0;
+
+ D3D12_ROOT_PARAMETER param[2] = {};
+
+ param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
+ param[0].Constants.ShaderRegister = 0;
+ param[0].Constants.RegisterSpace = 0;
+ param[0].Constants.Num32BitValues = 16;
+ param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
+
+ param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
+ param[1].DescriptorTable.NumDescriptorRanges = 1;
+ param[1].DescriptorTable.pDescriptorRanges = &descRange;
+ param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ // Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
+ D3D12_STATIC_SAMPLER_DESC staticSampler[1] = {};
+ staticSampler[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
+ staticSampler[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ staticSampler[0].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ staticSampler[0].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
+ staticSampler[0].MipLODBias = 0.f;
+ staticSampler[0].MaxAnisotropy = 0;
+ staticSampler[0].ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ staticSampler[0].BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
+ staticSampler[0].MinLOD = 0.f;
+ staticSampler[0].MaxLOD = D3D12_FLOAT32_MAX;
+ staticSampler[0].ShaderRegister = 0;
+ staticSampler[0].RegisterSpace = 0;
+ staticSampler[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
+
+ D3D12_ROOT_SIGNATURE_DESC desc = {};
+ desc.NumParameters = _countof(param);
+ desc.pParameters = param;
+ desc.NumStaticSamplers = 1;
+ desc.pStaticSamplers = &staticSampler[0];
+ desc.Flags =
+ D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
+ D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
+ D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
+ D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
+
+ // Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7.
+ // See if any version of d3d12.dll is already loaded in the process. If so, give preference to that.
+ static HINSTANCE d3d12_dll = ::GetModuleHandleA("d3d12.dll");
+ if (d3d12_dll == nullptr)
+ {
+ // Attempt to load d3d12.dll from local directories. This will only succeed if
+ // (1) the current OS is Windows 7, and
+ // (2) there exists a version of d3d12.dll for Windows 7 (D3D12On7) in one of the following directories.
+ // See https://github.com/ocornut/imgui/pull/3696 for details.
+ const char* localD3d12Paths[] = { ".\\d3d12.dll", ".\\d3d12on7\\d3d12.dll", ".\\12on7\\d3d12.dll" }; // A. current directory, B. used by some games, C. used in Microsoft D3D12On7 sample
+ for (int i = 0; i < IM_ARRAYSIZE(localD3d12Paths); i++)
+ if ((d3d12_dll = ::LoadLibraryA(localD3d12Paths[i])) != nullptr)
+ break;
+
+ // If failed, we are on Windows >= 10.
+ if (d3d12_dll == nullptr)
+ d3d12_dll = ::LoadLibraryA("d3d12.dll");
+
+ if (d3d12_dll == nullptr)
+ return false;
+ }
+
+ _PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (_PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)(void*)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature");
+ if (D3D12SerializeRootSignatureFn == nullptr)
+ return false;
+
+ ID3DBlob* blob = nullptr;
+ if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK)
+ return false;
+
+ bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
+ blob->Release();
+ }
+
+ // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
+ // If you would like to use this DX12 sample code but remove this dependency you can:
+ // 1) compile once, save the compiled shader blobs into a file or source code and assign them to psoDesc.VS/PS [preferred solution]
+ // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
+ // See https://github.com/ocornut/imgui/pull/638 for sources and details.
+
+ D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
+ psoDesc.NodeMask = 1;
+ psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+ psoDesc.pRootSignature = bd->pRootSignature;
+ psoDesc.SampleMask = UINT_MAX;
+ psoDesc.NumRenderTargets = 1;
+ psoDesc.RTVFormats[0] = bd->RTVFormat;
+ psoDesc.DSVFormat = bd->DSVFormat;
+ psoDesc.SampleDesc.Count = 1;
+ psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
+
+ ID3DBlob* vertexShaderBlob;
+ ID3DBlob* pixelShaderBlob;
+
+ // Create the vertex shader
+ {
+ static const char* vertexShader =
+ "cbuffer vertexBuffer : register(b0) \
+ {\
+ float4x4 ProjectionMatrix; \
+ };\
+ struct VS_INPUT\
+ {\
+ float2 pos : POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ \
+ PS_INPUT main(VS_INPUT input)\
+ {\
+ PS_INPUT output;\
+ output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
+ output.col = input.col;\
+ output.uv = input.uv;\
+ return output;\
+ }";
+
+ if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_5_0", 0, 0, &vertexShaderBlob, nullptr)))
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
+
+ // Create the input layout
+ static D3D12_INPUT_ELEMENT_DESC local_layout[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)offsetof(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+ };
+ psoDesc.InputLayout = { local_layout, 3 };
+ }
+
+ // Create the pixel shader
+ {
+ static const char* pixelShader =
+ "struct PS_INPUT\
+ {\
+ float4 pos : SV_POSITION;\
+ float4 col : COLOR0;\
+ float2 uv : TEXCOORD0;\
+ };\
+ SamplerState sampler0 : register(s0);\
+ Texture2D texture0 : register(t0);\
+ \
+ float4 main(PS_INPUT input) : SV_Target\
+ {\
+ float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
+ return out_col; \
+ }";
+
+ if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_5_0", 0, 0, &pixelShaderBlob, nullptr)))
+ {
+ vertexShaderBlob->Release();
+ return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
+ }
+ psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
+ }
+
+ // Create the blending setup
+ {
+ D3D12_BLEND_DESC& desc = psoDesc.BlendState;
+ desc.AlphaToCoverageEnable = false;
+ desc.RenderTarget[0].BlendEnable = true;
+ desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
+ desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
+ desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
+ desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
+ desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+ }
+
+ // Create the rasterizer state
+ {
+ D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState;
+ desc.FillMode = D3D12_FILL_MODE_SOLID;
+ desc.CullMode = D3D12_CULL_MODE_NONE;
+ desc.FrontCounterClockwise = FALSE;
+ desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
+ desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
+ desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
+ desc.DepthClipEnable = true;
+ desc.MultisampleEnable = FALSE;
+ desc.AntialiasedLineEnable = FALSE;
+ desc.ForcedSampleCount = 0;
+ desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
+ }
+
+ // Create depth-stencil State
+ {
+ D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState;
+ desc.DepthEnable = false;
+ desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
+ desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ desc.StencilEnable = false;
+ desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
+ desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
+ desc.BackFace = desc.FrontFace;
+ }
+
+ HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
+ vertexShaderBlob->Release();
+ pixelShaderBlob->Release();
+ if (result_pipeline_state != S_OK)
+ return false;
+
+ // Create command allocator and command list for ImGui_ImplDX12_UpdateTexture()
+ hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&bd->pTexCmdAllocator));
+ IM_ASSERT(SUCCEEDED(hr));
+ hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, bd->pTexCmdAllocator, nullptr, IID_PPV_ARGS(&bd->pTexCmdList));
+ IM_ASSERT(SUCCEEDED(hr));
+ hr = bd->pTexCmdList->Close();
+ IM_ASSERT(SUCCEEDED(hr));
+
+ // Create fence.
+ hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&bd->Fence));
+ IM_ASSERT(hr == S_OK);
+ bd->FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ IM_ASSERT(bd->FenceEvent != nullptr);
+
+ return true;
+}
+
+void ImGui_ImplDX12_InvalidateDeviceObjects()
+{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ if (!bd || !bd->pd3dDevice)
+ return;
+
+ SafeRelease(bd->pdxgiFactory);
+ if (bd->commandQueueOwned)
+ SafeRelease(bd->pCommandQueue);
+ bd->commandQueueOwned = false;
+ SafeRelease(bd->pRootSignature);
+ SafeRelease(bd->pPipelineState);
+ if (bd->pTexUploadBufferMapped)
+ {
+ D3D12_RANGE range = { 0, bd->pTexUploadBufferSize };
+ bd->pTexUploadBuffer->Unmap(0, &range);
+ bd->pTexUploadBufferMapped = nullptr;
+ }
+ SafeRelease(bd->pTexUploadBuffer);
+ SafeRelease(bd->pTexCmdList);
+ SafeRelease(bd->pTexCmdAllocator);
+ SafeRelease(bd->Fence);
+ CloseHandle(bd->FenceEvent);
+ bd->FenceEvent = nullptr;
+
+ // Destroy all textures
+ for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
+ if (tex->RefCount == 1)
+ ImGui_ImplDX12_DestroyTexture(tex);
+
+ for (UINT i = 0; i < bd->numFramesInFlight; i++)
+ {
+ ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
+ SafeRelease(fr->IndexBuffer);
+ SafeRelease(fr->VertexBuffer);
+ }
+}
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+static void ImGui_ImplDX12_InitLegacySingleDescriptorMode(ImGui_ImplDX12_InitInfo* init_info)
+{
+ // Wrap legacy behavior of passing space for a single descriptor
+ IM_ASSERT(init_info->LegacySingleSrvCpuDescriptor.ptr != 0 && init_info->LegacySingleSrvGpuDescriptor.ptr != 0);
+ init_info->SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_handle)
+ {
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ IM_ASSERT(bd->LegacySingleDescriptorUsed == false && "Only 1 simultaneous texture allowed with legacy ImGui_ImplDX12_Init() signature!");
+ *out_cpu_handle = bd->InitInfo.LegacySingleSrvCpuDescriptor;
+ *out_gpu_handle = bd->InitInfo.LegacySingleSrvGpuDescriptor;
+ bd->LegacySingleDescriptorUsed = true;
+ };
+ init_info->SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE)
+ {
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ IM_ASSERT(bd->LegacySingleDescriptorUsed == true);
+ bd->LegacySingleDescriptorUsed = false;
+ };
+}
+#endif
+
+bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
+ bd->InitInfo = *init_info; // Deep copy
+ init_info = &bd->InitInfo;
+
+ bd->pd3dDevice = init_info->Device;
+ IM_ASSERT(init_info->CommandQueue != NULL);
+ bd->pCommandQueue = init_info->CommandQueue;
+ bd->RTVFormat = init_info->RTVFormat;
+ bd->DSVFormat = init_info->DSVFormat;
+ bd->numFramesInFlight = init_info->NumFramesInFlight;
+ bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap;
+ bd->tearingSupport = false;
+
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_dx12";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ if (init_info->SrvDescriptorAllocFn == nullptr)
+ ImGui_ImplDX12_InitLegacySingleDescriptorMode(init_info);
+#endif
+ IM_ASSERT(init_info->SrvDescriptorAllocFn != nullptr && init_info->SrvDescriptorFreeFn != nullptr);
+
+ // Create buffers with a default size (they will later be grown as needed)
+ bd->frameIndex = UINT_MAX;
+ bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[bd->numFramesInFlight];
+ for (int i = 0; i < (int)bd->numFramesInFlight; i++)
+ {
+ ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
+ fr->IndexBuffer = nullptr;
+ fr->VertexBuffer = nullptr;
+ fr->IndexBufferSize = 10000;
+ fr->VertexBufferSize = 5000;
+ }
+
+ return true;
+}
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+// Legacy initialization API Obsoleted in 1.91.5
+// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
+bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
+{
+ ImGui_ImplDX12_InitInfo init_info;
+ init_info.Device = device;
+ init_info.NumFramesInFlight = num_frames_in_flight;
+ init_info.RTVFormat = rtv_format;
+ init_info.SrvDescriptorHeap = srv_descriptor_heap;
+ init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle;
+ init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle;
+
+ D3D12_COMMAND_QUEUE_DESC queueDesc = {};
+ queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+ queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
+ queueDesc.NodeMask = 1;
+ HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue));
+ IM_ASSERT(SUCCEEDED(hr));
+
+ bool ret = ImGui_ImplDX12_Init(&init_info);
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ bd->commandQueueOwned = true;
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; // Using legacy ImGui_ImplDX12_Init() call with 1 SRV descriptor we cannot support multiple textures.
+
+ return ret;
+}
+#endif
+
+void ImGui_ImplDX12_Shutdown()
+{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ ImGui_ImplDX12_InvalidateDeviceObjects();
+ delete[] bd->pFrameResources;
+
+ io.BackendRendererName = nullptr;
+ io.BackendRendererUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
+ platform_io.ClearRendererHandlers();
+ IM_DELETE(bd);
+}
+
+void ImGui_ImplDX12_NewFrame()
+{
+ ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX12_Init()?");
+
+ if (!bd->pPipelineState)
+ if (!ImGui_ImplDX12_CreateDeviceObjects())
+ IM_ASSERT(0 && "ImGui_ImplDX12_CreateDeviceObjects() failed!");
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx12.h b/Alphanium/Source/imgui/backends/imgui_impl_dx12.h
new file mode 100644
index 0000000..3bb66c1
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx12.h
@@ -0,0 +1,79 @@
+// dear imgui: Renderer Backend for DirectX12
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
+
+// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
+// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+#include // DXGI_FORMAT
+#include // D3D12_CPU_DESCRIPTOR_HANDLE
+
+// Initialization data, for ImGui_ImplDX12_Init()
+struct ImGui_ImplDX12_InitInfo
+{
+ ID3D12Device* Device;
+ ID3D12CommandQueue* CommandQueue; // Command queue used for queuing texture uploads.
+ int NumFramesInFlight;
+ DXGI_FORMAT RTVFormat; // RenderTarget format.
+ DXGI_FORMAT DSVFormat; // DepthStencilView format.
+ void* UserData;
+
+ // Allocating SRV descriptors for textures is up to the application, so we provide callbacks.
+ // (current version of the backend will only allocate one descriptor, from 1.92 the backend will need to allocate more)
+ ID3D12DescriptorHeap* SrvDescriptorHeap;
+ void (*SrvDescriptorAllocFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE* out_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE* out_gpu_desc_handle);
+ void (*SrvDescriptorFreeFn)(ImGui_ImplDX12_InitInfo* info, D3D12_CPU_DESCRIPTOR_HANDLE cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE gpu_desc_handle);
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ D3D12_CPU_DESCRIPTOR_HANDLE LegacySingleSrvCpuDescriptor; // To facilitate transition from single descriptor to allocator callback, you may use those.
+ D3D12_GPU_DESCRIPTOR_HANDLE LegacySingleSrvGpuDescriptor;
+#endif
+
+ ImGui_ImplDX12_InitInfo() { memset(this, 0, sizeof(*this)); }
+};
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* info);
+IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+// Legacy initialization API Obsoleted in 1.91.5
+// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
+// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field.
+IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
+#endif
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex);
+
+// [BETA] Selected render state data shared with callbacks.
+// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplDX12_RenderDrawData() call.
+// (Please open an issue if you feel you need access to more data)
+struct ImGui_ImplDX12_RenderState
+{
+ ID3D12Device* Device;
+ ID3D12GraphicsCommandList* CommandList;
+};
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx9.cpp b/Alphanium/Source/imgui/backends/imgui_impl_dx9.cpp
new file mode 100644
index 0000000..44d29cd
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx9.cpp
@@ -0,0 +1,480 @@
+// dear imgui: Renderer Backend for DirectX9
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
+// 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
+// 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap.
+// 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575)
+// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
+// 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.
+// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
+// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
+// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
+// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
+// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
+// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
+// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
+// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
+// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
+// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+
+#include "../imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_dx9.h"
+
+// DirectX
+#include
+
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast // yes, they are more terse.
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#endif
+
+// DirectX data
+struct ImGui_ImplDX9_Data
+{
+ LPDIRECT3DDEVICE9 pd3dDevice;
+ LPDIRECT3DVERTEXBUFFER9 pVB;
+ LPDIRECT3DINDEXBUFFER9 pIB;
+ int VertexBufferSize;
+ int IndexBufferSize;
+ bool HasRgbaSupport;
+
+ ImGui_ImplDX9_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
+};
+
+struct CUSTOMVERTEX
+{
+ float pos[3];
+ D3DCOLOR col;
+ float uv[2];
+};
+#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
+
+#ifdef IMGUI_USE_BGRA_PACKED_COLOR
+#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
+#else
+#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
+#endif
+
+// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+static ImGui_ImplDX9_Data* ImGui_ImplDX9_GetBackendData()
+{
+ return ImGui::GetCurrentContext() ? (ImGui_ImplDX9_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
+}
+
+// Functions
+static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
+{
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+
+ // Setup viewport
+ D3DVIEWPORT9 vp;
+ vp.X = vp.Y = 0;
+ vp.Width = (DWORD)draw_data->DisplaySize.x;
+ vp.Height = (DWORD)draw_data->DisplaySize.y;
+ vp.MinZ = 0.0f;
+ vp.MaxZ = 1.0f;
+
+ LPDIRECT3DDEVICE9 device = bd->pd3dDevice;
+ device->SetViewport(&vp);
+
+ // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient), bilinear sampling.
+ device->SetPixelShader(nullptr);
+ device->SetVertexShader(nullptr);
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
+ device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_ZENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+ device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+ device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
+ device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ device->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
+ device->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+ device->SetRenderState(D3DRS_FOGENABLE, FALSE);
+ device->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
+ device->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
+ device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ device->SetRenderState(D3DRS_CLIPPING, TRUE);
+ device->SetRenderState(D3DRS_LIGHTING, FALSE);
+ device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
+ device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
+ device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
+ device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
+ device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
+ device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
+ device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
+ device->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ // Setup orthographic projection matrix
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
+ // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
+ {
+ float L = draw_data->DisplayPos.x + 0.5f;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
+ float T = draw_data->DisplayPos.y + 0.5f;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
+ D3DMATRIX mat_identity = { { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } } };
+ D3DMATRIX mat_projection =
+ { { {
+ 2.0f/(R-L), 0.0f, 0.0f, 0.0f,
+ 0.0f, 2.0f/(T-B), 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.5f, 0.0f,
+ (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f
+ } } };
+ device->SetTransform(D3DTS_WORLD, &mat_identity);
+ device->SetTransform(D3DTS_VIEW, &mat_identity);
+ device->SetTransform(D3DTS_PROJECTION, &mat_projection);
+ }
+}
+
+// Render function.
+void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
+{
+ // Avoid rendering when minimized
+ if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
+ return;
+
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+ LPDIRECT3DDEVICE9 device = bd->pd3dDevice;
+
+ // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
+ // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
+ if (draw_data->Textures != nullptr)
+ for (ImTextureData* tex : *draw_data->Textures)
+ if (tex->Status != ImTextureStatus_OK)
+ ImGui_ImplDX9_UpdateTexture(tex);
+
+ // Create and grow buffers if needed
+ if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount)
+ {
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
+ bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
+ if (device->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0)
+ return;
+ }
+ if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
+ {
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
+ bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
+ if (device->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
+ return;
+ }
+
+ // Backup the DX9 state
+ IDirect3DStateBlock9* state_block = nullptr;
+ if (device->CreateStateBlock(D3DSBT_ALL, &state_block) < 0)
+ return;
+ if (state_block->Capture() < 0)
+ {
+ state_block->Release();
+ return;
+ }
+
+ // Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
+ D3DMATRIX last_world, last_view, last_projection;
+ device->GetTransform(D3DTS_WORLD, &last_world);
+ device->GetTransform(D3DTS_VIEW, &last_view);
+ device->GetTransform(D3DTS_PROJECTION, &last_projection);
+
+ // Allocate buffers
+ CUSTOMVERTEX* vtx_dst;
+ ImDrawIdx* idx_dst;
+ if (bd->pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
+ {
+ state_block->Release();
+ return;
+ }
+ if (bd->pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
+ {
+ bd->pVB->Unlock();
+ state_block->Release();
+ return;
+ }
+
+ // Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
+ // FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
+ // 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
+ // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ const ImDrawVert* vtx_src = draw_list->VtxBuffer.Data;
+ for (int i = 0; i < draw_list->VtxBuffer.Size; i++)
+ {
+ vtx_dst->pos[0] = vtx_src->pos.x;
+ vtx_dst->pos[1] = vtx_src->pos.y;
+ vtx_dst->pos[2] = 0.0f;
+ vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
+ vtx_dst->uv[0] = vtx_src->uv.x;
+ vtx_dst->uv[1] = vtx_src->uv.y;
+ vtx_dst++;
+ vtx_src++;
+ }
+ memcpy(idx_dst, draw_list->IdxBuffer.Data, draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+ idx_dst += draw_list->IdxBuffer.Size;
+ }
+ bd->pVB->Unlock();
+ bd->pIB->Unlock();
+ device->SetStreamSource(0, bd->pVB, 0, sizeof(CUSTOMVERTEX));
+ device->SetIndices(bd->pIB);
+ device->SetFVF(D3DFVF_CUSTOMVERTEX);
+
+ // Setup desired DX state
+ ImGui_ImplDX9_SetupRenderState(draw_data);
+
+ // Render command lists
+ // (Because we merged all buffers into a single one, we maintain our own offset into them)
+ int global_vtx_offset = 0;
+ int global_idx_offset = 0;
+ ImVec2 clip_off = draw_data->DisplayPos;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback != nullptr)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplDX9_SetupRenderState(draw_data);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
+ ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
+ if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
+ continue;
+
+ // Apply scissor/clipping rectangle
+ const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
+ device->SetScissorRect(&r);
+
+ // Bind texture, Draw
+ const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
+ device->SetTexture(0, texture);
+ device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, pcmd->VtxOffset + global_vtx_offset, 0, (UINT)draw_list->VtxBuffer.Size, pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
+ }
+ }
+ global_idx_offset += draw_list->IdxBuffer.Size;
+ global_vtx_offset += draw_list->VtxBuffer.Size;
+ }
+
+ // Restore the DX9 transform
+ device->SetTransform(D3DTS_WORLD, &last_world);
+ device->SetTransform(D3DTS_VIEW, &last_view);
+ device->SetTransform(D3DTS_PROJECTION, &last_projection);
+
+ // Restore the DX9 state
+ state_block->Apply();
+ state_block->Release();
+}
+
+static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMAT format)
+{
+ LPDIRECT3D9 pd3d = nullptr;
+ if (pDevice->GetDirect3D(&pd3d) != D3D_OK)
+ return false;
+ D3DDEVICE_CREATION_PARAMETERS param = {};
+ D3DDISPLAYMODE mode = {};
+ if (pDevice->GetCreationParameters(¶m) != D3D_OK || pDevice->GetDisplayMode(0, &mode) != D3D_OK)
+ {
+ pd3d->Release();
+ return false;
+ }
+ // Font texture should support linear filter, color blend and write to render-target
+ bool support = (pd3d->CheckDeviceFormat(param.AdapterOrdinal, param.DeviceType, mode.Format, D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, format)) == D3D_OK;
+ pd3d->Release();
+ return support;
+}
+
+bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
+
+ // Setup backend capabilities flags
+ ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_dx9";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
+
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
+
+ bd->pd3dDevice = device;
+ bd->pd3dDevice->AddRef();
+ bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
+
+ return true;
+}
+
+void ImGui_ImplDX9_Shutdown()
+{
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ ImGui_ImplDX9_InvalidateDeviceObjects();
+ if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
+
+ io.BackendRendererName = nullptr;
+ io.BackendRendererUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
+ platform_io.ClearRendererHandlers();
+ IM_DELETE(bd);
+}
+
+// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
+static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h)
+{
+#ifndef IMGUI_USE_BGRA_PACKED_COLOR
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+ const bool convert_rgba_to_bgra = (!bd->HasRgbaSupport && tex_use_colors);
+#else
+ const bool convert_rgba_to_bgra = false;
+ IM_UNUSED(tex_use_colors);
+#endif
+ for (int y = 0; y < h; y++)
+ {
+ const ImU32* src_p = (const ImU32*)(const void*)((const unsigned char*)src + src_pitch * y);
+ ImU32* dst_p = (ImU32*)(void*)((unsigned char*)dst + dst_pitch * y);
+ if (convert_rgba_to_bgra)
+ for (int x = w; x > 0; x--, src_p++, dst_p++) // Convert copy
+ *dst_p = IMGUI_COL_TO_DX9_ARGB(*src_p);
+ else
+ memcpy(dst_p, src_p, w * 4); // Raw copy
+ }
+}
+
+void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex)
+{
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+
+ if (tex->Status == ImTextureStatus_WantCreate)
+ {
+ // Create and upload new texture to graphics system
+ //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+ LPDIRECT3DTEXTURE9 dx_tex = nullptr;
+ HRESULT hr = bd->pd3dDevice->CreateTexture(tex->Width, tex->Height, 1, D3DUSAGE_DYNAMIC, bd->HasRgbaSupport ? D3DFMT_A8B8G8R8 : D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &dx_tex, nullptr);
+ if (hr < 0)
+ {
+ IM_ASSERT(hr >= 0 && "Backend failed to create texture!");
+ return;
+ }
+
+ D3DLOCKED_RECT locked_rect;
+ if (dx_tex->LockRect(0, &locked_rect, nullptr, 0) == D3D_OK)
+ {
+ ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixels(), tex->Width * 4, (ImU32*)locked_rect.pBits, (ImU32)locked_rect.Pitch, tex->Width, tex->Height);
+ dx_tex->UnlockRect(0);
+ }
+
+ // Store identifiers
+ tex->SetTexID((ImTextureID)(intptr_t)dx_tex);
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ else if (tex->Status == ImTextureStatus_WantUpdates)
+ {
+ // Update selected blocks. We only ever write to textures regions which have never been used before!
+ // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
+ LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)(intptr_t)tex->TexID;
+ RECT update_rect = { (LONG)tex->UpdateRect.x, (LONG)tex->UpdateRect.y, (LONG)(tex->UpdateRect.x + tex->UpdateRect.w), (LONG)(tex->UpdateRect.y + tex->UpdateRect.h) };
+ D3DLOCKED_RECT locked_rect;
+ if (backend_tex->LockRect(0, &locked_rect, &update_rect, 0) == D3D_OK)
+ for (ImTextureRect& r : tex->Updates)
+ ImGui_ImplDX9_CopyTextureRegion(tex->UseColors, (ImU32*)tex->GetPixelsAt(r.x, r.y), tex->Width * 4,
+ (ImU32*)locked_rect.pBits + (r.x - update_rect.left) + (r.y - update_rect.top) * (locked_rect.Pitch / 4), (int)locked_rect.Pitch, r.w, r.h);
+ backend_tex->UnlockRect(0);
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ else if (tex->Status == ImTextureStatus_WantDestroy)
+ {
+ if (LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID)
+ {
+ IM_ASSERT(tex->TexID == (ImTextureID)(intptr_t)backend_tex);
+ backend_tex->Release();
+
+ // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
+ tex->SetTexID(ImTextureID_Invalid);
+ }
+ tex->SetStatus(ImTextureStatus_Destroyed);
+ }
+}
+
+bool ImGui_ImplDX9_CreateDeviceObjects()
+{
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+ if (!bd || !bd->pd3dDevice)
+ return false;
+ return true;
+}
+
+void ImGui_ImplDX9_InvalidateDeviceObjects()
+{
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+ if (!bd || !bd->pd3dDevice)
+ return;
+
+ // Destroy all textures
+ for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
+ if (tex->RefCount == 1)
+ {
+ tex->SetStatus(ImTextureStatus_WantDestroy);
+ ImGui_ImplDX9_UpdateTexture(tex);
+ }
+ if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
+ if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
+}
+
+void ImGui_ImplDX9_NewFrame()
+{
+ ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplDX9_Init()?");
+ IM_UNUSED(bd);
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_dx9.h b/Alphanium/Source/imgui/backends/imgui_impl_dx9.h
new file mode 100644
index 0000000..a24da39
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_dx9.h
@@ -0,0 +1,37 @@
+// dear imgui: Renderer Backend for DirectX9
+// This needs to be used along with a Platform Backend (e.g. Win32)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+// [X] Renderer: IMGUI_USE_BGRA_PACKED_COLOR support, as this is the optimal color encoding for DirectX9.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "../imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct IDirect3DDevice9;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9* device);
+IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
+IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data);
+
+// Use if you want to reset your rendering device without losing Dear ImGui state.
+IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
+IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex);
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_glfw.cpp b/Alphanium/Source/imgui/backends/imgui_impl_glfw.cpp
new file mode 100644
index 0000000..ac176a0
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_glfw.cpp
@@ -0,0 +1,1067 @@
+// dear imgui: Platform Backend for GLFW
+// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
+// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
+// (Requires: GLFW 3.0+. Prefer GLFW 3.3+/3.4+ for full feature support.)
+
+// Implemented features:
+// [X] Platform: Clipboard support.
+// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
+// [X] Multiple Dear ImGui contexts support.
+// Missing features or Issues:
+// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround.
+// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+// About Emscripten support:
+// - Emscripten provides its own GLFW (3.2.1) implementation (syntax: "-sUSE_GLFW=3"), but Joystick is broken and several features are not supported (multiple windows, clipboard, timer, etc.)
+// - A third-party Emscripten GLFW (3.4.0) implementation (syntax: "--use-port=contrib.glfw3") fixes the Joystick issue and implements all relevant features for the browser.
+// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Comparison.md for details.
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-11-06: Lower minimum requirement to GLFW 3.0. Though a recent version e.g GLFW 3.4 is highly recommended.
+// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown.
+// 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921)
+// 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733)
+// 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069)
+// 2025-06-11: Added ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window) and ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor) helper to facilitate making DPI-aware apps.
+// 2025-03-10: Map GLFW_KEY_WORLD_1 and GLFW_KEY_WORLD_2 into ImGuiKey_Oem102.
+// 2025-03-03: Fixed clipboard handler assertion when using GLFW <= 3.2.1 compiled with asserts enabled.
+// 2024-08-22: Moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
+// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
+// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
+// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn
+// 2024-07-31: Added ImGui_ImplGlfw_Sleep() helper function for usage by our examples app, since GLFW doesn't provide one.
+// 2024-07-08: *BREAKING* Renamed ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback to ImGui_ImplGlfw_InstallEmscriptenCallbacks(), added GLFWWindow* parameter.
+// 2024-07-08: Emscripten: Added support for GLFW3 contrib port (GLFW 3.4.0 features + bug fixes): to enable, replace -sUSE_GLFW=3 with --use-port=contrib.glfw3 (requires emscripten 3.1.59+) (https://github.com/pongasoft/emscripten-glfw)
+// 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions.
+// 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)
+// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen/ImGuiMouseSource_Pen on Windows ONLY, using a custom WndProc hook. (#2702)
+// 2023-03-16: Inputs: Fixed key modifiers handling on secondary viewports (docking branch). Broken on 2023/01/04. (#6248, #6034)
+// 2023-03-14: Emscripten: Avoid using glfwGetError() and glfwGetGamepadState() which are not correctly implemented in Emscripten emulation. (#6240)
+// 2023-02-03: Emscripten: Registering custom low-level mouse wheel handler to get more accurate scrolling impulses on Emscripten. (#4019, #6096)
+// 2023-01-04: Inputs: Fixed mods state on Linux when using Alt-GR text input (e.g. German keyboard layout), could lead to broken text input. Revert a 2022/01/17 change were we resumed using mods provided by GLFW, turns out they were faulty.
+// 2022-11-22: Perform a dummy glfwGetError() read to cancel missing names with glfwGetKeyName(). (#5908)
+// 2022-10-18: Perform a dummy glfwGetError() read to cancel missing mouse cursors errors. Using GLFW_VERSION_COMBINED directly. (#5785)
+// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
+// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
+// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position *EDIT* Reverted 2023-07-18.
+// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX.
+// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11.
+// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend.
+// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
+// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
+// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
+// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
+// 2022-01-12: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
+// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
+// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
+// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
+// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
+// 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).
+// 2020-01-17: Inputs: Disable error callback while assigning mouse cursors because some X11 setup don't have them and it generates errors.
+// 2019-12-05: Inputs: Added support for new mouse cursors added in GLFW 3.4+ (resizing cursors, not allowed cursor).
+// 2019-10-18: Misc: Previously installed user callbacks are now restored on shutdown.
+// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
+// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
+// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
+// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
+// 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them.
+// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
+// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
+// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
+// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
+// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
+// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
+// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
+// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
+// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
+// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
+// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
+// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
+// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_glfw.h"
+
+// Clang warnings with -Weverything
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
+#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
+#pragma clang diagnostic ignored "-Wexit-time-destructors" // warning: declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
+#pragma clang diagnostic ignored "-Wglobal-constructors" // warning: declaration requires a global destructor // similar to above, not sure what the exact difference is.
+#endif
+
+// GLFW
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#define GLFW_HAS_X11_OR_WAYLAND 1
+#else
+#define GLFW_HAS_X11_OR_WAYLAND 0
+#endif
+#include
+#ifdef _WIN32
+#undef APIENTRY
+#ifndef GLFW_EXPOSE_NATIVE_WIN32 // for glfwGetWin32Window()
+#define GLFW_EXPOSE_NATIVE_WIN32
+#endif
+#include
+#elif defined(__APPLE__)
+#ifndef GLFW_EXPOSE_NATIVE_COCOA // for glfwGetCocoaWindow()
+#define GLFW_EXPOSE_NATIVE_COCOA
+#endif
+#include
+#elif GLFW_HAS_X11_OR_WAYLAND
+#ifndef GLFW_EXPOSE_NATIVE_X11 // for glfwGetX11Display(), glfwGetX11Window() on Freedesktop (Linux, BSD, etc.)
+#define GLFW_EXPOSE_NATIVE_X11
+#endif
+#include
+#endif
+#undef Status // X11 headers are leaking this.
+#ifndef _WIN32
+#include // for usleep()
+#endif
+#include // for snprintf()
+
+#ifdef __EMSCRIPTEN__
+#include
+#include
+#ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3
+#include
+#else
+#define EMSCRIPTEN_USE_EMBEDDED_GLFW3
+#endif
+#endif
+
+// We gather version tests as define in order to easily see which features are version-dependent.
+#define GLFW_VERSION_COMBINED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 + GLFW_VERSION_REVISION)
+#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetMonitorContentScale
+#ifdef GLFW_RESIZE_NESW_CURSOR // Let's be nice to people who pulled GLFW between 2019-04-16 (3.4 define) and 2019-11-29 (cursors defines) // FIXME: Remove when GLFW 3.4 is released?
+#define GLFW_HAS_NEW_CURSORS (GLFW_VERSION_COMBINED >= 3400) // 3.4+ GLFW_RESIZE_ALL_CURSOR, GLFW_RESIZE_NESW_CURSOR, GLFW_RESIZE_NWSE_CURSOR, GLFW_NOT_ALLOWED_CURSOR
+#else
+#define GLFW_HAS_NEW_CURSORS (0)
+#endif
+#define GLFW_HAS_CREATECURSOR (GLFW_VERSION_COMBINED >= 3100) // 3.1+ glfwCreateCursor()
+#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetGamepadState() new api
+#define GLFW_HAS_GETKEYNAME (GLFW_VERSION_COMBINED >= 3200) // 3.2+ glfwGetKeyName()
+#define GLFW_HAS_GETERROR (GLFW_VERSION_COMBINED >= 3300) // 3.3+ glfwGetError()
+#define GLFW_HAS_GETPLATFORM (GLFW_VERSION_COMBINED >= 3400) // 3.4+ glfwGetPlatform()
+
+// Map GLFWWindow* to ImGuiContext*.
+// - Would be simpler if we could use glfwSetWindowUserPointer()/glfwGetWindowUserPointer(), but this is a single and shared resource.
+// - Would be simpler if we could use e.g. std::map<> as well. But we don't.
+// - This is not particularly optimized as we expect size to be small and queries to be rare.
+struct ImGui_ImplGlfw_WindowToContext { GLFWwindow* Window; ImGuiContext* Context; };
+static ImVector g_ContextMap;
+static void ImGui_ImplGlfw_ContextMap_Add(GLFWwindow* window, ImGuiContext* ctx) { g_ContextMap.push_back(ImGui_ImplGlfw_WindowToContext{ window, ctx }); }
+static void ImGui_ImplGlfw_ContextMap_Remove(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) { g_ContextMap.erase_unsorted(&entry); if (g_ContextMap.empty()) g_ContextMap.clear(); return; } }
+static ImGuiContext* ImGui_ImplGlfw_ContextMap_Get(GLFWwindow* window) { for (ImGui_ImplGlfw_WindowToContext& entry : g_ContextMap) if (entry.Window == window) return entry.Context; return nullptr; }
+
+enum GlfwClientApi
+{
+ GlfwClientApi_OpenGL,
+ GlfwClientApi_Vulkan,
+ GlfwClientApi_Unknown, // Anything else fits here.
+};
+
+// GLFW data
+struct ImGui_ImplGlfw_Data
+{
+ ImGuiContext* Context;
+ GLFWwindow* Window;
+ GlfwClientApi ClientApi;
+ double Time;
+ GLFWwindow* MouseWindow;
+#if GLFW_HAS_CREATECURSOR
+ GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
+#endif
+ ImVec2 LastValidMousePos;
+ bool IsWayland;
+ bool InstalledCallbacks;
+ bool CallbacksChainForAllWindows;
+ char BackendPlatformName[32];
+#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
+ const char* CanvasSelector;
+#endif
+
+ // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
+ GLFWwindowfocusfun PrevUserCallbackWindowFocus;
+ GLFWcursorposfun PrevUserCallbackCursorPos;
+ GLFWcursorenterfun PrevUserCallbackCursorEnter;
+ GLFWmousebuttonfun PrevUserCallbackMousebutton;
+ GLFWscrollfun PrevUserCallbackScroll;
+ GLFWkeyfun PrevUserCallbackKey;
+ GLFWcharfun PrevUserCallbackChar;
+ GLFWmonitorfun PrevUserCallbackMonitor;
+#ifdef _WIN32
+ WNDPROC PrevWndProc;
+#endif
+
+ ImGui_ImplGlfw_Data() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
+// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
+// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
+// - Because glfwPollEvents() process all windows and some events may be called outside of it, you will need to register your own callbacks
+// (passing install_callbacks=false in ImGui_ImplGlfw_InitXXX functions), set the current dear imgui context and then call our callbacks.
+// - Otherwise we may need to store a GLFWWindow* -> ImGuiContext* map and handle this in the backend, adding a little bit of extra complexity to it.
+// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
+namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); }
+static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData()
+{
+ // Get data for current context
+ return ImGui::GetCurrentContext() ? (ImGui_ImplGlfw_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
+}
+static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData(GLFWwindow* window)
+{
+ // Get data for a given GLFW window, regardless of current context (since GLFW events are sent together)
+ ImGuiContext* ctx = ImGui_ImplGlfw_ContextMap_Get(window);
+ return (ImGui_ImplGlfw_Data*)ImGui::GetIO(ctx).BackendPlatformUserData;
+}
+
+// Functions
+static bool ImGui_ImplGlfw_IsWayland()
+{
+#if !GLFW_HAS_X11_OR_WAYLAND
+ return false;
+#elif GLFW_HAS_GETPLATFORM
+ return glfwGetPlatform() == GLFW_PLATFORM_WAYLAND;
+#else
+ const char* version = glfwGetVersionString();
+ if (strstr(version, "Wayland") == NULL) // e.g. Ubuntu 22.04 ships with GLFW 3.3.6 compiled without Wayland
+ return false;
+#ifdef GLFW_EXPOSE_NATIVE_X11
+ if (glfwGetX11Display() != NULL)
+ return false;
+#endif
+ return true;
+#endif
+}
+
+// Not static to allow third-party code to use that if they want to (but undocumented)
+ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode);
+ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int keycode, int scancode)
+{
+ IM_UNUSED(scancode);
+ switch (keycode)
+ {
+ case GLFW_KEY_TAB: return ImGuiKey_Tab;
+ case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
+ case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
+ case GLFW_KEY_UP: return ImGuiKey_UpArrow;
+ case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
+ case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
+ case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
+ case GLFW_KEY_HOME: return ImGuiKey_Home;
+ case GLFW_KEY_END: return ImGuiKey_End;
+ case GLFW_KEY_INSERT: return ImGuiKey_Insert;
+ case GLFW_KEY_DELETE: return ImGuiKey_Delete;
+ case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
+ case GLFW_KEY_SPACE: return ImGuiKey_Space;
+ case GLFW_KEY_ENTER: return ImGuiKey_Enter;
+ case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
+ case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
+ case GLFW_KEY_COMMA: return ImGuiKey_Comma;
+ case GLFW_KEY_MINUS: return ImGuiKey_Minus;
+ case GLFW_KEY_PERIOD: return ImGuiKey_Period;
+ case GLFW_KEY_SLASH: return ImGuiKey_Slash;
+ case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
+ case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
+ case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
+ case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
+ case GLFW_KEY_WORLD_1: return ImGuiKey_Oem102;
+ case GLFW_KEY_WORLD_2: return ImGuiKey_Oem102;
+ case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
+ case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
+ case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
+ case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
+ case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
+ case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
+ case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
+ case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
+ case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
+ case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
+ case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
+ case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
+ case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
+ case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
+ case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
+ case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
+ case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
+ case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
+ case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
+ case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
+ case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
+ case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
+ case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
+ case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
+ case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
+ case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
+ case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
+ case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
+ case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
+ case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
+ case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
+ case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
+ case GLFW_KEY_MENU: return ImGuiKey_Menu;
+ case GLFW_KEY_0: return ImGuiKey_0;
+ case GLFW_KEY_1: return ImGuiKey_1;
+ case GLFW_KEY_2: return ImGuiKey_2;
+ case GLFW_KEY_3: return ImGuiKey_3;
+ case GLFW_KEY_4: return ImGuiKey_4;
+ case GLFW_KEY_5: return ImGuiKey_5;
+ case GLFW_KEY_6: return ImGuiKey_6;
+ case GLFW_KEY_7: return ImGuiKey_7;
+ case GLFW_KEY_8: return ImGuiKey_8;
+ case GLFW_KEY_9: return ImGuiKey_9;
+ case GLFW_KEY_A: return ImGuiKey_A;
+ case GLFW_KEY_B: return ImGuiKey_B;
+ case GLFW_KEY_C: return ImGuiKey_C;
+ case GLFW_KEY_D: return ImGuiKey_D;
+ case GLFW_KEY_E: return ImGuiKey_E;
+ case GLFW_KEY_F: return ImGuiKey_F;
+ case GLFW_KEY_G: return ImGuiKey_G;
+ case GLFW_KEY_H: return ImGuiKey_H;
+ case GLFW_KEY_I: return ImGuiKey_I;
+ case GLFW_KEY_J: return ImGuiKey_J;
+ case GLFW_KEY_K: return ImGuiKey_K;
+ case GLFW_KEY_L: return ImGuiKey_L;
+ case GLFW_KEY_M: return ImGuiKey_M;
+ case GLFW_KEY_N: return ImGuiKey_N;
+ case GLFW_KEY_O: return ImGuiKey_O;
+ case GLFW_KEY_P: return ImGuiKey_P;
+ case GLFW_KEY_Q: return ImGuiKey_Q;
+ case GLFW_KEY_R: return ImGuiKey_R;
+ case GLFW_KEY_S: return ImGuiKey_S;
+ case GLFW_KEY_T: return ImGuiKey_T;
+ case GLFW_KEY_U: return ImGuiKey_U;
+ case GLFW_KEY_V: return ImGuiKey_V;
+ case GLFW_KEY_W: return ImGuiKey_W;
+ case GLFW_KEY_X: return ImGuiKey_X;
+ case GLFW_KEY_Y: return ImGuiKey_Y;
+ case GLFW_KEY_Z: return ImGuiKey_Z;
+ case GLFW_KEY_F1: return ImGuiKey_F1;
+ case GLFW_KEY_F2: return ImGuiKey_F2;
+ case GLFW_KEY_F3: return ImGuiKey_F3;
+ case GLFW_KEY_F4: return ImGuiKey_F4;
+ case GLFW_KEY_F5: return ImGuiKey_F5;
+ case GLFW_KEY_F6: return ImGuiKey_F6;
+ case GLFW_KEY_F7: return ImGuiKey_F7;
+ case GLFW_KEY_F8: return ImGuiKey_F8;
+ case GLFW_KEY_F9: return ImGuiKey_F9;
+ case GLFW_KEY_F10: return ImGuiKey_F10;
+ case GLFW_KEY_F11: return ImGuiKey_F11;
+ case GLFW_KEY_F12: return ImGuiKey_F12;
+ case GLFW_KEY_F13: return ImGuiKey_F13;
+ case GLFW_KEY_F14: return ImGuiKey_F14;
+ case GLFW_KEY_F15: return ImGuiKey_F15;
+ case GLFW_KEY_F16: return ImGuiKey_F16;
+ case GLFW_KEY_F17: return ImGuiKey_F17;
+ case GLFW_KEY_F18: return ImGuiKey_F18;
+ case GLFW_KEY_F19: return ImGuiKey_F19;
+ case GLFW_KEY_F20: return ImGuiKey_F20;
+ case GLFW_KEY_F21: return ImGuiKey_F21;
+ case GLFW_KEY_F22: return ImGuiKey_F22;
+ case GLFW_KEY_F23: return ImGuiKey_F23;
+ case GLFW_KEY_F24: return ImGuiKey_F24;
+ default: return ImGuiKey_None;
+ }
+}
+
+// X11 does not include current pressed/released modifier key in 'mods' flags submitted by GLFW
+// See https://github.com/ocornut/imgui/issues/6034 and https://github.com/glfw/glfw/issues/1630
+static void ImGui_ImplGlfw_UpdateKeyModifiers(ImGuiIO& io, GLFWwindow* window)
+{
+ io.AddKeyEvent(ImGuiMod_Ctrl, (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS));
+ io.AddKeyEvent(ImGuiMod_Shift, (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS));
+ io.AddKeyEvent(ImGuiMod_Alt, (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS));
+ io.AddKeyEvent(ImGuiMod_Super, (glfwGetKey(window, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS) || (glfwGetKey(window, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS));
+}
+
+static bool ImGui_ImplGlfw_ShouldChainCallback(ImGui_ImplGlfw_Data* bd, GLFWwindow* window)
+{
+ return bd->CallbacksChainForAllWindows ? true : (window == bd->Window);
+}
+
+void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackMousebutton != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackMousebutton(window, button, action, mods);
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ ImGui_ImplGlfw_UpdateKeyModifiers(io, window);
+ if (button >= 0 && button < ImGuiMouseButton_COUNT)
+ io.AddMouseButtonEvent(button, action == GLFW_PRESS);
+}
+
+void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackScroll != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackScroll(window, xoffset, yoffset);
+
+#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
+ // Ignore GLFW events: will be processed in ImGui_ImplEmscripten_WheelCallback().
+ return;
+#endif
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
+}
+
+// FIXME: should this be baked into ImGui_ImplGlfw_KeyToImGuiKey()? then what about the values passed to io.SetKeyEventNativeData()?
+static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
+{
+#if GLFW_HAS_GETKEYNAME && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3)
+ // GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
+ // (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
+ // See https://github.com/glfw/glfw/issues/1502 for details.
+ // Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
+ // This won't cover edge cases but this is at least going to cover common cases.
+ if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
+ return key;
+ GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
+ const char* key_name = glfwGetKeyName(key, scancode);
+ glfwSetErrorCallback(prev_error_callback);
+#if GLFW_HAS_GETERROR && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3) // Eat errors (see #5908)
+ (void)glfwGetError(nullptr);
+#endif
+ if (key_name && key_name[0] != 0 && key_name[1] == 0)
+ {
+ const char char_names[] = "`-=[]\\,;\'./";
+ const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
+ IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
+ if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
+ else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
+ else if (key_name[0] >= 'a' && key_name[0] <= 'z') { key = GLFW_KEY_A + (key_name[0] - 'a'); }
+ else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
+ }
+ // if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
+#else
+ IM_UNUSED(scancode);
+#endif
+ return key;
+}
+
+void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackKey != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
+
+ if (action != GLFW_PRESS && action != GLFW_RELEASE)
+ return;
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ ImGui_ImplGlfw_UpdateKeyModifiers(io, window);
+
+ keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
+
+ ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode, scancode);
+ io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
+ io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
+}
+
+void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackWindowFocus != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackWindowFocus(window, focused);
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ io.AddFocusEvent(focused != 0);
+}
+
+void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackCursorPos != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackCursorPos(window, x, y);
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ io.AddMousePosEvent((float)x, (float)y);
+ bd->LastValidMousePos = ImVec2((float)x, (float)y);
+}
+
+// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
+// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
+void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackCursorEnter != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackCursorEnter(window, entered);
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ if (entered)
+ {
+ bd->MouseWindow = window;
+ io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
+ }
+ else if (!entered && bd->MouseWindow == window)
+ {
+ bd->LastValidMousePos = io.MousePos;
+ bd->MouseWindow = nullptr;
+ io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
+ }
+}
+
+void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (bd->PrevUserCallbackChar != nullptr && ImGui_ImplGlfw_ShouldChainCallback(bd, window))
+ bd->PrevUserCallbackChar(window, c);
+
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ io.AddInputCharacter(c);
+}
+
+void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
+{
+ // Unused in 'master' branch but 'docking' branch will use this, so we declare it ahead of it so if you have to install callbacks you can install this one too.
+}
+
+#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
+static EM_BOOL ImGui_ImplEmscripten_WheelCallback(int, const EmscriptenWheelEvent* ev, void* user_data)
+{
+ // Mimic Emscripten_HandleWheel() in SDL.
+ // Corresponding equivalent in GLFW JS emulation layer has incorrect quantizing preventing small values. See #6096
+ ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)user_data;
+ float multiplier = 0.0f;
+ if (ev->deltaMode == DOM_DELTA_PIXEL) { multiplier = 1.0f / 100.0f; } // 100 pixels make up a step.
+ else if (ev->deltaMode == DOM_DELTA_LINE) { multiplier = 1.0f / 3.0f; } // 3 lines make up a step.
+ else if (ev->deltaMode == DOM_DELTA_PAGE) { multiplier = 80.0f; } // A page makes up 80 steps.
+ float wheel_x = ev->deltaX * -multiplier;
+ float wheel_y = ev->deltaY * -multiplier;
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+ io.AddMouseWheelEvent(wheel_x, wheel_y);
+ //IMGUI_DEBUG_LOG("[Emsc] mode %d dx: %.2f, dy: %.2f, dz: %.2f --> feed %.2f %.2f\n", (int)ev->deltaMode, ev->deltaX, ev->deltaY, ev->deltaZ, wheel_x, wheel_y);
+ return EM_TRUE;
+}
+#endif
+
+#ifdef _WIN32
+// GLFW doesn't allow to distinguish Mouse vs TouchScreen vs Pen.
+// Add support for Win32 (based on imgui_impl_win32), because we rely on _TouchScreen info to trickle inputs differently.
+static ImGuiMouseSource GetMouseSourceFromMessageExtraInfo()
+{
+ LPARAM extra_info = ::GetMessageExtraInfo();
+ if ((extra_info & 0xFFFFFF80) == 0xFF515700)
+ return ImGuiMouseSource_Pen;
+ if ((extra_info & 0xFFFFFF80) == 0xFF515780)
+ return ImGuiMouseSource_TouchScreen;
+ return ImGuiMouseSource_Mouse;
+}
+static LRESULT CALLBACK ImGui_ImplGlfw_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ImGui_ImplGlfw_Data* bd = (ImGui_ImplGlfw_Data*)::GetPropA(hWnd, "IMGUI_BACKEND_DATA");
+ ImGuiIO& io = ImGui::GetIO(bd->Context);
+
+ switch (msg)
+ {
+ case WM_MOUSEMOVE: case WM_NCMOUSEMOVE:
+ case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: case WM_LBUTTONUP:
+ case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: case WM_RBUTTONUP:
+ case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: case WM_MBUTTONUP:
+ case WM_XBUTTONDOWN: case WM_XBUTTONDBLCLK: case WM_XBUTTONUP:
+ io.AddMouseSourceEvent(GetMouseSourceFromMessageExtraInfo());
+ break;
+ default: break;
+ }
+ return ::CallWindowProcW(bd->PrevWndProc, hWnd, msg, wParam, lParam);
+}
+#endif
+
+void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
+ IM_ASSERT(bd->Window == window);
+
+ bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
+ bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
+ bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
+ bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
+ bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
+ bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
+ bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
+ bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
+ bd->InstalledCallbacks = true;
+}
+
+void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
+ IM_ASSERT(bd->Window == window);
+
+ glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
+ glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
+ glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
+ glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
+ glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
+ glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
+ glfwSetCharCallback(window, bd->PrevUserCallbackChar);
+ glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
+ bd->InstalledCallbacks = false;
+ bd->PrevUserCallbackWindowFocus = nullptr;
+ bd->PrevUserCallbackCursorEnter = nullptr;
+ bd->PrevUserCallbackCursorPos = nullptr;
+ bd->PrevUserCallbackMousebutton = nullptr;
+ bd->PrevUserCallbackScroll = nullptr;
+ bd->PrevUserCallbackKey = nullptr;
+ bd->PrevUserCallbackChar = nullptr;
+ bd->PrevUserCallbackMonitor = nullptr;
+}
+
+// Set to 'true' to enable chaining installed callbacks for all windows (including secondary viewports created by backends or by user).
+// This is 'false' by default meaning we only chain callbacks for the main viewport.
+// We cannot set this to 'true' by default because user callbacks code may be not testing the 'window' parameter of their callback.
+// If you set this to 'true' your user callback code will need to make sure you are testing the 'window' parameter.
+void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows)
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ bd->CallbacksChainForAllWindows = chain_for_all_windows;
+}
+
+#ifdef __EMSCRIPTEN__
+#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
+void ImGui_ImplGlfw_EmscriptenOpenURL(const char* url) { if (url) emscripten::glfw3::OpenURL(url); }
+#else
+EM_JS(void, ImGui_ImplGlfw_EmscriptenOpenURL, (const char* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); });
+#endif
+#endif
+
+static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
+ //printf("GLFW_VERSION: %d.%d.%d (%d)", GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION, GLFW_VERSION_COMBINED);
+
+ // Setup backend capabilities flags
+ ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
+ snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_glfw (%d)", GLFW_VERSION_COMBINED);
+ io.BackendPlatformUserData = (void*)bd;
+ io.BackendPlatformName = bd->BackendPlatformName;
+#if GLFW_HAS_CREATECURSOR
+ io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
+#endif
+ io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
+
+ bd->Context = ImGui::GetCurrentContext();
+ bd->Window = window;
+ bd->Time = 0.0;
+ bd->IsWayland = ImGui_ImplGlfw_IsWayland();
+ ImGui_ImplGlfw_ContextMap_Add(window, bd->Context);
+
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+#if GLFW_VERSION_COMBINED < 3300
+ platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window, text); };
+ platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window); };
+#else
+ platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(nullptr, text); };
+ platform_io.Platform_GetClipboardTextFn = [](ImGuiContext*) { return glfwGetClipboardString(nullptr); };
+#endif
+
+#ifdef __EMSCRIPTEN__
+ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplGlfw_EmscriptenOpenURL(url); return true; };
+#endif
+
+ // Create mouse cursors
+ // (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
+ // GLFW will emit an error which will often be printed by the app, so we temporarily disable error reporting.
+ // Missing cursors will return nullptr and our _UpdateMouseCursor() function will use the Arrow cursor instead.)
+#if GLFW_HAS_CREATECURSOR
+ GLFWerrorfun prev_error_callback = glfwSetErrorCallback(nullptr);
+ bd->MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
+#if GLFW_HAS_NEW_CURSORS
+ bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_RESIZE_ALL_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_RESIZE_NESW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_RESIZE_NWSE_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_NOT_ALLOWED_CURSOR);
+#else
+ bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+ bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
+#endif
+ glfwSetErrorCallback(prev_error_callback);
+#endif
+#if GLFW_HAS_GETERROR && !defined(__EMSCRIPTEN__) // Eat errors (see #5908)
+ (void)glfwGetError(nullptr);
+#endif
+
+ // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
+ if (install_callbacks)
+ ImGui_ImplGlfw_InstallCallbacks(window);
+
+ // Set platform dependent data in viewport
+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
+ main_viewport->PlatformHandle = (void*)bd->Window;
+#ifdef _WIN32
+ main_viewport->PlatformHandleRaw = glfwGetWin32Window(bd->Window);
+#elif defined(__APPLE__)
+ main_viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(bd->Window);
+#else
+ IM_UNUSED(main_viewport);
+#endif
+
+ // Windows: register a WndProc hook so we can intercept some messages.
+#ifdef _WIN32
+ HWND hwnd = (HWND)main_viewport->PlatformHandleRaw;
+ ::SetPropA(hwnd, "IMGUI_BACKEND_DATA", bd);
+ bd->PrevWndProc = (WNDPROC)::GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
+ IM_ASSERT(bd->PrevWndProc != nullptr);
+ ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)ImGui_ImplGlfw_WndProc);
+#endif
+
+ // Emscripten: the same application can run on various platforms, so we detect the Apple platform at runtime
+ // to override io.ConfigMacOSXBehaviors from its default (which is always false in Emscripten).
+#ifdef __EMSCRIPTEN__
+#if EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 >= 34020240817
+ if (emscripten::glfw3::IsRuntimePlatformApple())
+ {
+ io.ConfigMacOSXBehaviors = true;
+
+ // Due to how the browser (poorly) handles the Meta Key, this line essentially disables repeats when used.
+ // This means that Meta + V only registers a single key-press, even if the keys are held.
+ // This is a compromise for dealing with this issue in ImGui since ImGui implements key repeat itself.
+ // See https://github.com/pongasoft/emscripten-glfw/blob/v3.4.0.20240817/docs/Usage.md#the-problem-of-the-super-key
+ emscripten::glfw3::SetSuperPlusKeyTimeouts(10, 10);
+ }
+#endif
+#endif
+
+ bd->ClientApi = client_api;
+ return true;
+}
+
+bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
+{
+ return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
+}
+
+bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
+{
+ return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
+}
+
+bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
+{
+ return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Unknown);
+}
+
+void ImGui_ImplGlfw_Shutdown()
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
+
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ if (bd->InstalledCallbacks)
+ ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
+#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
+ if (bd->CanvasSelector)
+ emscripten_set_wheel_callback(bd->CanvasSelector, nullptr, false, nullptr);
+#endif
+#if GLFW_HAS_CREATECURSOR
+ for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
+ glfwDestroyCursor(bd->MouseCursors[cursor_n]);
+#endif
+ // Windows: restore our WndProc hook
+#ifdef _WIN32
+ ImGuiViewport* main_viewport = ImGui::GetMainViewport();
+ ::SetPropA((HWND)main_viewport->PlatformHandleRaw, "IMGUI_BACKEND_DATA", nullptr);
+ ::SetWindowLongPtrW((HWND)main_viewport->PlatformHandleRaw, GWLP_WNDPROC, (LONG_PTR)bd->PrevWndProc);
+ bd->PrevWndProc = nullptr;
+#endif
+
+ io.BackendPlatformName = nullptr;
+ io.BackendPlatformUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
+ platform_io.ClearPlatformHandlers();
+ ImGui_ImplGlfw_ContextMap_Remove(bd->Window);
+ IM_DELETE(bd);
+}
+
+static void ImGui_ImplGlfw_UpdateMouseData()
+{
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ ImGuiIO& io = ImGui::GetIO();
+
+ // (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
+ {
+ GLFWwindow* window = bd->Window;
+#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
+ const bool is_window_focused = true;
+#else
+ const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
+#endif
+ if (is_window_focused)
+ {
+ // (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when io.ConfigNavMoveSetMousePos is enabled by user)
+ if (io.WantSetMousePos)
+ glfwSetCursorPos(window, (double)io.MousePos.x, (double)io.MousePos.y);
+
+ // (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
+ if (bd->MouseWindow == nullptr)
+ {
+ double mouse_x, mouse_y;
+ glfwGetCursorPos(window, &mouse_x, &mouse_y);
+ bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
+ io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
+ }
+ }
+ }
+}
+
+static void ImGui_ImplGlfw_UpdateMouseCursor()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
+ return;
+
+ ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
+ // (those braces are here to reduce diff with multi-viewports support in 'docking' branch)
+ {
+ GLFWwindow* window = bd->Window;
+ if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
+ {
+ // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
+ }
+ else
+ {
+ // Show OS mouse cursor
+ // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
+#if GLFW_HAS_CREATECURSOR
+ glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
+#endif
+ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+ }
+ }
+}
+
+// Update gamepad inputs
+static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
+static void ImGui_ImplGlfw_UpdateGamepads()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs, but see #8075
+ return;
+
+ io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
+#if GLFW_HAS_GAMEPAD_API && !defined(EMSCRIPTEN_USE_EMBEDDED_GLFW3)
+ GLFWgamepadstate gamepad;
+ if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
+ return;
+ #define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
+ #define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
+#else
+ int axes_count = 0, buttons_count = 0;
+ const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
+ const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
+ if (axes_count == 0 || buttons_count == 0)
+ return;
+ #define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
+ #define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
+#endif
+ io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
+ MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
+ MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
+ MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
+ MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
+ MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
+ MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
+ MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
+ MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
+ MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
+ MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
+ MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
+ MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
+ MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
+ MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
+ MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
+ MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
+ MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
+ #undef MAP_BUTTON
+ #undef MAP_ANALOG
+}
+
+// - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend.
+// - Apple platforms use FramebufferScale so we always return 1.0f.
+// - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle.
+float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window)
+{
+#if GLFW_HAS_X11_OR_WAYLAND
+ if (ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window))
+ if (bd->IsWayland)
+ return 1.0f;
+#endif
+#if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__))
+ float x_scale, y_scale;
+ glfwGetWindowContentScale(window, &x_scale, &y_scale);
+ return x_scale;
+#else
+ IM_UNUSED(window);
+ return 1.0f;
+#endif
+}
+
+float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor)
+{
+#if GLFW_HAS_X11_OR_WAYLAND
+ if (ImGui_ImplGlfw_IsWayland()) // We can't access our bd->IsWayland cache for a monitor.
+ return 1.0f;
+#endif
+#if GLFW_HAS_PER_MONITOR_DPI && !(defined(__APPLE__) || defined(__EMSCRIPTEN__) || defined(__ANDROID__))
+ float x_scale, y_scale;
+ glfwGetMonitorContentScale(monitor, &x_scale, &y_scale);
+ return x_scale;
+#else
+ IM_UNUSED(monitor);
+ return 1.0f;
+#endif
+}
+
+static void ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(GLFWwindow* window, ImVec2* out_size, ImVec2* out_framebuffer_scale)
+{
+ int w, h;
+ int display_w, display_h;
+ glfwGetWindowSize(window, &w, &h);
+ glfwGetFramebufferSize(window, &display_w, &display_h);
+ float fb_scale_x = (w > 0) ? (float)display_w / (float)w : 1.0f;
+ float fb_scale_y = (h > 0) ? (float)display_h / (float)h : 1.0f;
+#if GLFW_HAS_X11_OR_WAYLAND
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(window);
+ if (!bd->IsWayland)
+ fb_scale_x = fb_scale_y = 1.0f;
+#endif
+ if (out_size != nullptr)
+ *out_size = ImVec2((float)w, (float)h);
+ if (out_framebuffer_scale != nullptr)
+ *out_framebuffer_scale = ImVec2(fb_scale_x, fb_scale_y);
+}
+
+void ImGui_ImplGlfw_NewFrame()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplGlfw_InitForXXX()?");
+
+ // Setup main viewport size (every frame to accommodate for window resizing)
+ ImGui_ImplGlfw_GetWindowSizeAndFramebufferScale(bd->Window, &io.DisplaySize, &io.DisplayFramebufferScale);
+
+ // Setup time step
+ // (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
+ double current_time = glfwGetTime();
+ if (current_time <= bd->Time)
+ current_time = bd->Time + 0.00001f;
+ io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
+ bd->Time = current_time;
+
+ ImGui_ImplGlfw_UpdateMouseData();
+ ImGui_ImplGlfw_UpdateMouseCursor();
+
+ // Update game controllers (if enabled and available)
+ ImGui_ImplGlfw_UpdateGamepads();
+}
+
+// GLFW doesn't provide a portable sleep function
+void ImGui_ImplGlfw_Sleep(int milliseconds)
+{
+#ifdef _WIN32
+ ::Sleep(milliseconds);
+#else
+ usleep(milliseconds * 1000);
+#endif
+}
+
+#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
+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_InstallEmscriptenCallbacks(GLFWwindow*, const char* canvas_selector)
+{
+ IM_ASSERT(canvas_selector != nullptr);
+ ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
+ IM_ASSERT(bd != nullptr && "Context or backend not initialized! 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);
+
+ // Register Emscripten Wheel callback to workaround issue in Emscripten GLFW Emulation (#6096)
+ // We intentionally do not check 'if (install_callbacks)' here, as some users may set it to false and call GLFW callback themselves.
+ // FIXME: May break chaining in case user registered their own Emscripten callback?
+ emscripten_set_wheel_callback(bd->CanvasSelector, bd, false, ImGui_ImplEmscripten_WheelCallback);
+}
+#elif defined(EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3)
+// When using --use-port=contrib.glfw3 for the GLFW implementation, you can override the behavior of this call
+// by invoking emscripten_glfw_make_canvas_resizable afterward.
+// See https://github.com/pongasoft/emscripten-glfw/blob/master/docs/Usage.md#how-to-make-the-canvas-resizable-by-the-user for an explanation
+void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* canvas_selector)
+{
+ GLFWwindow* w = (GLFWwindow*)(EM_ASM_INT({ return Module.glfwGetWindow(UTF8ToString($0)); }, canvas_selector));
+ IM_ASSERT(window == w); // Sanity check
+ IM_UNUSED(w);
+ emscripten_glfw_make_canvas_resizable(window, "window", nullptr);
+}
+#endif // #ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3
+
+//-----------------------------------------------------------------------------
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_glfw.h b/Alphanium/Source/imgui/backends/imgui_impl_glfw.h
new file mode 100644
index 0000000..ce954ed
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_glfw.h
@@ -0,0 +1,70 @@
+// dear imgui: Platform Backend for GLFW
+// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
+// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
+
+// Implemented features:
+// [X] Platform: Clipboard support.
+// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen (Windows only).
+// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLFW_KEY_* values are obsolete since 1.87 and not supported since 1.91.5]
+// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
+// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors) with GLFW 3.1+. Resizing cursors requires GLFW 3.4+! Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
+// [X] Multiple Dear ImGui contexts support.
+// Missing features or Issues:
+// [ ] Touch events are only correctly identified as Touch on Windows. This create issues with some interactions. GLFW doesn't provide a way to identify touch inputs from mouse inputs, we cannot call io.AddMouseSourceEvent() to identify the source. We provide a Windows-specific workaround.
+// [ ] Missing ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress cursors.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// Learn about Dear ImGui:
+// - FAQ https://dearimgui.com/faq
+// - Getting Started https://dearimgui.com/getting-started
+// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
+// - Introduction, links and more at the top of imgui.cpp
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+struct GLFWwindow;
+struct GLFWmonitor;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
+IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
+IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks);
+IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
+
+// Emscripten related initialization phase methods (call after ImGui_ImplGlfw_InitForOpenGL)
+#ifdef __EMSCRIPTEN__
+IMGUI_IMPL_API void ImGui_ImplGlfw_InstallEmscriptenCallbacks(GLFWwindow* window, const char* canvas_selector);
+//static inline void ImGui_ImplGlfw_InstallEmscriptenCanvasResizeCallback(const char* canvas_selector) { ImGui_ImplGlfw_InstallEmscriptenCallbacks(nullptr, canvas_selector); } } // Renamed in 1.91.0
+#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.
+IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
+IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
+
+// GFLW callbacks options:
+// - Set 'chain_for_all_windows=true' to enable chaining callbacks for all windows (including secondary viewports created by backends or by user)
+IMGUI_IMPL_API void ImGui_ImplGlfw_SetCallbacksChainForAllWindows(bool chain_for_all_windows);
+
+// GLFW callbacks (individual callbacks to call yourself if you didn't install callbacks)
+IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
+IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
+IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
+IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
+IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
+IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
+IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int event);
+
+// GLFW helpers
+IMGUI_IMPL_API void ImGui_ImplGlfw_Sleep(int milliseconds);
+IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForWindow(GLFWwindow* window);
+IMGUI_IMPL_API float ImGui_ImplGlfw_GetContentScaleForMonitor(GLFWmonitor* monitor);
+
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_glut.cpp b/Alphanium/Source/imgui/backends/imgui_impl_glut.cpp
new file mode 100644
index 0000000..a68f9db
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_glut.cpp
@@ -0,0 +1,309 @@
+// dear imgui: Platform Backend for GLUT/FreeGLUT
+// This needs to be used along with a Renderer (e.g. OpenGL2)
+
+// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
+// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
+// !!! Nowadays, prefer using GLFW or SDL instead!
+
+// Implemented features:
+// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values are obsolete since 1.87 and not supported since 1.91.5]
+// Missing features or Issues:
+// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
+// [ ] Platform: Missing horizontal mouse wheel support.
+// [ ] Platform: Missing mouse cursor shape/visibility support.
+// [ ] Platform: Missing clipboard support (not supported by Glut).
+// [ ] Platform: Missing gamepad support.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2023-04-17: BREAKING: Removed call to ImGui::NewFrame() from ImGui_ImplGLUT_NewFrame(). Needs to be called from the main application loop, like with every other backends.
+// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
+// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
+// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
+// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
+// 2019-04-03: Misc: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h.
+// 2019-03-25: Misc: Made io.DeltaTime always above zero.
+// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
+// 2018-03-22: Added GLUT Platform binding.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_glut.h"
+#define GL_SILENCE_DEPRECATION
+#ifdef __APPLE__
+#include
+#else
+#include
+#endif
+
+#ifdef _MSC_VER
+#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
+#endif
+
+static int g_Time = 0; // Current time, in milliseconds
+
+// Glut has one function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
+static ImGuiKey ImGui_ImplGLUT_KeyToImGuiKey(int key)
+{
+ switch (key)
+ {
+ case '\t': return ImGuiKey_Tab;
+ case 256 + GLUT_KEY_LEFT: return ImGuiKey_LeftArrow;
+ case 256 + GLUT_KEY_RIGHT: return ImGuiKey_RightArrow;
+ case 256 + GLUT_KEY_UP: return ImGuiKey_UpArrow;
+ case 256 + GLUT_KEY_DOWN: return ImGuiKey_DownArrow;
+ case 256 + GLUT_KEY_PAGE_UP: return ImGuiKey_PageUp;
+ case 256 + GLUT_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
+ case 256 + GLUT_KEY_HOME: return ImGuiKey_Home;
+ case 256 + GLUT_KEY_END: return ImGuiKey_End;
+ case 256 + GLUT_KEY_INSERT: return ImGuiKey_Insert;
+ case 127: return ImGuiKey_Delete;
+ case 8: return ImGuiKey_Backspace;
+ case ' ': return ImGuiKey_Space;
+ case 13: return ImGuiKey_Enter;
+ case 27: return ImGuiKey_Escape;
+ case 39: return ImGuiKey_Apostrophe;
+ case 44: return ImGuiKey_Comma;
+ case 45: return ImGuiKey_Minus;
+ case 46: return ImGuiKey_Period;
+ case 47: return ImGuiKey_Slash;
+ case 59: return ImGuiKey_Semicolon;
+ case 61: return ImGuiKey_Equal;
+ case 91: return ImGuiKey_LeftBracket;
+ case 92: return ImGuiKey_Backslash;
+ case 93: return ImGuiKey_RightBracket;
+ case 96: return ImGuiKey_GraveAccent;
+ //case 0: return ImGuiKey_CapsLock;
+ //case 0: return ImGuiKey_ScrollLock;
+ case 256 + 0x006D: return ImGuiKey_NumLock;
+ //case 0: return ImGuiKey_PrintScreen;
+ //case 0: return ImGuiKey_Pause;
+ //case '0': return ImGuiKey_Keypad0;
+ //case '1': return ImGuiKey_Keypad1;
+ //case '2': return ImGuiKey_Keypad2;
+ //case '3': return ImGuiKey_Keypad3;
+ //case '4': return ImGuiKey_Keypad4;
+ //case '5': return ImGuiKey_Keypad5;
+ //case '6': return ImGuiKey_Keypad6;
+ //case '7': return ImGuiKey_Keypad7;
+ //case '8': return ImGuiKey_Keypad8;
+ //case '9': return ImGuiKey_Keypad9;
+ //case 46: return ImGuiKey_KeypadDecimal;
+ //case 47: return ImGuiKey_KeypadDivide;
+ case 42: return ImGuiKey_KeypadMultiply;
+ //case 45: return ImGuiKey_KeypadSubtract;
+ case 43: return ImGuiKey_KeypadAdd;
+ //case 13: return ImGuiKey_KeypadEnter;
+ //case 0: return ImGuiKey_KeypadEqual;
+ case 256 + 0x0072: return ImGuiKey_LeftCtrl;
+ case 256 + 0x0070: return ImGuiKey_LeftShift;
+ case 256 + 0x0074: return ImGuiKey_LeftAlt;
+ //case 0: return ImGuiKey_LeftSuper;
+ case 256 + 0x0073: return ImGuiKey_RightCtrl;
+ case 256 + 0x0071: return ImGuiKey_RightShift;
+ case 256 + 0x0075: return ImGuiKey_RightAlt;
+ //case 0: return ImGuiKey_RightSuper;
+ //case 0: return ImGuiKey_Menu;
+ case '0': return ImGuiKey_0;
+ case '1': return ImGuiKey_1;
+ case '2': return ImGuiKey_2;
+ case '3': return ImGuiKey_3;
+ case '4': return ImGuiKey_4;
+ case '5': return ImGuiKey_5;
+ case '6': return ImGuiKey_6;
+ case '7': return ImGuiKey_7;
+ case '8': return ImGuiKey_8;
+ case '9': return ImGuiKey_9;
+ case 'A': case 'a': return ImGuiKey_A;
+ case 'B': case 'b': return ImGuiKey_B;
+ case 'C': case 'c': return ImGuiKey_C;
+ case 'D': case 'd': return ImGuiKey_D;
+ case 'E': case 'e': return ImGuiKey_E;
+ case 'F': case 'f': return ImGuiKey_F;
+ case 'G': case 'g': return ImGuiKey_G;
+ case 'H': case 'h': return ImGuiKey_H;
+ case 'I': case 'i': return ImGuiKey_I;
+ case 'J': case 'j': return ImGuiKey_J;
+ case 'K': case 'k': return ImGuiKey_K;
+ case 'L': case 'l': return ImGuiKey_L;
+ case 'M': case 'm': return ImGuiKey_M;
+ case 'N': case 'n': return ImGuiKey_N;
+ case 'O': case 'o': return ImGuiKey_O;
+ case 'P': case 'p': return ImGuiKey_P;
+ case 'Q': case 'q': return ImGuiKey_Q;
+ case 'R': case 'r': return ImGuiKey_R;
+ case 'S': case 's': return ImGuiKey_S;
+ case 'T': case 't': return ImGuiKey_T;
+ case 'U': case 'u': return ImGuiKey_U;
+ case 'V': case 'v': return ImGuiKey_V;
+ case 'W': case 'w': return ImGuiKey_W;
+ case 'X': case 'x': return ImGuiKey_X;
+ case 'Y': case 'y': return ImGuiKey_Y;
+ case 'Z': case 'z': return ImGuiKey_Z;
+ case 256 + GLUT_KEY_F1: return ImGuiKey_F1;
+ case 256 + GLUT_KEY_F2: return ImGuiKey_F2;
+ case 256 + GLUT_KEY_F3: return ImGuiKey_F3;
+ case 256 + GLUT_KEY_F4: return ImGuiKey_F4;
+ case 256 + GLUT_KEY_F5: return ImGuiKey_F5;
+ case 256 + GLUT_KEY_F6: return ImGuiKey_F6;
+ case 256 + GLUT_KEY_F7: return ImGuiKey_F7;
+ case 256 + GLUT_KEY_F8: return ImGuiKey_F8;
+ case 256 + GLUT_KEY_F9: return ImGuiKey_F9;
+ case 256 + GLUT_KEY_F10: return ImGuiKey_F10;
+ case 256 + GLUT_KEY_F11: return ImGuiKey_F11;
+ case 256 + GLUT_KEY_F12: return ImGuiKey_F12;
+ default: return ImGuiKey_None;
+ }
+}
+
+bool ImGui_ImplGLUT_Init()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+
+#ifdef FREEGLUT
+ io.BackendPlatformName = "imgui_impl_glut (freeglut)";
+#else
+ io.BackendPlatformName = "imgui_impl_glut";
+#endif
+ g_Time = 0;
+
+ return true;
+}
+
+void ImGui_ImplGLUT_InstallFuncs()
+{
+ glutReshapeFunc(ImGui_ImplGLUT_ReshapeFunc);
+ glutMotionFunc(ImGui_ImplGLUT_MotionFunc);
+ glutPassiveMotionFunc(ImGui_ImplGLUT_MotionFunc);
+ glutMouseFunc(ImGui_ImplGLUT_MouseFunc);
+#ifdef __FREEGLUT_EXT_H__
+ glutMouseWheelFunc(ImGui_ImplGLUT_MouseWheelFunc);
+#endif
+ glutKeyboardFunc(ImGui_ImplGLUT_KeyboardFunc);
+ glutKeyboardUpFunc(ImGui_ImplGLUT_KeyboardUpFunc);
+ glutSpecialFunc(ImGui_ImplGLUT_SpecialFunc);
+ glutSpecialUpFunc(ImGui_ImplGLUT_SpecialUpFunc);
+}
+
+void ImGui_ImplGLUT_Shutdown()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.BackendPlatformName = nullptr;
+}
+
+void ImGui_ImplGLUT_NewFrame()
+{
+ // Setup time step
+ ImGuiIO& io = ImGui::GetIO();
+ int current_time = glutGet(GLUT_ELAPSED_TIME);
+ int delta_time_ms = (current_time - g_Time);
+ if (delta_time_ms <= 0)
+ delta_time_ms = 1;
+ io.DeltaTime = delta_time_ms / 1000.0f;
+ g_Time = current_time;
+}
+
+static void ImGui_ImplGLUT_UpdateKeyModifiers()
+{
+ ImGuiIO& io = ImGui::GetIO();
+ int glut_key_mods = glutGetModifiers();
+ io.AddKeyEvent(ImGuiMod_Ctrl, (glut_key_mods & GLUT_ACTIVE_CTRL) != 0);
+ io.AddKeyEvent(ImGuiMod_Shift, (glut_key_mods & GLUT_ACTIVE_SHIFT) != 0);
+ io.AddKeyEvent(ImGuiMod_Alt, (glut_key_mods & GLUT_ACTIVE_ALT) != 0);
+}
+
+static void ImGui_ImplGLUT_AddKeyEvent(ImGuiKey key, bool down, int native_keycode)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddKeyEvent(key, down);
+ io.SetKeyEventNativeData(key, native_keycode, -1); // To support legacy indexing (<1.87 user code)
+}
+
+void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
+{
+ // Send character to imgui
+ //printf("char_down_func %d '%c'\n", c, c);
+ ImGuiIO& io = ImGui::GetIO();
+ if (c >= 32)
+ io.AddInputCharacter((unsigned int)c);
+
+ ImGuiKey key = ImGui_ImplGLUT_KeyToImGuiKey(c);
+ ImGui_ImplGLUT_AddKeyEvent(key, true, c);
+ ImGui_ImplGLUT_UpdateKeyModifiers();
+ (void)x; (void)y; // Unused
+}
+
+void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y)
+{
+ //printf("char_up_func %d '%c'\n", c, c);
+ ImGuiKey key = ImGui_ImplGLUT_KeyToImGuiKey(c);
+ ImGui_ImplGLUT_AddKeyEvent(key, false, c);
+ ImGui_ImplGLUT_UpdateKeyModifiers();
+ (void)x; (void)y; // Unused
+}
+
+void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y)
+{
+ //printf("key_down_func %d\n", key);
+ ImGuiKey imgui_key = ImGui_ImplGLUT_KeyToImGuiKey(key + 256);
+ ImGui_ImplGLUT_AddKeyEvent(imgui_key, true, key + 256);
+ ImGui_ImplGLUT_UpdateKeyModifiers();
+ (void)x; (void)y; // Unused
+}
+
+void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y)
+{
+ //printf("key_up_func %d\n", key);
+ ImGuiKey imgui_key = ImGui_ImplGLUT_KeyToImGuiKey(key + 256);
+ ImGui_ImplGLUT_AddKeyEvent(imgui_key, false, key + 256);
+ ImGui_ImplGLUT_UpdateKeyModifiers();
+ (void)x; (void)y; // Unused
+}
+
+void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddMousePosEvent((float)x, (float)y);
+ int button = -1;
+ if (glut_button == GLUT_LEFT_BUTTON) button = 0;
+ if (glut_button == GLUT_RIGHT_BUTTON) button = 1;
+ if (glut_button == GLUT_MIDDLE_BUTTON) button = 2;
+ if (button != -1 && (state == GLUT_DOWN || state == GLUT_UP))
+ io.AddMouseButtonEvent(button, state == GLUT_DOWN);
+}
+
+#ifdef __FREEGLUT_EXT_H__
+void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddMousePosEvent((float)x, (float)y);
+ if (dir != 0)
+ io.AddMouseWheelEvent(0.0f, dir > 0 ? 1.0f : -1.0f);
+ (void)button; // Unused
+}
+#endif
+
+void ImGui_ImplGLUT_ReshapeFunc(int w, int h)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.DisplaySize = ImVec2((float)w, (float)h);
+}
+
+void ImGui_ImplGLUT_MotionFunc(int x, int y)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ io.AddMousePosEvent((float)x, (float)y);
+}
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_glut.h b/Alphanium/Source/imgui/backends/imgui_impl_glut.h
new file mode 100644
index 0000000..20e77db
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_glut.h
@@ -0,0 +1,47 @@
+// dear imgui: Platform Backend for GLUT/FreeGLUT
+// This needs to be used along with a Renderer (e.g. OpenGL2)
+
+// !!! GLUT/FreeGLUT IS OBSOLETE PREHISTORIC SOFTWARE. Using GLUT is not recommended unless you really miss the 90's. !!!
+// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
+// !!! Nowadays, prefer using GLFW or SDL instead!
+
+// Implemented features:
+// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values are obsolete since 1.87 and not supported since 1.91.5]
+// Missing features or Issues:
+// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
+// [ ] Platform: Missing horizontal mouse wheel support.
+// [ ] Platform: Missing mouse cursor shape/visibility support.
+// [ ] Platform: Missing clipboard support (not supported by Glut).
+// [ ] Platform: Missing gamepad support.
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+#pragma once
+#ifndef IMGUI_DISABLE
+#include "imgui.h" // IMGUI_IMPL_API
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplGLUT_Init();
+IMGUI_IMPL_API void ImGui_ImplGLUT_InstallFuncs();
+IMGUI_IMPL_API void ImGui_ImplGLUT_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplGLUT_NewFrame();
+
+// You can call ImGui_ImplGLUT_InstallFuncs() to get all those functions installed automatically,
+// or call them yourself from your own GLUT handlers. We are using the same weird names as GLUT for consistency..
+//------------------------------------ GLUT name ---------------------------------------------- Decent Name ---------
+IMGUI_IMPL_API void ImGui_ImplGLUT_ReshapeFunc(int w, int h); // ~ ResizeFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_MotionFunc(int x, int y); // ~ MouseMoveFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_MouseFunc(int button, int state, int x, int y); // ~ MouseButtonFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y); // ~ MouseWheelFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y); // ~ CharPressedFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y); // ~ CharReleasedFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y); // ~ KeyPressedFunc
+IMGUI_IMPL_API void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y); // ~ KeyReleasedFunc
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_metal.h b/Alphanium/Source/imgui/backends/imgui_impl_metal.h
new file mode 100644
index 0000000..2a9a26a
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_metal.h
@@ -0,0 +1,78 @@
+// dear imgui: Renderer Backend for Metal
+// This needs to be used along with a Platform Backend (e.g. OSX)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+#pragma once
+#include "imgui.h" // IMGUI_IMPL_API
+#ifndef IMGUI_DISABLE
+
+//-----------------------------------------------------------------------------
+// ObjC API
+//-----------------------------------------------------------------------------
+
+#ifdef __OBJC__
+
+@class MTLRenderPassDescriptor;
+@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplMetal_Init(id device);
+IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor);
+IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* drawData,
+ id commandBuffer,
+ id commandEncoder);
+
+// Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id device);
+IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
+
+#endif
+
+//-----------------------------------------------------------------------------
+// C++ API
+//-----------------------------------------------------------------------------
+
+// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
+// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
+
+#ifdef IMGUI_IMPL_METAL_CPP
+#include
+#ifndef __OBJC__
+
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
+IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
+IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
+IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
+IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
+ MTL::CommandBuffer* commandBuffer,
+ MTL::RenderCommandEncoder* commandEncoder);
+
+// Called by Init/NewFrame/Shutdown
+IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
+IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
+
+// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
+IMGUI_IMPL_API void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex);
+
+#endif
+#endif
+
+//-----------------------------------------------------------------------------
+
+#endif // #ifndef IMGUI_DISABLE
diff --git a/Alphanium/Source/imgui/backends/imgui_impl_metal.mm b/Alphanium/Source/imgui/backends/imgui_impl_metal.mm
new file mode 100644
index 0000000..2746efa
--- /dev/null
+++ b/Alphanium/Source/imgui/backends/imgui_impl_metal.mm
@@ -0,0 +1,654 @@
+// dear imgui: Renderer Backend for Metal
+// This needs to be used along with a Platform Backend (e.g. OSX)
+
+// Implemented features:
+// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
+// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
+// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
+
+// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
+// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
+// 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
+
+// CHANGELOG
+// (minor and older changes stripped away, please see git history for details)
+// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
+// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture().
+// 2025-02-03: Metal: Crash fix. (#8367)
+// 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419).
+// 2022-08-23: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'.
+// 2022-07-05: Metal: Add dispatch synchronization.
+// 2022-06-30: Metal: Use __bridge for ARC based systems.
+// 2022-06-01: Metal: Fixed null dereference on exit inside command buffer completion handler.
+// 2022-04-27: Misc: Store backend data in a per-context struct, allowing to use this backend with multiple contexts.
+// 2022-01-03: Metal: Ignore ImDrawCmd where ElemCount == 0 (very rare but can technically be manufactured by user code).
+// 2021-12-30: Metal: Added Metal C++ support. Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.
+// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
+// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
+// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
+// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
+// 2019-05-29: Metal: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
+// 2019-04-30: Metal: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
+// 2019-02-11: Metal: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
+// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
+// 2018-07-05: Metal: Added new Metal backend implementation.
+
+#include "imgui.h"
+#ifndef IMGUI_DISABLE
+#include "imgui_impl_metal.h"
+#import
+#import
+
+#pragma mark - Support classes
+
+// A wrapper around a MTLBuffer object that knows the last time it was reused
+@interface MetalBuffer : NSObject
+@property (nonatomic, strong) id buffer;
+@property (nonatomic, assign) double lastReuseTime;
+- (instancetype)initWithBuffer:(id)buffer;
+@end
+
+// An object that encapsulates the data necessary to uniquely identify a
+// render pipeline state. These are used as cache keys.
+@interface FramebufferDescriptor : NSObject
+@property (nonatomic, assign) unsigned long sampleCount;
+@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
+@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
+@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
+- (instancetype)initWithRenderPassDescriptor:(MTLRenderPassDescriptor*)renderPassDescriptor;
+@end
+
+@interface MetalTexture : NSObject
+@property (nonatomic, strong) id metalTexture;
+- (instancetype)initWithTexture:(id)metalTexture;
+@end
+
+// A singleton that stores long-lived objects that are needed by the Metal
+// renderer backend. Stores the render pipeline state cache and the default
+// font texture, and manages the reusable buffer cache.
+@interface MetalContext : NSObject
+@property (nonatomic, strong) id device;
+@property (nonatomic, strong) id depthStencilState;
+@property (nonatomic, strong) FramebufferDescriptor* framebufferDescriptor; // framebuffer descriptor for current frame; transient
+@property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
+@property (nonatomic, strong) NSMutableArray* bufferCache;
+@property (nonatomic, assign) double lastBufferCachePurge;
+- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id)device;
+- (id)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id)device;
+@end
+
+struct ImGui_ImplMetal_Data
+{
+ MetalContext* SharedMetalContext;
+
+ ImGui_ImplMetal_Data() { memset((void*)this, 0, sizeof(*this)); }
+};
+
+static ImGui_ImplMetal_Data* ImGui_ImplMetal_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; }
+static void ImGui_ImplMetal_DestroyBackendData(){ IM_DELETE(ImGui_ImplMetal_GetBackendData()); }
+
+static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); }
+
+#ifdef IMGUI_IMPL_METAL_CPP
+
+#pragma mark - Dear ImGui Metal C++ Backend API
+
+bool ImGui_ImplMetal_Init(MTL::Device* device)
+{
+ return ImGui_ImplMetal_Init((__bridge id)(device));
+}
+
+void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor)
+{
+ ImGui_ImplMetal_NewFrame((__bridge MTLRenderPassDescriptor*)(renderPassDescriptor));
+}
+
+void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
+ MTL::CommandBuffer* commandBuffer,
+ MTL::RenderCommandEncoder* commandEncoder)
+{
+ ImGui_ImplMetal_RenderDrawData(draw_data,
+ (__bridge id)(commandBuffer),
+ (__bridge id)(commandEncoder));
+
+}
+
+bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
+{
+ return ImGui_ImplMetal_CreateDeviceObjects((__bridge id)(device));
+}
+
+#endif // #ifdef IMGUI_IMPL_METAL_CPP
+
+#pragma mark - Dear ImGui Metal Backend API
+
+bool ImGui_ImplMetal_Init(id device)
+{
+ ImGuiIO& io = ImGui::GetIO();
+ IMGUI_CHECKVERSION();
+ IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
+
+ ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)();
+ io.BackendRendererUserData = (void*)bd;
+ io.BackendRendererName = "imgui_impl_metal";
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
+ io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
+
+ bd->SharedMetalContext = [[MetalContext alloc] init];
+ bd->SharedMetalContext.device = device;
+
+ return true;
+}
+
+void ImGui_ImplMetal_Shutdown()
+{
+ ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
+ IM_UNUSED(bd);
+ IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
+ ImGuiIO& io = ImGui::GetIO();
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+
+ ImGui_ImplMetal_DestroyDeviceObjects();
+ ImGui_ImplMetal_DestroyBackendData();
+
+ io.BackendRendererName = nullptr;
+ io.BackendRendererUserData = nullptr;
+ io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
+ platform_io.ClearRendererHandlers();
+}
+
+void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor)
+{
+ ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
+ IM_ASSERT(bd != nil && "Context or backend not initialized! Did you call ImGui_ImplMetal_Init()?");
+#ifdef IMGUI_IMPL_METAL_CPP
+ bd->SharedMetalContext.framebufferDescriptor = [[[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]autorelease];
+#else
+ bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
+#endif
+ if (bd->SharedMetalContext.depthStencilState == nil)
+ ImGui_ImplMetal_CreateDeviceObjects(bd->SharedMetalContext.device);
+}
+
+static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id commandBuffer,
+ id commandEncoder, id renderPipelineState,
+ MetalBuffer* vertexBuffer, size_t vertexBufferOffset)
+{
+ IM_UNUSED(commandBuffer);
+ ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
+ [commandEncoder setCullMode:MTLCullModeNone];
+ [commandEncoder setDepthStencilState:bd->SharedMetalContext.depthStencilState];
+
+ // Setup viewport, orthographic projection matrix
+ // Our visible imgui space lies from draw_data->DisplayPos (top left) to
+ // draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
+ MTLViewport viewport =
+ {
+ .originX = 0.0,
+ .originY = 0.0,
+ .width = (double)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x),
+ .height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y),
+ .znear = 0.0,
+ .zfar = 1.0
+ };
+ [commandEncoder setViewport:viewport];
+
+ float L = draw_data->DisplayPos.x;
+ float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
+ float T = draw_data->DisplayPos.y;
+ float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
+ float N = (float)viewport.znear;
+ float F = (float)viewport.zfar;
+ const float ortho_projection[4][4] =
+ {
+ { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
+ { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
+ { 0.0f, 0.0f, 1/(F-N), 0.0f },
+ { (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
+ };
+ [commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
+
+ [commandEncoder setRenderPipelineState:renderPipelineState];
+
+ [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
+ [commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
+}
+
+// Metal Render function.
+void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id commandBuffer, id commandEncoder)
+{
+ ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
+ MetalContext* ctx = bd->SharedMetalContext;
+
+ // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
+ int fb_width = (int)(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->CmdLists.Size == 0)
+ return;
+
+ // Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
+ // (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
+ if (draw_data->Textures != nullptr)
+ for (ImTextureData* tex : *draw_data->Textures)
+ if (tex->Status != ImTextureStatus_OK)
+ ImGui_ImplMetal_UpdateTexture(tex);
+
+ // Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
+ // The hit rate for this cache should be very near 100%.
+ id renderPipelineState = ctx.renderPipelineStateCache[ctx.framebufferDescriptor];
+ if (renderPipelineState == nil)
+ {
+ // No luck; make a new render pipeline state
+ renderPipelineState = [ctx renderPipelineStateForFramebufferDescriptor:ctx.framebufferDescriptor device:commandBuffer.device];
+
+ // Cache render pipeline state for later reuse
+ ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState;
+ }
+
+ size_t vertexBufferLength = (size_t)draw_data->TotalVtxCount * sizeof(ImDrawVert);
+ size_t indexBufferLength = (size_t)draw_data->TotalIdxCount * sizeof(ImDrawIdx);
+ MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
+ MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
+
+ ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);
+
+ // Will project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
+ ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
+
+ // Render command lists
+ size_t vertexBufferOffset = 0;
+ size_t indexBufferOffset = 0;
+ for (const ImDrawList* draw_list : draw_data->CmdLists)
+ {
+ memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert));
+ memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
+
+ for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
+ {
+ const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
+ if (pcmd->UserCallback)
+ {
+ // User callback, registered via ImDrawList::AddCallback()
+ // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
+ if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
+ ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);
+ else
+ pcmd->UserCallback(draw_list, pcmd);
+ }
+ else
+ {
+ // Project scissor/clipping rectangles into framebuffer space
+ ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
+ ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
+
+ // Clamp to viewport as setScissorRect() 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;
+ if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
+ continue;
+
+ // Apply scissor/clipping rectangle
+ MTLScissorRect scissorRect =
+ {
+ .x = NSUInteger(clip_min.x),
+ .y = NSUInteger(clip_min.y),
+ .width = NSUInteger(clip_max.x - clip_min.x),
+ .height = NSUInteger(clip_max.y - clip_min.y)
+ };
+ [commandEncoder setScissorRect:scissorRect];
+
+ // Bind texture, Draw
+ if (ImTextureID tex_id = pcmd->GetTexID())
+ [commandEncoder setFragmentTexture:(__bridge id)(void*)(intptr_t)(tex_id) atIndex:0];
+
+ [commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
+ [commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
+ indexCount:pcmd->ElemCount
+ indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
+ indexBuffer:indexBuffer.buffer
+ indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
+ }
+ }
+
+ vertexBufferOffset += (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert);
+ indexBufferOffset += (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx);
+ }
+
+ MetalContext* sharedMetalContext = bd->SharedMetalContext;
+ [commandBuffer addCompletedHandler:^(id)
+ {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ @synchronized(sharedMetalContext.bufferCache)
+ {
+ [sharedMetalContext.bufferCache addObject:vertexBuffer];
+ [sharedMetalContext.bufferCache addObject:indexBuffer];
+ }
+ });
+ }];
+}
+
+static void ImGui_ImplMetal_DestroyTexture(ImTextureData* tex)
+{
+ if (MetalTexture* backend_tex = (__bridge_transfer MetalTexture*)(tex->BackendUserData))
+ {
+ IM_ASSERT(backend_tex.metalTexture == (__bridge id)(void*)(intptr_t)tex->TexID);
+ backend_tex.metalTexture = nil;
+
+ // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
+ tex->SetTexID(ImTextureID_Invalid);
+ tex->BackendUserData = nullptr;
+ }
+ tex->SetStatus(ImTextureStatus_Destroyed);
+}
+
+void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex)
+{
+ ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
+ if (tex->Status == ImTextureStatus_WantCreate)
+ {
+ // Create and upload new texture to graphics system
+ //IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
+ IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
+ IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+
+ // We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
+ // In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
+ // However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
+ // You can make that change in your implementation.
+ MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
+ width:(NSUInteger)tex->Width
+ height:(NSUInteger)tex->Height
+ mipmapped:NO];
+ textureDescriptor.usage = MTLTextureUsageShaderRead;
+ #if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+ textureDescriptor.storageMode = MTLStorageModeManaged;
+ #else
+ textureDescriptor.storageMode = MTLStorageModeShared;
+ #endif
+ id texture = [bd->SharedMetalContext.device newTextureWithDescriptor:textureDescriptor];
+ [texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)tex->Width, (NSUInteger)tex->Height) mipmapLevel:0 withBytes:tex->Pixels bytesPerRow:(NSUInteger)tex->Width * 4];
+ MetalTexture* backend_tex = [[MetalTexture alloc] initWithTexture:texture];
+
+ // Store identifiers
+ tex->SetTexID((ImTextureID)(intptr_t)texture);
+ tex->SetStatus(ImTextureStatus_OK);
+ tex->BackendUserData = (__bridge_retained void*)(backend_tex);
+ }
+ else if (tex->Status == ImTextureStatus_WantUpdates)
+ {
+ // Update selected blocks. We only ever write to textures regions which have never been used before!
+ // This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
+ MetalTexture* backend_tex = (__bridge MetalTexture*)(tex->BackendUserData);
+ for (ImTextureRect& r : tex->Updates)
+ {
+ [backend_tex.metalTexture replaceRegion:MTLRegionMake2D((NSUInteger)r.x, (NSUInteger)r.y, (NSUInteger)r.w, (NSUInteger)r.h)
+ mipmapLevel:0
+ withBytes:tex->GetPixelsAt(r.x, r.y)
+ bytesPerRow:(NSUInteger)tex->Width * 4];
+ }
+ tex->SetStatus(ImTextureStatus_OK);
+ }
+ else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
+ {
+ ImGui_ImplMetal_DestroyTexture(tex);
+ }
+}
+
+bool ImGui_ImplMetal_CreateDeviceObjects(id