From 59a85207cc712f1e844e2103e1ce80d2ca3cfae9 Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:13:57 +0100 Subject: [PATCH 1/7] Move public macros from imgui.h to imgui_macros.h C++20 modules don't export macros, so users of 'import imgui;' need another way to get IMGUI_VERSION, IM_COL32() and friends. Gather the version, the imconfig.h include and every public macro into a standalone header. imgui.h includes it, so header users see no change. imgui_internal.h now includes imgui.h unconditionally, because a defined IMGUI_VERSION no longer implies that imgui.h was included. imgui.h's #pragma once already prevents double inclusion. --- imgui.h | 145 +--------------------------------------- imgui_internal.h | 2 - imgui_macros.h | 171 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 145 deletions(-) create mode 100644 imgui_macros.h diff --git a/imgui.h b/imgui.h index a108888a2..8d3587aa4 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: @@ -60,12 +53,8 @@ Index of this file: #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 @@ -79,65 +68,6 @@ Index of this file: #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 #ifdef _MSC_VER #pragma warning (push) @@ -350,13 +280,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()`. @@ -1544,10 +1467,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 +2135,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 +2144,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 +2673,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 +2893,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 @@ -4244,8 +4112,6 @@ 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 - //-- OBSOLETED in 1.92.0: ImFontAtlasCustomRect becomes ImTextureRect // - ImFontAtlasCustomRect::X,Y --> ImTextureRect::x,y // - ImFontAtlasCustomRect::Width,Height --> ImTextureRect::w,h @@ -4292,13 +4158,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__) diff --git a/imgui_internal.h b/imgui_internal.h index 0ffadedc3..1bdbf1733 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -50,9 +50,7 @@ Index of this file: // [SECTION] Header mess //----------------------------------------------------------------------------- -#ifndef IMGUI_VERSION #include "imgui.h" -#endif #include // FILE*, sscanf #include // NULL, malloc, free, qsort, atoi, atof diff --git a/imgui_macros.h b/imgui_macros.h new file mode 100644 index 000000000..5750fb466 --- /dev/null +++ b/imgui_macros.h @@ -0,0 +1,171 @@ +// 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. + +#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 + +// 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 From f3dd5566c659e3ef8776cba4a4ec115ca7acb09f Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:18:32 +0100 Subject: [PATCH 2/7] Add constexpr alternatives to public macros Macros can't be exported from a C++20 module, and they ignore scope and type in any case. Add typed constexpr equivalents for the values people commonly use: version, payload types, unicode limits, colour packing, IM_COUNTOF() and IMGUI_CHECKVERSION(). Each is defined from its macro, so the two always agree, including when imconfig.h overrides them. They need C++17 inline variables, so they sit behind IMGUI_HAS_CONSTEXPR and C++11 builds are unaffected. --- imgui.h | 40 ++++++++++++++++++++++++++++++++++++++++ imgui_macros.h | 6 ++++++ 2 files changed, 46 insertions(+) diff --git a/imgui.h b/imgui.h index 8d3587aa4..7b7cccd9b 100644 --- a/imgui.h +++ b/imgui.h @@ -47,6 +47,7 @@ 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 */ @@ -4010,6 +4011,45 @@ struct ImGuiPlatformImeData ImGuiPlatformImeData() { memset((void*)this, 0, sizeof(*this)); } }; +//----------------------------------------------------------------------------- +// [SECTION] Constexpr alternatives to macros +// (requires C++17: see IMGUI_HAS_CONSTEXPR in imgui_macros.h) +//----------------------------------------------------------------------------- + +#ifdef IMGUI_HAS_CONSTEXPR +// 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); } + +// Check that version and structures layouts are matching between compiled imgui code and caller (= IMGUI_CHECKVERSION()) +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) diff --git a/imgui_macros.h b/imgui_macros.h index 5750fb466..e8189f0d9 100644 --- a/imgui_macros.h +++ b/imgui_macros.h @@ -36,6 +36,12 @@ #define IMGUI_IMPL_API IMGUI_API #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. +// (C++17 is required for 'inline' variables) +#if (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 From da548b83e798650e1e07c3cd8f042737cdde0124 Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:19:45 +0100 Subject: [PATCH 3/7] Guard system includes for inclusion in a C++20 module purview imgui.cppm compiles the core sources inside its module purview. System headers #included there would attach their declarations to the module, which is ill-formed and clashes with the same declarations in the global module or in 'import std;'. The module includes them in its global module fragment instead, so under IMGUI_CXX_MODULE the sources skip their own includes. Header builds are unchanged. For the same reason: - imstb_rectpack.h and imstb_truetype.h skip their extern "C" blocks, which would attach their declarations to the global module. - imgui_draw.cpp defines STBTT_cos/acos/memcpy/memset, so stb_truetype doesn't include and itself. --- imgui.cpp | 16 +++++++++++++++- imgui.h | 2 ++ imgui_demo.cpp | 2 ++ imgui_draw.cpp | 6 ++++++ imgui_internal.h | 6 ++++++ imgui_tables.cpp | 2 ++ imgui_widgets.cpp | 2 ++ imstb_rectpack.h | 4 ++-- imstb_truetype.h | 4 ++-- 9 files changed, 39 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index fb86370b9..ae6d48f16 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1257,10 +1257,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 @@ -1282,11 +1286,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 @@ -1296,7 +1302,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 @@ -16282,7 +16288,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 @@ -16370,7 +16378,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 @@ -16383,8 +16393,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__) @@ -16417,7 +16429,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.h b/imgui.h index 7b7cccd9b..7f0b2915e 100644 --- a/imgui.h +++ b/imgui.h @@ -64,10 +64,12 @@ Index of this file: //----------------------------------------------------------------------------- // 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 +#endif // Warnings #ifdef _MSC_VER 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 a4097bf38..9f3eb5daa 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 1bdbf1733..c55eaaff7 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -52,20 +52,26 @@ Index of this file: #include "imgui.h" +#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_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 From 6e99a5c717ecc69c7029ff2ab9fe225651569e81 Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:27:46 +0100 Subject: [PATCH 4/7] Add C++20 named module 'imgui' imgui.cppm builds Dear ImGui as a named module that exports the same API as imgui.h. The global module fragment includes imgui_macros.h and the C system headers, then the purview imports std.compat and #includes imgui.h. The .cpp files and imgui_internal.h go in 'module :private;', so internals stay hidden and the whole library is one translation unit. Exports are marked in imgui.h rather than listed separately, so they can't drift from the header: - IMGUI_EXPORT prefixes the ImGui namespace. - IMGUI_EXPORT_BEGIN/END wrap runs of global declarations, leaving out the out-of-line member definitions, which can't be exported. All three expand to nothing outside the module. ImHashData() and the GetIO(ImGuiContext*) overload live in imgui_internal.h but backends need them, so imgui.cppm exports them explicitly. NavUpdateAnyRequestFlag() loses its 'inline' forward declaration. Clang rejects a static inline function that is declared before its definition inside 'module :private;'. The definition is unchanged, so the optimiser can still inline it. --- imgui.cpp | 2 +- imgui.cppm | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ imgui.h | 24 ++++++-- imgui_macros.h | 23 +++++++- 4 files changed, 196 insertions(+), 7 deletions(-) create mode 100644 imgui.cppm diff --git a/imgui.cpp b/imgui.cpp index ae6d48f16..f187231da 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1417,7 +1417,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); 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 7f0b2915e..64af3a168 100644 --- a/imgui.h +++ b/imgui.h @@ -95,6 +95,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 //----------------------------------------------------------------------------- @@ -316,12 +318,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. @@ -1098,6 +1102,8 @@ namespace ImGui } // namespace ImGui +IMGUI_EXPORT_BEGIN + //----------------------------------------------------------------------------- // [SECTION] Flags & Enumerations //----------------------------------------------------------------------------- @@ -3868,6 +3874,8 @@ struct ImFont IMGUI_API bool IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last); }; +IMGUI_EXPORT_END + // This is provided for consistency (but we don't actually use this) inline ImTextureID ImTextureRef::GetTexID() const { @@ -3888,6 +3896,8 @@ inline ImTextureID ImDrawCmd::GetTexID() const return tex_id; } +IMGUI_EXPORT_BEGIN + //----------------------------------------------------------------------------- // [SECTION] Viewports //----------------------------------------------------------------------------- @@ -4013,12 +4023,15 @@ 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) +// (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; @@ -4044,9 +4057,10 @@ 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()) -namespace ImGui +IMGUI_EXPORT namespace ImGui { inline bool CheckVersion() { return IMGUI_CHECKVERSION(); } } @@ -4059,7 +4073,7 @@ namespace ImGui //----------------------------------------------------------------------------- #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. @@ -4154,12 +4168,14 @@ namespace ImGui //static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42 } +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 diff --git a/imgui_macros.h b/imgui_macros.h index e8189f0d9..cccf990b2 100644 --- a/imgui_macros.h +++ b/imgui_macros.h @@ -3,6 +3,10 @@ // 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 @@ -36,9 +40,24 @@ #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. -// (C++17 is required for 'inline' variables) -#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L +// (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 From 08fbbd9624b652d39e82a59b5680622ed42bd428 Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:30:10 +0100 Subject: [PATCH 5/7] backends: prepare for inclusion in a C++20 module purview Each backend becomes its own module that imports 'imgui' and includes its header and source in the purview. Do the same preparation as for the core: - Skip system, platform and graphics API includes under IMGUI_CXX_MODULE, because the module includes them in its global module fragment. - Skip the forward declarations of platform types (GLFWwindow, SDL_Window, ID3D11Device...). Declared in the purview, they would be new types attached to the backend module instead of the real ones. For the same reason, sdl2 drops the elaborated 'struct _SDL_GameController'. - Wrap each header's API in IMGUI_EXPORT_BEGIN/END. - win32: export ImGui_ImplWin32_WndProcHandler() under IMGUI_CXX_MODULE. The header keeps it commented out to avoid pulling in , but a module user can't forward-declare it themselves. - glfw: skip the local GetIO(ImGuiContext*) declaration, because 'imgui' exports it. --- backends/imgui_impl_allegro5.cpp | 2 ++ backends/imgui_impl_allegro5.h | 4 ++++ backends/imgui_impl_android.cpp | 2 ++ backends/imgui_impl_android.h | 4 ++++ backends/imgui_impl_dx10.cpp | 2 ++ backends/imgui_impl_dx10.h | 4 ++++ backends/imgui_impl_dx11.cpp | 2 ++ backends/imgui_impl_dx11.h | 4 ++++ backends/imgui_impl_dx12.cpp | 2 ++ backends/imgui_impl_dx12.h | 5 +++++ backends/imgui_impl_dx9.cpp | 2 ++ backends/imgui_impl_dx9.h | 4 ++++ backends/imgui_impl_glfw.cpp | 4 ++++ backends/imgui_impl_glfw.h | 5 ++++- backends/imgui_impl_glut.cpp | 2 ++ backends/imgui_impl_glut.h | 2 ++ backends/imgui_impl_null.h | 2 ++ backends/imgui_impl_opengl2.cpp | 6 ++++++ backends/imgui_impl_opengl2.h | 2 ++ backends/imgui_impl_opengl3.cpp | 6 ++++++ backends/imgui_impl_opengl3.h | 4 +++- backends/imgui_impl_qnx.cpp | 2 ++ backends/imgui_impl_qnx.h | 4 ++++ backends/imgui_impl_sdl2.cpp | 6 +++++- backends/imgui_impl_sdl2.h | 6 +++++- backends/imgui_impl_sdl3.cpp | 2 ++ backends/imgui_impl_sdl3.h | 4 ++++ backends/imgui_impl_sdlgpu3.h | 4 ++++ backends/imgui_impl_sdlrenderer2.cpp | 4 ++++ backends/imgui_impl_sdlrenderer2.h | 4 ++++ backends/imgui_impl_sdlrenderer3.cpp | 4 ++++ backends/imgui_impl_sdlrenderer3.h | 4 ++++ backends/imgui_impl_vulkan.cpp | 2 ++ backends/imgui_impl_vulkan.h | 5 +++++ backends/imgui_impl_wgpu.cpp | 6 ++++++ backends/imgui_impl_wgpu.h | 6 ++++++ backends/imgui_impl_win32.cpp | 4 ++++ backends/imgui_impl_win32.h | 5 +++++ 38 files changed, 138 insertions(+), 4 deletions(-) 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.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.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.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.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.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.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.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.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.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.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 73dc349d8..20595810f 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -133,11 +133,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__) @@ -158,6 +160,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 @@ -189,6 +192,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 @@ -231,7 +235,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.h b/backends/imgui_impl_opengl3.h index e1d999bd3..bc1981bfc 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(); @@ -53,7 +54,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex); && !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__)) @@ -77,5 +78,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.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.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.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.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.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.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.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.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.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 From eaed70b5842318eb5639c28991a664c9709ba646 Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:30:20 +0100 Subject: [PATCH 6/7] backends: add C++20 named modules 'imgui.impl.*' Each imgui_impl_X.cppm builds one backend as module imgui.impl.X, following the same layout as imgui.cppm. The global module fragment holds the platform and graphics API headers, using the same conditions as the backend's .cpp. The purview imports std.compat and imgui and includes the backend header. The .cpp goes in 'module :private;'. The backend header includes imgui.h, but its declarations already come from 'import imgui;' and must not be redeclared in this module. Module units therefore define IMGUI_CXX_MODULE_IMPORTED, which makes imgui.h contribute only its macros. Usage: 'import imgui; import imgui.impl.glfw;'. Link the module library in place of the backend .cpp. --- backends/imgui_impl_allegro5.cppm | 27 +++++++++++++ backends/imgui_impl_android.cppm | 27 +++++++++++++ backends/imgui_impl_dx10.cppm | 25 ++++++++++++ backends/imgui_impl_dx11.cppm | 24 +++++++++++ backends/imgui_impl_dx12.cppm | 26 ++++++++++++ backends/imgui_impl_dx9.cppm | 22 ++++++++++ backends/imgui_impl_glfw.cppm | 58 +++++++++++++++++++++++++++ backends/imgui_impl_glut.cppm | 27 +++++++++++++ backends/imgui_impl_null.cppm | 19 +++++++++ backends/imgui_impl_opengl2.cppm | 34 ++++++++++++++++ backends/imgui_impl_opengl3.cppm | 58 +++++++++++++++++++++++++++ backends/imgui_impl_qnx.cppm | 24 +++++++++++ backends/imgui_impl_sdl2.cppm | 36 +++++++++++++++++ backends/imgui_impl_sdl3.cppm | 32 +++++++++++++++ backends/imgui_impl_sdlgpu3.cppm | 23 +++++++++++ backends/imgui_impl_sdlrenderer2.cppm | 24 +++++++++++ backends/imgui_impl_sdlrenderer3.cppm | 24 +++++++++++ backends/imgui_impl_vulkan.cppm | 38 ++++++++++++++++++ backends/imgui_impl_wgpu.cppm | 37 +++++++++++++++++ backends/imgui_impl_win32.cppm | 32 +++++++++++++++ imgui.h | 5 ++- 21 files changed, 620 insertions(+), 2 deletions(-) create mode 100644 backends/imgui_impl_allegro5.cppm create mode 100644 backends/imgui_impl_android.cppm create mode 100644 backends/imgui_impl_dx10.cppm create mode 100644 backends/imgui_impl_dx11.cppm create mode 100644 backends/imgui_impl_dx12.cppm create mode 100644 backends/imgui_impl_dx9.cppm create mode 100644 backends/imgui_impl_glfw.cppm create mode 100644 backends/imgui_impl_glut.cppm create mode 100644 backends/imgui_impl_null.cppm create mode 100644 backends/imgui_impl_opengl2.cppm create mode 100644 backends/imgui_impl_opengl3.cppm create mode 100644 backends/imgui_impl_qnx.cppm create mode 100644 backends/imgui_impl_sdl2.cppm create mode 100644 backends/imgui_impl_sdl3.cppm create mode 100644 backends/imgui_impl_sdlgpu3.cppm create mode 100644 backends/imgui_impl_sdlrenderer2.cppm create mode 100644 backends/imgui_impl_sdlrenderer3.cppm create mode 100644 backends/imgui_impl_vulkan.cppm create mode 100644 backends/imgui_impl_wgpu.cppm create mode 100644 backends/imgui_impl_win32.cppm 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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/imgui.h b/imgui.h index 64af3a168..25ed4f588 100644 --- a/imgui.h +++ b/imgui.h @@ -57,7 +57,8 @@ Index of this file: // 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 @@ -4238,4 +4239,4 @@ IMGUI_EXPORT_END #endif #endif -#endif // #ifndef IMGUI_DISABLE +#endif // #if !defined(IMGUI_DISABLE) && !defined(IMGUI_CXX_MODULE_IMPORTED) From a92dba93d902696099a6f6d2d2724b27931a34c0 Mon Sep 17 00:00:00 2001 From: Sharadh Rajaraman Date: Mon, 28 Sep 2026 16:30:53 +0100 Subject: [PATCH 7/7] misc/cxx_module: add CMake build and tests for the C++20 modules Module support is easy to break from the header side, e.g. by a new system include, a forward-declared platform type, or an export block that misses a declaration. This adds a CMake project that builds every module whose platform library is found, alongside the header build of the same code. Linking alone doesn't show that the module behaves like the headers, so the main check is differential. 'DIFF' tests are compiled once with 'import imgui;' and once with '#include "imgui.h"'. Both builds run the same scripted frames and must print the same hash of the draw data and texture uploads (test_diff.h, compare_output.cmake). Backends that need a GPU or a display are only linked, and wgpu is only compiled. The core module and the null backend are also built for each compile-time configuration that CI builds example_null with, because IMGUI_DISABLE_* and friends change what gets exported. Presets use Clang, Ninja and 'import std'. Toolchains for cross builds belong in CMakeUserPresets.json, which is ignored along with build/. --- .gitignore | 2 + misc/cxx_module/CMakeLists.txt | 231 ++++++++++++++++++++++ misc/cxx_module/CMakePresets.json | 38 ++++ misc/cxx_module/compare_output.cmake | 13 ++ misc/cxx_module/test_backend_allegro5.cpp | 23 +++ misc/cxx_module/test_backend_android.cpp | 49 +++++ misc/cxx_module/test_backend_gpu.cpp | 63 ++++++ misc/cxx_module/test_backend_null.cpp | 38 ++++ misc/cxx_module/test_backend_sdl2.cpp | 74 +++++++ misc/cxx_module/test_backend_sdl3.cpp | 92 +++++++++ misc/cxx_module/test_backend_wgpu.cpp | 21 ++ misc/cxx_module/test_backend_windows.cpp | 93 +++++++++ misc/cxx_module/test_diff.h | 86 ++++++++ misc/cxx_module/test_header_internal.cpp | 31 +++ misc/cxx_module/test_module.cpp | 103 ++++++++++ misc/cxx_module/test_module_macros.cpp | 46 +++++ 16 files changed, 1003 insertions(+) create mode 100644 misc/cxx_module/CMakeLists.txt create mode 100644 misc/cxx_module/CMakePresets.json create mode 100644 misc/cxx_module/compare_output.cmake create mode 100644 misc/cxx_module/test_backend_allegro5.cpp create mode 100644 misc/cxx_module/test_backend_android.cpp create mode 100644 misc/cxx_module/test_backend_gpu.cpp create mode 100644 misc/cxx_module/test_backend_null.cpp create mode 100644 misc/cxx_module/test_backend_sdl2.cpp create mode 100644 misc/cxx_module/test_backend_sdl3.cpp create mode 100644 misc/cxx_module/test_backend_wgpu.cpp create mode 100644 misc/cxx_module/test_backend_windows.cpp create mode 100644 misc/cxx_module/test_diff.h create mode 100644 misc/cxx_module/test_header_internal.cpp create mode 100644 misc/cxx_module/test_module.cpp create mode 100644 misc/cxx_module/test_module_macros.cpp 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/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; +}