diff --git a/.gitignore b/.gitignore index 009e61ede..23c174e03 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,5 @@ 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 +misc/cxx_module/build/ +misc/cxx_module/CMakeUserPresets.json diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index bd877f322..bd282e149 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -66,6 +66,7 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_allegro5.h" +#ifndef IMGUI_CXX_MODULE #include // uint64_t #include // memcpy @@ -75,6 +76,7 @@ #ifdef _WIN32 #include #endif +#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 diff --git a/backends/imgui_impl_allegro5.cppm b/backends/imgui_impl_allegro5.cppm new file mode 100644 index 000000000..96e25e005 --- /dev/null +++ b/backends/imgui_impl_allegro5.cppm @@ -0,0 +1,27 @@ +// dear imgui: Renderer + Platform Backend for Allegro 5, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.allegro5;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX + +// Allegro (same as imgui_impl_allegro5.cpp) +#include +#include +#ifdef _WIN32 +#include +#endif + +export module imgui.impl.allegro5; + +import std.compat; +import imgui; + +#include "imgui_impl_allegro5.h" + +module :private; + +#include "imgui_impl_allegro5.cpp" diff --git a/backends/imgui_impl_allegro5.h b/backends/imgui_impl_allegro5.h index 84ebf4338..c7b6cc190 100644 --- a/backends/imgui_impl_allegro5.h +++ b/backends/imgui_impl_allegro5.h @@ -24,9 +24,12 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct ALLEGRO_DISPLAY; union ALLEGRO_EVENT; +#endif +IMGUI_EXPORT_BEGIN // 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(); @@ -41,5 +44,6 @@ 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 = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_android.cpp b/backends/imgui_impl_android.cpp index 21a7ae526..68dd0ab4a 100644 --- a/backends/imgui_impl_android.cpp +++ b/backends/imgui_impl_android.cpp @@ -34,11 +34,13 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_android.h" +#ifndef IMGUI_CXX_MODULE #include #include #include #include #include +#endif // Android data static double g_Time = 0.0; diff --git a/backends/imgui_impl_android.cppm b/backends/imgui_impl_android.cppm new file mode 100644 index 000000000..4144dba31 --- /dev/null +++ b/backends/imgui_impl_android.cppm @@ -0,0 +1,27 @@ +// dear imgui: Platform Binding for Android native app, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.android;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX +#include // CLOCK_MONOTONIC + +// Android NDK (same as imgui_impl_android.cpp) +#include +#include +#include +#include + +export module imgui.impl.android; + +import std.compat; +import imgui; + +#include "imgui_impl_android.h" + +module :private; + +#include "imgui_impl_android.cpp" diff --git a/backends/imgui_impl_android.h b/backends/imgui_impl_android.h index 8f22e9b76..a1e92675c 100644 --- a/backends/imgui_impl_android.h +++ b/backends/imgui_impl_android.h @@ -25,13 +25,17 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct ANativeWindow; struct AInputEvent; +#endif +IMGUI_EXPORT_BEGIN // 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(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index a81d81305..25a5b039a 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -47,10 +47,12 @@ #include "imgui_impl_dx10.h" // DirectX +#ifndef IMGUI_CXX_MODULE #include #include #include #include +#endif #ifdef _MSC_VER #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif diff --git a/backends/imgui_impl_dx10.cppm b/backends/imgui_impl_dx10.cppm new file mode 100644 index 000000000..2b2f73b2d --- /dev/null +++ b/backends/imgui_impl_dx10.cppm @@ -0,0 +1,25 @@ +// dear imgui: Renderer Backend for DirectX10, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.dx10;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// DirectX (same as imgui_impl_dx10.cpp) +#include +#include +#include + +export module imgui.impl.dx10; + +import std.compat; +import imgui; + +#include "imgui_impl_dx10.h" + +module :private; + +#include "imgui_impl_dx10.cpp" diff --git a/backends/imgui_impl_dx10.h b/backends/imgui_impl_dx10.h index 3ab1669a9..753f81228 100644 --- a/backends/imgui_impl_dx10.h +++ b/backends/imgui_impl_dx10.h @@ -19,10 +19,13 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct ID3D10Device; struct ID3D10SamplerState; struct ID3D10Buffer; +#endif +IMGUI_EXPORT_BEGIN // 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(); @@ -47,5 +50,6 @@ struct ImGui_ImplDX10_RenderState //ID3D10SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; IMGUI_IMPL_API ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index a7d2cdf73..ca7bf7dfb 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -48,9 +48,11 @@ #include "imgui_impl_dx11.h" // DirectX +#ifndef IMGUI_CXX_MODULE #include #include #include +#endif #ifdef _MSC_VER #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif diff --git a/backends/imgui_impl_dx11.cppm b/backends/imgui_impl_dx11.cppm new file mode 100644 index 000000000..2e17b4cec --- /dev/null +++ b/backends/imgui_impl_dx11.cppm @@ -0,0 +1,24 @@ +// dear imgui: Renderer Backend for DirectX11, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.dx11;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// DirectX (same as imgui_impl_dx11.cpp) +#include +#include + +export module imgui.impl.dx11; + +import std.compat; +import imgui; + +#include "imgui_impl_dx11.h" + +module :private; + +#include "imgui_impl_dx11.cpp" diff --git a/backends/imgui_impl_dx11.h b/backends/imgui_impl_dx11.h index 5fd8ddca9..d079867ca 100644 --- a/backends/imgui_impl_dx11.h +++ b/backends/imgui_impl_dx11.h @@ -19,11 +19,14 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct ID3D11Device; struct ID3D11DeviceContext; struct ID3D11SamplerState; struct ID3D11Buffer; +#endif +IMGUI_EXPORT_BEGIN // 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(); @@ -49,5 +52,6 @@ struct ImGui_ImplDX11_RenderState //ID3D11SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest) }; IMGUI_IMPL_API ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 22a9bdc97..902c23a9a 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -63,9 +63,11 @@ #include "imgui_impl_dx12.h" // DirectX +#ifndef IMGUI_CXX_MODULE #include #include #include +#endif #ifdef _MSC_VER #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. #endif diff --git a/backends/imgui_impl_dx12.cppm b/backends/imgui_impl_dx12.cppm new file mode 100644 index 000000000..6f9dae60c --- /dev/null +++ b/backends/imgui_impl_dx12.cppm @@ -0,0 +1,26 @@ +// dear imgui: Renderer Backend for DirectX12, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.dx12;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// DirectX (same as imgui_impl_dx12.h, imgui_impl_dx12.cpp) +#include +#include +#include +#include + +export module imgui.impl.dx12; + +import std.compat; +import imgui; + +#include "imgui_impl_dx12.h" + +module :private; + +#include "imgui_impl_dx12.cpp" diff --git a/backends/imgui_impl_dx12.h b/backends/imgui_impl_dx12.h index 106b4b4d2..a9df2ccea 100644 --- a/backends/imgui_impl_dx12.h +++ b/backends/imgui_impl_dx12.h @@ -21,8 +21,10 @@ #pragma once #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE #include // DXGI_FORMAT #include // D3D12_CPU_DESCRIPTOR_HANDLE +#endif // Clang/GCC warnings with -Weverything #if defined(__clang__) @@ -30,6 +32,7 @@ #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast #endif +IMGUI_EXPORT_BEGIN // Initialization data, for ImGui_ImplDX12_Init() struct ImGui_ImplDX12_InitInfo { @@ -84,6 +87,8 @@ IMGUI_IMPL_API ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState(); //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 +IMGUI_EXPORT_END + #if defined(__clang__) #pragma clang diagnostic pop #endif diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 360398f04..94d2c9794 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -47,7 +47,9 @@ #include "imgui_impl_dx9.h" // DirectX +#ifndef IMGUI_CXX_MODULE #include +#endif // Clang/GCC warnings with -Weverything #if defined(__clang__) diff --git a/backends/imgui_impl_dx9.cppm b/backends/imgui_impl_dx9.cppm new file mode 100644 index 000000000..df36d2789 --- /dev/null +++ b/backends/imgui_impl_dx9.cppm @@ -0,0 +1,22 @@ +// dear imgui: Renderer Backend for DirectX9, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.dx9;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" + +// DirectX (same as imgui_impl_dx9.cpp) +#include + +export module imgui.impl.dx9; + +import std.compat; +import imgui; + +#include "imgui_impl_dx9.h" + +module :private; + +#include "imgui_impl_dx9.cpp" diff --git a/backends/imgui_impl_dx9.h b/backends/imgui_impl_dx9.h index 021439b9a..bffee9228 100644 --- a/backends/imgui_impl_dx9.h +++ b/backends/imgui_impl_dx9.h @@ -19,8 +19,11 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct IDirect3DDevice9; +#endif +IMGUI_EXPORT_BEGIN // 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(); @@ -33,5 +36,6 @@ 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 = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 678129a07..466a46883 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -132,6 +132,7 @@ #else #define GLFW_HAS_WAYLAND 0 #endif +#ifndef IMGUI_CXX_MODULE #include #ifdef _WIN32 #undef APIENTRY @@ -165,6 +166,7 @@ #define EMSCRIPTEN_USE_EMBEDDED_GLFW3 #endif #endif +#endif // #ifndef IMGUI_CXX_MODULE // 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) @@ -241,7 +243,9 @@ struct ImGui_ImplGlfw_Data // (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. +#ifndef IMGUI_CXX_MODULE namespace ImGui { extern ImGuiIO& GetIO(ImGuiContext*); } +#endif static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() { // Get data for current context diff --git a/backends/imgui_impl_glfw.cppm b/backends/imgui_impl_glfw.cppm new file mode 100644 index 000000000..820a2980d --- /dev/null +++ b/backends/imgui_impl_glfw.cppm @@ -0,0 +1,58 @@ +// dear imgui: Platform Backend for GLFW, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.glfw;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX + +// GLFW (same as imgui_impl_glfw.cpp) +#if defined(__has_include) +#if !__has_include() || !__has_include() +#define IMGUI_IMPL_GLFW_DISABLE_X11 +#endif +#endif +#include +#ifdef _WIN32 +#undef APIENTRY +#ifndef GLFW_EXPOSE_NATIVE_WIN32 +#define GLFW_EXPOSE_NATIVE_WIN32 +#endif +#include +#elif defined(__APPLE__) +#ifndef GLFW_EXPOSE_NATIVE_COCOA +#define GLFW_EXPOSE_NATIVE_COCOA +#endif +#include +#elif !defined(IMGUI_IMPL_GLFW_DISABLE_X11) && (defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)) +#ifndef GLFW_EXPOSE_NATIVE_X11 +#define GLFW_EXPOSE_NATIVE_X11 +#endif +#include +#endif +#undef Status +#ifndef _WIN32 +#include +#endif +#ifdef __EMSCRIPTEN__ +#include +#include +#ifdef EMSCRIPTEN_USE_PORT_CONTRIB_GLFW3 +#include +#else +#define EMSCRIPTEN_USE_EMBEDDED_GLFW3 +#endif +#endif + +export module imgui.impl.glfw; + +import std.compat; +import imgui; + +#include "imgui_impl_glfw.h" + +module :private; + +#include "imgui_impl_glfw.cpp" diff --git a/backends/imgui_impl_glfw.h b/backends/imgui_impl_glfw.h index 7dc8cb5e1..5799d453f 100644 --- a/backends/imgui_impl_glfw.h +++ b/backends/imgui_impl_glfw.h @@ -26,9 +26,12 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct GLFWwindow; struct GLFWmonitor; +#endif +IMGUI_EXPORT_BEGIN // 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); @@ -66,6 +69,6 @@ IMGUI_IMPL_API void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor* monitor, int 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); - +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_glut.cpp b/backends/imgui_impl_glut.cpp index a68f9dbc8..dd899c5d9 100644 --- a/backends/imgui_impl_glut.cpp +++ b/backends/imgui_impl_glut.cpp @@ -37,12 +37,14 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_glut.h" +#ifndef IMGUI_CXX_MODULE #define GL_SILENCE_DEPRECATION #ifdef __APPLE__ #include #else #include #endif +#endif #ifdef _MSC_VER #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff) diff --git a/backends/imgui_impl_glut.cppm b/backends/imgui_impl_glut.cppm new file mode 100644 index 000000000..3464dbc39 --- /dev/null +++ b/backends/imgui_impl_glut.cppm @@ -0,0 +1,27 @@ +// dear imgui: Platform Backend for GLUT/FreeGLUT, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.glut;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" + +// GLUT (same as imgui_impl_glut.cpp) +#define GL_SILENCE_DEPRECATION +#ifdef __APPLE__ +#include +#else +#include +#endif + +export module imgui.impl.glut; + +import std.compat; +import imgui; + +#include "imgui_impl_glut.h" + +module :private; + +#include "imgui_impl_glut.cpp" diff --git a/backends/imgui_impl_glut.h b/backends/imgui_impl_glut.h index 20e77dbce..d30eed08e 100644 --- a/backends/imgui_impl_glut.h +++ b/backends/imgui_impl_glut.h @@ -26,6 +26,7 @@ #ifndef IMGUI_DISABLE #include "imgui.h" // IMGUI_IMPL_API +IMGUI_EXPORT_BEGIN // 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(); @@ -43,5 +44,6 @@ IMGUI_IMPL_API void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int 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 +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_null.cppm b/backends/imgui_impl_null.cppm new file mode 100644 index 000000000..99289137c --- /dev/null +++ b/backends/imgui_impl_null.cppm @@ -0,0 +1,19 @@ +// dear imgui: Null Platform+Renderer Backends, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.null;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" + +export module imgui.impl.null; + +import std.compat; +import imgui; + +#include "imgui_impl_null.h" + +module :private; + +#include "imgui_impl_null.cpp" diff --git a/backends/imgui_impl_null.h b/backends/imgui_impl_null.h index b5cfb5a2c..0c27801c8 100644 --- a/backends/imgui_impl_null.h +++ b/backends/imgui_impl_null.h @@ -13,6 +13,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! // Null = NullPlatform + NullRender @@ -30,5 +31,6 @@ IMGUI_IMPL_API bool ImGui_ImplNullRender_Init(); IMGUI_IMPL_API void ImGui_ImplNullRender_Shutdown(); IMGUI_IMPL_API void ImGui_ImplNullRender_NewFrame(); IMGUI_IMPL_API void ImGui_ImplNullRender_RenderDrawData(ImDrawData* draw_data); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 88eed8c5f..15f7ca085 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -56,7 +56,9 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_opengl2.h" +#ifndef IMGUI_CXX_MODULE #include // intptr_t +#endif // Clang/GCC warnings with -Weverything #if defined(__clang__) @@ -66,6 +68,7 @@ #endif // Include OpenGL header (without an OpenGL loader) requires a bit of fiddling +#ifndef IMGUI_CXX_MODULE #if defined(_WIN32) && !defined(APIENTRY) #define APIENTRY __stdcall // It is customary to use APIENTRY for OpenGL function pointer declarations on all platforms. Additionally, the Windows OpenGL header needs APIENTRY. #endif @@ -78,11 +81,14 @@ #else #include #endif +#endif // [Debugging] //#define IMGUI_IMPL_OPENGL_DEBUG #ifdef IMGUI_IMPL_OPENGL_DEBUG +#ifndef IMGUI_CXX_MODULE #include +#endif #define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check #else #define GL_CALL(_CALL) _CALL // Call without error check diff --git a/backends/imgui_impl_opengl2.cppm b/backends/imgui_impl_opengl2.cppm new file mode 100644 index 000000000..4630919fb --- /dev/null +++ b/backends/imgui_impl_opengl2.cppm @@ -0,0 +1,34 @@ +// dear imgui: Renderer Backend for OpenGL2 (legacy OpenGL, fixed pipeline), as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.opengl2;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// OpenGL (same as imgui_impl_opengl2.cpp) +#if defined(_WIN32) && !defined(APIENTRY) +#define APIENTRY __stdcall +#endif +#if defined(_WIN32) && !defined(WINGDIAPI) +#define WINGDIAPI __declspec(dllimport) +#endif +#if defined(__APPLE__) +#define GL_SILENCE_DEPRECATION +#include +#else +#include +#endif + +export module imgui.impl.opengl2; + +import std.compat; +import imgui; + +#include "imgui_impl_opengl2.h" + +module :private; + +#include "imgui_impl_opengl2.cpp" diff --git a/backends/imgui_impl_opengl2.h b/backends/imgui_impl_opengl2.h index b9f7453f5..8870f843c 100644 --- a/backends/imgui_impl_opengl2.h +++ b/backends/imgui_impl_opengl2.h @@ -28,6 +28,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOpenGL2_Init(); IMGUI_IMPL_API void ImGui_ImplOpenGL2_Shutdown(); @@ -40,5 +41,6 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL2_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 = nullptr to handle this manually. IMGUI_IMPL_API void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 568067c5f..61a11fb5d 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -136,11 +136,13 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_opengl3.h" +#ifndef IMGUI_CXX_MODULE #include #include // intptr_t #if defined(__APPLE__) #include #endif +#endif // Clang/GCC warnings with -Weverything #if defined(__clang__) @@ -161,6 +163,7 @@ #endif // GL includes +#ifndef IMGUI_CXX_MODULE #if defined(IMGUI_IMPL_OPENGL_ES2) #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) #include // Use GL ES 2 @@ -192,6 +195,7 @@ #define IMGUI_IMPL_OPENGL_LOADER_IMGL3W #include "imgui_impl_opengl3_loader.h" #endif +#endif // #ifndef IMGUI_CXX_MODULE // Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension #ifndef IMGUI_IMPL_OPENGL_ES2 @@ -234,7 +238,9 @@ // [Debugging] //#define IMGUI_IMPL_OPENGL_DEBUG #ifdef IMGUI_IMPL_OPENGL_DEBUG +#ifndef IMGUI_CXX_MODULE #include +#endif #define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check #else #define GL_CALL(_CALL) _CALL // Call without error check diff --git a/backends/imgui_impl_opengl3.cppm b/backends/imgui_impl_opengl3.cppm new file mode 100644 index 000000000..12ce2d6cf --- /dev/null +++ b/backends/imgui_impl_opengl3.cppm @@ -0,0 +1,58 @@ +// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.opengl3;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof +#include // stderr + +// GL ES auto-detection (same as imgui_impl_opengl3.h) +#if defined(__APPLE__) +#include +#endif +#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) +#define IMGUI_IMPL_OPENGL_ES3 +#elif defined(__EMSCRIPTEN__) || defined(__amigaos4__) +#define IMGUI_IMPL_OPENGL_ES2 +#endif +#endif + +// GL includes (same as imgui_impl_opengl3.cpp) +#if defined(IMGUI_IMPL_OPENGL_ES2) +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) +#include +#else +#include +#endif +#if defined(__EMSCRIPTEN__) +#ifndef GL_GLEXT_PROTOTYPES +#define GL_GLEXT_PROTOTYPES +#endif +#include +#endif +#elif defined(IMGUI_IMPL_OPENGL_ES3) +#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) +#include +#else +#include +#endif +#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) +#define IMGL3W_IMPL +#define IMGUI_IMPL_OPENGL_LOADER_IMGL3W +#include "imgui_impl_opengl3_loader.h" +#endif + +export module imgui.impl.opengl3; + +import std.compat; +import imgui; + +#include "imgui_impl_opengl3.h" + +module :private; + +#include "imgui_impl_opengl3.cpp" diff --git a/backends/imgui_impl_opengl3.h b/backends/imgui_impl_opengl3.h index 17a49cd51..1cb6ad48f 100644 --- a/backends/imgui_impl_opengl3.h +++ b/backends/imgui_impl_opengl3.h @@ -31,6 +31,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr); IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); @@ -56,7 +57,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_SetClipOrigin(unsigned int gl_clip_ori && !defined(IMGUI_IMPL_OPENGL_ES3) // Try to detect GLES on matching platforms -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(IMGUI_CXX_MODULE) #include #endif #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__)) @@ -80,5 +81,6 @@ struct ImGui_ImplOpenGL3_RenderState unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterFilter == true }; IMGUI_IMPL_API ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_qnx.cpp b/backends/imgui_impl_qnx.cpp index 3730f54d2..09969f422 100644 --- a/backends/imgui_impl_qnx.cpp +++ b/backends/imgui_impl_qnx.cpp @@ -20,11 +20,13 @@ #ifndef IMGUI_DISABLE #include "imgui_impl_qnx.h" +#ifndef IMGUI_CXX_MODULE #include #include #include #include #include +#endif static unsigned int ImGui_ImplQNX_KeySymToUnicode(unsigned int keysym); diff --git a/backends/imgui_impl_qnx.cppm b/backends/imgui_impl_qnx.cppm new file mode 100644 index 000000000..4665e2331 --- /dev/null +++ b/backends/imgui_impl_qnx.cppm @@ -0,0 +1,24 @@ +// dear imgui: Platform Backend for QNX Screen, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.qnx;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX + +// QNX (same as imgui_impl_qnx.h, imgui_impl_qnx.cpp) +#include +#include + +export module imgui.impl.qnx; + +import std.compat; +import imgui; + +#include "imgui_impl_qnx.h" + +module :private; + +#include "imgui_impl_qnx.cpp" diff --git a/backends/imgui_impl_qnx.h b/backends/imgui_impl_qnx.h index 7bd86f439..e006fcf5a 100644 --- a/backends/imgui_impl_qnx.h +++ b/backends/imgui_impl_qnx.h @@ -23,13 +23,17 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE #include +#endif +IMGUI_EXPORT_BEGIN // The application owns the Screen context, window and event object. // Poll events with screen_get_event() and pass each non-NONE event to ProcessEvent(). IMGUI_IMPL_API bool ImGui_ImplQNX_Init(screen_context_t context, screen_window_t window); IMGUI_IMPL_API void ImGui_ImplQNX_Shutdown(); IMGUI_IMPL_API void ImGui_ImplQNX_NewFrame(); IMGUI_IMPL_API bool ImGui_ImplQNX_ProcessEvent(screen_event_t event); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index a93bcc29e..f9e081ae7 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -118,6 +118,7 @@ #endif // SDL +#ifndef IMGUI_CXX_MODULE #include #include #include // for snprintf() @@ -127,6 +128,7 @@ #ifdef __EMSCRIPTEN__ #include #endif +#endif #undef Status // X11 headers are leaking this. #if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) @@ -142,12 +144,14 @@ #define SDL_HAS_METAL 0 #endif #define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14) +#ifndef IMGUI_CXX_MODULE #if SDL_HAS_VULKAN #include #endif #if SDL_HAS_METAL #include #endif +#endif // SDL Data struct ImGui_ImplSDL2_Data @@ -803,7 +807,7 @@ static void ImGui_ImplSDL2_CloseGamepads() bd->Gamepads.resize(0); } -void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array, int manual_gamepads_count) +void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, _SDL_GameController** manual_gamepads_array, int manual_gamepads_count) { ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); ImGui_ImplSDL2_CloseGamepads(); diff --git a/backends/imgui_impl_sdl2.cppm b/backends/imgui_impl_sdl2.cppm new file mode 100644 index 000000000..b67fa0179 --- /dev/null +++ b/backends/imgui_impl_sdl2.cppm @@ -0,0 +1,36 @@ +// dear imgui: Platform Backend for SDL2, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.sdl2;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX + +// SDL (same as imgui_impl_sdl2.cpp) +#include +#include +#ifdef __APPLE__ +#include +#endif +#ifdef __EMSCRIPTEN__ +#include +#endif +#if SDL_VERSION_ATLEAST(2,0,6) +#include +#endif +#if defined(__APPLE__) && SDL_VERSION_ATLEAST(2,0,14) +#include +#endif + +export module imgui.impl.sdl2; + +import std.compat; +import imgui; + +#include "imgui_impl_sdl2.h" + +module :private; + +#include "imgui_impl_sdl2.cpp" diff --git a/backends/imgui_impl_sdl2.h b/backends/imgui_impl_sdl2.h index 63ef7071a..b6ee4a140 100644 --- a/backends/imgui_impl_sdl2.h +++ b/backends/imgui_impl_sdl2.h @@ -22,11 +22,14 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct SDL_Window; struct SDL_Renderer; struct _SDL_GameController; typedef union SDL_Event SDL_Event; +#endif +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); @@ -45,7 +48,7 @@ IMGUI_IMPL_API float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_ind // Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this. // When using manual mode, caller is responsible for opening/closing gamepad. enum ImGui_ImplSDL2_GamepadMode { ImGui_ImplSDL2_GamepadMode_AutoFirst, ImGui_ImplSDL2_GamepadMode_AutoAll, ImGui_ImplSDL2_GamepadMode_Manual }; -IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, struct _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); +IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode mode, _SDL_GameController** manual_gamepads_array = nullptr, int manual_gamepads_count = -1); // (Advanced, for X11 users) Override Mouse Capture mode. Mouse capture allows receiving updated mouse position after clicking inside our window and dragging outside it. // Having this 'Enabled' is in theory always better. But, on X11 if you crash/break to debugger while capture is active you may temporarily lose access to your mouse. @@ -53,5 +56,6 @@ IMGUI_IMPL_API void ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode // But you may independently decide on X11, when a debugger is attached, to set this value to ImGui_ImplSDL2_MouseCaptureMode_Disabled. enum ImGui_ImplSDL2_MouseCaptureMode { ImGui_ImplSDL2_MouseCaptureMode_Enabled, ImGui_ImplSDL2_MouseCaptureMode_EnabledAfterDrag, ImGui_ImplSDL2_MouseCaptureMode_Disabled }; IMGUI_IMPL_API void ImGui_ImplSDL2_SetMouseCaptureMode(ImGui_ImplSDL2_MouseCaptureMode mode); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 05f6498f1..7ded18b80 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -77,6 +77,7 @@ #endif // SDL +#ifndef IMGUI_CXX_MODULE #include #include // for snprintf() #if defined(__APPLE__) @@ -88,6 +89,7 @@ #endif #include #endif +#endif #if !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__) #define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1 diff --git a/backends/imgui_impl_sdl3.cppm b/backends/imgui_impl_sdl3.cppm new file mode 100644 index 000000000..17a49426a --- /dev/null +++ b/backends/imgui_impl_sdl3.cppm @@ -0,0 +1,32 @@ +// dear imgui: Platform Backend for SDL3, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.sdl3;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX + +// SDL (same as imgui_impl_sdl3.cpp) +#include +#if defined(__APPLE__) +#include +#endif +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +export module imgui.impl.sdl3; + +import std.compat; +import imgui; + +#include "imgui_impl_sdl3.h" + +module :private; + +#include "imgui_impl_sdl3.cpp" diff --git a/backends/imgui_impl_sdl3.h b/backends/imgui_impl_sdl3.h index 0720283c0..6af8185b8 100644 --- a/backends/imgui_impl_sdl3.h +++ b/backends/imgui_impl_sdl3.h @@ -22,11 +22,14 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE struct SDL_Window; struct SDL_Renderer; struct SDL_Gamepad; typedef union SDL_Event SDL_Event; +#endif +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window); @@ -50,5 +53,6 @@ IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode // But you may independently decide on X11, when a debugger is attached, to set this value to ImGui_ImplSDL3_MouseCaptureMode_Disabled. enum ImGui_ImplSDL3_MouseCaptureMode { ImGui_ImplSDL3_MouseCaptureMode_Enabled, ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag, ImGui_ImplSDL3_MouseCaptureMode_Disabled }; IMGUI_IMPL_API void ImGui_ImplSDL3_SetMouseCaptureMode(ImGui_ImplSDL3_MouseCaptureMode mode); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlgpu3.cppm b/backends/imgui_impl_sdlgpu3.cppm new file mode 100644 index 000000000..305cb8634 --- /dev/null +++ b/backends/imgui_impl_sdlgpu3.cppm @@ -0,0 +1,23 @@ +// dear imgui: Renderer Backend for SDL_GPU (SDL3), as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.sdlgpu3;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// SDL (same as imgui_impl_sdlgpu3.h) +#include + +export module imgui.impl.sdlgpu3; + +import std.compat; +import imgui; + +#include "imgui_impl_sdlgpu3.h" + +module :private; + +#include "imgui_impl_sdlgpu3.cpp" diff --git a/backends/imgui_impl_sdlgpu3.h b/backends/imgui_impl_sdlgpu3.h index a517c43b1..63f80e0b3 100644 --- a/backends/imgui_impl_sdlgpu3.h +++ b/backends/imgui_impl_sdlgpu3.h @@ -25,8 +25,11 @@ #pragma once #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +#ifndef IMGUI_CXX_MODULE #include +#endif +IMGUI_EXPORT_BEGIN // Initialization data, for ImGui_ImplSDLGPU_Init() // - Remember to set ColorTargetFormat to the correct format. If you're rendering to the swapchain, call SDL_GetGPUSwapchainTextureFormat() to query the right value struct ImGui_ImplSDLGPU3_InitInfo @@ -60,5 +63,6 @@ struct ImGui_ImplSDLGPU3_RenderState SDL_GPUDevice* Device; }; IMGUI_IMPL_API ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index d8dcfb154..53874c1b6 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -44,7 +44,9 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_sdlrenderer2.h" +#ifndef IMGUI_CXX_MODULE #include // intptr_t +#endif // Clang warnings with -Weverything #if defined(__clang__) @@ -55,8 +57,10 @@ #endif // SDL +#ifndef IMGUI_CXX_MODULE #include #include +#endif #if !SDL_VERSION_ATLEAST(2,0,17) #error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function #endif diff --git a/backends/imgui_impl_sdlrenderer2.cppm b/backends/imgui_impl_sdlrenderer2.cppm new file mode 100644 index 000000000..29e4c0aa5 --- /dev/null +++ b/backends/imgui_impl_sdlrenderer2.cppm @@ -0,0 +1,24 @@ +// dear imgui: Renderer Backend for SDL_Renderer for SDL2, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.sdlrenderer2;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// SDL (same as imgui_impl_sdlrenderer2.cpp) +#include +#include + +export module imgui.impl.sdlrenderer2; + +import std.compat; +import imgui; + +#include "imgui_impl_sdlrenderer2.h" + +module :private; + +#include "imgui_impl_sdlrenderer2.cpp" diff --git a/backends/imgui_impl_sdlrenderer2.h b/backends/imgui_impl_sdlrenderer2.h index e16b8cae9..c5fe269c3 100644 --- a/backends/imgui_impl_sdlrenderer2.h +++ b/backends/imgui_impl_sdlrenderer2.h @@ -29,8 +29,11 @@ #ifndef IMGUI_DISABLE #include "imgui.h" // IMGUI_IMPL_API +#ifndef IMGUI_CXX_MODULE struct SDL_Renderer; +#endif +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer); IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown(); @@ -52,5 +55,6 @@ struct ImGui_ImplSDLRenderer2_RenderState SDL_Renderer* Renderer; }; IMGUI_IMPL_API ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 6dd4c14fe..813a7d07b 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -41,7 +41,9 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_sdlrenderer3.h" +#ifndef IMGUI_CXX_MODULE #include // intptr_t +#endif // Clang warnings with -Weverything #if defined(__clang__) @@ -52,8 +54,10 @@ #endif // SDL +#ifndef IMGUI_CXX_MODULE #include #include +#endif #if !SDL_VERSION_ATLEAST(3,0,0) #error This backend requires SDL 3.0.0+ #endif diff --git a/backends/imgui_impl_sdlrenderer3.cppm b/backends/imgui_impl_sdlrenderer3.cppm new file mode 100644 index 000000000..3006a5920 --- /dev/null +++ b/backends/imgui_impl_sdlrenderer3.cppm @@ -0,0 +1,24 @@ +// dear imgui: Renderer Backend for SDL_Renderer for SDL3, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.sdlrenderer3;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof + +// SDL (same as imgui_impl_sdlrenderer3.cpp) +#include +#include + +export module imgui.impl.sdlrenderer3; + +import std.compat; +import imgui; + +#include "imgui_impl_sdlrenderer3.h" + +module :private; + +#include "imgui_impl_sdlrenderer3.cpp" diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index ee701be38..c45c80793 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -28,8 +28,11 @@ #ifndef IMGUI_DISABLE // For SDL_ScaleMode which cannot be forward declared. +#ifndef IMGUI_CXX_MODULE #include +#endif +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer); IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_Shutdown(); @@ -52,5 +55,6 @@ struct ImGui_ImplSDLRenderer3_RenderState SDL_ScaleMode CurrentScaleMode; // Current scale mode during render. Set to SDL_SCALEMODE_INVALID to use "SetSamplerFromTex" mode. }; IMGUI_IMPL_API ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState(); +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 80b9d58ab..c3f01a0ff 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -118,7 +118,9 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_vulkan.h" +#ifndef IMGUI_CXX_MODULE #include +#endif #ifndef IM_MAX #define IM_MAX(A, B) (((A) >= (B)) ? (A) : (B)) #endif diff --git a/backends/imgui_impl_vulkan.cppm b/backends/imgui_impl_vulkan.cppm new file mode 100644 index 000000000..b06482224 --- /dev/null +++ b/backends/imgui_impl_vulkan.cppm @@ -0,0 +1,38 @@ +// dear imgui: Renderer Backend for Vulkan, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.vulkan;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // offsetof +#include // UINT64_MAX + +// Vulkan (same as imgui_impl_vulkan.h) +#if defined(IMGUI_IMPL_VULKAN_NO_PROTOTYPES) && !defined(VK_NO_PROTOTYPES) +#define VK_NO_PROTOTYPES +#endif +#if defined(VK_USE_PLATFORM_WIN32_KHR) && !defined(NOMINMAX) +#define NOMINMAX +#endif +#ifdef IMGUI_IMPL_VULKAN_USE_VOLK +#ifdef IMGUI_IMPL_VULKAN_VOLK_FILENAME +#include IMGUI_IMPL_VULKAN_VOLK_FILENAME +#else +#include +#endif +#else +#include +#endif + +export module imgui.impl.vulkan; + +import std.compat; +import imgui; + +#include "imgui_impl_vulkan.h" + +module :private; + +#include "imgui_impl_vulkan.cpp" diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 0f2da5e2d..1e9bd8c96 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -64,6 +64,7 @@ #endif // Vulkan includes +#ifndef IMGUI_CXX_MODULE #ifdef IMGUI_IMPL_VULKAN_USE_VOLK #ifdef IMGUI_IMPL_VULKAN_VOLK_FILENAME #include IMGUI_IMPL_VULKAN_VOLK_FILENAME @@ -73,6 +74,7 @@ #else #include #endif +#endif #if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering) #define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING #endif @@ -81,6 +83,7 @@ #define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE (8) // Minimum per atlas #define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE (2) // Minimum for linear + nearest +IMGUI_EXPORT_BEGIN // Specify settings to create pipeline and swapchain struct ImGui_ImplVulkan_PipelineInfo { @@ -273,6 +276,8 @@ struct ImGui_ImplVulkanH_Window } }; +IMGUI_EXPORT_END + #if defined(__clang__) #pragma clang diagnostic pop #endif diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 002967b92..6ed052372 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -57,8 +57,10 @@ #ifndef IMGUI_DISABLE #include "imgui_impl_wgpu.h" +#ifndef IMGUI_CXX_MODULE #include #include +#endif // One of IMGUI_IMPL_WEBGPU_BACKEND_DAWN or IMGUI_IMPL_WEBGPU_BACKEND_WGPU must be provided. See imgui_impl_wgpu.h for more details. #if !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK) @@ -69,7 +71,9 @@ #endif // Dear ImGui prototypes from imgui_internal.h +#ifndef IMGUI_CXX_MODULE extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed); +#endif #define MEMALIGN(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align (copied from IM_ALIGN() macro). // WebGPU data @@ -1083,12 +1087,14 @@ void ImGui_ImplWGPU_DebugPrintAdapterInfo(const WGPUAdapter& adapter) #if defined(__APPLE__) // MacOS specific: is necessary to compile with "-x objective-c++" flags // (e.g. using cmake: set_source_files_properties(${IMGUI_DIR}/backends/imgui_impl_wgpu.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++") ) +#ifndef IMGUI_CXX_MODULE #include #if TARGET_OS_OSX #include #include #endif #endif +#endif WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceInfo* info) { diff --git a/backends/imgui_impl_wgpu.cppm b/backends/imgui_impl_wgpu.cppm new file mode 100644 index 000000000..7d30dbcc6 --- /dev/null +++ b/backends/imgui_impl_wgpu.cppm @@ -0,0 +1,37 @@ +// dear imgui: Renderer Backend for WebGPU, as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.wgpu;' +// Define one of IMGUI_IMPL_WEBGPU_BACKEND_DAWN, IMGUI_IMPL_WEBGPU_BACKEND_WGPU, IMGUI_IMPL_WEBGPU_BACKEND_WGVK when compiling this file (see imgui_impl_wgpu.h). + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // UINT_MAX + +// WebGPU (same as imgui_impl_wgpu.h, imgui_impl_wgpu.cpp) +#if defined(__EMSCRIPTEN__) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#include +#endif +#include +#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) +#include +#endif +#if defined(__APPLE__) && !defined(__EMSCRIPTEN__) +#include +#if TARGET_OS_OSX +#include +#include +#endif +#endif + +export module imgui.impl.wgpu; + +import std.compat; +import imgui; + +#include "imgui_impl_wgpu.h" + +module :private; + +#include "imgui_impl_wgpu.cpp" diff --git a/backends/imgui_impl_wgpu.h b/backends/imgui_impl_wgpu.h index 9f206db32..0706abec9 100644 --- a/backends/imgui_impl_wgpu.h +++ b/backends/imgui_impl_wgpu.h @@ -34,15 +34,20 @@ // Setup Emscripten default if not specified. #if defined(__EMSCRIPTEN__) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) && !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) +#ifndef IMGUI_CXX_MODULE #include +#endif #define IMGUI_IMPL_WEBGPU_BACKEND_DAWN #endif +#ifndef IMGUI_CXX_MODULE #include #if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__) #include // WGPULogLevel #endif +#endif +IMGUI_EXPORT_BEGIN // Initialization data, for ImGui_ImplWGPU_Init() struct ImGui_ImplWGPU_InitInfo { @@ -115,5 +120,6 @@ struct ImGui_ImplWGPU_CreateSurfaceInfo }; WGPUSurface ImGui_ImplWGPU_CreateWGPUSurfaceHelper(ImGui_ImplWGPU_CreateSurfaceInfo* info); #endif // #ifndef __EMSCRIPTEN__ +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 787329bf6..0c2098688 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -86,6 +86,7 @@ #include "imgui.h" #ifndef IMGUI_DISABLE #include "imgui_impl_win32.h" +#ifndef IMGUI_CXX_MODULE #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -93,10 +94,13 @@ #include // GET_X_LPARAM(), GET_Y_LPARAM() #include #include +#endif // Using XInput for gamepad (will load DLL dynamically) #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +#ifndef IMGUI_CXX_MODULE #include +#endif typedef DWORD(WINAPI* PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*); typedef DWORD(WINAPI* PFN_XInputGetState)(DWORD, XINPUT_STATE*); #endif diff --git a/backends/imgui_impl_win32.cppm b/backends/imgui_impl_win32.cppm new file mode 100644 index 000000000..9753ce0f1 --- /dev/null +++ b/backends/imgui_impl_win32.cppm @@ -0,0 +1,32 @@ +// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications), as a C++20 named module. +// See imgui.cppm for usage and design. Import with: 'import imgui; import imgui.impl.win32;' + +module; + +#define IMGUI_CXX_MODULE 1 +#define IMGUI_CXX_MODULE_IMPORTED 1 +#include "imgui_macros.h" +#include // FLT_MAX + +// Windows (same as imgui_impl_win32.cpp) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include +#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD +#include +#endif + +export module imgui.impl.win32; + +import std.compat; +import imgui; + +#include "imgui_impl_win32.h" + +module :private; + +#include "imgui_impl_win32.cpp" diff --git a/backends/imgui_impl_win32.h b/backends/imgui_impl_win32.h index d2a960059..72ca52871 100644 --- a/backends/imgui_impl_win32.h +++ b/backends/imgui_impl_win32.h @@ -20,6 +20,7 @@ #include "imgui.h" // IMGUI_IMPL_API #ifndef IMGUI_DISABLE +IMGUI_EXPORT_BEGIN // Follow "Getting Started" link and check examples/ folder to learn about using backends! IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); @@ -34,6 +35,9 @@ IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); #if 0 extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); #endif +#ifdef IMGUI_CXX_MODULE // (C++20 module: exported instead, as a forward declaration in your code wouldn't be attached to the module) +IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +#endif // DPI-related helpers (optional) // - Use to enable DPI awareness without having to create an application manifest. @@ -49,5 +53,6 @@ IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // // - Use to enable alpha compositing transparency with the desktop. // - Use together with e.g. clearing your framebuffer with zero-alpha. IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd +IMGUI_EXPORT_END #endif // #ifndef IMGUI_DISABLE diff --git a/imgui.cpp b/imgui.cpp index ef9ca7f29..dd97a5e66 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1258,10 +1258,14 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures: #include "imgui_internal.h" // System includes +#ifndef IMGUI_CXX_MODULE #include // vsnprintf, sscanf, printf #include // intptr_t +#endif #ifndef IMGUI_DISABLE_TIME_FUNCTIONS +#ifndef IMGUI_CXX_MODULE #include // time(), localtime_r()/localtime_s() +#endif #if defined(_WIN32) static tm* localtime_r(const time_t* timep, tm* result) { return localtime_s(result, timep) == 0 ? result : NULL; } #endif @@ -1283,11 +1287,13 @@ static tm* localtime_r(const time_t* timep, tm* result) { return localtime_s(res #ifndef NOMINMAX #define NOMINMAX #endif +#ifndef IMGUI_CXX_MODULE #ifndef __MINGW32__ #include // _wfopen, OpenClipboard #else #include #endif +#endif #if defined(WINAPI_FAMILY) && ((defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP) || (defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES)) // The UWP and GDK Win32 API subsets don't support clipboard nor IME functions #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS @@ -1297,7 +1303,7 @@ static tm* localtime_r(const time_t* timep, tm* result) { return localtime_s(res #endif // [Apple] OS specific includes -#if defined(__APPLE__) +#if defined(__APPLE__) && !defined(IMGUI_CXX_MODULE) #include #endif @@ -1412,7 +1418,7 @@ static void NavUpdateContextMenuRequest(); static void NavUpdateCreateMoveRequest(); static void NavUpdateCreateTabbingRequest(); static float NavUpdatePageUpPageDown(); -static inline void NavUpdateAnyRequestFlag(); +static void NavUpdateAnyRequestFlag(); static void NavUpdateCreateWrappingRequest(); static void NavEndFrame(); static bool NavScoreItem(ImGuiNavItemData* result, const ImRect& nav_bb); @@ -16283,7 +16289,9 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* t #elif defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) +#ifndef IMGUI_CXX_MODULE #include // Use old API to avoid need for separate .mm file +#endif static PasteboardRef main_clipboard = 0; // OSX clipboard implementation @@ -16371,7 +16379,9 @@ static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const cha #ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS #ifdef _WIN32 +#ifndef IMGUI_CXX_MODULE #include // ShellExecuteA() +#endif #ifdef _MSC_VER #pragma comment(lib, "shell32") #endif @@ -16384,8 +16394,10 @@ static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) return (INT_PTR)::ShellExecuteW(NULL, L"open", path_wbuf.Data, NULL, NULL, SW_SHOWDEFAULT) > 32; } #else +#ifndef IMGUI_CXX_MODULE #include #include +#endif static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path) { #if defined(__APPLE__) @@ -16418,7 +16430,9 @@ static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { ret // Win32 API IME support (for Asian languages, etc.) #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) +#ifndef IMGUI_CXX_MODULE #include +#endif #ifdef _MSC_VER #pragma comment(lib, "imm32") #endif diff --git a/imgui.cppm b/imgui.cppm new file mode 100644 index 000000000..68398de6e --- /dev/null +++ b/imgui.cppm @@ -0,0 +1,154 @@ +// dear imgui +// (C++20 named module interface: 'import imgui;') + +// Usage: +// - Compile this file as the (primary) module interface unit of module 'imgui', e.g. with CMake (see misc/cxx_module/CMakeLists.txt): +// add_library(imgui) +// target_sources(imgui PUBLIC FILE_SET CXX_MODULES FILES imgui.cppm) +// set_target_properties(imgui PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON) +// Do NOT additionally compile imgui.cpp, imgui_demo.cpp, imgui_draw.cpp, imgui_tables.cpp, imgui_widgets.cpp: +// they are compiled as part of this unit (see the private module fragment at the bottom of this file). +// - Requires C++20 modules + the C++23 standard library modules ('import std.compat;', usable as an extension in C++20 by Clang/MSVC/GCC). +// - Then, in your code: +// import imgui; +// ImGui::CreateContext(); +// ImGui::NewFrame(); ... +// - Compile-time configuration (IMGUI_USER_CONFIG, imconfig.h, IMGUI_DISABLE_XXX, ImTextureID etc.) applies when compiling +// THIS file. Every consumer of the module sees the configuration the module was built with. + +// Design: +// - This follows the "ABI-breaking style" described in https://clang.llvm.org/docs/StandardCPlusPlusModules.html#abi-breaking-style +// (as opposed to an "export-using style" wrapper that would list 'export using ::ImGui::Xxx;' for every symbol): +// imgui.h is included in the module purview, so its declarations are attached to module 'imgui'. +// Symbols are mangled differently from a regular (non-module) build of Dear ImGui: don't link both into the same program. +// - IMGUI_CXX_MODULE is defined below, before anything else. It is used by imgui.h and the .cpp files to: +// - define IMGUI_EXPORT as 'export' and IMGUI_EXPORT_BEGIN/IMGUI_EXPORT_END as 'export {' / '}' (they expand to nothing in regular builds). +// Namespaces of imgui.h are prefixed by IMGUI_EXPORT; declarations of the global namespace are enclosed in IMGUI_EXPORT_BEGIN/END blocks. +// - skip including system/standard headers. The C library comes from 'import std.compat;'; the few headers still needed +// for their macros (and OS headers) are included here in the global module fragment, so they remain attached to the global module. +// - imgui_internal.h is NOT part of the exported interface: it is only included by the .cpp files in the private module fragment. +// Types that are opaque in imgui.h (e.g. ImGuiContext, ImDrawListSharedData) remain incomplete for importers. +// - Maths operators for ImVec2/ImVec4 (IMGUI_DEFINE_MATH_OPERATORS) are always enabled and exported, +// since the implementation requires them. (Being found by ADL, they couldn't be hidden from importers anyway.) +// - Macros are not exported by C++20 modules: IMGUI_VERSION, IMGUI_CHECKVERSION(), IM_ASSERT(), IM_COL32(), IM_COUNTOF() etc. +// are provided by imgui_macros.h, which importers may include (before or after 'import imgui;'). +// Some have exported constexpr alternatives, e.g. ImCol32(), ImCol32_White, ImCountOf(), ImGui::CheckVersion() (see imgui.h). + +// Limitations (for now): +// - The private module fragment requires this file to be the only unit of module 'imgui'. +// Backends are expected to be provided as separate modules that 'import imgui;'. +// - Not supported yet: IMGUI_ENABLE_FREETYPE, IMGUI_ENABLE_TEST_ENGINE, and linking stb_truetype/stb_rect_pack/stb_sprintf +// implementations from another translation unit (IMGUI_DISABLE_STB_XXX_IMPLEMENTATION, IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION), +// since the corresponding declarations would be attached to module 'imgui' while their definitions are not. + +//----------------------------------------------------------------------------- +// [SECTION] Global module fragment +//----------------------------------------------------------------------------- + +module; + +#define IMGUI_CXX_MODULE 1 + +// Version, configuration file with compile-time options (imconfig.h) and macros +// (included here rather than from imgui.h, so any user declarations stay attached to the global module) +#include "imgui_macros.h" + +#if defined(IMGUI_ENABLE_FREETYPE) +#error "The 'imgui' C++20 module doesn't support IMGUI_ENABLE_FREETYPE yet." +#endif +#if defined(IMGUI_ENABLE_TEST_ENGINE) +#error "The 'imgui' C++20 module doesn't support IMGUI_ENABLE_TEST_ENGINE yet." +#endif + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +// C library functions and types come from 'import std.compat;' below. Modules don't export macros, so we still need: +#include // FLT_MAX, FLT_MIN, DBL_MAX +#include // INT_MAX, INT_MIN, UINT_MAX +#include // va_start, va_end, va_copy +#include // offsetof +#include // stdout +#ifndef IMGUI_DISABLE_TIME_FUNCTIONS +#include // localtime_r (POSIX) +#endif + +// SSE intrinsics (same condition as in imgui_internal.h) +#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) && !defined(_M_ARM64) && !defined(_M_ARM64EC) +#include +#if (defined __AVX__ || defined __SSE4_2__) +#include +#endif +#endif + +// [Windows] OS specific includes (see imgui.cpp) +#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include +#ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS +#include // ShellExecuteW() +#endif +#include // ImmGetContext() etc. +#endif + +// [Apple] OS specific includes (see imgui.cpp) +#if defined(__APPLE__) +#include +#if defined(TARGET_OS_OSX) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS) +#include +#endif +#endif + +// [POSIX] Default shell functions (see imgui.cpp) +#if !defined(_WIN32) && !defined(IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS) && defined(__has_include) +#if __has_include() && __has_include() +#include +#include +#endif +#endif + +// [Emscripten] (see imgui_demo.cpp) +#ifdef __EMSCRIPTEN__ +#include +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Module interface +//----------------------------------------------------------------------------- + +export module imgui; + +import std.compat; + +// Always enable maths operators: the implementation requires them, and imgui.h won't be included again by the .cpp files. +#ifndef IMGUI_DEFINE_MATH_OPERATORS +#define IMGUI_DEFINE_MATH_OPERATORS +#endif + +#include "imgui.h" + +// Internal functions used by backends (declared in imgui_internal.h) +#ifndef IMGUI_DISABLE +export namespace ImGui { IMGUI_API ImGuiIO& GetIO(ImGuiContext* ctx); } // imgui_impl_glfw.cpp +export IMGUI_API ImGuiID ImHashData(const void* data, size_t data_size, ImGuiID seed); // imgui_impl_wgpu.cpp +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Private module fragment (implementation) +//----------------------------------------------------------------------------- +// Nothing below is reachable from importers: this includes imgui_internal.h and all file-local (static) helpers. +// (same order as misc/single_file/imgui_single_file.h) + +module :private; + +#include "imgui.cpp" +#include "imgui_demo.cpp" +#include "imgui_draw.cpp" +#include "imgui_tables.cpp" +#include "imgui_widgets.cpp" diff --git a/imgui.h b/imgui.h index 8c5be4a44..f77534759 100644 --- a/imgui.h +++ b/imgui.h @@ -27,13 +27,6 @@ // EVERYTHING ELSE should be asked in 'Issues'! We are building a database of cross-linked knowledge there. // Since 1.92, we encourage font loading questions to also be posted in 'Issues'. -// Library Version -// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') -#define IMGUI_VERSION "1.93.0 WIP" -#define IMGUI_VERSION_NUM 19297 -#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 -#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 - /* Index of this file: @@ -54,88 +47,29 @@ Index of this file: // [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFontBaked, ImFont) // [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport) // [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformImeData) +// [SECTION] Constexpr alternatives to macros // [SECTION] Obsolete functions and types */ #pragma once -// Configuration file with compile-time options -// (edit imconfig.h or '#define IMGUI_USER_CONFIG "myfilename.h" from your build system) -#ifdef IMGUI_USER_CONFIG -#include IMGUI_USER_CONFIG -#endif -#include "imconfig.h" +// Version, configuration file with compile-time options (imconfig.h) and macros +#include "imgui_macros.h" -#ifndef IMGUI_DISABLE +// (C++20 modules importing 'imgui', e.g. backends/imgui_impl_*.cppm, get the declarations below from 'import imgui;') +#if !defined(IMGUI_DISABLE) && !defined(IMGUI_CXX_MODULE_IMPORTED) //----------------------------------------------------------------------------- // [SECTION] Header mess //----------------------------------------------------------------------------- // Includes +#ifndef IMGUI_CXX_MODULE #include // FLT_MIN, FLT_MAX #include // va_list, va_start, va_end #include // ptrdiff_t, NULL #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp - -// Define attributes of all API symbols declarations (e.g. for DLL under Windows) -// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) -// Using dear imgui via a shared library is not recommended: we don't guarantee backward nor forward ABI compatibility + this is a call-heavy library and function call overhead adds up. -#ifndef IMGUI_API -#define IMGUI_API -#endif -#ifndef IMGUI_IMPL_API -#define IMGUI_IMPL_API IMGUI_API -#endif - -// Helper Macros -// (note: compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes.) -#ifndef IM_ASSERT -#include -#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h -#endif -#define IM_COUNTOF(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! -#define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. -#define IM_STRINGIFY_HELPER(_EXPR) #_EXPR -#define IM_STRINGIFY(_EXPR) IM_STRINGIFY_HELPER(_EXPR) // Preprocessor idiom to stringify e.g. an integer or a macro. - -// Check that version and structures layouts are matching between compiled imgui code and caller. Read comments above DebugCheckVersionAndDataLayout() for details. -#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) - -// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. -// (MSVC provides an equivalent mechanism via SAL Annotations but it requires the macros in a different -// location. e.g. #include + void myprintf(_Printf_format_string_ const char* format, ...), -// and only works when using Code Analysis, rather than just normal compiling). -// (see https://github.com/ocornut/imgui/issues/8871 for a patch to enable this for MSVC's Code Analysis) -#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) -#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) -#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) -#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) -#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) -#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) -#else -#define IM_FMTARGS(FMT) -#define IM_FMTLIST(FMT) -#endif - -// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) -#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(IMGUI_DEBUG_PARANOID) -#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) -#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) -#else -#define IM_MSVC_RUNTIME_CHECKS_OFF -#define IM_MSVC_RUNTIME_CHECKS_RESTORE -#endif - -// Alternative to using a .natstepfilter file or other scripts in misc/debuggers/ to skip debug-stepping selected trivial functions. -// If you get a compiler error or warning related to use, please report it to us! -#if (defined(__clang__) && (__clang_major__ >= 7)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) -#define IM_NODEBUGSTEP [[gnu::artificial]] -#elif defined(_MSC_VER) && (_MSC_VER >= 1915) -#define IM_NODEBUGSTEP __declspec(non_user_code) -#else -#define IM_NODEBUGSTEP #endif // Warnings @@ -162,6 +96,8 @@ Index of this file: #pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead #endif +IMGUI_EXPORT_BEGIN + //----------------------------------------------------------------------------- // [SECTION] Forward declarations and basic types //----------------------------------------------------------------------------- @@ -350,13 +286,6 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or integer). A majority of backends are ok with that. #endif -// Define this if you need to change the invalid value for your backend. -// - If your backend is using ImTextureID to store an index/offset and you need 0 to be valid, You can add '#define ImTextureID_Invalid ((ImTextureID)-1)' in your imconfig.h file. -// - From 2026/03/12 to 2026/03/19 we experimented with changing to default to -1, but I worried it would cause too many issues in third-party code so it was reverted. -#ifndef ImTextureID_Invalid -#define ImTextureID_Invalid ((ImTextureID)0) -#endif - // ImTextureRef = higher-level identifier for a texture. Store a ImTextureID _or_ a ImTextureData*. // The identifier is valid even before the texture has been uploaded to the GPU/graphics system. // This is what gets passed to functions such as `ImGui::Image()`, `ImDrawList::AddImage()`. @@ -390,12 +319,14 @@ struct ImTextureRef }; IM_MSVC_RUNTIME_CHECKS_RESTORE +IMGUI_EXPORT_END + //----------------------------------------------------------------------------- // [SECTION] Dear ImGui end-user API functions // (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!) //----------------------------------------------------------------------------- -namespace ImGui +IMGUI_EXPORT namespace ImGui { // Context creation and access // - Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between contexts. @@ -1172,6 +1103,8 @@ namespace ImGui } // namespace ImGui +IMGUI_EXPORT_BEGIN + //----------------------------------------------------------------------------- // [SECTION] Flags & Enumerations //----------------------------------------------------------------------------- @@ -1544,10 +1477,6 @@ enum ImGuiDragDropFlags_ #endif }; -// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. -#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. -#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. - // A primary data type enum ImGuiDataType_ { @@ -2216,16 +2145,6 @@ struct ImGuiTableColumnSortSpecs // [SECTION] Helpers: Debug log, memory allocations macros, ImVector<> //----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -// Debug Logging into ShowDebugLogWindow(), tty and more. -//----------------------------------------------------------------------------- - -#ifndef IMGUI_DISABLE_DEBUG_TOOLS -#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) -#else -#define IMGUI_DEBUG_LOG(...) ((void)0) -#endif - //----------------------------------------------------------------------------- // IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax. @@ -2235,10 +2154,6 @@ struct ImGuiTableColumnSortSpecs struct ImNewWrapper {}; inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; } inline void operator delete(void*, ImNewWrapper, void*) {} // This is only required so we can use the symmetrical new() -#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) -#define IM_FREE(_PTR) ImGui::MemFree(_PTR) -#define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) -#define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE template void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } } //----------------------------------------------------------------------------- @@ -2768,14 +2683,6 @@ struct ImGuiPayload // [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor) //----------------------------------------------------------------------------- -// Helper: Unicode defines -#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). -#ifdef IMGUI_USE_WCHAR32 -#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. -#else -#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. -#endif - // Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create a UI within deep-nested code that runs multiple times every frame. // Usage: static ImGuiOnceUponAFrame oaf; if (oaf) ImGui::Text("This will be called only once per frame"); struct ImGuiOnceUponAFrame @@ -2996,29 +2903,6 @@ IM_NODEBUGSTEP inline bool operator!=(const ImVec4& lhs, const ImVec4& rhs) { IM_MSVC_RUNTIME_CHECKS_RESTORE #endif -// Helpers macros to generate 32-bit encoded colors -// - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. -// - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. -#ifndef IM_COL32_R_SHIFT -#ifdef IMGUI_USE_BGRA_PACKED_COLOR -#define IM_COL32_R_SHIFT 16 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 0 -#define IM_COL32_A_SHIFT 24 -#define IM_COL32_A_MASK 0xFF000000 -#else -#define IM_COL32_R_SHIFT 0 -#define IM_COL32_G_SHIFT 8 -#define IM_COL32_B_SHIFT 16 -#define IM_COL32_A_SHIFT 24 -#define IM_COL32_A_MASK 0xFF000000 -#endif -#endif -#define IM_COL32(R,G,B,A) (((ImU32)(A)<TexRef @@ -3999,6 +3877,8 @@ struct ImFont //inline void AddRemapChar(ImWchar from_codepoint, ImWchar to_codepoint) { AddRemapCodepoint(from_codepoint, to_codepoint); } // Renamed in 1.93.0 (Sep 2026) }; +IMGUI_EXPORT_END + // This is provided for consistency (but we don't actually use this) inline ImTextureID ImTextureRef::GetTexID() const { @@ -4019,6 +3899,8 @@ inline ImTextureID ImDrawCmd::GetTexID() const return tex_id; } +IMGUI_EXPORT_BEGIN + //----------------------------------------------------------------------------- // [SECTION] Viewports //----------------------------------------------------------------------------- @@ -4144,6 +4026,49 @@ struct ImGuiPlatformImeData ImGuiPlatformImeData() { memset((void*)this, 0, sizeof(*this)); } }; +IMGUI_EXPORT_END + +//----------------------------------------------------------------------------- +// [SECTION] Constexpr alternatives to macros +// (requires C++17: see IMGUI_HAS_CONSTEXPR in imgui_macros.h. Exported by the C++20 module, which doesn't export macros) +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_CONSTEXPR +IMGUI_EXPORT_BEGIN +// Version (= IMGUI_VERSION, IMGUI_VERSION_NUM) +inline constexpr char ImGuiVersion[] = IMGUI_VERSION; +inline constexpr int ImGuiVersionNum = IMGUI_VERSION_NUM; + +// Standard Drag and Drop payload types (= IMGUI_PAYLOAD_TYPE_COLOR_3F, IMGUI_PAYLOAD_TYPE_COLOR_4F) +inline constexpr char ImGuiPayloadType_Color3F[] = IMGUI_PAYLOAD_TYPE_COLOR_3F; +inline constexpr char ImGuiPayloadType_Color4F[] = IMGUI_PAYLOAD_TYPE_COLOR_4F; + +// Unicode (= IM_UNICODE_CODEPOINT_INVALID, IM_UNICODE_CODEPOINT_MAX) +inline constexpr ImWchar32 ImUnicodeCodepoint_Invalid = IM_UNICODE_CODEPOINT_INVALID; +inline constexpr ImWchar32 ImUnicodeCodepoint_Max = IM_UNICODE_CODEPOINT_MAX; + +// 32-bit encoded colors (= IM_COL32(), IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32_BLACK_TRANS, IM_COL32_X_SHIFT, IM_COL32_A_MASK) +constexpr ImU32 ImCol32(ImU32 r, ImU32 g, ImU32 b, ImU32 a) { return IM_COL32(r, g, b, a); } +inline constexpr ImU32 ImCol32_White = IM_COL32_WHITE; +inline constexpr ImU32 ImCol32_Black = IM_COL32_BLACK; +inline constexpr ImU32 ImCol32_BlackTrans = IM_COL32_BLACK_TRANS; +inline constexpr int ImCol32_RShift = IM_COL32_R_SHIFT; +inline constexpr int ImCol32_GShift = IM_COL32_G_SHIFT; +inline constexpr int ImCol32_BShift = IM_COL32_B_SHIFT; +inline constexpr int ImCol32_AShift = IM_COL32_A_SHIFT; +inline constexpr ImU32 ImCol32_AMask = IM_COL32_A_MASK; + +// Size of a static C-style array (= IM_COUNTOF(), but won't compile with pointers) +template constexpr int ImCountOf(const T (&arr)[N]) { return IM_COUNTOF(arr); } +IMGUI_EXPORT_END + +// Check that version and structures layouts are matching between compiled imgui code and caller (= IMGUI_CHECKVERSION()) +IMGUI_EXPORT namespace ImGui +{ + inline bool CheckVersion() { return IMGUI_CHECKVERSION(); } +} +#endif // #ifdef IMGUI_HAS_CONSTEXPR + //----------------------------------------------------------------------------- // [SECTION] Obsolete functions and types // (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details) @@ -4151,7 +4076,7 @@ struct ImGuiPlatformImeData //----------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -namespace ImGui +IMGUI_EXPORT namespace ImGui { // OBSOLETED in 1.92.9 (from July 2026) IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags); // set current options for if you want to select a default format, picker type, etc. User will be able to change those settings, unless you pass the _NoOptions flag to your calls. @@ -4246,14 +4171,14 @@ namespace ImGui //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 } -#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-8) // OBSOLETED in 1.92.8: Use ImGui::GetPlatformIO().DrawCallback_ResetRenderState - +IMGUI_EXPORT_BEGIN //-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect // - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y // - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h // - ImFontAtlasCustomRect::GlyphColored --> if you need to write to this, instead you can write to 'font->Glyphs.back()->Colored' after calling AddCustomRectFontGlyph() // We could make ImTextureRect an union to use old names, but 1) this would be confusing 2) the fix is easy 3) ImFontAtlasCustomRect was always a rather esoteric api. typedef ImFontAtlasRect ImFontAtlasCustomRect; +IMGUI_EXPORT_END /*struct ImFontAtlasCustomRect { unsigned short X, Y; // Output // Packed position in Atlas @@ -4294,13 +4219,6 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect; #endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS -#define IM_ARRAYSIZE IM_COUNTOF // RENAMED IN 1.92.6: IM_ARRAYSIZE -> IM_COUNTOF - -// RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022) -#ifdef IMGUI_DISABLE_METRICS_WINDOW -#error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name. -#endif - //----------------------------------------------------------------------------- #if defined(__clang__) @@ -4323,4 +4241,4 @@ typedef ImFontAtlasRect ImFontAtlasCustomRect; #endif #endif -#endif // #ifndef IMGUI_DISABLE +#endif // #if !defined(IMGUI_DISABLE) && !defined(IMGUI_CXX_MODULE_IMPORTED) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 0b16dab3c..eae093265 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -135,6 +135,7 @@ Index of this file: #ifndef IMGUI_DISABLE // System includes +#ifndef IMGUI_CXX_MODULE #include // toupper #include // INT_MIN, INT_MAX #include // sqrtf, powf, cosf, sinf, floorf, ceilf @@ -147,6 +148,7 @@ Index of this file: #ifdef __EMSCRIPTEN__ #include // __EMSCRIPTEN_MAJOR__ etc. #endif +#endif // Visual Studio warnings #ifdef _MSC_VER diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e2085f6e6..c65da352b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -40,8 +40,10 @@ Index of this file: #include "misc/freetype/imgui_freetype.h" #endif +#ifndef IMGUI_CXX_MODULE #include // vsnprintf, sscanf, printf #include // intptr_t +#endif // Visual Studio warnings #ifdef _MSC_VER @@ -150,6 +152,10 @@ namespace IMGUI_STB_NAMESPACE #define STBTT_ifloor(x) ((int)ImFloor(x)) #define STBTT_iceil(x) ((int)ImCeil(x)) #define STBTT_strlen(x) ImStrlen(x) +#define STBTT_cos(x) cos(x) // Same as stb_truetype defaults, but avoid it including / itself (e.g. in C++20 module purview) +#define STBTT_acos(x) acos(x) +#define STBTT_memcpy memcpy +#define STBTT_memset memset #define STBTT_STATIC #define STB_TRUETYPE_IMPLEMENTATION #else diff --git a/imgui_internal.h b/imgui_internal.h index b0f8856f8..67584c0ab 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -50,24 +50,28 @@ Index of this file: // [SECTION] Header mess //----------------------------------------------------------------------------- -#ifndef IMGUI_VERSION #include "imgui.h" -#endif +#ifndef IMGUI_CXX_MODULE #include // FILE*, sscanf #include // NULL, malloc, free, qsort, atoi, atof #include // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf #include // INT_MIN, INT_MAX +#endif // Enable SSE intrinsics if available #if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE) && !defined(_M_ARM64) && !defined(_M_ARM64EC) #define IMGUI_ENABLE_SSE +#ifndef IMGUI_CXX_MODULE #include +#endif #if (defined __AVX__ || defined __SSE4_2__) #define IMGUI_ENABLE_SSE4_2 +#ifndef IMGUI_CXX_MODULE #include #endif #endif +#endif // Emscripten has partial SSE 4.2 support where _mm_crc32_u32 is not available. See https://emscripten.org/docs/porting/simd.html#id11 and #8213 #if defined(IMGUI_ENABLE_SSE4_2) && !defined(IMGUI_USE_LEGACY_CRC32_ADLER) && !defined(__EMSCRIPTEN__) #define IMGUI_ENABLE_SSE4_2_CRC diff --git a/imgui_macros.h b/imgui_macros.h new file mode 100644 index 000000000..cccf990b2 --- /dev/null +++ b/imgui_macros.h @@ -0,0 +1,196 @@ +// dear imgui, v1.93.0 WIP +// (macros) + +// Version, compile-time configuration and all preprocessor macros of the public API. +// - This is included by imgui.h: you don't need to include it yourself when using imgui.h. +// - Macros are not exported by C++20 modules: when using 'import imgui;' (see imgui.cppm), include this file to access them: +// #include "imgui_macros.h" +// import imgui; +// Use the same compile-time configuration (IMGUI_USER_CONFIG, imconfig.h, defines) as the one the module was built with. + +#pragma once + +// Library Version +// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') +#define IMGUI_VERSION "1.93.0 WIP" +#define IMGUI_VERSION_NUM 19297 +#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 +#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 + +// Configuration file with compile-time options +// (edit imconfig.h or '#define IMGUI_USER_CONFIG "myfilename.h" from your build system) +#ifdef IMGUI_USER_CONFIG +#include IMGUI_USER_CONFIG +#endif +#include "imconfig.h" + +#ifndef IMGUI_DISABLE + +//----------------------------------------------------------------------------- +// [SECTION] Attributes and helper macros +//----------------------------------------------------------------------------- + +// Define attributes of all API symbols declarations (e.g. for DLL under Windows) +// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h) +// Using dear imgui via a shared library is not recommended: we don't guarantee backward nor forward ABI compatibility + this is a call-heavy library and function call overhead adds up. +#ifndef IMGUI_API +#define IMGUI_API +#endif +#ifndef IMGUI_IMPL_API +#define IMGUI_IMPL_API IMGUI_API +#endif + +// Export declarations from the C++20 named module 'imgui' (see imgui.cppm): +// - IMGUI_EXPORT namespace ImGui { ... } exports a namespace and everything in it. +// - Declarations of the global namespace are exported by enclosing them in IMGUI_EXPORT_BEGIN / IMGUI_EXPORT_END. +// (out-of-line definitions of member functions can't be exported: keep them outside of those blocks) +// IMGUI_CXX_MODULE is defined by imgui.cppm only: don't define it yourself. In regular (header) builds, those expand to nothing. +#ifdef IMGUI_CXX_MODULE +#define IMGUI_EXPORT export +#define IMGUI_EXPORT_BEGIN export { +#define IMGUI_EXPORT_END } +#else +#define IMGUI_EXPORT +#define IMGUI_EXPORT_BEGIN +#define IMGUI_EXPORT_END +#endif + +// Constexpr alternatives to some of the macros below (e.g. ImCol32() for IM_COL32()) are declared in imgui.h ('Constexpr alternatives to macros' section) when compiling as C++17 or later. +// (always the case for the C++20 module; C++17 is required for 'inline' variables) +#if defined(IMGUI_CXX_MODULE) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L +#define IMGUI_HAS_CONSTEXPR +#endif + +// Helper Macros +// (note: compiling with NDEBUG will usually strip out assert() to nothing, which is NOT recommended because we use asserts to notify of programmer mistakes.) +#ifndef IM_ASSERT +#include +#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h +#endif +#define IM_COUNTOF(_ARR) ((int)(sizeof(_ARR) / sizeof(*(_ARR)))) // Size of a static C-style array. Don't use on pointers! +#define IM_UNUSED(_VAR) ((void)(_VAR)) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds. +#define IM_STRINGIFY_HELPER(_EXPR) #_EXPR +#define IM_STRINGIFY(_EXPR) IM_STRINGIFY_HELPER(_EXPR) // Preprocessor idiom to stringify e.g. an integer or a macro. + +// Check that version and structures layouts are matching between compiled imgui code and caller. Read comments above DebugCheckVersionAndDataLayout() for details. +#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) + +// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. +// (MSVC provides an equivalent mechanism via SAL Annotations but it requires the macros in a different +// location. e.g. #include + void myprintf(_Printf_format_string_ const char* format, ...), +// and only works when using Code Analysis, rather than just normal compiling). +// (see https://github.com/ocornut/imgui/issues/8871 for a patch to enable this for MSVC's Code Analysis) +#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) +#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) +#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__)) +#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) +#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0))) +#else +#define IM_FMTARGS(FMT) +#define IM_FMTLIST(FMT) +#endif + +// Disable some of MSVC most aggressive Debug runtime checks in function header/footer (used in some simple/low-level functions) +#if defined(_MSC_VER) && !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(IMGUI_DEBUG_PARANOID) +#define IM_MSVC_RUNTIME_CHECKS_OFF __pragma(runtime_checks("",off)) __pragma(check_stack(off)) __pragma(strict_gs_check(push,off)) +#define IM_MSVC_RUNTIME_CHECKS_RESTORE __pragma(runtime_checks("",restore)) __pragma(check_stack()) __pragma(strict_gs_check(pop)) +#else +#define IM_MSVC_RUNTIME_CHECKS_OFF +#define IM_MSVC_RUNTIME_CHECKS_RESTORE +#endif + +// Alternative to using a .natstepfilter file or other scripts in misc/debuggers/ to skip debug-stepping selected trivial functions. +// If you get a compiler error or warning related to use, please report it to us! +#if (defined(__clang__) && (__clang_major__ >= 7)) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) +#define IM_NODEBUGSTEP [[gnu::artificial]] +#elif defined(_MSC_VER) && (_MSC_VER >= 1915) +#define IM_NODEBUGSTEP __declspec(non_user_code) +#else +#define IM_NODEBUGSTEP +#endif + +//----------------------------------------------------------------------------- +// [SECTION] Constants and helpers macros +//----------------------------------------------------------------------------- + +// Define this if you need to change the invalid value for your backend. +// - If your backend is using ImTextureID to store an index/offset and you need 0 to be valid, You can add '#define ImTextureID_Invalid ((ImTextureID)-1)' in your imconfig.h file. +// - From 2026/03/12 to 2026/03/19 we experimented with changing to default to -1, but I worried it would cause too many issues in third-party code so it was reverted. +#ifndef ImTextureID_Invalid +#define ImTextureID_Invalid ((ImTextureID)0) +#endif + +// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui. +#define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. +#define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. + +// Debug Logging into ShowDebugLogWindow(), tty and more. +#ifndef IMGUI_DISABLE_DEBUG_TOOLS +#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__) +#else +#define IMGUI_DEBUG_LOG(...) ((void)0) +#endif + +// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW() (+ IM_DELETE() function in imgui.h) +#define IM_ALLOC(_SIZE) ImGui::MemAlloc(_SIZE) +#define IM_FREE(_PTR) ImGui::MemFree(_PTR) +#define IM_PLACEMENT_NEW(_PTR) new(ImNewWrapper(), _PTR) +#define IM_NEW(_TYPE) new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE + +// Helper: Unicode defines +#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD // Invalid Unicode code point (standard value). +#ifdef IMGUI_USE_WCHAR32 +#define IM_UNICODE_CODEPOINT_MAX 0x10FFFF // Maximum Unicode code point supported by this build. +#else +#define IM_UNICODE_CODEPOINT_MAX 0xFFFF // Maximum Unicode code point supported by this build. +#endif + +// Helpers macros to generate 32-bit encoded colors +// - User can declare their own format by #defining the 5 _SHIFT/_MASK macros in their imconfig file. +// - Any setting other than the default will need custom backend support. The only standard backend that supports anything else than the default is DirectX9. +#ifndef IM_COL32_R_SHIFT +#ifdef IMGUI_USE_BGRA_PACKED_COLOR +#define IM_COL32_R_SHIFT 16 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 0 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#else +#define IM_COL32_R_SHIFT 0 +#define IM_COL32_G_SHIFT 8 +#define IM_COL32_B_SHIFT 16 +#define IM_COL32_A_SHIFT 24 +#define IM_COL32_A_MASK 0xFF000000 +#endif +#endif +#define IM_COL32(R,G,B,A) (((ImU32)(A)< IM_COUNTOF + +// RENAMED IMGUI_DISABLE_METRICS_WINDOW > IMGUI_DISABLE_DEBUG_TOOLS in 1.88 (from June 2022) +#ifdef IMGUI_DISABLE_METRICS_WINDOW +#error IMGUI_DISABLE_METRICS_WINDOW was renamed to IMGUI_DISABLE_DEBUG_TOOLS, please use new name. +#endif + +#endif // #ifndef IMGUI_DISABLE diff --git a/imgui_tables.cpp b/imgui_tables.cpp index b3e0458eb..150f5c83e 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -202,7 +202,9 @@ Index of this file: #include "imgui_internal.h" // System includes +#ifndef IMGUI_CXX_MODULE #include // intptr_t +#endif // Visual Studio warnings #ifdef _MSC_VER diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ceabc13ba..5f2b361a4 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -45,7 +45,9 @@ Index of this file: #include "imgui_internal.h" // System includes +#ifndef IMGUI_CXX_MODULE #include // intptr_t +#endif //------------------------------------------------------------------------- // Warnings diff --git a/imstb_rectpack.h b/imstb_rectpack.h index ad0892130..ffaab7f62 100644 --- a/imstb_rectpack.h +++ b/imstb_rectpack.h @@ -78,7 +78,7 @@ #define STBRP_DEF extern #endif -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(IMGUI_CXX_MODULE) // [DEAR IMGUI] extern "C" would attach declarations to the global module extern "C" { #endif @@ -195,7 +195,7 @@ struct stbrp_context stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' }; -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(IMGUI_CXX_MODULE) // [DEAR IMGUI] } #endif diff --git a/imstb_truetype.h b/imstb_truetype.h index ec4d42c7d..87f6c9af8 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -510,7 +510,7 @@ int main(int arg, char **argv) #define STBTT_DEF extern #endif -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(IMGUI_CXX_MODULE) // [DEAR IMGUI] extern "C" would attach declarations to the global module extern "C" { #endif @@ -1095,7 +1095,7 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 }; -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(IMGUI_CXX_MODULE) // [DEAR IMGUI] } #endif diff --git a/misc/cxx_module/CMakeLists.txt b/misc/cxx_module/CMakeLists.txt new file mode 100644 index 000000000..4e7993287 --- /dev/null +++ b/misc/cxx_module/CMakeLists.txt @@ -0,0 +1,231 @@ +# dear imgui: build and test the C++20 named modules 'imgui' (imgui.cppm) and 'imgui.impl.' (backends/imgui_impl_.cppm). +# Requires CMake with non-experimental 'import std' support (4.5, or a 4.4 development build), a Ninja generator, and Clang. +# Tested with CMake 4.4-dev + Clang 21 on Linux (libstdc++ 15), Android (NDK r29, libc++), Windows (MinGW-w64 libstdc++ 15, clang-cl + MSVC STL 14.44). +# Usage (see CMakePresets.json): +# cmake --workflow --preset clang +# Backends are enabled when their platform library is found, e.g. on Debian/Ubuntu: +# apt install libopengl-dev libglut-dev libsdl2-dev libsdl3-dev libglfw3-dev libvulkan-dev liballegro5-dev +# WebGPU has no system package: pass its headers with -DIMGUI_WEBGPU_INCLUDE_DIRS=<...> (compile-only test). +# Tests: +# - Every test is built against the module ('import imgui;') and, where relevant, against the headers ('#include "imgui.h"'): +# 'DIFF' tests run both builds with the same scripted input and check that they render the same draw data and textures. +# - The core library, the null backend and their tests are built for each compile-time configuration (imgui_add_config() below). + +cmake_minimum_required(VERSION 3.30) +project(imgui_cxx_module LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(IMGUI_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." CACHE PATH "Dear ImGui root directory") +if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + set(IMGUI_WARNINGS /W4 /WX -Wno-reserved-module-identifier # clang-cl: /W4 = -Wall -Wextra (its -Wall = -Weverything) + -Wno-include-angled-in-module-purview # MSVC STL's std.ixx includes its headers after 'export module std;' + -Wno-unused-command-line-argument # CMake passes both -TP and '-x c++-module' for module units + /D_CRT_SECURE_NO_WARNINGS) # imgui sources #define it before CRT headers, but modules get those from 'std' +else() + set(IMGUI_WARNINGS -Wall -Wextra -Werror -Wno-reserved-module-identifier) +endif() # the synthesized 'std' targets inherit these flags +if(ANDROID) + # bionic defines some C library functions 'static inline' (ctype.h, FORTIFY wrappers), which libc++'s 'std' module can't export. + # (options, not definitions: the synthesized 'std' targets only inherit options) + add_compile_options(-D__BIONIC_CTYPE_INLINE=inline -U_FORTIFY_SOURCE) +endif() + +enable_testing() + +#----------------------------------------------------------------------------- +# Helpers +#----------------------------------------------------------------------------- +# Targets are suffixed with ${IMGUI_SFX}: empty for the default configuration, '_' otherwise (see imgui_add_config()). + +# imgui_add_backend( [OPTIONS ]) +# - imgui_impl_: module 'imgui.impl.' +# - imgui_header_impl_: regular (header) build of the backend, to check it's unaffected by the module support +function(imgui_add_backend name) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "OPTIONS") + set(module imgui_impl_${name}${IMGUI_SFX}) + add_library(${module} STATIC) + target_sources(${module} PUBLIC FILE_SET CXX_MODULES BASE_DIRS "${IMGUI_DIR}" FILES "${IMGUI_DIR}/backends/imgui_impl_${name}.cppm") + target_link_libraries(${module} PUBLIC imgui${IMGUI_SFX} ${arg_UNPARSED_ARGUMENTS}) + target_compile_options(${module} PRIVATE ${IMGUI_WARNINGS} ${arg_OPTIONS}) + set(header imgui_header_impl_${name}${IMGUI_SFX}) + add_library(${header} STATIC "${IMGUI_DIR}/backends/imgui_impl_${name}.cpp") + target_include_directories(${header} PUBLIC "${IMGUI_DIR}/backends") + target_link_libraries(${header} PUBLIC imgui_header${IMGUI_SFX} ${arg_UNPARSED_ARGUMENTS}) + target_compile_options(${header} PRIVATE ${IMGUI_WARNINGS} ${arg_OPTIONS}) + set(IMGUI_BACKENDS ${IMGUI_BACKENDS} ${name} PARENT_SCOPE) +endfunction() + +# imgui_add_test( RUN|DIFF|LINK|COMPILE LIBS ) +# - RUN: compile, link, and run (natively or with CMAKE_CROSSCOMPILING_EMULATOR); LINK: compile and link; COMPILE: compile only. +# - DIFF: like RUN, and also build in header mode (IMGUI_TEST_HEADER defined, linking the 'imgui_header*' equivalent +# of each LIBS target), run both, and check that their outputs match. +# - Skipped if any of the LIBS targets doesn't exist (backend not found). +function(imgui_add_test name kind) + cmake_parse_arguments(PARSE_ARGV 2 arg "" "" "LIBS") + foreach(lib IN LISTS arg_LIBS) + if(NOT TARGET ${lib}) + return() + endif() + endforeach() + set(name ${name}${IMGUI_SFX}) + if(kind STREQUAL "COMPILE") + add_library(${name} OBJECT ${arg_UNPARSED_ARGUMENTS}) + else() + add_executable(${name} ${arg_UNPARSED_ARGUMENTS}) + endif() + target_link_libraries(${name} PRIVATE ${arg_LIBS}) + target_compile_options(${name} PRIVATE ${IMGUI_WARNINGS}) + if(kind STREQUAL "DIFF") + list(TRANSFORM arg_LIBS REPLACE "^imgui" "imgui_header") + add_executable(${name}_header ${arg_UNPARSED_ARGUMENTS}) + target_link_libraries(${name}_header PRIVATE ${arg_LIBS}) + target_compile_definitions(${name}_header PRIVATE IMGUI_TEST_HEADER) + target_compile_options(${name}_header PRIVATE ${IMGUI_WARNINGS}) + endif() + if(NOT CMAKE_CROSSCOMPILING OR CMAKE_CROSSCOMPILING_EMULATOR) + if(kind STREQUAL "RUN") + add_test(NAME ${name} COMMAND ${name}) + elseif(kind STREQUAL "DIFF") + add_test(NAME ${name} COMMAND "${CMAKE_COMMAND}" "-DEMULATOR=${CMAKE_CROSSCOMPILING_EMULATOR}" + "-DEXPECTED=$" "-DACTUAL=$" -P "${CMAKE_CURRENT_SOURCE_DIR}/compare_output.cmake") + endif() + endif() +endfunction() + +# imgui_add_config( [LIBRARIES_ONLY] ) +# Builds the 'imgui' module, its header-mode equivalent, the null backend, and (unless LIBRARIES_ONLY) the core tests +# with a compile-time configuration. Definitions are PUBLIC: importers must use the same configuration (see imgui_macros.h). +function(imgui_add_config cfg) + cmake_parse_arguments(PARSE_ARGV 1 arg "LIBRARIES_ONLY" "" "") + if(NOT cfg STREQUAL "default") + set(IMGUI_SFX _${cfg}) + endif() + + # Module 'imgui' + add_library(imgui${IMGUI_SFX} STATIC) + target_sources(imgui${IMGUI_SFX} PUBLIC FILE_SET CXX_MODULES BASE_DIRS "${IMGUI_DIR}" FILES "${IMGUI_DIR}/imgui.cppm") + target_include_directories(imgui${IMGUI_SFX} PUBLIC "${IMGUI_DIR}") # imgui_macros.h, imconfig.h + target_compile_definitions(imgui${IMGUI_SFX} PUBLIC ${arg_UNPARSED_ARGUMENTS}) + target_compile_options(imgui${IMGUI_SFX} PRIVATE ${IMGUI_WARNINGS}) + + # Regular (header) build of the same sources, to check it's unaffected by the module support + add_library(imgui_header${IMGUI_SFX} STATIC + "${IMGUI_DIR}/imgui.cpp" "${IMGUI_DIR}/imgui_demo.cpp" "${IMGUI_DIR}/imgui_draw.cpp" "${IMGUI_DIR}/imgui_tables.cpp" "${IMGUI_DIR}/imgui_widgets.cpp") + target_include_directories(imgui_header${IMGUI_SFX} PUBLIC "${IMGUI_DIR}") + target_compile_definitions(imgui_header${IMGUI_SFX} PUBLIC ${arg_UNPARSED_ARGUMENTS}) + target_compile_options(imgui_header${IMGUI_SFX} PRIVATE ${IMGUI_WARNINGS}) + + imgui_add_backend(null) + if(arg_LIBRARIES_ONLY) + return() + endif() + + imgui_add_test(test_module RUN test_module.cpp test_module_macros.cpp LIBS imgui${IMGUI_SFX}) + imgui_add_test(test_header_internal RUN test_header_internal.cpp LIBS imgui_header${IMGUI_SFX}) + imgui_add_test(test_backend_null DIFF test_backend_null.cpp LIBS imgui_impl_null${IMGUI_SFX}) +endfunction() + +#----------------------------------------------------------------------------- +# Compile-time configurations (same as the example_null builds of .github/workflows/build.yml) +#----------------------------------------------------------------------------- + +imgui_add_config(default) +imgui_add_config(no_obsolete IMGUI_DISABLE_OBSOLETE_FUNCTIONS) +imgui_add_config(wchar32 IMGUI_USE_WCHAR32) +imgui_add_config(large_idx "ImDrawIdx=unsigned int" "ImTextureID=void*") +imgui_add_config(no_demo_debug IMGUI_DISABLE_DEMO_WINDOWS IMGUI_DISABLE_DEBUG_TOOLS) +imgui_add_config(no_file IMGUI_DISABLE_FILE_FUNCTIONS) +imgui_add_config(bgra IMGUI_USE_BGRA_PACKED_COLOR) +imgui_add_config(math_operators IMGUI_DEFINE_MATH_OPERATORS) +imgui_add_config(disable LIBRARIES_ONLY IMGUI_DISABLE) + +#----------------------------------------------------------------------------- +# Modules 'imgui.impl.' (default configuration) +#----------------------------------------------------------------------------- + +if(WIN32) + imgui_add_backend(win32 gdi32 dwmapi) + imgui_add_backend(dx9 d3d9) + imgui_add_backend(dx10 d3d10 d3dcompiler) + imgui_add_backend(dx11 d3d11 d3dcompiler) + imgui_add_backend(dx12 d3d12 dxgi d3dcompiler OPTIONS -Wno-unused-but-set-variable) # upstream warning with NDEBUG (header build too): 'hr' only used by IM_ASSERT() +endif() + +if(ANDROID) + imgui_add_backend(android android log OPTIONS -Wno-unused-variable) # upstream warning (header build too): unused 'g_LogTag' + imgui_add_backend(opengl3 GLESv3) # OpenGL ES 3 is selected automatically on Android +else() + find_package(OpenGL) + if(TARGET OpenGL::GL) + imgui_add_backend(opengl2 OpenGL::GL) + if(WIN32) + imgui_add_backend(opengl3 OpenGL::GL) + else() + imgui_add_backend(opengl3 ${CMAKE_DL_LIBS}) # uses its own loader (imgui_impl_opengl3_loader.h) + endif() + endif() + find_package(GLUT) + if(TARGET GLUT::GLUT AND TARGET OpenGL::GL) + imgui_add_backend(glut GLUT::GLUT OpenGL::GL) + endif() +endif() + +find_package(SDL2 CONFIG) +if(TARGET SDL2::SDL2) + imgui_add_backend(sdl2 SDL2::SDL2) + imgui_add_backend(sdlrenderer2 SDL2::SDL2) +endif() + +find_package(SDL3 CONFIG) +if(TARGET SDL3::SDL3) + imgui_add_backend(sdl3 SDL3::SDL3) + imgui_add_backend(sdlrenderer3 SDL3::SDL3) + imgui_add_backend(sdlgpu3 SDL3::SDL3) +endif() + +find_package(glfw3 CONFIG) +if(TARGET glfw) + imgui_add_backend(glfw glfw) +endif() + +find_package(Vulkan) +if(TARGET Vulkan::Vulkan) + imgui_add_backend(vulkan Vulkan::Vulkan) +endif() + +if(NOT CMAKE_CROSSCOMPILING) + find_package(PkgConfig) + if(PKG_CONFIG_FOUND) + pkg_check_modules(ALLEGRO5 IMPORTED_TARGET allegro-5 allegro_primitives-5) + endif() + if(TARGET PkgConfig::ALLEGRO5) + imgui_add_backend(allegro5 PkgConfig::ALLEGRO5 OPTIONS -Wno-unused-variable) # upstream warning (header build too): unused 'platform_io' + endif() +endif() + +set(IMGUI_WEBGPU_INCLUDE_DIRS "" CACHE STRING "WebGPU include directories providing (enables the compile-only 'wgpu' backend)") +set(IMGUI_WEBGPU_BACKEND "DAWN" CACHE STRING "WebGPU implementation: DAWN or WGPU") +if(IMGUI_WEBGPU_INCLUDE_DIRS) + add_library(imgui_webgpu_headers INTERFACE) + target_include_directories(imgui_webgpu_headers SYSTEM INTERFACE ${IMGUI_WEBGPU_INCLUDE_DIRS}) + target_compile_definitions(imgui_webgpu_headers INTERFACE IMGUI_IMPL_WEBGPU_BACKEND_${IMGUI_WEBGPU_BACKEND}) + imgui_add_backend(wgpu imgui_webgpu_headers) +endif() + +message(STATUS "imgui backend modules: ${IMGUI_BACKENDS}") + +#----------------------------------------------------------------------------- +# Backend tests (default configuration) +#----------------------------------------------------------------------------- + +imgui_add_test(test_backend_sdl2 DIFF test_backend_sdl2.cpp LIBS imgui_impl_sdl2 imgui_impl_sdlrenderer2) +imgui_add_test(test_backend_sdl3 DIFF test_backend_sdl3.cpp LIBS imgui_impl_sdl3 imgui_impl_sdlrenderer3 imgui_impl_sdlgpu3) +# Backends that need a GPU/display to run +imgui_add_test(test_backend_gpu LINK test_backend_gpu.cpp LIBS imgui_impl_opengl2 imgui_impl_opengl3 imgui_impl_glut imgui_impl_glfw imgui_impl_vulkan) +imgui_add_test(test_backend_allegro5 LINK test_backend_allegro5.cpp LIBS imgui_impl_allegro5) +imgui_add_test(test_backend_windows LINK test_backend_windows.cpp LIBS imgui_impl_win32 imgui_impl_dx9 imgui_impl_dx10 imgui_impl_dx11 imgui_impl_dx12 imgui_impl_opengl2 imgui_impl_opengl3) +imgui_add_test(test_backend_android LINK test_backend_android.cpp LIBS imgui_impl_android imgui_impl_opengl3 imgui_impl_vulkan) +imgui_add_test(test_backend_wgpu COMPILE test_backend_wgpu.cpp LIBS imgui_impl_wgpu) # headers only, nothing to link diff --git a/misc/cxx_module/CMakePresets.json b/misc/cxx_module/CMakePresets.json new file mode 100644 index 000000000..556fe8be1 --- /dev/null +++ b/misc/cxx_module/CMakePresets.json @@ -0,0 +1,38 @@ +{ + "version": 6, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "clang", + "displayName": "Clang + Ninja + import std", + "inherits": "base", + "cacheVariables": { "CMAKE_CXX_COMPILER": "clang++" } + } + ], + "buildPresets": [ + { "name": "clang", "configurePreset": "clang" } + ], + "testPresets": [ + { "name": "base", "hidden": true, "output": { "outputOnFailure": true }, "execution": { "noTestsAction": "error" } }, + { "name": "clang", "inherits": "base", "configurePreset": "clang" } + ], + "workflowPresets": [ + { + "name": "clang", + "steps": [ + { "type": "configure", "name": "clang" }, + { "type": "build", "name": "clang" }, + { "type": "test", "name": "clang" } + ] + } + ] +} diff --git a/misc/cxx_module/compare_output.cmake b/misc/cxx_module/compare_output.cmake new file mode 100644 index 000000000..e0ad2b9aa --- /dev/null +++ b/misc/cxx_module/compare_output.cmake @@ -0,0 +1,13 @@ +# dear imgui: run two test executables (header and module builds of the same source) and check that their outputs match. +# Usage: cmake [-DEMULATOR=] -DEXPECTED=
-DACTUAL= -P compare_output.cmake + +foreach(exe IN ITEMS EXPECTED ACTUAL) + execute_process(COMMAND ${EMULATOR} "${${exe}}" OUTPUT_VARIABLE output_${exe} RESULT_VARIABLE result ERROR_VARIABLE error) + if(NOT result EQUAL 0) + message(FATAL_ERROR "${${exe}} failed (${result}):\n${output_${exe}}${error}") + endif() +endforeach() +message("${output_ACTUAL}") +if(NOT output_EXPECTED STREQUAL output_ACTUAL) + message(FATAL_ERROR "Output differs from the header build:\n${output_EXPECTED}") +endif() diff --git a/misc/cxx_module/test_backend_allegro5.cpp b/misc/cxx_module/test_backend_allegro5.cpp new file mode 100644 index 000000000..d18efd825 --- /dev/null +++ b/misc/cxx_module/test_backend_allegro5.cpp @@ -0,0 +1,23 @@ +// dear imgui: compile/link test for the C++20 backend module 'imgui.impl.allegro5' (needs a display to run). + +#include // application-side platform headers +import std; +import imgui; +import imgui.impl.allegro5; + +static_assert(std::is_same_v); + +void RenderFrameAllegro5(ALLEGRO_DISPLAY* display, ALLEGRO_EVENT* event) +{ + ImGui_ImplAllegro5_Init(display); + ImGui_ImplAllegro5_ProcessEvent(event); + ImGui_ImplAllegro5_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplAllegro5_RenderDrawData(ImGui::GetDrawData()); +} + +int main() +{ + return 0; +} diff --git a/misc/cxx_module/test_backend_android.cpp b/misc/cxx_module/test_backend_android.cpp new file mode 100644 index 000000000..e55acac82 --- /dev/null +++ b/misc/cxx_module/test_backend_android.cpp @@ -0,0 +1,49 @@ +// dear imgui: compile/link test for the C++20 backend modules for Android: +// 'imgui.impl.android', 'imgui.impl.opengl3' (OpenGL ES 3), 'imgui.impl.vulkan'. +// Checks that their API is exported, usable from an importer, and links (not run). + +#include // application-side platform headers +#include +#include +import std; +import imgui; +import imgui.impl.android; +import imgui.impl.opengl3; +import imgui.impl.vulkan; + +static_assert(std::is_same_v); +static_assert(sizeof(ImGui_ImplVulkan_InitInfo) > 0); + +void RenderFrameOpenGL3(ANativeWindow* window, const AInputEvent* input_event) +{ + ImGui_ImplAndroid_Init(window); + ImGui_ImplOpenGL3_Init("#version 300 es"); + ImGui_ImplAndroid_HandleInputEvent(input_event); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplAndroid_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +void RenderFrameVulkan(VkInstance instance, VkDevice device, VkQueue queue, VkCommandBuffer command_buffer) +{ + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.ApiVersion = VK_API_VERSION_1_1; + init_info.Instance = instance; + init_info.PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(instance); + init_info.Device = device; + init_info.Queue = queue; + init_info.MinImageCount = 2; + init_info.ImageCount = 2; + ImGui_ImplVulkan_Init(&init_info); + ImGui_ImplVulkan_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), command_buffer); +} + +int main() +{ + return 0; +} diff --git a/misc/cxx_module/test_backend_gpu.cpp b/misc/cxx_module/test_backend_gpu.cpp new file mode 100644 index 000000000..336d262f2 --- /dev/null +++ b/misc/cxx_module/test_backend_gpu.cpp @@ -0,0 +1,63 @@ +// dear imgui: compile/link test for the C++20 backend modules that need a GPU/display to run: +// 'imgui.impl.opengl2', 'imgui.impl.opengl3', 'imgui.impl.glut', 'imgui.impl.glfw', 'imgui.impl.vulkan'. +// Checks that their API is exported, usable from an importer, and links (not run). + +#include // application-side platform headers +#include +import std; +import imgui; +import imgui.impl.opengl2; +import imgui.impl.opengl3; +import imgui.impl.glut; +import imgui.impl.glfw; +import imgui.impl.vulkan; + +// Exported structs are complete types +static_assert(sizeof(ImGui_ImplVulkan_InitInfo) > 0); +static_assert(sizeof(ImGui_ImplVulkanH_Window) > 0); +static_assert(sizeof(ImGui_ImplOpenGL3_RenderState) > 0); +static_assert(std::is_same_v); + +void RenderFrameOpenGL3(GLFWwindow* window) +{ + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init("#version 130"); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); +} + +void RenderFrameOpenGL2() +{ + ImGui_ImplGLUT_Init(); + ImGui_ImplOpenGL2_Init(); + ImGui_ImplOpenGL2_NewFrame(); + ImGui_ImplGLUT_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); +} + +void RenderFrameVulkan(VkInstance instance, VkDevice device, VkQueue queue, VkCommandBuffer command_buffer) +{ + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.ApiVersion = VK_API_VERSION_1_3; + init_info.Instance = instance; + init_info.PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(instance); + init_info.Device = device; + init_info.Queue = queue; + init_info.MinImageCount = 2; + init_info.ImageCount = 2; + ImGui_ImplVulkan_Init(&init_info); + ImGui_ImplVulkan_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), command_buffer); +} + +int main() +{ + return 0; +} diff --git a/misc/cxx_module/test_backend_null.cpp b/misc/cxx_module/test_backend_null.cpp new file mode 100644 index 000000000..9f99e3965 --- /dev/null +++ b/misc/cxx_module/test_backend_null.cpp @@ -0,0 +1,38 @@ +// dear imgui: run test for the C++20 backend module 'imgui.impl.null' (see backends/imgui_impl_null.cppm). +// Differential test (see test_diff.h): the header build (IMGUI_TEST_HEADER) and the module build must print the same output. + +#ifdef IMGUI_TEST_HEADER +#include "imgui.h" +#include "imgui_impl_null.h" +#include +#else +import std.compat; +import imgui; +import imgui.impl.null; +#endif +#include "test_diff.h" + +int main() +{ + ImGui::CreateContext(); + TestDiff_Init(); + if (!ImGui_ImplNull_Init()) + return 1; + + TestHash hash; + for (int frame = 0; frame < TestDiff_FrameCount; frame++) + { + ImGui_ImplNull_NewFrame(); + TestDiff_NewFrame(frame); + ImGui::NewFrame(); + TestDiff_ShowWindows(); + ImGui::Render(); + TestDiff_HashDrawData(hash, ImGui::GetDrawData()); + ImGui_ImplNullRender_RenderDrawData(ImGui::GetDrawData()); + } + + ImGui_ImplNull_Shutdown(); + ImGui::DestroyContext(); + hash.Print("imgui.impl.null"); + return hash.VtxCount > 0 ? 0 : 1; +} diff --git a/misc/cxx_module/test_backend_sdl2.cpp b/misc/cxx_module/test_backend_sdl2.cpp new file mode 100644 index 000000000..ca342c9f5 --- /dev/null +++ b/misc/cxx_module/test_backend_sdl2.cpp @@ -0,0 +1,74 @@ +// dear imgui: run test for the C++20 backend modules 'imgui.impl.sdl2' + 'imgui.impl.sdlrenderer2'. +// Runs headless using SDL's "dummy" video driver and the software renderer. +// Differential test (see test_diff.h): the header build (IMGUI_TEST_HEADER) and the module build must print the same output. + +#include // SDL API + macros for the application (modules don't export SDL) +#ifdef IMGUI_TEST_HEADER +#include "imgui.h" +#include "imgui_impl_sdl2.h" +#include "imgui_impl_sdlrenderer2.h" +#include +#else +import std.compat; +import imgui; +import imgui.impl.sdl2; +import imgui.impl.sdlrenderer2; +#endif +#include "test_diff.h" + +int main(int, char**) +{ + SDL_setenv("SDL_VIDEODRIVER", "dummy", 1); + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + printf("SDL_Init() failed: %s\n", SDL_GetError()); + return 1; + } + SDL_Window* window = SDL_CreateWindow("imgui module test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 720, 0); + SDL_Renderer* renderer = window ? SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE) : nullptr; + if (renderer == nullptr) + { + printf("SDL_CreateWindow()/SDL_CreateRenderer() failed: %s\n", SDL_GetError()); + return 1; + } + + ImGui::CreateContext(); + TestDiff_Init(); + ImGui_ImplSDL2_InitForSDLRenderer(window, renderer); + ImGui_ImplSDLRenderer2_Init(renderer); + ImGui_ImplSDL2_SetGamepadMode(ImGui_ImplSDL2_GamepadMode_AutoFirst); + + TestHash hash; + for (int frame = 0; frame < TestDiff_FrameCount; frame++) + { + SDL_Event event; + while (SDL_PollEvent(&event)) + ImGui_ImplSDL2_ProcessEvent(&event); + ImGui_ImplSDLRenderer2_NewFrame(); + ImGui_ImplSDL2_NewFrame(); + TestDiff_NewFrame(frame); + ImGui::NewFrame(); + TestDiff_ShowWindows(); + ImGui::Render(); + TestDiff_HashDrawData(hash, ImGui::GetDrawData()); + SDL_RenderClear(renderer); + ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), renderer); + } + + // Rendered image of the last frame + int w = 0, h = 0; + SDL_GetRendererOutputSize(renderer, &w, &h); + ImVector pixels; + pixels.resize(w * h * 4); + SDL_RenderReadPixels(renderer, nullptr, SDL_PIXELFORMAT_RGBA32, pixels.Data, w * 4); + hash.Add(pixels.Data, (size_t)pixels.Size); + + ImGui_ImplSDLRenderer2_Shutdown(); + ImGui_ImplSDL2_Shutdown(); + ImGui::DestroyContext(); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + hash.Print("imgui.impl.sdl2 + imgui.impl.sdlrenderer2"); + return hash.VtxCount > 0 ? 0 : 1; +} diff --git a/misc/cxx_module/test_backend_sdl3.cpp b/misc/cxx_module/test_backend_sdl3.cpp new file mode 100644 index 000000000..0e0293fed --- /dev/null +++ b/misc/cxx_module/test_backend_sdl3.cpp @@ -0,0 +1,92 @@ +// dear imgui: run test for the C++20 backend modules 'imgui.impl.sdl3' + 'imgui.impl.sdlrenderer3' + 'imgui.impl.sdlgpu3'. +// Runs sdl3 + sdlrenderer3 headless using SDL's "dummy" video driver and the software renderer. sdlgpu3 is compiled/linked only. +// Differential test (see test_diff.h): the header build (IMGUI_TEST_HEADER) and the module build must print the same output. + +#include // SDL API + macros for the application (modules don't export SDL) +#ifdef IMGUI_TEST_HEADER +#include "imgui.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_sdlrenderer3.h" +#include "imgui_impl_sdlgpu3.h" +#include +#else +import std.compat; +import imgui; +import imgui.impl.sdl3; +import imgui.impl.sdlrenderer3; +import imgui.impl.sdlgpu3; +#endif +#include "test_diff.h" + +static_assert(sizeof(ImGui_ImplSDLGPU3_InitInfo) > 0); + +void RenderFrameSDLGPU3(SDL_Window* window, SDL_GPUDevice* device, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass) +{ + ImGui_ImplSDL3_InitForSDLGPU(window); + ImGui_ImplSDLGPU3_InitInfo init_info; + init_info.Device = device; + init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(device, window); + ImGui_ImplSDLGPU3_Init(&init_info); + ImGui_ImplSDLGPU3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplSDLGPU3_PrepareDrawData(ImGui::GetDrawData(), command_buffer); + ImGui_ImplSDLGPU3_RenderDrawData(ImGui::GetDrawData(), command_buffer, render_pass); +} + +int main(int, char**) +{ + SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "dummy"); + if (!SDL_Init(SDL_INIT_VIDEO)) + { + printf("SDL_Init() failed: %s\n", SDL_GetError()); + return 1; + } + SDL_Window* window = SDL_CreateWindow("imgui module test", 1280, 720, 0); + SDL_Renderer* renderer = window ? SDL_CreateRenderer(window, SDL_SOFTWARE_RENDERER) : nullptr; + if (renderer == nullptr) + { + printf("SDL_CreateWindow()/SDL_CreateRenderer() failed: %s\n", SDL_GetError()); + return 1; + } + + ImGui::CreateContext(); + TestDiff_Init(); + ImGui_ImplSDL3_InitForSDLRenderer(window, renderer); + ImGui_ImplSDLRenderer3_Init(renderer); + ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode_AutoFirst); + + TestHash hash; + for (int frame = 0; frame < TestDiff_FrameCount; frame++) + { + SDL_Event event; + while (SDL_PollEvent(&event)) + ImGui_ImplSDL3_ProcessEvent(&event); + ImGui_ImplSDLRenderer3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + TestDiff_NewFrame(frame); + ImGui::NewFrame(); + TestDiff_ShowWindows(); + ImGui::Render(); + TestDiff_HashDrawData(hash, ImGui::GetDrawData()); + SDL_RenderClear(renderer); + ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); + } + + // Rendered image of the last frame + if (SDL_Surface* surface = SDL_RenderReadPixels(renderer, nullptr)) + { + hash.Add(surface->pixels, (size_t)(surface->pitch * surface->h)); + SDL_DestroySurface(surface); + } + + ImGui_ImplSDLRenderer3_Shutdown(); + ImGui_ImplSDL3_Shutdown(); + ImGui::DestroyContext(); + SDL_DestroyRenderer(renderer); + SDL_DestroyWindow(window); + SDL_Quit(); + hash.Print("imgui.impl.sdl3 + imgui.impl.sdlrenderer3"); + return hash.VtxCount > 0 ? 0 : 1; +} diff --git a/misc/cxx_module/test_backend_wgpu.cpp b/misc/cxx_module/test_backend_wgpu.cpp new file mode 100644 index 000000000..d387d7136 --- /dev/null +++ b/misc/cxx_module/test_backend_wgpu.cpp @@ -0,0 +1,21 @@ +// dear imgui: compile-only test for the C++20 backend module 'imgui.impl.wgpu' (Dawn or wgpu-native headers, no library needed). + +#include // application-side platform headers +import std; +import imgui; +import imgui.impl.wgpu; + +static_assert(sizeof(ImGui_ImplWGPU_InitInfo) > 0); + +void RenderFrameWGPU(WGPUDevice device, WGPURenderPassEncoder pass_encoder) +{ + ImGui_ImplWGPU_InitInfo init_info; + init_info.Device = device; + init_info.RenderTargetFormat = WGPUTextureFormat_BGRA8Unorm; + ImGui_ImplWGPU_Init(&init_info); + ImGui_ImplWGPU_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplWGPU_RenderDrawData(ImGui::GetDrawData(), pass_encoder); + std::println("{}", ImGui_ImplWGPU_GetBackendTypeName(WGPUBackendType_Vulkan)); +} diff --git a/misc/cxx_module/test_backend_windows.cpp b/misc/cxx_module/test_backend_windows.cpp new file mode 100644 index 000000000..0838d2a8b --- /dev/null +++ b/misc/cxx_module/test_backend_windows.cpp @@ -0,0 +1,93 @@ +// dear imgui: compile/link test for the C++20 backend modules for Windows: +// 'imgui.impl.win32', 'imgui.impl.dx9', 'imgui.impl.dx10', 'imgui.impl.dx11', 'imgui.impl.dx12', 'imgui.impl.opengl2', 'imgui.impl.opengl3'. +// Checks that their API is exported, usable from an importer, and links (not run). + +#include // application-side platform headers +#include +#include +#include +#include +#include +import std; +import imgui; +import imgui.impl.win32; +import imgui.impl.dx9; +import imgui.impl.dx10; +import imgui.impl.dx11; +import imgui.impl.dx12; +import imgui.impl.opengl2; +import imgui.impl.opengl3; + +static_assert(sizeof(ImGui_ImplDX12_InitInfo) > 0); +static_assert(std::is_same_v); + +LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) + return true; + return ::DefWindowProcW(hWnd, msg, wParam, lParam); +} + +void RenderFrameDX9(HWND hwnd, IDirect3DDevice9* device) +{ + ImGui_ImplWin32_Init(hwnd); + ImGui_ImplDX9_Init(device); + ImGui_ImplDX9_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); +} + +void RenderFrameDX10(ID3D10Device* device) +{ + ImGui_ImplDX10_Init(device); + ImGui_ImplDX10_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData()); +} + +void RenderFrameDX11(ID3D11Device* device, ID3D11DeviceContext* device_context) +{ + ImGui_ImplDX11_Init(device, device_context); + ImGui_ImplDX11_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); +} + +void RenderFrameDX12(ID3D12Device* device, ID3D12CommandQueue* command_queue, ID3D12DescriptorHeap* srv_heap, ID3D12GraphicsCommandList* command_list) +{ + ImGui_ImplDX12_InitInfo init_info; + init_info.Device = device; + init_info.CommandQueue = command_queue; + init_info.NumFramesInFlight = 2; + init_info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + init_info.DSVFormat = DXGI_FORMAT_UNKNOWN; + init_info.SrvDescriptorHeap = srv_heap; + ImGui_ImplDX12_Init(&init_info); + ImGui_ImplDX12_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), command_list); +} + +void RenderFrameOpenGL(HWND hwnd) +{ + ImGui_ImplWin32_InitForOpenGL(hwnd); + ImGui_ImplOpenGL2_Init(); + ImGui_ImplOpenGL3_Init(); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplWin32_NewFrame(); + ImGui::NewFrame(); + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + ImGui_ImplOpenGL2_RenderDrawData(ImGui::GetDrawData()); +} + +int main() +{ + ImGui_ImplWin32_EnableDpiAwareness(); + return 0; +} diff --git a/misc/cxx_module/test_diff.h b/misc/cxx_module/test_diff.h new file mode 100644 index 000000000..69c44990a --- /dev/null +++ b/misc/cxx_module/test_diff.h @@ -0,0 +1,86 @@ +// dear imgui: helpers for the differential tests (see imgui_add_test(... DIFF ...) in CMakeLists.txt). +// Each test is built twice, with 'import imgui;' and with '#include "imgui.h"' (IMGUI_TEST_HEADER), runs the same scripted frames, +// and prints a hash of everything rendered (draw data, texture uploads): the outputs of both builds must match. +// Included after the imports/includes: uses no other header. + +#pragma once + +static const int TestDiff_FrameCount = 120; + +// FNV-1a hash +struct TestHash +{ + unsigned long long Value = 14695981039346656037ull; + int VtxCount = 0; + void Add(const void* data, size_t size) { const unsigned char* p = (const unsigned char*)data; for (size_t n = 0; n < size; n++) Value = (Value ^ p[n]) * 1099511628211ull; } + template void Add(const T& v) { Add(&v, sizeof(v)); } + void Print(const char* name) const { printf("%s: frames=%d vertices=%d hash=%08x%08x\n", name, TestDiff_FrameCount, VtxCount, (unsigned int)(Value >> 32), (unsigned int)Value); } +}; + +static void TestDiff_Init() +{ + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = nullptr; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + ImGui::GetPlatformIO().Platform_OpenInShellFn = [](ImGuiContext*, const char*) { return false; }; // scripted clicks may hit links +} + +// Call after the backends' NewFrame(): scripted input (mouse moves and clicks, keyboard navigation and text), fixed time step +static void TestDiff_NewFrame(int frame) +{ + ImGuiIO& io = ImGui::GetIO(); + io.DeltaTime = 1.0f / 60.0f; + io.AddMousePosEvent((float)(frame * 37 % 1000), (float)(frame * 23 % 700)); + io.AddMouseButtonEvent(ImGuiMouseButton_Left, frame % 10 == 5); + io.AddKeyEvent(ImGuiKey_DownArrow, frame % 4 == 1); + io.AddKeyEvent(ImGuiKey_Space, frame % 12 == 7); + if (frame % 8 == 3) + io.AddInputCharacter('a' + frame % 26); +} + +static void TestDiff_ShowWindows() +{ + ImGui::ShowDemoWindow(); + ImGui::ShowDebugLogWindow(); + ImGui::ShowIDStackToolWindow(); + ImGui::Begin("Style Editor"); + ImGui::ShowStyleEditor(); + ImGui::End(); + // Not compared: ShowMetricsWindow() displays pointers, which differ between runs, and ShowAboutWindow() displays build + // information, which differs between builds (e.g. like imgui_single_file.h, imgui.cppm compiles imgui_demo.cpp after + // imgui_internal.h, which defines IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS when IMGUI_DISABLE_FILE_FUNCTIONS is defined). +} + +// Call after ImGui::Render(), before the renderer backend processes the texture requests +static void TestDiff_HashDrawData(TestHash& hash, const ImDrawData* draw_data) +{ + hash.Add(draw_data->DisplayPos); + hash.Add(draw_data->DisplaySize); + hash.VtxCount += draw_data->TotalVtxCount; + for (const ImDrawList* draw_list : draw_data->CmdLists) + { + hash.Add(draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.size_in_bytes()); + hash.Add(draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.size_in_bytes()); + for (const ImDrawCmd& cmd : draw_list->CmdBuffer) + { + hash.Add(cmd.ClipRect); + hash.Add(cmd.VtxOffset); + hash.Add(cmd.IdxOffset); + hash.Add(cmd.ElemCount); + hash.Add(cmd.TexRef._TexData ? cmd.TexRef._TexData->UniqueID : -1); // (not the texture pointer/identifier) + } + } + if (draw_data->Textures != nullptr) + for (const ImTextureData* tex : *draw_data->Textures) + { + hash.Add(tex->UniqueID); + hash.Add(tex->Status); + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) + { + hash.Add(tex->Format); + hash.Add(tex->Width); + hash.Add(tex->Height); + hash.Add(tex->Pixels, (size_t)tex->GetSizeInBytes()); + } + } +} diff --git a/misc/cxx_module/test_header_internal.cpp b/misc/cxx_module/test_header_internal.cpp new file mode 100644 index 000000000..2f7423c6d --- /dev/null +++ b/misc/cxx_module/test_header_internal.cpp @@ -0,0 +1,31 @@ +// dear imgui: header-only (non-module) test for imgui_internal.h. +// imgui_internal.h must work on its own, including after imgui_macros.h (which defines IMGUI_VERSION without the declarations of imgui.h). + +#include "imgui_macros.h" +#include "imgui_internal.h" +#include + +int main() +{ + IMGUI_CHECKVERSION(); + ImGuiContext* ctx = ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(ctx); // imgui_internal.h API + io.DisplaySize = ImVec2(1280.0f, 720.0f); + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // (no renderer: textures are never uploaded) + + ImGuiWindow* window = nullptr; + for (int frame = 0; frame < 2; frame++) // new windows are hidden on their first frame + { + ImGui::NewFrame(); + ImGui::Begin("Test"); + window = ImGui::GetCurrentWindow(); + ImGui::Text("Hello"); + ImGui::End(); + ImGui::Render(); + } + + const bool ok = window != nullptr && ImGui::GetDrawData()->TotalVtxCount > 0 && ctx->FrameCount == 2; + printf("window=%p vtx=%d frame=%d\n", (void*)window, ImGui::GetDrawData()->TotalVtxCount, ctx->FrameCount); + ImGui::DestroyContext(ctx); + return ok ? 0 : 1; +} diff --git a/misc/cxx_module/test_module.cpp b/misc/cxx_module/test_module.cpp new file mode 100644 index 000000000..7797f7a8b --- /dev/null +++ b/misc/cxx_module/test_module.cpp @@ -0,0 +1,103 @@ +// dear imgui: compile/run test for the C++20 named module 'imgui' (see imgui.cppm). +// This translation unit only imports modules: no macros are available, so it uses the constexpr alternatives. +// See test_module_macros.cpp for a translation unit that also includes imgui_macros.h. + +import std; +import imgui; + +#if defined(IMGUI_VERSION) || defined(IM_COL32) || defined(IM_ASSERT) || defined(IMGUI_EXPORT) +#error "Macros must not leak through 'import imgui;'" +#endif + +// Constexpr alternatives to macros +static_assert(ImGuiVersionNum >= 19200); +static_assert(ImGuiVersion[0] != 0); +static_assert(ImCol32(255, 255, 255, 255) == ImCol32_White); +static_assert(ImCol32(0, 0, 0, 255) == ImCol32_Black); +static_assert(ImCol32_BlackTrans == 0); +static_assert(((ImCol32(0x12, 0x34, 0x56, 0x78) >> ImCol32_GShift) & 0xFF) == 0x34); +static_assert((ImCol32_White & ImCol32_AMask) == ImCol32_AMask); +static_assert(ImUnicodeCodepoint_Invalid == 0xFFFD); +static_assert(std::string_view(ImGuiPayloadType_Color4F) == "_COL4F"); +constexpr int ints[] = { 1, 2, 3 }; +static_assert(ImCountOf(ints) == 3); + +// Math operators are exported +static_assert(requires(ImVec2 a, ImVec2 b) { a + b; a * 2.0f; a += b; }); + +// Exported types/enums +static_assert(std::is_enum_v); +static_assert(sizeof(ImDrawIdx) == 2 || sizeof(ImDrawIdx) == 4); +static_assert(std::is_same_v); + +// Internal types stay incomplete (imgui_internal.h is not exported) +template concept IsComplete = requires { sizeof(T); }; +static_assert(!IsComplete); + +int TestModuleWithMacros(); // test_module_macros.cpp + +static void RenderTextures(ImDrawData* draw_data) +{ + // Minimal renderer: acknowledge texture requests (same as imgui_impl_null.cpp) + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + { + if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates) + tex->SetStatus(ImTextureStatus_OK); + else if (tex->Status == ImTextureStatus_WantDestroy) + tex->SetStatus(ImTextureStatus_Destroyed); + } +} + +int main() +{ + if (!ImGui::CheckVersion()) + return 1; + + ImGuiContext* ctx = ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures; + io.IniFilename = nullptr; + + int vtx_count = 0; + for (int n = 0; n < 5; n++) + { + io.DisplaySize = ImVec2(1280, 720); + io.DeltaTime = 1.0f / 60.0f; + ImGui::NewFrame(); + + static float f = 0.5f; + static std::array buf = { "Hello, module!" }; + ImGui::Begin("Module test"); + ImGui::Text("Dear ImGui %s (%d)", ImGui::GetVersion(), ImGuiVersionNum); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + ImGui::InputText("text", buf.data(), buf.size()); + if (ImGui::BeginTable("table", 2)) + { + ImGui::TableNextColumn(); ImGui::TextUnformatted("A"); + ImGui::TableNextColumn(); ImGui::TextUnformatted("B"); + ImGui::EndTable(); + } + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + const ImVec2 p = ImGui::GetCursorScreenPos(); + draw_list->AddRect(p, p + ImVec2(50, 50) * 2.0f, ImCol32(255, 0, 0, 255)); + ImGui::End(); + ImGui::ShowDemoWindow(nullptr); + + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + RenderTextures(draw_data); + vtx_count = draw_data->TotalVtxCount; + } + + ImVector v; + v.push_back(1); + v.push_back(2); + + const int macros_result = TestModuleWithMacros(); + + ImGui::DestroyContext(ctx); + + std::println("imgui {}: vtx_count={} vector_size={} macros_result={}", ImGuiVersion, vtx_count, v.Size, macros_result); + return (vtx_count > 0 && v.Size == 2 && macros_result == 0) ? 0 : 1; +} diff --git a/misc/cxx_module/test_module_macros.cpp b/misc/cxx_module/test_module_macros.cpp new file mode 100644 index 000000000..bd56ec7db --- /dev/null +++ b/misc/cxx_module/test_module_macros.cpp @@ -0,0 +1,46 @@ +// dear imgui: compile test for the C++20 named module 'imgui' (see imgui.cppm), using the macros from imgui_macros.h. +// Modules don't export macros: include imgui_macros.h (with the same configuration as the module) before importing. + +#include "imgui_macros.h" +import std; +import imgui; + +// Macros and constexpr alternatives must agree +static_assert(IMGUI_VERSION_NUM == ImGuiVersionNum); +static_assert(IM_COL32(1, 2, 3, 4) == ImCol32(1, 2, 3, 4)); +static_assert(IM_COL32_WHITE == ImCol32_White); +static_assert(IM_UNICODE_CODEPOINT_MAX == ImUnicodeCodepoint_Max); + +struct TestObject +{ + int Value; + TestObject(int value) : Value(value) {} +}; + +int TestModuleWithMacros() +{ + if (!IMGUI_CHECKVERSION()) + return 1; + + // IM_NEW/IM_DELETE rely on the exported ImNewWrapper placement new and IM_DELETE template + TestObject* obj = IM_NEW(TestObject)(42); + IM_ASSERT(obj->Value == 42); + IM_DELETE(obj); + + const char* names[] = { "a", "b", "c", "d" }; + IM_UNUSED(names); + static_assert(IM_COUNTOF(names) == 4); + + ImGui::NewFrame(); + ImGui::Begin("Macros"); + ImGui::GetWindowDrawList()->AddLine(ImVec2(0, 0), ImVec2(10, 10), IM_COL32_WHITE); + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + const float col[4] = { 1, 0, 0, 1 }; + ImGui::SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, col, sizeof(col)); + ImGui::EndDragDropSource(); + } + ImGui::End(); + ImGui::EndFrame(); + return 0; +}