Compare commits

...

350 commits

Author SHA1 Message Date
ocornut
580c00c316 InputText: fixed a crash using Home key with WordWrap+ReadOnly. (#9561)
Some checks failed
build / Build - Windows (push) Has been cancelled
build / Build - Linux (push) Has been cancelled
build / Build - MacOS (push) Has been cancelled
build / Build - iOS (push) Has been cancelled
build / Build - Emscripten (push) Has been cancelled
build / Build - Android (push) Has been cancelled
build / Test - Windows (push) Has been cancelled
build / Test - Linux (push) Has been cancelled
Only the change in STB_TEXTEDIT_MOVELINESTART_IMPL() is required. The others are just for nicer semantic.
2026-09-28 17:47:39 +02:00
Stanislaw Halik
db436a15bc Misc: fixed strict aliasing violation in ImHashData() affecting Clang 23 + SSE 4.2 + -flto. (#9557, #9560) 2026-09-28 17:19:42 +02:00
ocornut
09f7a0f062 Docs: tweak PR template. 2026-09-28 15:12:49 +02:00
ocornut
aa0181478b imgui_freetype: tweak rounding code. (#9348, #9233) 2026-09-25 14:22:08 +02:00
ocornut
5c6a86a9d2 imgui_freetype: fixed ExtraSizeScale (used by embedded ProggyForever) leading to non-pixel aligned vertical offset. (#9348, #9233) + Added ImRoundPositive64(), ImRoundSigned64(). 2026-09-25 14:22:08 +02:00
Brenton Bostick
e728936797 Docs: fixed typos/repeated words. (#9555) 2026-09-24 14:33:24 +02:00
Daniel Castonguay
623ba46120 DrawList: fixed dangling ImDrawList::_OwnerName when using animated label. (#9552) 2026-09-23 16:04:56 +02:00
ocornut
cc072ca90e Tables: comments for saving fix when using ImGuiTableFlags_Sortable and no user changes were made. (#9519, #9108)
Because SortOrder save is gated, it doesn't guarantee every column gets an .ini entry. Amend 1d7b37dc9b.
We set ImGuiTableFlags_Reorderable but technically any other field would work, tho ImGuiTableFlags_Reorderable makes more sense.
2026-09-22 17:13:16 +02:00
ocornut
a6784c378f Tables: fixed reconcile path being needlessly taken on first frame of every table. (#9108) 2026-09-22 16:54:13 +02:00
ocornut
7bfc192814 Tables: tweak struct packing. 2026-09-22 16:48:51 +02:00
ocornut
d12321803d Popups: reworked GetMousePosOnOpeningCurrentPopup() to be legal to call within the BeginPopup/EndPopup scope of a popup which was just closed. (#9551) 2026-09-22 15:57:40 +02:00
ocornut
58d7570b8b ImGuiTextFilterItem: shallow renames. 2026-09-21 18:26:00 +02:00
ocornut
6cf8332f93 ImGuiTextFilterItem: added MatchIncludesMask support field for e.g. ImGuiTextFilterMultiMatch. 2026-09-21 16:52:48 +02:00
ocornut
e19fea020f ImGuiTextFilter: moved ImGuiTextFilterItem to internals. (#2435) 2026-09-21 15:12:59 +02:00
ocornut
d5c68c301a ImGuiTextFilter: reworked filter to make space an AND operator. Demo: tweaked demo.
Removed FilterOp, MinWordSize added a few commits ago.
2026-09-21 14:29:04 +02:00
ocornut
420f179341 Backends: fixed Clang -Wold-style-cast warnings.
Amend 8e17468
2026-09-18 22:31:58 +02:00
ocornut
249e5a939d ImGuiTextFilter: added undocumented FilterOp support. (#2435) 2026-09-18 22:10:31 +02:00
ocornut
565564bb5c ImGuiTextFilter: reworked items parsing/storage to be able to simplify PassFilter().
As PassFilter() is the bottleneck.
2026-09-18 22:10:31 +02:00
ocornut
c0041b7d3c ImGuiTextFilter: added undocumented MinWordSize support. (#2435) 2026-09-18 22:09:14 +02:00
ocornut
c74e7e93a3 ImGuiTextFilter: Added support for space ' ' as separator. Added support for quoted "xxx" blocks. (#2435, #30) 2026-09-18 22:08:22 +02:00
ocornut
54f86be71e ImGuiTextFilter: fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude" match always filters out. (#2435)
+ fix typo in ImToUpper
2026-09-18 22:07:26 +02:00
ocornut
fc98dc4a72 (Internal) ImGuiTextFilter: renaming ImGuiTextRange->ImGuiTextFilterItem, Filters->Items. (#2435) 2026-09-18 22:04:44 +02:00
ocornut
a14bebd948 (Breaking) ImGuiTextFilter: removed float width parameter of Draw(const char* filter, float width). (#6206, #6395, #6447)
The reasoning is to (1) keep things consistent with DrawWithHint() without polluting the new function with width. (2) keep things consistent with other items.
2026-09-18 19:33:21 +02:00
ocornut
f7ada78e32 ImGuiTextFilter: added DrawWithHint(). (#6206, #6395, #6447) 2026-09-18 19:33:21 +02:00
ocornut
c8fc1829d0 ImGuiTextFilter: minor tweaks, made ImGuiTextRange fields match upcoming ImStrv. Removed exposed ImGuiTextRange helpers.
Rename CountGrep to CountInclude (#3906)
Toward #2435
2026-09-18 19:33:21 +02:00
ocornut
f09485d7be Style: inverted ImGuiCol_TitleBgXXX colors for StyleColorsLight().
So that the selected window title bar appears brighter.
2026-09-18 16:05:56 +02:00
ocornut
6d07f6eb09 Selectable: fixed ImGuiSelectableFlags_SelectOnNav triggering during NavInit.
Style Editor: fixed style/colors combo box applying style when opening Combo.
2026-09-18 15:49:00 +02:00
ocornut
5a0ac1678c Minor rename. 2026-09-17 21:09:14 +02:00
ocornut
eabff0fd08 Backends: OpenGL2/OpenGL3: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378) 2026-09-17 20:36:02 +02:00
ocornut
25e16fd8b6 Backends: OpenGL3: minor refactor for both sampler callback to share more code + comments. (#9378) 2026-09-17 20:36:02 +02:00
ocornut
333f5186e3 Backends: OpenGL2, OpenGL3: fixed DrawCallback_ResetRenderState handler not reseting all states in the glTexParameter() path. (#9378)
+ made OpenGL3 SetSamplerLinear/SetSamplerNearest check UseBindSampler for consistency.
2026-09-17 20:36:02 +02:00
ocornut
b5135f270f Backends: SDLRenderer3: added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378) 2026-09-17 19:08:19 +02:00
ocornut
09b7ff9385 Backends: rework header comments about ImGui_ImplXXX_GetRenderState() functions.
Amend 8e17468
2026-09-17 19:08:18 +02:00
ocornut
8d3e37eb53 Backends: SDLRenderer3: restore modified texture scale modes at the end of RenderDrawData(). (#9378, #9543) 2026-09-17 15:17:26 +02:00
ocornut
7cb5ded5d2 Backends: SDLRenderer2, SDLRenderer3: reduce includes. (#9543)
Amend a5b5f2d
2026-09-17 11:36:57 +02:00
Clownacy
a5b5f2d85a Backends: SDLRenderer3: expose CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState. (#9543) 2026-09-17 11:36:46 +02:00
ocornut
8e174685ae Backends: added ImGui_ImplXXXX_GetRenderState() helpers to all backends not having one. 2026-09-16 16:14:06 +02:00
ocornut
b00dd14a34 TabBar: using <> scrolling buttons while the selected Tab is at either end of the section mid-section but not fully visible always makes it fully visible. 2026-09-14 19:50:43 +02:00
ocornut
c8b9f0d6be TabBar: Improved scroll target when clicking a Tab that is larger than the scrolling region width.
The margin that is useful to indicate other tabs being available gets in the way of visibility in this case.
2026-09-14 19:05:13 +02:00
ocornut
ea60e7b748 TabBar: added TabBarGetTabPos() helper.
# Conflicts:
#	imgui_internal.h
#	imgui_widgets.cpp
2026-09-14 15:56:57 +02:00
ocornut
e0a2f6dea9 Drag and Drop: minor refactor into a helper RenderDragDropTargetRectForViewport() function. 2026-09-10 18:32:44 +02:00
ocornut
e8602501bb Mixed Value: various fixes. (#5518, #5677, #6865)
- With MixedValue+LiveEdit: a single edit that ends up with same output reports as edited.
- Standardize path sin TempInputscalar(), InputScalar(), InputTextEx().
- Refer to changes in imgui_test_suite, in particular "widgets_datatype_1", "widgets_status_liveedit_off",
2026-09-09 20:44:34 +02:00
ocornut
ea6d21687b BeginComboPreview(): fixed issues with nesting. Previous comments were wrong. (#1658, #4168) 2026-09-08 21:52:23 +02:00
ocornut
db5b735a5d (Breaking) BeginComboPreview: removed ImGuiComboFlags_CustomPreview: now unnecessary + better detect issues (#1658, #4168) 2026-09-08 19:38:42 +02:00
ocornut
32c3f6095a BeginComboPreview: set/restore WorkRect.Max.x. (#1658, #4168) 2026-09-08 17:44:56 +02:00
ocornut
148d128f6e Mixed Value: use ImGuiCol_TextMixedValue (= ImGuiCol_TextDisabled). Set MixedValueLabel to null to display original value. (#5518, #5677, #6865) 2026-09-08 16:47:04 +02:00
ocornut
334f484892 ColorEdit4, ColorPicker4: added support for ImGuiItemFlags_MixedValue. (#5518, #5677, #6865) 2026-09-07 19:48:28 +02:00
ocornut
dd32dace81 InputText: using MixedValue automatically sets ImGuiInputTextFlags_AutoSelectAll. (#5518, #5677, #6865) 2026-09-07 19:09:24 +02:00
ocornut
04b37d6d23 Added ImGuiItemFlags_MixedValue support for Drags, Sliders, InputScalar, InputText, RadioButton, Combo. (#5518, #5677, #6865) 2026-09-07 18:56:32 +02:00
ocornut
9090ba71e5 Fixed Tesselation -> Tessellation in comments. 2026-09-07 16:38:38 +02:00
ocornut
53d421955f Amend Changelog. (#8564, #9534) 2026-09-07 16:23:01 +02:00
ocornut
687f7fb8ac Drags, Sliders: ongoing drags may be cancelled using Right-Mouse mouse button, reverting to the initial value. (#8564, #9534) 2026-09-07 16:16:55 +02:00
Lukasz Stalmirski
4ebb04333b IO: restore default platform handlers on ClearPlatformHandlers. (#9537, #8945, #2769)
Amend d4f722d5b.
2026-09-07 13:05:15 +02:00
ocornut
4898533613 Backends: DX10, DX11, DX12, Metal/4, OpenGL2/3, SDLGPU3, Vulkan: round framebuffer dimensions instead of truncating. (#9538, #9515, #8628) 2026-09-07 12:47:03 +02:00
SlowRiot
080319c4ce Backends: WebGPU: round framebuffer dimensions instead of truncating. (#9538, #9515, #8628) 2026-09-07 12:38:02 +02:00
ocornut
96b6eb7728 Fixed PVS-Studio false positives.
Not sure if there's a way to report them.
2026-09-04 12:37:48 +02:00
ocornut
f150bf09f9 Drags, Sliders: ongoing drags may be cancelled using Escape or Gamepad Triangle, reverting to the initial value. (#8564, #9534) 2026-09-04 12:24:49 +02:00
ocornut
51c3c0c992 Sliders: moved code from SliderBehaviorT() to SliderBehavior().
Remove a level of indent too.
2026-09-03 17:28:48 +02:00
Lukasz Stalmirski
5316e70614 Backends: Vulkan: support multiple Vulkan contexts with custom loader. (#6616)
Vulkan function calls now go through a short trampoline function, only apply when IMGUI_IMPL_VULKAN_USE_LOADER is set.
2026-09-03 17:01:15 +02:00
slowriot
7edd2b1f12
Sliders, Drags: adjust ScaleValueFromRatioT() to increase remapping precision (in theory). (#9536)
Omar: couldn't detect any output difference in test suite with large u64/s64 ranges drag/sliders.
I believe this is entirely theoretical and it's principal value is to shut Linter warnings
2026-09-03 15:42:24 +02:00
ocornut
1807b25b9a ScaleValueFromRatioT: removed unnecessary check, amend f27af1b20. 2026-09-03 15:29:37 +02:00
ocornut
4dbb921b22 Examples: disabled /JMC in Visual Studio projects (unnecessary overhead). 2026-09-02 17:15:39 +02:00
ocornut
e2e9533991 Added IM_NODEBUGSTEP helper. Tagged ImVec2, ImVec4, ImRect and various operators.
cc #3038. Amend 1bc6f82091, 301c956039
2026-09-02 17:13:47 +02:00
ocornut
a15761f11c TreeNode: fixed UB shifts and general tree issues when using ImGuiTreeNodeFlags_DrawLinesXXX flags and over 32 deep. (#9509)
+ fix minor typo (#9533)
2026-09-01 20:06:02 +02:00
ocornut
f562ab8e32 DrawList: reworked assert in PushTexture() to allow convenience grace period of using texture already queued for destroy during the same frame. (#9528, #8465)
Amend 131f5c57ab
2026-09-01 16:22:14 +02:00
nilFinx
e0537bf72b
Fixed build issue with MacPorts Clang 16 (missing TARGET_OS_OSX). (#9498) 2026-08-31 18:42:46 +02:00
ocornut
ebc7307db5 ColorButton, RenderColorRectWithAlphaCheckerboard: fixed issues/inconsistencies with checkerboard rendering when combining color alpha and global style alpha. (#9511)
Cleanup hacks in ColorButton(). Amend d851775c80, e9ff7162b.
2026-08-31 18:04:03 +02:00
ocornut
fd74775a0d ColorButton: fixed double style alpha multiply. Remove call to GetColorU32() in RenderColorRectWithAlphaCheckerboard() for consistency. (#9511)
The main fix is the change from GetColorU32() to ColorConvertFloat4ToU32() in calling code.
The change from GetColorU32() to manual multiply in RenderColorRectWithAlphaCheckerboard() is merely for consistency with other ::Render calls.
2026-08-31 17:29:10 +02:00
ocornut
19ead810d2 ColorButton, ColorEdit, ColorPicker: cancel-out alpha caused by BeginDisabled() so disabled color buttons have the same color. (#9511) 2026-08-31 17:29:10 +02:00
ocornut
7e0de0e411 Examples: GLFW/SDL2/SDL3+WebGPU: fixed running with wgpu-native missing wgpuInstanceWaitAny(). (#9377) 2026-08-31 12:30:37 +02:00
ocornut
35a13e9948 Backends, Examples: WebGPU: further simplications. (#9377, #9532, #9530)
Suggested by @lucascompython
2026-08-31 12:23:26 +02:00
ocornut
e44b1129bd Backends, Examples: WebGPU: fixed warnings, renamed .sln, fixed SDL2+WGPU cmakefile. 2026-08-31 12:11:39 +02:00
ocornut
6d1f88fe4a Backends: WebGPU: update to build with wgpu-native 29.0+. (#9532, #9530) 2026-08-31 11:56:01 +02:00
ocornut
760dff3244 Docs: misc additions. 2026-08-31 11:32:24 +02:00
ocornut
d3c5ff395c Drags, Sliders: fixed an overflow using ImGuiSliderFlags_Logarithmic with S32/S64 types. (#9526, #3361, #1823, #1316, #642) 2026-08-30 19:44:15 +02:00
ocornut
1e51b6ffdc Comments/fixes about using IMGUI_DEFINE_MATH_OPERATORS in imconfig.h (#9524) 2026-08-28 12:40:14 +02:00
ocornut
0af8f475d1 Fixed GetBackgroundDrawList()/GetForegroundDrawList() not being properly reset every frame when cumulated session time is very large. (#9521)
Using a FrameCount for compare. Kept time as float to be consistent with other GC-related timestamps: if there is an actual need to use double we'll switch everywhere.
2026-08-23 13:05:33 +02:00
ocornut
1d7b37dc9b Tables: fix/workaround for losing display order. (#9519, #9108) 2026-08-19 13:27:31 +02:00
rubbededo
3e9d0f7e82 Backends: WebGPU: fixed passing non-integer sizes to wgpuRenderPassEncoderSetViewport(). (#9515, #8628) 2026-08-18 12:47:14 +02:00
ocornut
46d39d56fe Fixed GCC false positive. (#9508) 2026-08-07 18:42:39 +02:00
ocornut
551a0a6bc0 TextAligned, TextAlignedV: rework to always use provided width. (#7024, #9455, #1980) 2026-08-07 17:48:50 +02:00
ocornut
5de45fb1d9 Trim trailing white spaces. Changes some NULL to nullptr. 2026-08-07 16:00:53 +02:00
Daniel K. O. (dkosmari)
49fa47fc19 Added IM_FMTARGS/IM_FMTLIST to TextAligned() functions. (#1980, #9455) 2026-08-07 15:41:20 +02:00
ocornut
5b6e19bb50 Examples: Apple+OpenGL3: added new example. 2026-08-06 23:10:56 +02:00
ocornut
70e60a3c4c Examples: Apple+OpenGL2: silence warnings.
Example is precisely to demonstrate OpenGL.
2026-08-06 23:01:56 +02:00
ocornut
2ddb5fc095 Examples: SDL2+Metal: stop using SDL_CreateRenderer(). (#5592) 2026-08-06 21:28:57 +02:00
ocornut
98f3efcf07 Examples: SDL2+Metal: fixed mismatches with other examples. 2026-08-06 21:19:59 +02:00
ocornut
730f099239 Backends: OpenGL3: fixed unused variable warning. (#9507) 2026-08-06 19:01:49 +02:00
ocornut
724c69b182 Backends: SDL2: fixed querying framebuffer scale/density when using Metal. (#5592) 2026-08-06 18:34:33 +02:00
ocornut
6a6d7bc3ca Internals: added SetNextWindowFlags(), SetNextWindowChildFlags() helpers + made BeginChildEx() itself read from them. (#9503, #8280, #9412, #9499, #9393, #8488)
As a result BeginTable() doesn't need to read itself and pass that to BeginChildEx().
2026-08-05 21:16:35 +02:00
ocornut
a5a3e1bd04 (Breaking) Backends: DX12: removed support for legacy ImGui_ImplDX12_Init() signature obsoleted in 1.91.6. (#9487)
Amend 40b2286d1, 142827f7, eefe5d5aa.
2026-08-05 14:58:59 +02:00
ocornut
2de0a07cd4 Fixed PVS Studio false positive. 2026-08-04 14:33:31 +02:00
ocornut
7c9f0c148c Backends, Examples: QNX: amends. Moved ignore list to main file. Removed .use files. (#9492)
Moved functions in example_qnx_opengl3/main.cpp to match structure of other examples.
2026-08-04 14:20:12 +02:00
Mike Gorchak
40ec568762 Backends+Examples: QNX Screen: added initial QNX support to backends and examples. (#9492) 2026-08-04 14:10:19 +02:00
ocornut
5108603789 DrawList: apply current pixel density to DrawList's fringe scale. Added ImDrawList::_SetPixelDensity(). Reword FontRasterizerDensity as CurrentPixelDensity.
Amend 94a4322.

# Conflicts:
#	imgui.cpp
#	imgui.h
#	imgui_draw.cpp
#	imgui_internal.h
2026-08-04 13:15:05 +02:00
ocornut
fdc1152281 (Breaking) Style: obsoleted style.CurveTessellationTol in favor of style.CurveTesselationMaxError.
cc #3127, #3664, #3665
2026-08-03 17:05:44 +02:00
ocornut
b647af2100 Fonts: AddFontDefault() uses framebuffer scale.
If running before DisplaySize is set, assume a different default on Apple.
2026-08-03 15:01:23 +02:00
ocornut
ebd752a0ec Version 1.93.0 WIP 2026-08-03 14:42:56 +02:00
ocornut
9b7699f325 Backends: amend comments to state that bilinear filtering is required ahead of 1.93. 2026-07-31 22:07:01 +02:00
ocornut
f1cc2ae15e Version 1.92.9b 2026-07-31 16:14:42 +02:00
ocornut
448ef2baa9 DragXXX, SliderXXX: fixed a regression in 1.92.9 where clicking a previously Ctrl+Clicked field would flick it to text edit mode for a frame. (#9476, #701) 2026-07-31 13:09:40 +02:00
thedmd
b9adace7b5 Tables: fixed X position of angled borders being off by half a pixel. 2026-07-30 22:03:40 +02:00
thedmd
ed252c55aa Tables: fixed Y position of lower horizontal border being off by one pixel when vertical ones are not also enabled.
Attributed to thedmd who reported this to me.
2026-07-30 21:40:26 +02:00
ocornut
ffbf21af6b Demo: Custom Rendering: enable LiveEdit. Tweaks. 2026-07-30 16:20:09 +02:00
ocornut
e47e6b0d9d Fonts: made GetDefaultCompressedFontDataProggyClean()/GetDefaultCompressedFontDataProggyForever() undocumented non-static. (#9493) 2026-07-30 16:03:42 +02:00
ocornut
950d27137e Tweaks. 2026-07-29 15:51:15 +02:00
omar
8c131021b0
Update pull_request_template.md 2026-07-29 15:26:51 +02:00
ocornut
ff135cf5e5 Backends: DirectX11: removed obsolete comment that got left in this backend only. 2026-07-27 21:49:46 +02:00
ocornut
a9e7a8c880 ImDrawData: fixed a regression in 1.92.9 where legacy ImDrawData::CmdListsCount was always 0. 2026-07-26 15:42:48 +02:00
ocornut
01380c5797 Version 1.92.9 2026-07-25 13:28:06 +02:00
ocornut
e722165561 Docs: rework FAQ index, added multi-threading and string-view details. 2026-07-25 12:41:02 +02:00
ocornut
d94d0f3649 Examples: SDL+WebGPU: removed stray glfw from cmakefiles. (#9387, #9428) 2026-07-23 18:56:53 +02:00
ocornut
f31f98f4cd ImDrawData: fixed late initialized field. (Amend 6f41d13)
Would effectively be initialized on use but best to clear on constructor.
2026-07-23 17:56:02 +02:00
ocornut
f594633b54 Popups: added bool return value to OpenPopup(), OpenPopupOnItemClick() functions. (#9429)
Following on 795cf6fcb5.
2026-07-23 17:49:39 +02:00
ocornut
b335bf4328 Added ImTextureData::QueueUserData for staged-rendering texture queues e.g. imgui_threaded_rendering.h. (#8597, #9136) 2026-07-22 15:14:45 +02:00
ocornut
6f41d13c7a DrawData: added FrameCount field to facilitate debugging multi-threading issues. (#8597, #9136) 2026-07-20 17:00:32 +02:00
ocornut
548389359c (Breaking) ImDrawData: marked draw_data->CmdListsCount as obsolete. Use draw_data->CmdLists.Size.
# Conflicts:
#	docs/CHANGELOG.txt
#	imgui.cpp
2026-07-20 16:58:45 +02:00
omar
295385ff96
Update FAQ.md 2026-07-20 15:23:35 +02:00
omar
c9c458c40a
Update FAQ.md 2026-07-20 15:20:27 +02:00
ocornut
e4f7c5c722 Disabling ImGuiItemFlags_LiveEditOnInputScalar by default! (#9476, #701) 2026-07-20 14:26:57 +02:00
ocornut
d00a87565b Fixed build when using IMGUI_DEBUG_HIGHLIGHT_ALL_ID_CONFLICTS + IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#9482)
Amend 6df50a0667
2026-07-20 14:11:21 +02:00
rbrtc
7038887c32
Docs: fixed link in FAQ index. (#9480) 2026-07-17 13:51:28 +02:00
Brenton Bostick
61a093635c Backends: OpenGL3: fixed updating textures. (#9478, #9477, #9473, #8802)
Fixed 0ff4a8a.
2026-07-17 13:49:02 +02:00
ocornut
26b8292635 Split ImGuiItemFlags_LiveEdit into ImGuiItemFlags_LiveEditText, ImGuiItemFlags_LiveEditScalar. Added Demo contents. (#9476, #701)
cc #3936, #3946, #5904, #6284, #8149, #8065, #8665, #9117, #9299, #700, #1351, #1875, #2060, #2215, #2380, #2550, #3083, #3338, #3556, #4373, #4714, #4885, #5184,#5777, #6707, #6766, #8004, #8303, #8915, #9308
2026-07-16 15:46:47 +02:00
ocornut
c958f16059 EndGroup: fixed reporting combined Edit when it happens at the same time as tabbing to next ActiveId. (#9476, #701) 2026-07-16 15:46:43 +02:00
ocornut
4853f5c96b Internals: rename NextItemData.ItemFlags -> ItemFlagsSet 2026-07-16 15:46:40 +02:00
ocornut
18d63b12be Added ImGuiItemFlags_LiveEdit flag, and much-awaited support for disabling it. (#9476, #701)
cc #3936, #3946, #5904, #6284, #8149, #8065, #8665, #9117, #9299, #700, #1351, #1875, #2060, #2215, #2380, #2550, #3083, #3338, #3556, #4373, #4714, #4885, #5184,#5777, #6707, #6766, #8004, #8303, #8915, #9308
2026-07-16 15:39:53 +02:00
ocornut
2392a52660 InputText: tag InputTextDeactivatedState with an elapsing frame. Avoid unnecessary InputTextDeactivateHook() call on manual deactivation. InputTextDeactivateHook() only takes a record when Edited + callback marks edited. (#9476, #701)
for _NoLiveEdit it's easier than we don't use IsItemDeactivatedAfterEdit() in InputText()'s `if (g.InputTextDeactivatedState.ID == id)` block.
2026-07-16 15:39:52 +02:00
ocornut
baeea39c1a Settings: fixed issues caliing ClearWindowSettings() followed by LoadIniSettingsFromMemory().
While not done with core, this would be useful to load .ini over a clean slate.
2026-07-15 19:22:44 +02:00
ocornut
0ff4a8a900 Backends: OpenGL2/3: Backup and restore GL_UNPACK state in UpdateTexture(). Amends. (#9473, #8802)
Fix setting GL_UNPACK_ROW_LENGTH twice.
2026-07-15 18:20:05 +02:00
Turtle Dove
e3927dc004 Backends: OpenGL2/3: Backup and restore GL_UNPACK state in UpdateTexture() (#9473, #8802) 2026-07-15 18:16:57 +02:00
Turtle Dove
35a7e8e864 Backends: SDL2: restore SDL_StartTextInput()/SDL_StopTextInput() calls on Android (#7636, #9474) 2026-07-15 17:59:25 +02:00
Turtle Dove
909082890a Backends: Android: clear mouse position on touch release. (#6627, #9474) 2026-07-15 17:36:39 +02:00
Turtle Dove
0302703a7d
CI: Android: Gradle 9.4.1 via setup-gradle action for AGP 9.2.0 (#8878) (#9467) 2026-07-15 14:36:59 +02:00
ShiroKSH
0720d59bb7 Tables: validate ini settings column count. (#9472)
+ Amend with comment by ocornut.
2026-07-15 14:16:31 +02:00
ocornut
addbfa5021 Settings: fixed ConfigIniSettingsAutoDiscardMonths not calling Cleanup (#9460, #9471) 2026-07-15 13:57:48 +02:00
ocornut
bad1ee71f8 Backends: SDL_Renderer3: fixed changing scale mode not actually working on all platforms. (#7616, #9470, #9378) 2026-07-15 13:44:03 +02:00
ShiroKSH
003ee19d9e Backends: SDL_Renderer3: fixed default sampler not being Linear. (#7616, #9470, #9378) 2026-07-15 13:44:01 +02:00
ocornut
b62bfd6b06 InputText: reworked io.ConfigInputTextEnterKeepActive mode so that pressing Ctrl+Enter or Shift+Enter still allows to deactivate.
cc #9239
2026-07-10 21:36:43 +02:00
ocornut
da137cbbb0 (Breaking) Drag and Drop: commented out legacy name ImGuiDragDropFlags_SourceAutoExpirePayload. Use ImGuiDragDropFlags_PayloadAutoExpire. 2026-07-08 18:40:29 +02:00
ocornut
9bb131fb2f CI: enable Metal4 examples. (#9466, #9451)
(Untested)
2026-07-08 18:28:37 +02:00
Jonathan Hoffstadt
62399b5bfe Examples: Apple + Metal4: add example (#9466, #9451)
+ Amend edit to EXAMPLES.md, comment build.xml
2026-07-08 18:04:30 +02:00
ocornut
68fce9f3bd Settings: added DiscardAll option to CleanupIniSettings() / ImGuiSettingsCleanupArgs. (#9460)
+ Demo: tweak for scaling.
2026-07-08 15:03:19 +02:00
ocornut
f903a7e8e2 Settings: fixed Windows not honoring DiscardWhenMissingDate. (#9460) 2026-07-07 22:52:47 +02:00
ocornut
112d6d9eab Settings: added a type name filter to CleanupIniSettings() / ImGuiSettingsCleanupArgs. Amends. (#9460)
Request hash because storing const char* strings in struct is not entirely zen. Amend 2c49da4.
2026-07-07 22:30:15 +02:00
ocornut
2c49da44be Settings: added a type name filter to CleanupIniSettings() / ImGuiSettingsCleanupArgs. (#9460) 2026-07-07 22:18:01 +02:00
ocornut
85593d0869 Tables, Settings: make TableSettingsCreate() recycle existing unbound entry (might happen after a GC or anything clearing table->SettingsOffset. (#9460, #9108) 2026-07-07 22:06:43 +02:00
ocornut
d1eb8d031c Settings: added explicit DiscardWhenMissingDate. (#9460, #9108) 2026-07-07 22:00:26 +02:00
Kian
481f2cea17 Backends: Metal4: added ImTextureID tex_id to residency set. (#9461, #9458, #9451)
This will resolve runtime errors identified by XCode's Metal Shader Validator.
2026-07-07 16:35:23 +02:00
Kian
520a29dd51 Backends: Metal4: added metal-cpp support. (#9461)
with amends.
2026-07-07 16:29:02 +02:00
ocornut
cfdc953ba9 ColorPicker: added option to fix Saturation/Value triangle in wheel picker. Amends. (#9337)
The heat makes this week really not good with human mistakes I guess.
2026-07-07 16:21:36 +02:00
ocornut
f626c1c793 ColorPicker: added option to fix Saturation/Value triangle in wheel picker. Amends. (#9337)
ConfigColorPickerRotateTriangle -> !ImGuiColorEditFlags_PickerNoRotate
2026-07-07 16:18:34 +02:00
ocornut
5d56c09432 ColorPicker: added option to fix Saturation/Value triangle in wheel picker. Amends. (#9337) 2026-07-07 16:14:13 +02:00
SeanTheBuilder1
0785cdb2bb ColorPicker: added option to fix Saturation/Value triangle in wheel picker. (#9337) 2026-07-07 16:14:11 +02:00
ocornut
aca69173df (Breaking) ColorEdit: obsoleted SetColorEditOptions() function in favor of poking to io.ConfigColorEditFlags. (Amend 0e479b9, 9f7d808)
Apologies, 9f7d808 was extremely flaky.
2026-07-07 16:10:35 +02:00
ocornut
9f7d8086fe (Breaking) ColorEdit: obsoleted SetColorEditOptions() function in favor of poking to io.ColorEditFlags. (Amend 0e479b9)
Reordered IO fields breaks ABI backward compat which was never guaranteed. Occasional breaking is a good way to enforce that lack of guarantee!
2026-07-06 16:02:17 +02:00
ocornut
0e479b9554 (Breaking) ColorEdit: obsoleted SetColorEditOptions() function in favor of poking to style.ColorEditFlags. 2026-07-06 15:34:13 +02:00
ocornut
776bf2ab0d Examples: OpenGL3+Win32: rework OpenGL initialization to allow Wine compatibility. Fix. (#9427, #6577)
Fixed commented out test code.
2026-07-03 18:59:37 +02:00
ocornut
4f1ea369ea Examples: OpenGL3+Win32: rework OpenGL initialization to allow Wine compatibility. (#9427, #6577) 2026-07-03 18:57:14 +02:00
ocornut
a977144955 Examples: OpenGL3+GLFW,SDL2,SDL3: improve Wine compatibility by passing empty GLSL version to ImGui_ImplOpenGL3_Init(). (#9427, #6577) 2026-07-03 18:57:10 +02:00
ocornut
e616ace74d CI, Backends: Metal4: fixed CI, added comments. (#9458) 2026-07-03 17:48:11 +02:00
ocornut
5c2160ac85 Settings, IO: move ConfigDebugIniSettings in same section. 2026-07-03 16:56:38 +02:00
ocornut
5fb77dfde1 Settings: added io.ConfigIniSettingsAutoDiscardMonths, trimming tool in in Metrics->Settings + internal CleanupIniSettings(). (#9460)
cc #437 #2564
2026-07-03 16:36:46 +02:00
ocornut
f7e8343ee9 Settings, IO: added io.ConfigIniSettingsSaveLastUsedDate, platform_io.Platform_SessionDate, IMGUI_DISABLE_TIME_FUNCTIONS(). (#9460)
cc #437
2026-07-03 16:36:45 +02:00
ocornut
7d43c74b59 CI: update PVS studio. Reduce Windows CI workload for typical push. 2026-07-02 15:14:32 +02:00
ocornut
8fc25800e0 Fonts, Context: assert that ImFontAtlas has no other references when destroying an owned atlas. (#9426) 2026-07-02 15:02:59 +02:00
ocornut
6824e2c2e4 Examples: Android: update to AGP 9.2.0 to support Gradle 9.6.0. 2026-07-02 14:26:46 +02:00
ocornut
e9ea19086b CI: fixed Android build on Ubuntu-latest by expliciting Gradle version to < 9.x. 2026-07-02 14:13:32 +02:00
ocornut
caddd26fb9 Backends: Metal4: minor tweaks/comments. (#9458, #9451) 2026-07-02 12:09:06 +02:00
Amélie Heinrich
fc6395365d Backends: Metal4: Added Metal 4 backend. Added SDL3+Metal4 example. (#9458, #9451) 2026-07-02 12:00:10 +02:00
ocornut
93dd4c1567 Backends: Metal4: copy imgui_imp_metal.* to imgui_impl_metal4.*, unmodified. (#9458, #9451) 2026-07-02 11:59:36 +02:00
ocornut
279d04f7a3 Added GetItemClickedCountWithSingleClickDelay(), io.MouseSingleClickDelay. (#8337) 2026-07-01 18:53:29 +02:00
ocornut
0edad6d097 Internals: track WasSelected/WasSoleSelected data for ActiveId. (#8337) 2026-07-01 18:53:27 +02:00
ocornut
e408733ecc BeginMenu(), MenuItem() use NextItemData.Flags + Fixed typo in comment. (#9456) 2026-07-01 12:38:32 +02:00
ocornut
9e6c0416fe Backends: GLFW,SDL2,SDL3: added wayland/driver marker in io.BackendPlatformName.
+ Stored bd->IsWayland variable for e.g. #7433
2026-06-29 18:26:59 +02:00
ocornut
c66d9a8190 Examples, SDL2/SDL3: use SDL_GetWindowSizeInPixels() to create framebuffers. (#8761, #9124)
+ cc #7433
2026-06-29 11:50:42 +02:00
ocornut
76f5be2749 Settings: minor struct packing. 2026-06-25 22:59:51 +02:00
ocornut
60fbdbb8d8 Multi-Select: reworked ImGuiMultiSelectFlags_NoAutoSelect as it carried side-effects that were hardcoded/designed to use multi-selection on checkboxes. (#9391) 2026-06-25 14:13:13 +02:00
ocornut
ac6f9683b5 Style: added MenuItemRounding, SelectableRounding, ImGuiStyleVar_MenuItemRounding, ImGuiStyleVar_SelectableRounding. (#7589, #9375, #9453) 2026-06-25 11:43:50 +02:00
ocornut
1c1241136a Tables: fixed (harmless) flag clearing issue in TableReconcileColumns(). (#9108)
Was actually harmless because IsNeedReconcileSrc never read again for this column.
2026-06-25 11:22:09 +02:00
ocornut
0e355af09e RenderNavCursor: take rounding as input. Removed ImGuiNavRenderCursorFlags_NoRounding.
Toward #7589
2026-06-24 18:34:30 +02:00
ocornut
26432cfdc6 Style, Nav: scale the NavCursor border thickness when using large values with ScallAllSizes(). 2026-06-24 17:57:04 +02:00
ocornut
be374fa598 TreeNode: fixed nav cursor rendering with rounding even though tree nodes don't have it. (#7589) 2026-06-24 17:32:36 +02:00
ocornut
e74453760b Tables: rewrote TableLoadSettingsForColumns() to match TableReconcileColumn() logic more precisely. (#9108)
Fixes issues with e.g. duplicate identifiers. See "table_topology_change_1" test.
2026-06-24 16:01:44 +02:00
ocornut
ec69495ca8 Tables: fixed some cases of reconcile/load handling when using duplicate identifiers. (#9108) 2026-06-24 16:01:44 +02:00
ocornut
b522576054 Tables: tracking topology changes by default. Match by ID then in sequential order for remaining. (#9108, #4046)
Removed ImGuiTableFlags_TrackTopologyChanges.
2026-06-24 16:01:43 +02:00
ocornut
570c0e03b7 Tables: extract part of TableLoadSettingsForColumns() into TableLoadSettingsForColumn(). (#9108) 2026-06-24 15:52:16 +02:00
ocornut
b9cf21733d Tables: avoid forcing a settings load on count change. (#9108)
At this very moment, I don't have a specific need/use for it. Went into this direction with solving the bigger problem, and it seems right but is not hard required right now.
2026-06-24 15:51:43 +02:00
ocornut
7930405c73 Tables: rework _TrackTopologyChanges to function without enforcing saving order/visibility. (#9108) 2026-06-24 15:51:22 +02:00
ocornut
f2fcdfe97f Tables: fixed duplicate settings entry. 2026-06-24 15:51:03 +02:00
ocornut
2f94e7dc13 Tables: add support for ImGuiTableFlags_TrackTopologyChanges (#9108, #4046) 2026-06-24 15:50:17 +02:00
Clownacy
b2377d616d Nav, Popups: fixed context menu activation with gamepad erroneously testing for _NavEnableKeyboard instead of _NavEnableGamepad. (#9454)
cc: #8803, #9270
2026-06-24 13:49:28 +02:00
ocornut
d15966ff6c Tables: fixed TableGcCompactSettings() not invalidating bound offset. A crash could in theory be triggered if clicking "Gc All" after saved tables have reduced column count.
Tested by "table_settings_5"
2026-06-18 19:48:53 +02:00
Cleroth
9a5c070308 Windows: fixed double-click collapse toggle not owning the mouse button. (#9439) 2026-06-17 15:21:36 +02:00
ocornut
73a6610e81 Backends: OpenGL3: Expose selected render state in ImGui_ImplOpenGL3_RenderState, allowing to dynamically select between use of glBindSampler() and glTexParameter(). (#9378) 2026-06-17 15:02:51 +02:00
Brenton Bostick
7aaf10f15b
Docs: fixed typos (#9449) 2026-06-17 14:11:19 +02:00
ocornut
13fc81fc82 Tables: fixes incorrect forward declaration for a missing function + fixed tooltip comment. (#9445, #9448) 2026-06-17 12:53:36 +02:00
ocornut
2064059a7f Docs, Backends: OpenGL3, Vulkan: added comments about custom sampler. (#9378) 2026-06-17 12:53:36 +02:00
Brenton Bostick
b47a3898b4
Fixed unused parameter 'table'. (#9447, #9446) 2026-06-17 12:51:54 +02:00
ocornut
138c0e6c7d Added IM_DEBUG_BREAK() handler for GCC+AArch64/ARM64. 2026-06-15 19:32:56 +02:00
ocornut
b46a37eac9 Tables: comments about misleading TableSetupColumn() user_id parameter, renamed to user_data.
ImGuiTableColumnSortSpecs::ColumnUserID should be changed to ColumnUserData.
2026-06-15 19:05:38 +02:00
ocornut
e6147a3993 Tables: allow calling TableQueueSetColumnDisplayOrder() between TableSetupColumn() and TableUpdateLayout() by removing an early out.
As `table->Columns[column_n].DisplayOrder` is not viable in this scope during a reconcile.
2026-06-15 18:25:08 +02:00
ocornut
721da6a34c Tables: apply queued requests in TableUpdateLayout()
To allow calling TableQueueSetColumnDisplayOrder() between TableSetupColumn() and between TableUpdateLayout()

# Conflicts:
#	imgui_tables.cpp
2026-06-15 18:24:43 +02:00
ocornut
360183924b CI: use Visual Studio 2026. (correct path) 2026-06-15 17:06:14 +02:00
ocornut
2aaa6d8173 CI: use Visual Studio 2026.
ref: https://github.com/actions/runner-images/blob/win25-vs2026/20260608.135/images/windows/Windows2025-VS2026-Readme.md
2026-06-15 16:52:52 +02:00
ocornut
3240201de2 Fixing build. 2026-06-15 16:37:26 +02:00
ocornut
94a3dcc5fa Tables: tweaked debug tools + minor data packing in in ImGuiTableColumn 2026-06-15 16:15:39 +02:00
ocornut
fea6f4603a ImSpan: added clear(), empty() helpers. 2026-06-15 16:13:25 +02:00
ocornut
d43c3f929c Tables: split code from TableSetupColumn() so it can be more easily deferred. 2026-06-15 16:13:25 +02:00
ocornut
36ea9728d1 Tables: save/restore column ID (unused)
Ditched UserID storage, which was provably broken/unused.
2026-06-15 16:13:25 +02:00
ocornut
2e0f949039 Tables, Debug Log: added IMGUI_DEBUG_LOG_TABLE, ImGuiDebugLogFlags_EventTable. Clicking "Clear settings" calls TableResetSettings() immediately. 2026-06-12 22:12:25 +02:00
ocornut
924f57181b Tables: Headers: fixed label being clipped early to reserve space for a sort marker even when no sort marker is displayed.
Amend 892b48e2d6: while fixing auto fit this was ditched.
2026-06-12 18:22:52 +02:00
ocornut
e5ff2d07d7 Tables: Context-menu: added "Reset" sub-menu and "Reset Visibility" option. 2026-06-11 19:15:55 +02:00
ocornut
b10137f92f Internals: move function declarations into Tables section. 2026-06-10 17:19:34 +02:00
ocornut
aa377352ef Tables: TableGcCompactTransientBuffers() can ditch AngledHeadersRequests data.
Amend b30df8890.(#6917)
2026-06-10 17:15:50 +02:00
ocornut
4312c4399f Tables: moved RefScale update and application to TableUpdateLayout(). 2026-06-10 17:15:41 +02:00
ocornut
f1dd18b75c Docs: minor amends to ImTextureData comments. 2026-06-10 15:55:48 +02:00
Oliver Dixon
5220a3f48d
Examples: WebGPU: Require C++20 to build Dawn examples (#9433, #9432) 2026-06-07 09:58:58 +02:00
ocornut
6acba3b47d ImDrawListSharedData: rename CircleSegmentMaxError to CircleTessellationMaxError. Remove misleading ArcFastRadiusCutoff assignment.
cc 051ce0765, f107693d9 (3808)
2026-06-04 13:51:57 +02:00
ocornut
fc5e2f28fe Examples: WGPU: fixed typo for wvgk cloning. (#9428, #9387) 2026-06-03 19:24:06 +02:00
Vladimir Perminov
7950c96f0e Backends: OpenGL3: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577)
Amend fc737d2333
2026-06-03 15:48:52 +02:00
ocornut
14278db024 Fonts: better document the fact that ImFontAtlas::Clear()/ClearFonts() functions are unlikely to be useful nowadays + fix tex->Updates[] ever-growing if ClearFonts() is called between frames. 2026-06-03 15:27:02 +02:00
ocornut
c4eaac6d48 Fonts: fixed an issue where passing a manually created ImFontAtlas to CreateContext() would incorrectly destroy it in DestroyContext() when ref-count gets back to zero. (#9426)
# Conflicts:
#	docs/CHANGELOG.txt
2026-06-02 19:05:40 +02:00
ocornut
5a42cddcd2 Fixed a build issue when defined IMGUI_API + IMGUI_DISABLE_OBSOLETE_FUNCTIONS. (#9424)
Amend 6df50a0
2026-06-02 18:40:14 +02:00
ocornut
995e4a65ff (Breaking) TreeNode: commented out legacy name ImGuiTreeNodeFlags_SpanTextWidth which was obsoleted in 1.90.7 (May 2024). Use ImGuiTreeNodeFlags_SpanLabelWidth instead. 2026-06-02 18:37:01 +02:00
omar
a054a016e2
Docs: Fonts: amends. 2026-06-02 18:09:48 +02:00
omar
045a0907f4
Docs: Fonts.md: added notes about TexMinWidth,TexMinHeight.
Probably misplaced: the document could have a section about memory usage considerations?
2026-06-02 18:05:23 +02:00
ocornut
5aa0393a15 DrawList: don't mark ImDrawListFlags_TextNoPixelSnap as internal in comments. (#3437, #9417, #2291) 2026-06-01 17:23:11 +02:00
ocornut
f241419b78 Tabs: use AddRectFilled(). 2026-06-01 16:49:18 +02:00
Flexan
3495e329f3
Fixed small typo in demo code (#9425) 2026-06-01 15:34:00 +02:00
ocornut
3b99fc4883 ColorButton: small rendering tweak/optimization for the alpha checkerboard.
Inverting the pattern means that for our typical 3x3 grid we don't need to draw 1+4 rounded rectangles, only 1.
This also fix the slightly rounding mismatch when switching from a=255 to a<255 paths.
2026-06-01 14:23:29 +02:00
Dex
70f02b0558
Docs: Fix small grammar mistake in README. (#9423) 2026-05-31 13:54:30 +02:00
ocornut
cac16b0d16 DrawList: rename ImDrawListFlags_NoTextPixelSnap -> ImDrawListFlags_TextNoPixelSnap. (#3437, #9417, #2291)
Amend 1d33ea9
2026-05-29 18:39:17 +02:00
ocornut
1d33ea939f DrawList: added ImDrawListFlags_NoTextPixelSnap to disable snapping of AddText() coordinates for a given scope. (#3437, #9417, #2291)
This may evolve into a per-call ImDrawFlags option as well.
+ clip_rect.Max.y early out may be applied before truncation.
2026-05-29 18:12:11 +02:00
ocornut
75f985998b Using custom ceilf inline impl in ImGui::CalcTextSize().
Amend 7b0bf230, 4622fa4b6, 12b7977. (#791)
2026-05-29 15:59:44 +02:00
ocornut
12b7977555 Tweak CalcTextSize() awkward width rounding/ceiling code to reduce floating-point imprecisions altering the result by 1 even at relatively small width. (#791) + apply same fudge factor to less important roundings.
ceilf() is still measurable e.g. ballpark +0.5 for 200k calls.
2026-05-28 19:19:11 +02:00
ocornut
33bb693b4c DrawList: skip PathLineTo/PathStroke calls for common AddLine(), AddLineH(), AddLineV() functions. (#4091) 2026-05-28 15:37:29 +02:00
ocornut
783eba926f Docs: retroactively amend 1.92.8 changelog about ImDrawFlags_Closed value.
Amend 6df50a0
2026-05-28 11:37:37 +02:00
qwer
ac07da2b5b Fonts: Added macros to disable ProggyClean/ProggyVector separately. (#9407) 2026-05-27 16:50:53 +02:00
ocornut
243097ca8f Docs: retroactively amend changelog for AddLineH(), AddLineV().
Amend 691b89b. (#9360)
2026-05-26 20:36:29 +02:00
ocornut
fbcf95193f ImFontAtlas: moved common TexData calls into a same helper functions, so adding new ones is easier. 2026-05-22 20:03:30 +02:00
ocornut
24a80f74a4 InputText, Style: added InputTextCursorSize to configure cursor/caret thickness. (#7031, #9409) 2026-05-22 19:12:36 +02:00
ocornut
904b663184 Clarify support for "%s" shortcuts in functions taking format strings. (#9404, #3466, #6846) 2026-05-19 18:50:39 +02:00
MouriNaruto
3e7b79aa17 Backends: Win32: use SetProcessDpiAwarenessContext instead of SetThreadDpiAwarenessContext when available, to fix the OpenGL3 Win32 example DPI scaling issue. (#9403) 2026-05-19 17:53:36 +02:00
ocornut
e41d691da1 Demo: Tree Nodes: extract 'Tree Nodes->Selectable Nodes' into its own thing.
+ comments (#9401)
2026-05-18 14:31:58 +02:00
ocornut
93e396ffb7 Textures: call ImTextureDataUpdateNewFrame() for textures registered via RegisterUserTexture(). (#8789, #8465)
Amend
2026-05-15 16:38:45 +02:00
ocornut
068e055510 Textures: extract ImTextureDataUpdateNewFrame() out of ImFontAtlasUpdateNewFrame(). (#8465) 2026-05-15 16:38:45 +02:00
ocornut
db161b84c9 Windows: clicking on a window's empty-space to move/focus a window checks for lack of queued focus request. (#9382) 2026-05-15 13:45:03 +02:00
ocornut
4088a4f40c Windows: clicking on a window's empty-space to move/focus a window checks for lack of mouse button ownership. (#9382) 2026-05-15 13:44:40 +02:00
ocornut
46a050fff2 Nav: minor optimization NavUpdate().
To be honest this is mostly to ease debug stepping in the common case.
2026-05-15 13:43:45 +02:00
ocornut
c7767926ce Version 1.92.9 WIP 2026-05-15 13:28:32 +02:00
ocornut
310c719a1f Rework definition of ImDrawFlags_InvalidMask_ so it more strictly fits in an int32 for non C/C++ languages where it matters. (#9396, #9397) 2026-05-15 10:48:24 +02:00
ocornut
b2546a5c93 Comments on not needing to use ImDrawFlags_RoundCornersAll. 2026-05-13 12:46:07 +02:00
ocornut
e0f5f9a14c Amend AddRect(), AddPolyline() error detection to safely return an trigger error handling mechanism.
Amend 6df50a0667
2026-05-12 17:40:28 +02:00
ocornut
8936b58fe2 Version 1.92.8
Include minor bits: adjust activeid logging, tweak comments.
2026-05-12 16:30:30 +02:00
omar
eebaddd340
Docs: added SECURITY.md. 2026-05-11 19:03:08 +02:00
ocornut
73afb6b6e6 Fonts: clarify that ClearFonts() be useful over calling Clear(). 2026-05-11 17:45:59 +02:00
ocornut
b8f6c51af7 Fonts: move ClearFonts(), ClearInputData(), ClearTexData() implementation (no other changes) 2026-05-11 17:42:08 +02:00
ocornut
4ac473b2c7 Fixed BeginMenu() leading to window with is_resizable_width=true. Fix/amend 95bd1577d + ac1f57b. (#9355) 2026-05-11 16:35:40 +02:00
ocornut
ac1f57ba0c Fixed BeginMenu() leading to window with is_resizable_width=true. Fix/amend 95bd1577d. (#9355)
We should instead probably make BeginChild() not set on ImGuiWindowFlags_AlwaysAutoResize on either ResizeX or ResizeY, but that'll be done later.
2026-05-11 16:34:33 +02:00
ocornut
821a396556 Fixed warning on Clang 26. 2026-05-11 15:59:42 +02:00
manuel
2b31f65167 Examples: WebGPU+GLFW/SDL2/SDL3: wire up the IMGUI_WGVK_DIR path. (#9387)
The block was a stub - find Vulkan, detect Wayland/X11, set the SUPPORT_*_SURFACE defines that wgvk.c needs.
2026-05-11 15:42:16 +02:00
manuel
b58836f287 Backends: WebGPU: detect WGSL support at runtime instead of excluding WGVK at compile time. (#9387)
Previously WGVK was hard-disabled from WGSL via #if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK),
forcing the SPIRV fallback unconditionally. Now the WGSL path is attempted on all backends
and an empty stage_desc is returned when the module fails to compile letting the existing
SPIRV fallback at the call site kick in.
2026-05-11 15:38:27 +02:00
ocornut
bca5a69928 BeginMenu()/MenuItem(): fixed accidental triggering of child menu items when opening a menu inside a small host window forcing the child menu window to be repositioned under the mouse cursor. (#8233, #9394)
nb: ImGuiSelectableFlags_NoHoldingActiveID is not used anymore. Would remove remove once we remove the unnecessary call to Selectable() from MenuItem().
2026-05-11 15:32:39 +02:00
ocornut
eb453f2be6 Checkbox, Style: added ImGuiCol_CheckboxSelectedBg. (#9392) 2026-05-11 14:30:34 +02:00
ocornut
56b37bf93c Inputs: SetItemKeyOwner(): does not set ownership is key is already taken.
(#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641)
2026-05-07 21:22:33 +02:00
ocornut
0eae77f783 Inputs: SetItemKeyOwner(): return true if ownership has been requested, which can to be checked to accurately gate further input test.
(#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641)
2026-05-07 21:15:27 +02:00
ocornut
02ccd9f348 Scrolling, Inputs: using mouse wheel to scroll takes and keeps ownership of the corresponding keys while a wheeling window is locked.
Ref 4448d975d. (#2604, #3795)
2026-05-07 20:51:57 +02:00
ocornut
163b8670c8 Demo: added image viewer with magnifier and grid. 2026-05-07 20:20:05 +02:00
ocornut
a70b97ee48 Warning fixes. 2026-05-07 16:51:34 +02:00
ocornut
6df50a0667 (Breaking) DrawList: swapped the last two arguments of AddRect(), AddPolyline(), PathStroke(). thickness<>flags.
Added inline redirection functions when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is off.
Marked the old functions are =delete when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is on, to allow for better type-checking.
The aim is to be able to use/add flags to more ImDrawList functions, and making existing functions consistents was deemed very desirable.
2026-05-07 16:37:57 +02:00
ocornut
976c5c0f3a Textures: extract ImTextureDataQueueUpload() out of ImFontAtlasTextureBlockQueueUpload() (#8465)
Not atlas specific, in support of texture system.
2026-05-06 16:19:39 +02:00
Mikko Mononen
691b89baae ImDrawList: added AddLineH(), AddLineV() helpers. (#9360)
This commit is aimed to be a lossless transform. Further layout fixes in subsequent commits.
2026-04-28 17:04:54 +02:00
ocornut
c0b693b1d4 MultiSelect: Box-Select + Tables: fixed when using SpanAllColumns paths. (#9383, #7994)
Amend d1a8995 which didn't fix the thing it claimed to fix, as my naive last minute refactor broke it.
2026-04-28 15:58:21 +02:00
Alexander "FireFox" Ong
865a6dfa59 InputScalar: fixed not parsing user input when the display format is configured not to show the scalar value. (#9385)
Useful e.g. for displaying "mixed" inputs, where a single field might represent multiple different values.
2026-04-28 15:25:12 +02:00
Vlad
dee9b15bbe Backends: Metal: add sampler states and DrawCallback_SetSamplerLinear / DrawCallback_SetSamplerNearest callbacks. (#9381, #9371, #9378) 2026-04-28 15:09:23 +02:00
ocornut
d1a8995634 MultiSelect: Box-Select + Tables: fixed when using SpanAllColumns paths. (#9383, #7994)
Amend ac88294 + d7b40ab
2026-04-28 14:58:47 +02:00
ocornut
ab36fbaf48 Drag and Drop, Style: added ImGuiStyleVar_DragDropTargetRounding. (#9056)
+ readded rounding arg to RenderDragDropTargetRectEx().
2026-04-27 18:23:56 +02:00
ocornut
e3033c3975 Examples: moving example_win32_directx11 on top of the .sln makes it the default selected project. 2026-04-24 17:38:51 +02:00
ocornut
10c378cdfc InputInt, InputFloat, InputScalar: reinstated and fixed ImGuiInputTextFlags_EnterReturnsTrue. (#8665, #9299, #8065, #3946, #6284, #9117) 2026-04-24 15:15:19 +02:00
ocornut
db23a78c60 Internals: store ImGuiItemStatusFlags_EditedInternal bypassing ImGuiItemFlags_NoMarkEdited.
Convenient if the same signal is not passed via e.g. return value. (#8665, #9299, #8065, #3946, #6284, #9117)
2026-04-24 15:15:16 +02:00
ocornut
bda49826cf Backends: OpenGL3: build fix for WebGL/ES2/Emscripten. (#9378)
Amend 6b05f71 which was incorrectly labelled.
2026-04-24 12:26:21 +02:00
ocornut
6b05f711fd Backends: WebGPU: build fix for WebGL/ES2. 2026-04-23 22:06:42 +02:00
ocornut
86ebb3bc11 Backends: removed samplers from ImGui_ImplDX10_RenderState, ImGui_ImplDX11_RenderState + fixed all Changelogs. (#9378) 2026-04-23 22:03:11 +02:00
ocornut
7e7f3adb80 Removed DrawCallback_SetSamplerCustom feature for now. Too unreliable to get working everywhere. (#9378) 2026-04-23 21:50:52 +02:00
ocornut
dfe6f9ebca Backends: WebGPU: added SetSamplerLinear/Nearest draw callbacks. (#9378) 2026-04-23 21:50:50 +02:00
ocornut
37952fb3b8 Backends: Vulkan, SDLGPU3: remove samplers from RenderState. (#9378)
Revert part of ac261203a5, 9ee3d731b5 (#8866, #8163, #7998, #7988) since we have a better solution.
2026-04-23 21:50:47 +02:00
omar
0a811e8ea1 Backends: DX9, DX10, DX11, DX12, Allegro5, OpenGL2, OpenGL3, SDLRenderer2, SDLRenderer3, SDLGPU3, Vulkan: added standard draw callbacks when possible. (#9378) 2026-04-23 21:50:45 +02:00
ocornut
82f46a73f8 (Breaking) Moved ImDrawCallback_ResetRenderState -> ImGui::GetPlatformIO().DrawCallback_ResetRenderState + added room in ImGuiPlatformIO for more standard backend-agnostic draw callbacks. (#9378) 2026-04-23 21:50:41 +02:00
ocornut
a6a16cf8a2 Backends: WebGPU: protect better against zero tex id. 2026-04-23 20:50:34 +02:00
ocornut
e887098740 Backends: WebGPU: always use SPIR-V shader on WGVK, as it cannot be detected at runtime. (#9316, #9246, #9257) 2026-04-23 19:42:29 +02:00
ocornut
f934719fbf TabBar: comments about ImGuiTabBarFlags_FittingPolicyMixed and TabMinWidthShrink. (#9376, #3421, #8800) 2026-04-23 18:31:53 +02:00
ocornut
ce3fe4078a Backends: WGPU: fixed build.
Incorrect line from a WIP branch slipped in ac06ad7
2026-04-23 17:31:14 +02:00
ocornut
f2f843c113 Fixed some extremely zealous warnings (GCC -Wconversion, -Wdouble-promotion)
(amend a1e0552)
2026-04-23 17:23:43 +02:00
ocornut
adc0027912 Backends: Vulkan: remove unused artefacts (mistakenly commited in 0453ae9). 2026-04-23 16:08:11 +02:00
ocornut
ac06ad7b48 ImDrawList: made AddCallback() user data default to NULL + minor amends/comments. 2026-04-23 15:58:44 +02:00
ocornut
4739af2d51 Update VS toolset in all .vcxproj from VS2015 (v140) to VS2017 (v141).
It supports vcpkg.
2026-04-23 15:58:04 +02:00
ocornut
b065713cec Backends: OpenGL2/3, SDLRenderer2/3, DirectX9, Metal: moved Init/Shutdown code lower in the file.
Allows to point to local functions without forward declaring them.
2026-04-23 15:53:28 +02:00
ocornut
fb308c14ce Remove noise from 0453ae9 + amend comments. (#914) 2026-04-22 14:50:15 +02:00
ocornut
ac261203a5 (Breaking) Backends: Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (fixes, amends) (#914) 2026-04-22 14:43:44 +02:00
yaz0r
0453ae96e8 (Breaking) Backends: Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (WIP) (#914) 2026-04-22 14:43:44 +02:00
ocornut
a5fd597be3 Backends: Vulkan: minor changes. 2026-04-22 14:23:42 +02:00
ocornut
382b99c334 PlotHistogram: add comments. (#9372) 2026-04-21 22:32:01 +02:00
ocornut
2d131ef5b7 Backends: Vulkan: renaming and moving code around to reduce diff in upcoming change. Should be no-op. 2026-04-21 22:22:06 +02:00
ocornut
a1e05521e9 Backends: GLFW: added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2. (#9003)
Since we ship GLFW 3.2 binaries for Windows this makes our examples a little better behaving by default.
Ideally we'd use ImGui_ImplWin32_GetDpiScaleForHwnd() and ImGui_ImplWin32_GetDpiScaleForMonitor() but they are too much code to copy.
2026-04-21 17:24:41 +02:00
ocornut
d7b40ab9a9 MultiSelect: Box-Select + Tables: Amend ac88294. fix usage of box-selection columns with items straying out of columns. (#7994, #2221) 2026-04-20 11:46:36 +02:00
ocornut
ac88294b4a MultiSelect: Box-Select +Tables: fix usage of box-selection columns with items straying out of columns. (#7994, #2221)
Use 00d3f9295e.
+ Assets Browser toggle to enable ScrollX.
2026-04-20 11:12:43 +02:00
ocornut
ea1c04f7ab Multi-Select + Tables: fixed an issue which could lead to an extra vertical offset in the Header row. (#8250, #7994)
Because BeginMultiSelect() does `ms->ScopeRectMin = window->DC.CursorMaxPos = window->DC.CursorPos` at a time where CursorPos is already past MaxPos.y because of ItemSpacing.y. Accumulate spacing.
2026-04-17 19:23:10 +02:00
ocornut
cdb046ac3f Demo: Assets Browser: fixed not submitting anything after a SetCursorScreenPos() call when no items. Would not manifest because BeginMultiSelect() altered CursorMaxPos. (#5548)
cc: 2819ab32f8, edcd5b113e
2026-04-17 19:23:04 +02:00
ocornut
97939e6837 Multi-Select: Box-Select: fixes for using accross nested child windows. (#8364)
- IsFocused scan nav focus route.
- When covering multiple windows, draw in front most ones (grabbed FindFrontMostVisibleChildWindow() from docking branch).
2026-04-17 16:36:09 +02:00
ocornut
c91b03060d Multi-Select: Box-Select: improve dirty unclip rectangle calculation + use in ImGuiMultiSelectFlags_BoxSelect1d mode when needed (e.g. wheel scrolling up). (#7994, #8250, #7821, #7850, #7970) 2026-04-17 14:38:12 +02:00
ocornut
a2eb6d99ed MultiSelect: Box-Select +Tables: revert 4d00bf8ad which seems unneeded since enforce table layout in BeginMultiSelect(). (#7970, #7821). 2026-04-16 23:59:44 +02:00
ocornut
a2916923a1 MultiSelect: Box-Select + Clipper: extend UnclipRect by ItemSpacing. (#7994, #8250, #7821, #7850, #7970)
Amend 1ac469b50f
2026-04-16 23:37:46 +02:00
ocornut
2cbdb7a337 TextLink(), BeginCombo(): fixed two remainig instances of needlessly scanning for ##. 2026-04-16 16:47:13 +02:00
ocornut
d4783bd553 Added missing Test Engine hooks for PlotXXX(), VSliderXXX(), TableHeader(). 2026-04-16 16:39:07 +02:00
ocornut
ce855cada2 Tables, Multi-Select: Fixed an issue using Multi-Select within a Table causing column width measurement to be invalid when trailing column contents is not submitted in the last row. (#9341, #8250) 2026-04-16 15:21:56 +02:00
ocornut
39e7bf5a08 Separator(): enforce a minimum border size if style.SeparatorSize is 0.0f. (#9369) 2026-04-16 11:32:40 +02:00
ocornut
0e318a5182 Backends: SDL2: Made ImGui_ImplSDL2_GetContentScaleXXX helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369) 2026-04-16 11:32:07 +02:00
ocornut
19753a30d8 Multi-Select: Box-Select+Tables: fixed Column return value when UnClipRect is active. (#7994, #8250)
Amend 6ce4b44 + bbd0af7. This probably should be redesigned to be more generic, e.g. move UnclipRect concept outside of Boxselect.
2026-04-15 15:08:49 +02:00
ocornut
6fb74f38af Demo: Assets Browser: make default icon size font dependant. 2026-04-15 14:26:50 +02:00
Andy Grundman
4b80d409e7 Backends: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for synchronize(). (#9367)
This also removes the dispatch onto main when adding the finished buffers back into the cache. This operation should be fine to run on any thread as long as it's inside the sync block.
2026-04-14 17:14:08 +02:00
ocornut
ed4dd679f1 Fixed vertical scrollbar top coordinates when using thick borders on windows with no title bar and no menu bar. (#9366) 2026-04-14 16:39:08 +02:00
ocornut
3cd8683061 Fonts: assert when using MergeMode with an explicit size over a target font with an implicit size, as scale factor are likely erroneous. (#9361) 2026-04-13 16:45:18 +02:00
ocornut
bbd0af7256 Multi-Select: Box-Select+Tables: fixed using BeginMultiSelect() before table layout is locked. (#8250) 2026-04-13 16:19:45 +02:00
ocornut
f83a378d62 TabBar: changed edge's TabItem ClipRect to not pass an inverted PushClipRect().
While not currently a problem, it would be if ImRect::Overlaps() is changed to use <= instead of < (cc: #3976 which deal with Contains but sort of similar topic).
Changing ImDrawList::PushClipRect()'s intersect_with_current_clip_rect path to use ClipRectFull() would also fix this, but it may ambiguous there which behavior would be correct.
Amend 1ec464eb9.
2026-04-13 14:11:19 +02:00
Flyinghead
84b4b35902 Fonts: rework UpdateCurrentFontSize() check. (#9364)
Consistent with line above.
2026-04-13 10:06:59 +02:00
ocornut
2dc64f99bc Minor optimization: reduce redudant label scanning in common widgets.
Missing stuff from 11de9df.
The 6 remaining use of CalcTextSize(...,true) don't need this.
2026-04-10 18:37:08 +02:00
ocornut
5da7eb0a84 DrawList: remove/strip old FixRectCornerFlags() code.
Amend 44a6b493e
2026-04-10 17:42:13 +02:00
ocornut
f678c91617 Multi-Select: disable MultiSelectAddSetRange() attempt at merging consecutive requests submitted from box-selection.
Essentially reverts 79b77d91c, f904a6646c which did the initial span merging.
Amend and disable change done for f08b33f.
2026-04-09 23:13:15 +02:00
ocornut
6ce4b44547 Mulit-Select: Box-Select: fixed an issue using in a table while relying on the TableNextColumn() return value to perform coarse clipping. (#7994)
This is presumably not sufficient as MultiSelectAddSetRange() is also deficient there.
2026-04-09 23:13:12 +02:00
ocornut
f08b33fd0c Multi-Select: Box-Select: fixed an issue where items out of horizontal view would sometimes lead to incorrect merging of sequential selection requests. (#7994, #1861, #6518)
SetNextItemSelectionUserData() could use g.NextItemData.SelectionUserData if we could guarantee if would be valid when nesting multi-select blocks.
But it doesn't make much of a difference as whole ImGuiMultiSelectTempData fits in 2 cache lines.
2026-04-09 22:16:47 +02:00
ocornut
b444694b3d Multi-Select: Box-Select: fixed an issue using ImGuiMultiSelectFlags_BoxSelect2d mode, where items out of view wouldn't be properly selected. (#7994, #1861, #6518)
Because BoxSelectRectPrev and BoxSelectRectCurr were clamped to scope boundaries, dragging mouse outside of the scope would usually keep one axis unchanged.
Amend 15391762dd
2026-04-09 21:40:29 +02:00
ocornut
24677c561e Multi-Select: Box-Select: add compile-time debug options. (#7994, #1861, #6518) 2026-04-09 21:40:13 +02:00
ocornut
01a4ad3a50 Docs: update legacy TODO list. 2026-04-09 15:01:40 +02:00
ocornut
f4ed421a88 InputText: CharFilter callback event sets CursorPos/SelectionStart/SelectionEnd. (#816) 2026-04-09 14:54:09 +02:00
ocornut
11de9df44c Minor optimization: reduce redudant label scanning in common widgets. 2026-04-09 14:25:34 +02:00
ocornut
c2565fe642 Update ignore list
Add .claude
2026-04-09 13:59:45 +02:00
ocornut
95bd1577d6 Windows: Child windows with only ImGuiChildFlags_AutoResizeY flag keep using the proportional default ItemWidth. (#9355)
+ Removed Tooltip flag check, it's from 8c4fcf1359 (!) where AlwaysAutoReszie was added after Tooltip. Nowadays Tooltips sets ImGuiChildFlags_AlwaysAutoResize.
2026-04-09 13:11:16 +02:00
ocornut
dd17495a42 Detect and report error when calling End() instead of EndPopup() on a popup. (#9351) 2026-04-08 21:40:05 +02:00
ocornut
1870a779e1 Windows: fixed a single-axis auto-resizing feedback loop issue with nested containers and varying scrollbar visibility. (#9352) 2026-04-08 21:26:16 +02:00
ocornut
a9bd173d89 Windows: shallow renames (should be no-op). 2026-04-08 20:40:35 +02:00
ocornut
bccec3eabc Tables: fixed IdealMaxPos.y/CursorMaxPos.y computation being wrong when vertically scrolling. (#9352, #7651)
See ""table_reported_size_outer" test amends (0f9d1e02b0).
2026-04-08 20:01:00 +02:00
ocornut
d946c6932b InputText: fixed a crash toggling ReadOnly flag while active. (#9354) 2026-04-08 15:56:59 +02:00
ocornut
4d38508c6b Tables: fixed an issue reporting ideal size to parent window/container when both scrollbars are visible but only one of ScrollX/ScrollY was explicitly requested. (#9352, #7651)
Since ScrollX de-facto also enables ScrollY we can't gate accounting for ScrollbarSizes.x based on explicit ScrollY.
Amend a31aa683f
2026-04-08 15:07:11 +02:00
ocornut
c0e6580b62 Reword code in CalcWindowAutoFitSize() to match the order used in size_desired calculation.
Should be no-op. Toward (#9352)
2026-04-08 14:31:11 +02:00
ocornut
6985925244 Clipper, Tables: Improved error reporting when misusing the clipper inside a table + made the assert a better recoverable error. (#9350)
Amend 20e040c8
2026-04-07 19:19:40 +02:00
ocornut
7cb0baeb77 imgui_freetype: add FreeType headers & compiled version number in the 'About Dear ImGui' user facing string. 2026-04-07 17:18:16 +02:00
hunam
49df3116bc Backends: Metal: avoid redundant vertex buffer bind in SetupRenderState. (#9343) 2026-04-03 19:14:23 +02:00
ocornut
03a0b00a34 InputTextMultiline: fixed an issue processing deactivation logic when an active multi-line edit is clipped due to being out of view. 2026-04-03 16:25:57 +02:00
ocornut
4a61188322 Version 1.92.8 WIP 2026-04-03 16:15:46 +02:00
135 changed files with 10437 additions and 2573 deletions

View file

@ -14,6 +14,7 @@ body:
attributes:
value: |
**Prerequisites:**
- I am not using a LLM to think or write for me. Please distill information to what's necessary and meaningful.
- I have read [Frequently Asked Questions](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md).
- I have read [Contributing Guidelines -> General Advices](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#getting-started--general-advice).
- I have read [Contributing Guidelines -> How to open an Issue](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#how-to-open-an-issue).

View file

@ -1,10 +1,12 @@
(Click "Preview" to turn any http URL into a clickable link)
1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md)
1. PLEASE CAREFULLY READ: [Contributing Guidelines](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md). By submitting a PR you are agreeing with the [CLA](https://github.com/ocornut/imgui/blob/master/docs/CONTRIBUTING.md#copyright--contributor-license-agreement).
2. **Make sure you're using a special branch just for this pull request**. (In git, 1 PR = 1 branch. If you update the branch the PR will be updated.)
3. Consider running the [imgui_test_suite](https://github.com/ocornut/imgui_test_engine) or adding new tests to test for expected behaviors.
4. Clear this template before submitting your PR.
4. PLEASE DO NOT SUBMIT AI-GENERATED PROSE. ONLY SUBMIT CODE THAT YOU REVIEWED AND UNDERSTAND. Submissions that are lacking proper human review/judgement before being passed to us are not welcome.
5. Clear this template before submitting your PR.

View file

@ -25,8 +25,8 @@ jobs:
working-directory: ${{ github.workspace }}/imgui
env:
VS_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\
MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\
VS_PATH: C:\Program Files\Microsoft Visual Studio\18\Enterprise
MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\
steps:
- uses: actions/checkout@v6
with:
@ -116,7 +116,7 @@ jobs:
cl.exe /D_USRDLL /D_WINDLL /I. example_single_file.cpp /LD /FeImGui.dll /link
cl.exe /DIMGUI_API=__declspec(dllimport) -DIMGUI_IMPL_API= /I. ImGui.lib /Feexample_null.exe examples/example_null/main.cpp
# Win64 examples are more frequently compilted than the Win32 examples.
# Win64 examples are more frequently compiled than the Win32 examples.
# More of the Win32 examples requires 'workflow_run' to reduce waste.
- name: Build Win32 example_glfw_opengl2
shell: cmd
@ -160,6 +160,7 @@ jobs:
- name: Build Win32 example_sdl3_opengl3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl3_opengl3/example_sdl3_opengl3.vcxproj /p:Platform=Win32 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win32 example_sdl3_sdlgpu3
shell: cmd
@ -200,6 +201,7 @@ jobs:
- name: Build Win64 example_glfw_opengl3
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_glfw_opengl3/example_glfw_opengl3.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win64 example_glfw_vulkan
shell: cmd
@ -228,6 +230,7 @@ jobs:
- name: Build Win64 example_sdl2_directx11
shell: cmd
run: '"%MSBUILD_PATH%\MSBuild.exe" examples/example_sdl2_directx11/example_sdl2_directx11.vcxproj /p:Platform=x64 /p:Configuration=Release'
if: github.event_name == 'workflow_run'
- name: Build Win64 example_sdl3_opengl3
shell: cmd
@ -506,7 +509,7 @@ jobs:
run: g++ -c -I. -std=c++11 -DIMGUI_IMPL_VULKAN_NO_PROTOTYPES=1 backends/imgui_impl_vulkan.cpp
Build-MacOS:
runs-on: macos-latest
runs-on: macos-26
name: Build - MacOS
defaults:
@ -572,6 +575,9 @@ jobs:
- name: Build macOS example_sdl2_metal
run: make -C examples/example_sdl2_metal
- name: Build macOS example_sdl3_metal4
run: make -C examples/example_sdl3_metal4
- name: Build macOS example_sdl2_opengl2
run: make -C examples/example_sdl2_opengl2
if: github.event_name == 'workflow_run'
@ -587,10 +593,18 @@ jobs:
run: xcodebuild -project examples/example_apple_metal/example_apple_metal.xcodeproj -target example_apple_metal_macos
if: github.event_name == 'workflow_run'
- name: Build macOS example_apple_metal4
run: xcodebuild -project examples/example_apple_metal4/example_apple_metal4.xcodeproj -target example_apple_metal_macos
if: github.event_name == 'workflow_run'
- name: Build macOS example_apple_opengl2
run: xcodebuild -project examples/example_apple_opengl2/example_apple_opengl2.xcodeproj -target example_osx_opengl2
if: github.event_name == 'workflow_run'
- name: Build macOS example_apple_opengl3
run: xcodebuild -project examples/example_apple_opengl3/example_apple_opengl3.xcodeproj -target example_osx_opengl3
if: github.event_name == 'workflow_run'
Build-iOS:
runs-on: macos-14
name: Build - iOS
@ -651,8 +665,12 @@ jobs:
name: Build - Android
steps:
- uses: actions/checkout@v6
- name: Setup Gradle 9.4.1
uses: gradle/actions/setup-gradle@v6
with:
gradle-version: '9.4.1'
- uses: actions/checkout@v6
- name: Build example_android_opengl3
run: |
cd examples/example_android_opengl3/android
@ -667,7 +685,7 @@ jobs:
working-directory: ${{ github.workspace }}/imgui
env:
MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\
MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\
steps:
- uses: actions/checkout@v6

View file

@ -23,9 +23,9 @@ jobs:
run: |
if [[ "$PVS_STUDIO_LICENSE" != "" ]];
then
wget -q https://files.viva64.com/etc/pubkey.txt
wget -q https://files.pvs-studio.com/etc/pubkey.txt
sudo apt-key add pubkey.txt
sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.viva64.com/etc/viva64.list
sudo wget -O /etc/apt/sources.list.d/viva64.list https://files.pvs-studio.com/etc/viva64.list
sudo apt-get update
sudo apt-get install -y pvs-studio
pvs-studio-analyzer credentials -o pvs-studio.lic $PVS_STUDIO_LICENSE

14
.gitignore vendored
View file

@ -1,5 +1,7 @@
## OSX artifacts
## Misc artifacts
.DS_Store
.claude
.vscode
## Dear ImGui artifacts
imgui.ini
@ -7,6 +9,8 @@ imgui*.ini
## General build artifacts
*.o
*.so*
*.a
*.obj
*.exe
examples/*/Debug/*
@ -55,12 +59,15 @@ examples/example_sdl3_wgpu/web/*
.idea
cmake-build-*
## VS code artifacts
.vscode
## QNX artifacts
*.pinfo
*.dep
*.gcno
## Unix executables from our example Makefiles
examples/example_apple_metal/example_apple_metal
examples/example_apple_opengl2/example_apple_opengl2
examples/example_apple_opengl3/example_apple_opengl3
examples/example_glfw_metal/example_glfw_metal
examples/example_glfw_opengl2/example_glfw_opengl2
examples/example_glfw_opengl3/example_glfw_opengl3
@ -73,6 +80,7 @@ examples/example_sdl2_opengl3/example_sdl2_opengl3
examples/example_sdl2_sdlrenderer2/example_sdl2_sdlrenderer2
examples/example_sdl2_vulkan/example_sdl2_vulkan
examples/example_sdl3_metal/example_sdl3_metal
examples/example_sdl3_metal4/example_sdl3_metal4
examples/example_sdl3_opengl3/example_sdl3_opengl3
examples/example_sdl3_sdlgpu3/example_sdl3_sdlgpu3
examples/example_sdl3_sdlrenderer3/example_sdl3_sdlrenderer3

View file

@ -9,6 +9,7 @@
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Missing features or Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation.
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@ -21,6 +22,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported by Allegro5). (#9378)
// 2025-09-18: Call platform_io.ClearRendererHandlers() and platform_io.ClearPlatformHandlers() on shutdown.
// 2025-08-12: Inputs: fixed missing support for ImGuiKey_PrintScreen under Windows, as raw Allegro 5 does not receive it.
// 2025-08-12: Added ImGui_ImplAllegro5_SetDisplay() function to change current ALLEGRO_DISPLAY, as Allegro applications often need to do that.
@ -136,7 +138,10 @@ static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
}
}
// Render function.
// Draw callbacks
static void ImGui_ImplAllegro5_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
// Render function
void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
@ -152,6 +157,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
// Backup Allegro state that will be modified
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ALLEGRO_TRANSFORM last_transform = *al_get_current_transform();
ALLEGRO_TRANSFORM last_projection_transform = *al_get_current_projection_transform();
int last_clip_x, last_clip_y, last_clip_w, last_clip_h;
@ -208,8 +214,7 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplAllegro5_DrawCallback_ResetRenderState)
ImGui_ImplAllegro5_SetupRenderState(draw_data);
else
pcmd->UserCallback(draw_list, pcmd);
@ -263,8 +268,7 @@ void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex)
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
// Create texture
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Create texture (bilinear sampling is required)
const int new_bitmap_flags = al_get_new_bitmap_flags();
int new_bitmap_format = al_get_new_bitmap_format();
al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP | ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
@ -486,11 +490,12 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
ImGui_ImplAllegro5_SetDisplay(display);
#if ALLEGRO_HAS_CLIPBOARD
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
#if ALLEGRO_HAS_CLIPBOARD
platform_io.Platform_SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
platform_io.Platform_GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
#endif
platform_io.DrawCallback_ResetRenderState = ImGui_ImplAllegro5_DrawCallback_ResetRenderState;
return true;
}

View file

@ -9,6 +9,7 @@
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Missing features or Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: Allegro5 cannot enable/disable LINEAR bitmap flags after creation.
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.

View file

@ -1,5 +1,5 @@
// dear imgui: Platform Binding for Android native app
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
@ -23,7 +23,9 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2026-07-15: Inputs: clear mouse position on touch release (AMOTION_EVENT_ACTION_UP) to prevent items from staying in hovered state. (#6627, #9474)
// 2023-04-11: Inputs: calling new io.AddMouseSourceEvent() to discriminate Mouse from Touch events.
// 2022-09-26: Inputs: renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
@ -230,6 +232,8 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(const AInputEvent* input_event)
{
io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN);
if (event_action == AMOTION_EVENT_ACTION_UP) // (#6627, #9474)
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
break;
}

View file

@ -1,5 +1,5 @@
// dear imgui: Platform Binding for Android native app
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
// Implemented features:
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values are obsolete since 1.87 and not supported since 1.91.5]

View file

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX10_GetRenderState().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -16,7 +17,9 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'.
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-04-23: DirectX10: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX10_RenderState. (#9378)
// 2026-01-19: DirectX10: Added 'SamplerNearest' in ImGui_ImplDX10_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'.
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
// 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows).
@ -98,6 +101,11 @@ static ImGui_ImplDX10_Data* ImGui_ImplDX10_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplDX10_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState()
{
return (ImGui_ImplDX10_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
// Functions
static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device* device)
{
@ -105,8 +113,8 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device*
// Setup viewport
D3D10_VIEWPORT vp = {};
vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
vp.Width = (UINT)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
vp.Height = (UINT)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
@ -147,12 +155,17 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device*
device->GSSetShader(nullptr);
// Setup render state
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
device->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
device->OMSetDepthStencilState(bd->pDepthStencilState, 0);
device->RSSetState(bd->pRasterizerState);
}
// Draw callbacks
static void ImGui_ImplDX10_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplDX10_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); bd->pd3dDevice->PSSetSamplers(0, 1, &bd->pTexSamplerLinear); }
static void ImGui_ImplDX10_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); bd->pd3dDevice->PSSetSamplers(0, 1, &bd->pTexSamplerNearest); }
// Render function
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
{
@ -177,7 +190,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D10_BUFFER_DESC desc = {};
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
desc.ByteWidth = (UINT)bd->VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D10_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
@ -191,7 +204,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D10_BUFFER_DESC desc = {};
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.ByteWidth = (UINT)bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D10_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
if (device->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
@ -260,8 +273,6 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplDX10_RenderState render_state;
render_state.Device = bd->pd3dDevice;
render_state.SamplerLinear = bd->pTexSamplerLinear;
render_state.SamplerNearest = bd->pTexSamplerNearest;
render_state.VertexConstantBuffer = bd->pVertexConstantBuffer;
platform_io.Renderer_RenderState = &render_state;
@ -279,8 +290,7 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplDX10_DrawCallback_ResetRenderState)
ImGui_ImplDX10_SetupRenderState(draw_data, device);
else
pcmd->UserCallback(draw_list, pcmd);
@ -443,7 +453,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
PS_INPUT main(VS_INPUT input)\
{\
PS_INPUT output;\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.0f, 1.0f));\
output.col = input.col;\
output.uv = input.uv;\
return output;\
@ -554,8 +564,7 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState);
}
// Create texture sampler
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Create texture sampler (bilinear sampling is required)
{
D3D10_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
@ -563,10 +572,10 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
desc.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP;
desc.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP;
desc.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
desc.MipLODBias = 0.f;
desc.MipLODBias = 0.0f;
desc.ComparisonFunc = D3D10_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
desc.MinLOD = 0.0f;
desc.MaxLOD = 0.0f;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerLinear);
desc.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerNearest);
@ -613,6 +622,9 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX10_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX10_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX10_DrawCallback_SetSamplerNearest;
// Get factory from device
IDXGIDevice* pDXGIDevice = nullptr;

View file

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX10_GetRenderState().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -41,9 +42,10 @@ IMGUI_IMPL_API void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex);
struct ImGui_ImplDX10_RenderState
{
ID3D10Device* Device;
ID3D10SamplerState* SamplerLinear;
ID3D10SamplerState* SamplerNearest;
ID3D10Buffer* VertexConstantBuffer;
//ID3D10SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear)
//ID3D10SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest)
};
IMGUI_IMPL_API ImGui_ImplDX10_RenderState* ImGui_ImplDX10_GetRenderState();
#endif // #ifndef IMGUI_DISABLE

View file

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX11_GetRenderState().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -17,6 +17,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-04-23: DirectX11: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplDX11_RenderState. (#9378)
// 2026-01-19: DirectX11: Added 'SamplerNearest' in ImGui_ImplDX11_RenderState. Renamed 'SamplerDefault' to 'SamplerLinear'.
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
@ -85,6 +86,7 @@ struct ImGui_ImplDX11_Data
ID3D11DepthStencilState* pDepthStencilState;
int VertexBufferSize;
int IndexBufferSize;
ImGui_ImplDX11_RenderState* RenderState; // == (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState during rendering.
ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; }
};
@ -101,6 +103,11 @@ static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState()
{
return (ImGui_ImplDX11_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
// Functions
static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11DeviceContext* device_ctx)
{
@ -108,8 +115,8 @@ static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11D
// Setup viewport
D3D11_VIEWPORT vp = {};
vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x;
vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y;
vp.Width = (float)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
vp.Height = (float)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0;
@ -153,12 +160,17 @@ static void ImGui_ImplDX11_SetupRenderState(const ImDrawData* draw_data, ID3D11D
device_ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used..
// Setup render state
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
device_ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff);
device_ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0);
device_ctx->RSSetState(bd->pRasterizerState);
}
// Draw callbacks
static void ImGui_ImplDX11_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplDX11_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &bd->pTexSamplerLinear); }
static void ImGui_ImplDX11_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); bd->RenderState->DeviceContext->PSSetSamplers(0, 1, &bd->pTexSamplerNearest); }
// Render function
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
{
@ -183,7 +195,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D11_BUFFER_DESC desc = {};
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert);
desc.ByteWidth = (UINT)bd->VertexBufferSize * sizeof(ImDrawVert);
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
@ -196,7 +208,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D11_BUFFER_DESC desc = {};
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.ByteWidth = (UINT)bd->IndexBufferSize * sizeof(ImDrawIdx);
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0)
@ -274,10 +286,8 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
ImGui_ImplDX11_RenderState render_state;
render_state.Device = bd->pd3dDevice;
render_state.DeviceContext = bd->pd3dDeviceContext;
render_state.SamplerLinear = bd->pTexSamplerLinear;
render_state.SamplerNearest = bd->pTexSamplerNearest;
render_state.VertexConstantBuffer = bd->pVertexConstantBuffer;
platform_io.Renderer_RenderState = &render_state;
platform_io.Renderer_RenderState = bd->RenderState = &render_state;
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
@ -293,8 +303,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplDX11_DrawCallback_ResetRenderState)
ImGui_ImplDX11_SetupRenderState(draw_data, device);
else
pcmd->UserCallback(draw_list, pcmd);
@ -320,7 +329,7 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
global_idx_offset += draw_list->IdxBuffer.Size;
global_vtx_offset += draw_list->VtxBuffer.Size;
}
platform_io.Renderer_RenderState = nullptr;
platform_io.Renderer_RenderState = bd->RenderState = nullptr;
// Restore modified DX state
device->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects);
@ -458,7 +467,7 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
PS_INPUT main(VS_INPUT input)\
{\
PS_INPUT output;\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.0f, 1.0f));\
output.col = input.col;\
output.uv = input.uv;\
return output;\
@ -570,7 +579,6 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
}
// Create texture sampler
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
{
D3D11_SAMPLER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
@ -578,10 +586,10 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.MipLODBias = 0.f;
desc.MipLODBias = 0.0f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.f;
desc.MaxLOD = 0.f;
desc.MinLOD = 0.0f;
desc.MaxLOD = 0.0f;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerLinear);
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
bd->pd3dDevice->CreateSamplerState(&desc, &bd->pTexSamplerNearest);
@ -629,6 +637,9 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX11_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX11_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX11_DrawCallback_SetSamplerNearest;
// Get factory from device
IDXGIDevice* pDXGIDevice = nullptr;

View file

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX11_GetRenderState().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -44,9 +44,10 @@ struct ImGui_ImplDX11_RenderState
{
ID3D11Device* Device;
ID3D11DeviceContext* DeviceContext;
ID3D11SamplerState* SamplerLinear;
ID3D11SamplerState* SamplerNearest;
ID3D11Buffer* VertexConstantBuffer;
//ID3D11SamplerState* SamplerLinear; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerLinear)
//ID3D11SamplerState* SamplerNearest; // Use ImDrawList::AddCallback(ImGui::GetPlatform().DrawCallback_SetSamplerNearest)
};
IMGUI_IMPL_API ImGui_ImplDX11_RenderState* ImGui_ImplDX11_GetRenderState();
#endif // #ifndef IMGUI_DISABLE

View file

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX12_GetRenderState().
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@ -20,6 +20,9 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-08-05: DirectX12: *BREAKING CHANGE* Removed support for legacy `ImGui_ImplDX12_Init()` signature obsoleted in 1.91.6 (2024-11-15) because it needed to forcefully disable support for ImGuiBackendFlags_RendererHasTextures. (#9487)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2025-10-11: DirectX12: Reuse texture upload buffer and grow it only when necessary. (#9002)
// 2025-09-29: DirectX12: Rework synchronization logic. (#8961)
// 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965)
@ -91,6 +94,8 @@ struct ImGui_ImplDX12_Texture
struct ImGui_ImplDX12_Data
{
ImGui_ImplDX12_InitInfo InitInfo;
ImGui_ImplDX12_RenderState* RenderState;
IDXGIFactory5* pdxgiFactory;
ID3D12Device* pd3dDevice;
ID3D12RootSignature* pRootSignatureLinear;
@ -128,6 +133,11 @@ static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState()
{
return (ImGui_ImplDX12_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
// Buffers used during the rendering of a frame
struct ImGui_ImplDX12_RenderBuffers
{
@ -142,19 +152,15 @@ struct VERTEX_CONSTANT_BUFFER_DX12
float mvp[4][4];
};
// FIXME-WIP: Allow user to forward declare those two, for until we come up with a backend agnostic API to do this. (#9173)
void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list);
void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list);
// Functions
void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list)
static void ImGui_ImplDX12_SetupSamplerLinear(ID3D12GraphicsCommandList* command_list)
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
command_list->SetPipelineState(bd->pPipelineStateLinear);
command_list->SetGraphicsRootSignature(bd->pRootSignatureLinear);
}
void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list)
static void ImGui_ImplDX12_SetupSamplerNearest(ID3D12GraphicsCommandList* command_list)
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
command_list->SetPipelineState(bd->pPipelineStateNearest);
@ -183,8 +189,8 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
// Setup viewport
D3D12_VIEWPORT vp = {};
vp.Width = draw_data->DisplaySize.x * draw_data->FramebufferScale.x;
vp.Height = draw_data->DisplaySize.y * draw_data->FramebufferScale.y;
vp.Width = (float)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
vp.Height = (float)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0.0f;
@ -200,7 +206,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
command_list->IASetVertexBuffers(0, 1, &vbv);
D3D12_INDEX_BUFFER_VIEW ibv = {};
ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress();
ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx);
ibv.SizeInBytes = (UINT)fr->IndexBufferSize * sizeof(ImDrawIdx);
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
command_list->IASetIndexBuffer(&ibv);
command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
@ -208,7 +214,7 @@ static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12Graphic
command_list->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
// Setup blend factor
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
command_list->OMSetBlendFactor(blend_factor);
}
@ -220,6 +226,11 @@ static inline void SafeRelease(T*& res)
res = nullptr;
}
// Draw callbacks
static void ImGui_ImplDX12_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplDX12_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); ImGui_ImplDX12_SetupSamplerLinear(bd->RenderState->CommandList); }
static void ImGui_ImplDX12_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); ImGui_ImplDX12_SetupSamplerNearest(bd->RenderState->CommandList); }
// Render function
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* command_list)
{
@ -317,7 +328,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
ImGui_ImplDX12_RenderState render_state;
render_state.Device = bd->pd3dDevice;
render_state.CommandList = command_list;
platform_io.Renderer_RenderState = &render_state;
platform_io.Renderer_RenderState = bd->RenderState = &render_state;
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
@ -334,7 +345,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplDX12_DrawCallback_ResetRenderState)
ImGui_ImplDX12_SetupRenderState(draw_data, command_list, fr);
else
pcmd->UserCallback(draw_list, pcmd);
@ -361,7 +372,7 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
global_idx_offset += draw_list->IdxBuffer.Size;
global_vtx_offset += draw_list->VtxBuffer.Size;
}
platform_io.Renderer_RenderState = nullptr;
platform_io.Renderer_RenderState = bd->RenderState = nullptr;
}
static void ImGui_ImplDX12_DestroyTexture(ImTextureData* tex)
@ -604,17 +615,17 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
param[1].DescriptorTable.pDescriptorRanges = &descRange;
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
// Bilinear sampling is required
D3D12_STATIC_SAMPLER_DESC staticSampler[1] = {};
staticSampler[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
staticSampler[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
staticSampler[0].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
staticSampler[0].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
staticSampler[0].MipLODBias = 0.f;
staticSampler[0].MipLODBias = 0.0f;
staticSampler[0].MaxAnisotropy = 0;
staticSampler[0].ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
staticSampler[0].BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
staticSampler[0].MinLOD = 0.f;
staticSampler[0].MinLOD = 0.0f;
staticSampler[0].MaxLOD = D3D12_FLOAT32_MAX;
staticSampler[0].ShaderRegister = 0;
staticSampler[0].RegisterSpace = 0;
@ -664,7 +675,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignatureLinear));
blob->Release();
// Root Signature for ImDrawCallback_SetSamplerNearest
// Nearest sampler
staticSampler[0].Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, nullptr) != S_OK)
return false;
@ -717,7 +728,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
PS_INPUT main(VS_INPUT input)\
{\
PS_INPUT output;\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.0f, 1.0f));\
output.col = input.col;\
output.uv = input.uv;\
return output;\
@ -813,7 +824,6 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
return false;
}
// Pipeline State for ImDrawCallback_SetSamplerNearest
psoDesc.pRootSignature = bd->pRootSignatureNearest;
result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineStateNearest));
@ -927,6 +937,11 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX12_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX12_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX12_DrawCallback_SetSamplerNearest;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (init_info->SrvDescriptorAllocFn == nullptr)
ImGui_ImplDX12_InitLegacySingleDescriptorMode(init_info);
@ -948,36 +963,6 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info)
return true;
}
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
{
ImGui_ImplDX12_InitInfo init_info;
init_info.Device = device;
init_info.NumFramesInFlight = num_frames_in_flight;
init_info.RTVFormat = rtv_format;
init_info.SrvDescriptorHeap = srv_descriptor_heap;
init_info.LegacySingleSrvCpuDescriptor = font_srv_cpu_desc_handle;
init_info.LegacySingleSrvGpuDescriptor = font_srv_gpu_desc_handle;
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 1;
HRESULT hr = device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&init_info.CommandQueue));
IM_ASSERT(SUCCEEDED(hr));
bool ret = ImGui_ImplDX12_Init(&init_info);
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
bd->commandQueueOwned = true;
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; // Using legacy ImGui_ImplDX12_Init() call with 1 SRV descriptor we cannot support multiple textures.
return ret;
}
#endif
void ImGui_ImplDX12_Shutdown()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();

View file

@ -5,7 +5,7 @@
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplDX12_GetRenderState().
// The aim of imgui_impl_dx12.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@ -59,13 +59,6 @@ IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* srv_descriptor_heap, D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
#endif
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
@ -81,6 +74,15 @@ struct ImGui_ImplDX12_RenderState
ID3D12Device* Device;
ID3D12GraphicsCommandList* CommandList;
};
IMGUI_IMPL_API ImGui_ImplDX12_RenderState* ImGui_ImplDX12_GetRenderState();
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// Legacy initialization API Obsoleted in 1.91.5
// - font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture, they must be in 'srv_descriptor_heap'
// - When we introduced the ImGui_ImplDX12_InitInfo struct we also added a 'ID3D12CommandQueue* CommandQueue' field.
// - DOES NOT SUPPORT ImGuiBackendFlags_RendererHasTextures.
//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
#if defined(__clang__)
#pragma clang diagnostic pop

View file

@ -17,6 +17,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas.
@ -162,6 +163,11 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
}
}
// Draw callbacks
static void ImGui_ImplDX9_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplDX9_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); }
static void ImGui_ImplDX9_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); bd->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); }
// Render function.
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{
@ -184,14 +190,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{
if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; }
bd->VertexBufferSize = draw_data->TotalVtxCount + 5000;
if (device->CreateVertexBuffer(bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0)
if (device->CreateVertexBuffer((UINT)bd->VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &bd->pVB, nullptr) < 0)
return;
}
if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount)
{
if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; }
bd->IndexBufferSize = draw_data->TotalIdxCount + 10000;
if (device->CreateIndexBuffer(bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
if (device->CreateIndexBuffer((UINT)bd->IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &bd->pIB, nullptr) < 0)
return;
}
@ -269,8 +275,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplDX9_DrawCallback_ResetRenderState)
ImGui_ImplDX9_SetupRenderState(draw_data);
else
pcmd->UserCallback(draw_list, pcmd);
@ -325,46 +330,6 @@ static bool ImGui_ImplDX9_CheckFormatSupport(LPDIRECT3DDEVICE9 pDevice, D3DFORMA
return support;
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx9";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
bd->pd3dDevice = device;
bd->pd3dDevice->AddRef();
bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
return true;
}
void ImGui_ImplDX9_Shutdown()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplDX9_InvalidateDeviceObjects();
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
static void ImGui_ImplDX9_CopyTextureRegion(bool tex_use_colors, const ImU32* src, int src_pitch, ImU32* dst, int dst_pitch, int w, int h)
{
@ -477,6 +442,50 @@ void ImGui_ImplDX9_NewFrame()
IM_UNUSED(bd);
}
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX9_Data* bd = IM_NEW(ImGui_ImplDX9_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx9";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = 4096;
platform_io.DrawCallback_ResetRenderState = ImGui_ImplDX9_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplDX9_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplDX9_DrawCallback_SetSamplerNearest;
bd->pd3dDevice = device;
bd->pd3dDevice->AddRef();
bd->HasRgbaSupport = ImGui_ImplDX9_CheckFormatSupport(bd->pd3dDevice, D3DFMT_A8B8G8R8);
return true;
}
void ImGui_ImplDX9_Shutdown()
{
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplDX9_InvalidateDeviceObjects();
if (bd->pd3dDevice) { bd->pd3dDevice->Release(); }
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
//-----------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE

View file

@ -29,6 +29,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-04-21: Added a Win32-specific implementation of ImGui_ImplGlfw_GetContentScaleXXXX functions for legacy GLFW 3.2.
// 2026-03-25: Mouse cursor is properly restored if changed by user app/code while using glfwSetInputMode(..., GLFW_CURSOR_DISABLED) or ImGuiConfigFlags_NoMouseCursorChange. Amend change from 2025-12-10.
// 2026-02-10: Try to set IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND automatically if corresponding headers are not accessible. (#9225)
// 2025-12-12: Added IMGUI_IMPL_GLFW_DISABLE_X11 / IMGUI_IMPL_GLFW_DISABLE_WAYLAND to forcefully disable either.
@ -212,7 +213,7 @@ struct ImGui_ImplGlfw_Data
bool IsWayland;
bool InstalledCallbacks;
bool CallbacksChainForAllWindows;
char BackendPlatformName[32];
char BackendPlatformName[40];
#ifdef EMSCRIPTEN_USE_EMBEDDED_GLFW3
const char* CanvasSelector;
#endif
@ -675,7 +676,13 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
// Setup backend capabilities flags
ImGui_ImplGlfw_Data* bd = IM_NEW(ImGui_ImplGlfw_Data)();
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_glfw (%d)", GLFW_VERSION_COMBINED);
bd->Context = ImGui::GetCurrentContext();
bd->Window = window;
bd->Time = 0.0;
bd->IsWayland = ImGui_ImplGlfw_IsWayland();
ImGui_ImplGlfw_ContextMap_Add(window, bd->Context);
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_glfw (%d)%s", GLFW_VERSION_COMBINED, bd->IsWayland ? " (Wayland)" : "");
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = bd->BackendPlatformName;
#if GLFW_HAS_CREATECURSOR
@ -683,12 +690,6 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
#endif
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
bd->Context = ImGui::GetCurrentContext();
bd->Window = window;
bd->Time = 0.0;
bd->IsWayland = ImGui_ImplGlfw_IsWayland();
ImGui_ImplGlfw_ContextMap_Add(window, bd->Context);
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
#if GLFW_VERSION_COMBINED < 3300
platform_io.Platform_SetClipboardTextFn = [](ImGuiContext*, const char* text) { glfwSetClipboardString(ImGui_ImplGlfw_GetBackendData()->Window, text); };
@ -948,6 +949,16 @@ static void ImGui_ImplGlfw_UpdateGamepads()
#undef MAP_ANALOG
}
// For GFLW 3.2 + Windows: include a simplified non-monitor aware version of ImGui_ImplWin32_GetDpiScaleForMonitor().
// This is merely a band-aid to make using GLFW 3.2 a little bit nicer, but prefer to use GLFW 3.3+ or the full correct functions from the Win32 backend.
#if !GLFW_HAS_PER_MONITOR_DPI && defined(_WIN32) && !defined(NOGDI)
static float ImGui_ImplWin32_GetLegacyDpiScale() { const HDC dc = ::GetDC(nullptr); UINT xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); ::ReleaseDC(nullptr, dc); return (float)xdpi / 96.0f; }
static void glfwGetWindowContentScale(GLFWwindow*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); }
static void glfwGetMonitorContentScale(GLFWmonitor*, float* x_scale, float* y_scale) { *x_scale = *y_scale = ImGui_ImplWin32_GetLegacyDpiScale(); }
#undef GLFW_HAS_PER_MONITOR_DPI
#define GLFW_HAS_PER_MONITOR_DPI 1
#endif
// - On Windows the process needs to be marked DPI-aware!! SDL2 doesn't do it by default. You can call ::SetProcessDPIAware() or call ImGui_ImplWin32_EnableDpiAwareness() from Win32 backend.
// - Apple platforms use FramebufferScale so we always return 1.0f.
// - Some accessibility applications are declaring virtual monitors with a DPI of 0.0f, see #7902. We preserve this value for caller to handle.
@ -1016,7 +1027,7 @@ void ImGui_ImplGlfw_NewFrame()
// (Accept glfwGetTime() not returning a monotonically increasing value. Seems to happens on disconnecting peripherals and probably on VMs and Emscripten, see #6491, #6189, #6114, #3644)
double current_time = glfwGetTime();
if (current_time <= bd->Time)
current_time = bd->Time + 0.00001f;
current_time = bd->Time + 0.00001;
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;

View file

@ -16,6 +16,11 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-04-28: Added support for standard draw callbacks (in platform_io): DrawCallback_SetSamplerLinear and DrawCallback_SetSamplerNearest. (#9378, #9381)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others are not yet supported). (#9378)
// 2026-04-14: Metal: use a dedicated bufferCacheLock to avoid crashing when bufferCache is replaced by a new object while being used for @synchronize(). (#9367)
// 2026-04-03: Metal: avoid redundant vertex buffer bind in SetupRenderState. (#9343)
// 2026-03-19: Fixed issue in ImGui_ImplMetal_RenderDrawData() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture().
@ -74,9 +79,12 @@
@interface MetalContext : NSObject
@property (nonatomic, strong) id<MTLDevice> device;
@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
@property (nonatomic, strong) id<MTLSamplerState> samplerStateLinear;
@property (nonatomic, strong) id<MTLSamplerState> samplerStateNearest;
@property (nonatomic, strong) FramebufferDescriptor* framebufferDescriptor; // framebuffer descriptor for current frame; transient
@property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache; // pipeline cache; keyed on framebuffer descriptors
@property (nonatomic, strong) NSMutableArray<MetalBuffer*>* bufferCache;
@property (nonatomic, strong) NSObject* bufferCacheLock;
@property (nonatomic, assign) double lastBufferCachePurge;
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;
@ -85,6 +93,7 @@
struct ImGui_ImplMetal_Data
{
MetalContext* SharedMetalContext;
id<MTLRenderCommandEncoder> RenderCommandEncoder;
ImGui_ImplMetal_Data() { memset((void*)this, 0, sizeof(*this)); }
};
@ -115,7 +124,6 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
ImGui_ImplMetal_RenderDrawData(draw_data,
(__bridge id<MTLCommandBuffer>)(commandBuffer),
(__bridge id<MTLRenderCommandEncoder>)(commandEncoder));
}
bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
@ -127,41 +135,6 @@ bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
#pragma mark - Dear ImGui Metal Backend API
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_metal";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
bd->SharedMetalContext = [[MetalContext alloc] init];
bd->SharedMetalContext.device = device;
return true;
}
void ImGui_ImplMetal_Shutdown()
{
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
IM_UNUSED(bd);
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplMetal_DestroyDeviceObjects();
ImGui_ImplMetal_DestroyBackendData();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
}
void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor)
{
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
@ -191,8 +164,8 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id<MTLComman
{
.originX = 0.0,
.originY = 0.0,
.width = (double)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x),
.height = (double)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y),
.width = (double)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f),
.height = (double)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f),
.znear = 0.0,
.zfar = 1.0
};
@ -214,11 +187,16 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id<MTLComman
[commandEncoder setVertexBytes:&ortho_projection length:sizeof(ortho_projection) atIndex:1];
[commandEncoder setRenderPipelineState:renderPipelineState];
[commandEncoder setFragmentSamplerState:bd->SharedMetalContext.samplerStateLinear atIndex:0];
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0];
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:vertexBufferOffset atIndex:0];
}
// Draw callbacks
static void ImGui_ImplMetal_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplMetal_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); [bd->RenderCommandEncoder setFragmentSamplerState:bd->SharedMetalContext.samplerStateLinear atIndex:0]; }
static void ImGui_ImplMetal_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); [bd->RenderCommandEncoder setFragmentSamplerState:bd->SharedMetalContext.samplerStateNearest atIndex:0]; }
// Metal Render function.
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer> commandBuffer, id<MTLRenderCommandEncoder> commandEncoder)
{
@ -226,8 +204,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
MetalContext* ctx = bd->SharedMetalContext;
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0)
return;
@ -255,6 +233,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
bd->RenderCommandEncoder = commandEncoder;
ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);
// Will project scissor/clipping rectangles into framebuffer space
@ -275,8 +254,7 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplMetal_DrawCallback_ResetRenderState)
ImGui_ImplMetal_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);
else
pcmd->UserCallback(draw_list, pcmd);
@ -290,8 +268,8 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
@ -328,14 +306,13 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id<MTLCommandBuffer>
MetalContext* sharedMetalContext = bd->SharedMetalContext;
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer>)
{
dispatch_async(dispatch_get_main_queue(), ^{
@synchronized(sharedMetalContext.bufferCache)
{
[sharedMetalContext.bufferCache addObject:vertexBuffer];
[sharedMetalContext.bufferCache addObject:indexBuffer];
}
});
@synchronized(sharedMetalContext.bufferCacheLock)
{
[sharedMetalContext.bufferCache addObject:vertexBuffer];
[sharedMetalContext.bufferCache addObject:indexBuffer];
}
}];
bd->RenderCommandEncoder = nil;
}
static void ImGui_ImplMetal_DestroyTexture(ImTextureData* tex)
@ -412,7 +389,17 @@ bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device)
depthStencilDescriptor.depthWriteEnabled = NO;
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear;
samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear;
samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear;
bd->SharedMetalContext.samplerStateLinear = [device newSamplerStateWithDescriptor:samplerDescriptor];
samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest;
samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest;
bd->SharedMetalContext.samplerStateNearest = [device newSamplerStateWithDescriptor:samplerDescriptor];
#ifdef IMGUI_IMPL_METAL_CPP
[samplerDescriptor release];
[depthStencilDescriptor release];
#endif
@ -429,6 +416,48 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
ImGui_ImplMetal_DestroyTexture(tex);
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
bd->SharedMetalContext.samplerStateLinear = nil;
bd->SharedMetalContext.samplerStateNearest = nil;
}
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
ImGui_ImplMetal_Data* bd = IM_NEW(ImGui_ImplMetal_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_metal";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplMetal_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplMetal_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplMetal_DrawCallback_SetSamplerNearest;
bd->SharedMetalContext = [[MetalContext alloc] init];
bd->SharedMetalContext.device = device;
return true;
}
void ImGui_ImplMetal_Shutdown()
{
ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData();
IM_UNUSED(bd);
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplMetal_DestroyDeviceObjects();
ImGui_ImplMetal_DestroyBackendData();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
}
#pragma mark - MetalBuffer implementation
@ -514,6 +543,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
{
self.renderPipelineStateCache = [NSMutableDictionary dictionary];
self.bufferCache = [NSMutableArray array];
self.bufferCacheLock = [[NSObject alloc] init];
_lastBufferCachePurge = GetMachAbsoluteTimeInSeconds();
}
return self;
@ -521,9 +551,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
{
uint64_t now = GetMachAbsoluteTimeInSeconds();
double now = GetMachAbsoluteTimeInSeconds();
@synchronized(self.bufferCache)
@synchronized(self.bufferCacheLock)
{
// Purge old buffers that haven't been useful for a while
if (now - self.lastBufferCachePurge > 1.0)
@ -555,7 +585,7 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
return [[MetalBuffer alloc] initWithBuffer:backing];
}
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
// Bilinear sampling is required.
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device
{
NSError* error = nil;
@ -590,9 +620,9 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
"}\n"
"\n"
"fragment half4 fragment_main(VertexOut in [[stage_in]],\n"
" texture2d<half, access::sample> texture [[texture(0)]]) {\n"
" constexpr sampler linearSampler(coord::normalized, min_filter::linear, mag_filter::linear, mip_filter::linear);\n"
" half4 texColor = texture.sample(linearSampler, in.texCoords);\n"
" texture2d<half, access::sample> texture [[texture(0)]],\n"
" sampler textureSampler [[sampler(0)]]) {\n"
" half4 texColor = texture.sample(textureSampler, in.texCoords);\n"
" return half4(in.color) * texColor;\n"
"}\n";

View file

@ -0,0 +1,89 @@
// dear imgui: Renderer Backend for Metal 4
// This needs to be used along with a Platform Backend (e.g. OSX)
// Metal 4 requires Apple Silicon and macOS 26+.
// Implemented features:
// [X] Renderer: User texture binding. Use 'MTLTexture.gpuResourceID' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// Missing features or Issues:
// [ ] Texture view pool support? Reevaluate which type to use for ImtextureID.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
//-----------------------------------------------------------------------------
// ObjC API
//-----------------------------------------------------------------------------
#ifdef __OBJC__
@class MTL4RenderPassDescriptor;
@protocol MTLDevice, MTL4CommandBuffer, MTL4RenderCommandEncoder, MTL4CommandQueue;
// framesInFlight must match the number of frames your application keeps in flight (e.g. the size of your own
// command buffer/allocator ring). The backend uses it to size its own per-frame-in-flight resources (constant
// buffer, vertex/index buffer cache) so the CPU never overwrites a slot the GPU may still be reading.
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplMetal4_Init(id<MTLDevice> device, id<MTL4CommandQueue> commandQueue, int framesInFlight);
IMGUI_IMPL_API void ImGui_ImplMetal4_Shutdown();
// frameInFlightIndex must match the slot you use to index your own per-frame-in-flight resources
// (e.g. the same index used to pick your command buffer/allocator), and must be < framesInFlight passed to Init().
IMGUI_IMPL_API void ImGui_ImplMetal4_NewFrame(MTL4RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex);
IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* drawData,
id<MTL4CommandBuffer> commandBuffer,
id<MTL4RenderCommandEncoder> commandEncoder);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal4_CreateDeviceObjects(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal4_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_ImplMetal4_UpdateTexture(ImTextureData* tex);
#endif
//-----------------------------------------------------------------------------
// C++ API
//-----------------------------------------------------------------------------
// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
#ifdef IMGUI_IMPL_METAL_CPP
#ifndef __OBJC__
// Forward declare relevant classes from the MTL and MTL4 namespace
namespace MTL { class Device; }
namespace MTL4 { class CommandQueue; class CommandBuffer; class RenderPassDescriptor; class RenderCommandEncoder; }
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplMetal4_Init(MTL::Device* device, MTL4::CommandQueue* commandQueue, int framesInFlight);
IMGUI_IMPL_API void ImGui_ImplMetal4_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal4_NewFrame(MTL4::RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex);
IMGUI_IMPL_API void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data,
MTL4::CommandBuffer* commandBuffer,
MTL4::RenderCommandEncoder* commandEncoder);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal4_CreateDeviceObjects(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal4_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_ImplMetal4_UpdateTexture(ImTextureData* tex);
#endif
#endif
//-----------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE

View file

@ -0,0 +1,744 @@
// dear imgui: Renderer Backend for Metal 4
// This needs to be used along with a Platform Backend (e.g. OSX)
// Metal 4 requires Apple Silicon and macOS 26+.
// Implemented features:
// [X] Renderer: User texture binding. Use 'MTLTexture' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// Missing features or Issues:
// [ ] Texture view pool support? Reevaluate which type to use for ImtextureID.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-07-07: Metal 4: Added metal-cpp support. (#9461)
// 2026-07-02: Metal 4: Added new Metal 4 backend implementation. (#9458)
#include "imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_metal4.h"
#import <time.h>
#import <Metal/Metal.h>
#ifdef IMGUI_IMPL_METAL_CPP
#include <Metal/Metal.hpp>
#endif
#pragma mark - Support classes and structs
struct ImGui_Metal4_ConstantData
{
float ModelViewProjectionMatrix[4][4];
};
@interface MetalBuffer : NSObject
@property (nonatomic, strong) id<MTLBuffer> buffer;
@property (nonatomic, assign) double lastReuseTime;
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer;
@end
// An object that encapsulates the data necessary to uniquely identify a
// render pipeline state. These are used as cache keys.
@interface FramebufferDescriptor : NSObject<NSCopying>
@property (nonatomic, assign) unsigned long sampleCount;
@property (nonatomic, assign) MTLPixelFormat colorPixelFormat;
@property (nonatomic, assign) MTLPixelFormat depthPixelFormat;
@property (nonatomic, assign) MTLPixelFormat stencilPixelFormat;
- (instancetype)initWithRenderPassDescriptor:(MTL4RenderPassDescriptor*)renderPassDescriptor;
@end
@interface MetalTexture : NSObject
@property (nonatomic, strong) id<MTLTexture> metalTexture;
- (instancetype)initWithTexture:(id<MTLTexture>)metalTexture;
@end
// A singleton that stores long-lived objects that are needed by the Metal
// renderer backend. Stores the render pipeline state cache and the default
// font texture, and manages the reusable buffer cache.
@interface MetalContext : NSObject
@property (nonatomic, strong) id<MTLDevice> device;
@property (nonatomic, strong) id<MTL4CommandQueue> commandQueue;
@property (nonatomic, strong) id<MTLDepthStencilState> depthStencilState;
@property (nonatomic, strong) id<MTL4ArgumentTable> argumentTable;
@property (nonatomic, strong) id<MTLSamplerState> samplerStateLinear;
@property (nonatomic, strong) id<MTLSamplerState> samplerStateNearest;
@property (nonatomic, strong) id<MTLResidencySet> residencySet;
@property (nonatomic, strong) FramebufferDescriptor* framebufferDescriptor;
@property (nonatomic, strong) NSMutableDictionary* renderPipelineStateCache;
@property (nonatomic, assign) NSUInteger framesInFlight;
@property (nonatomic, assign) NSUInteger currentFrameSlot;
@property (nonatomic, strong) NSArray<id<MTLBuffer>>* constantBuffers;
@property (nonatomic, assign) ImGui_Metal4_ConstantData** constantBufferContentsArray;
@property (nonatomic, strong) NSMutableArray<NSMutableArray<MetalBuffer*>*>* bufferCaches;
@property (nonatomic, strong) NSObject* bufferCacheLock;
@property (nonatomic, assign) double lastBufferCachePurge;
- (id<MTLBuffer>)currentConstantBuffer;
- (ImGui_Metal4_ConstantData*)currentConstantBufferContents;
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device;
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device;
@end
struct ImGui_ImplMetal4_Data
{
MetalContext* SharedMetalContext;
id<MTL4RenderCommandEncoder> RenderCommandEncoder;
ImGui_ImplMetal4_Data() { memset((void*)this, 0, sizeof(*this)); }
};
static ImGui_ImplMetal4_Data* ImGui_ImplMetal4_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplMetal4_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; }
static void ImGui_ImplMetal4_DestroyBackendData(){ IM_DELETE(ImGui_ImplMetal4_GetBackendData()); }
static inline CFTimeInterval GetMachAbsoluteTimeInSeconds() { return (CFTimeInterval)(double)(clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1e9); }
#ifdef IMGUI_IMPL_METAL_CPP
#pragma mark - Dear ImGui Metal C++ Backend API
bool ImGui_ImplMetal4_Init(MTL::Device* device, MTL4::CommandQueue* commandQueue, int framesInFlight)
{
return ImGui_ImplMetal4_Init((__bridge id<MTLDevice>)(device),(__bridge id<MTL4CommandQueue>)(commandQueue), framesInFlight);
}
void ImGui_ImplMetal4_NewFrame(MTL4::RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex)
{
ImGui_ImplMetal4_NewFrame((__bridge MTL4RenderPassDescriptor*)(renderPassDescriptor), frameInFlightIndex);
}
void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data,
MTL4::CommandBuffer* commandBuffer,
MTL4::RenderCommandEncoder* commandEncoder)
{
ImGui_ImplMetal4_RenderDrawData(draw_data,
(__bridge id<MTL4CommandBuffer>)(commandBuffer),
(__bridge id<MTL4RenderCommandEncoder>)(commandEncoder));
}
bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
{
return ImGui_ImplMetal4_CreateDeviceObjects((__bridge id<MTLDevice>)(device));
}
#endif // #ifdef IMGUI_IMPL_METAL_CPP
#pragma mark - Dear ImGui Metal Backend API
void ImGui_ImplMetal4_NewFrame(MTL4RenderPassDescriptor* renderPassDescriptor, int frameInFlightIndex)
{
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
IM_ASSERT(bd != nil && "Context or backend not initialized! Did you call ImGui_ImplMetal4_Init()?");
IM_ASSERT(frameInFlightIndex < bd->SharedMetalContext.framesInFlight && "frameInFlightIndex out of range! See framesInFlight passed to ImGui_ImplMetal4_Init().");
#ifdef IMGUI_IMPL_METAL_CPP
bd->SharedMetalContext.framebufferDescriptor = [[[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor]autorelease];
#else
bd->SharedMetalContext.framebufferDescriptor = [[FramebufferDescriptor alloc] initWithRenderPassDescriptor:renderPassDescriptor];
#endif
bd->SharedMetalContext.currentFrameSlot = (NSUInteger)frameInFlightIndex;
if (bd->SharedMetalContext.depthStencilState == nil)
ImGui_ImplMetal4_CreateDeviceObjects(bd->SharedMetalContext.device);
}
static void ImGui_ImplMetal4_SetupRenderState(ImDrawData* draw_data, id<MTL4CommandBuffer> commandBuffer,
id<MTL4RenderCommandEncoder> commandEncoder, id<MTLRenderPipelineState> renderPipelineState,
MetalBuffer* vertexBuffer, size_t vertexBufferOffset)
{
IM_UNUSED(commandBuffer);
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
[commandEncoder setCullMode:MTLCullModeNone];
[commandEncoder setDepthStencilState:bd->SharedMetalContext.depthStencilState];
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to
// draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
MTLViewport viewport =
{
.originX = 0.0,
.originY = 0.0,
.width = (double)(int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f),
.height = (double)(int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f),
.znear = 0.0,
.zfar = 1.0
};
[commandEncoder setViewport:viewport];
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float N = (float)viewport.znear;
float F = (float)viewport.zfar;
const float ortho_projection[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 1/(F-N), 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), N/(F-N), 1.0f },
};
ImGui_Metal4_ConstantData* constantBufferContents = [bd->SharedMetalContext currentConstantBufferContents];
memcpy(constantBufferContents->ModelViewProjectionMatrix, ortho_projection, sizeof(ortho_projection));
id<MTL4ArgumentTable> argumentTable = bd->SharedMetalContext.argumentTable;
[argumentTable setAddress:[bd->SharedMetalContext currentConstantBuffer].gpuAddress atIndex:1];
[argumentTable setAddress:(vertexBuffer.buffer.gpuAddress + vertexBufferOffset) attributeStride:sizeof(ImDrawVert) atIndex:0];
[argumentTable setSamplerState:bd->SharedMetalContext.samplerStateLinear.gpuResourceID atIndex:0];
[commandEncoder setArgumentTable:argumentTable atStages:MTLRenderStageVertex | MTLRenderStageFragment];
[commandEncoder setRenderPipelineState:renderPipelineState];
}
static void ImGui_ImplMetal4_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplMetal4_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData(); [bd->SharedMetalContext.argumentTable setSamplerState:bd->SharedMetalContext.samplerStateLinear.gpuResourceID atIndex:0]; }
static void ImGui_ImplMetal4_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData(); [bd->SharedMetalContext.argumentTable setSamplerState:bd->SharedMetalContext.samplerStateNearest.gpuResourceID atIndex:0]; }
void ImGui_ImplMetal4_RenderDrawData(ImDrawData* draw_data, id<MTL4CommandBuffer> commandBuffer, id<MTL4RenderCommandEncoder> commandEncoder)
{
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
MetalContext* ctx = bd->SharedMetalContext;
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0)
return;
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
if (draw_data->Textures != nullptr)
for (ImTextureData* tex : *draw_data->Textures)
if (tex->Status != ImTextureStatus_OK)
ImGui_ImplMetal4_UpdateTexture(tex);
// Try to retrieve a render pipeline state that is compatible with the framebuffer config for this frame
// The hit rate for this cache should be very near 100%.
id<MTLRenderPipelineState> renderPipelineState = ctx.renderPipelineStateCache[ctx.framebufferDescriptor];
if (renderPipelineState == nil)
{
// No luck; make a new render pipeline state
renderPipelineState = [ctx renderPipelineStateForFramebufferDescriptor:ctx.framebufferDescriptor device:commandBuffer.device];
// Cache render pipeline state for later reuse
ctx.renderPipelineStateCache[ctx.framebufferDescriptor] = renderPipelineState;
}
size_t vertexBufferLength = (size_t)draw_data->TotalVtxCount * sizeof(ImDrawVert);
size_t indexBufferLength = (size_t)draw_data->TotalIdxCount * sizeof(ImDrawIdx);
MetalBuffer* vertexBuffer = [ctx dequeueReusableBufferOfLength:vertexBufferLength device:commandBuffer.device];
MetalBuffer* indexBuffer = [ctx dequeueReusableBufferOfLength:indexBufferLength device:commandBuffer.device];
bd->RenderCommandEncoder = commandEncoder;
ImGui_ImplMetal4_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, 0);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
// Render command lists
size_t vertexBufferOffset = 0;
size_t indexBufferOffset = 0;
for (const ImDrawList* draw_list : draw_data->CmdLists)
{
memcpy((char*)vertexBuffer.buffer.contents + vertexBufferOffset, draw_list->VtxBuffer.Data, (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy((char*)indexBuffer.buffer.contents + indexBufferOffset, draw_list->IdxBuffer.Data, (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx));
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
if (pcmd->UserCallback == ImGui_ImplMetal4_DrawCallback_ResetRenderState)
ImGui_ImplMetal4_SetupRenderState(draw_data, commandBuffer, commandEncoder, renderPipelineState, vertexBuffer, vertexBufferOffset);
else
pcmd->UserCallback(draw_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
continue;
// Apply scissor/clipping rectangle
MTLScissorRect scissorRect =
{
.x = NSUInteger(clip_min.x),
.y = NSUInteger(clip_min.y),
.width = NSUInteger(clip_max.x - clip_min.x),
.height = NSUInteger(clip_max.y - clip_min.y)
};
[commandEncoder setScissorRect:scissorRect];
// Bind texture, Draw
ImTextureID tex_id = pcmd->GetTexID();
if (tex_id != ImTextureID_Invalid)
{
id<MTLTexture> texture = (__bridge id<MTLTexture>)(void*)(intptr_t)tex_id;
[bd->SharedMetalContext.residencySet addAllocation:texture];
[bd->SharedMetalContext.argumentTable setTexture:texture.gpuResourceID atIndex:0];
}
[bd->SharedMetalContext.argumentTable setAddress:(vertexBuffer.buffer.gpuAddress + vertexBufferOffset + (pcmd->VtxOffset * sizeof(ImDrawVert))) attributeStride:sizeof(ImDrawVert) atIndex:0];
size_t indexBufferCmdOffset = indexBufferOffset + (pcmd->IdxOffset * sizeof(ImDrawIdx));
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBuffer:indexBuffer.buffer.gpuAddress + indexBufferCmdOffset
indexBufferLength:indexBuffer.buffer.length - indexBufferCmdOffset];
}
}
vertexBufferOffset += (size_t)draw_list->VtxBuffer.Size * sizeof(ImDrawVert);
indexBufferOffset += (size_t)draw_list->IdxBuffer.Size * sizeof(ImDrawIdx);
}
MetalContext* sharedMetalContext = bd->SharedMetalContext;
@synchronized(sharedMetalContext.bufferCacheLock)
{
NSMutableArray<MetalBuffer*>* slotCache = sharedMetalContext.bufferCaches[sharedMetalContext.currentFrameSlot];
[slotCache addObject:vertexBuffer];
[slotCache addObject:indexBuffer];
}
// Commit residency set
[bd->SharedMetalContext.residencySet commit];
bd->RenderCommandEncoder = nil;
}
static void ImGui_ImplMetal4_DestroyTexture(ImTextureData* tex)
{
if (MetalTexture* backend_tex = (__bridge_transfer MetalTexture*)(tex->BackendUserData))
{
IM_ASSERT(backend_tex.metalTexture == (__bridge id<MTLTexture>)(void*)(intptr_t)tex->TexID);
backend_tex.metalTexture = nil;
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
tex->SetTexID(ImTextureID_Invalid);
tex->BackendUserData = nullptr;
}
tex->SetStatus(ImTextureStatus_Destroyed);
}
void ImGui_ImplMetal4_UpdateTexture(ImTextureData* tex)
{
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
if (tex->Status == ImTextureStatus_WantCreate)
{
// Create and upload new texture to graphics system
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
// We are retrieving and uploading the font atlas as a 4-channels RGBA texture here.
// In theory we could call GetTexDataAsAlpha8() and upload a 1-channel texture to save on memory access bandwidth.
// However, using a shader designed for 1-channel texture would make it less obvious to use the ImTextureID facility to render users own textures.
// You can make that change in your implementation.
MTLTextureDescriptor* textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
width:(NSUInteger)tex->Width
height:(NSUInteger)tex->Height
mipmapped:NO];
textureDescriptor.usage = MTLTextureUsageShaderRead;
textureDescriptor.storageMode = MTLStorageModeShared;
id <MTLTexture> texture = [bd->SharedMetalContext.device newTextureWithDescriptor:textureDescriptor];
[bd->SharedMetalContext.residencySet addAllocation:texture];
[texture replaceRegion:MTLRegionMake2D(0, 0, (NSUInteger)tex->Width, (NSUInteger)tex->Height) mipmapLevel:0 withBytes:tex->Pixels bytesPerRow:(NSUInteger)tex->Width * 4];
MetalTexture* backend_tex = [[MetalTexture alloc] initWithTexture:texture];
// Store identifiers
tex->SetTexID((ImTextureID)(intptr_t)texture);
tex->SetStatus(ImTextureStatus_OK);
tex->BackendUserData = (__bridge_retained void*)(backend_tex);
}
else if (tex->Status == ImTextureStatus_WantUpdates)
{
// Update selected blocks. We only ever write to textures regions which have never been used before!
// This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
MetalTexture* backend_tex = (__bridge MetalTexture*)(tex->BackendUserData);
for (ImTextureRect& r : tex->Updates)
{
[backend_tex.metalTexture replaceRegion:MTLRegionMake2D((NSUInteger)r.x, (NSUInteger)r.y, (NSUInteger)r.w, (NSUInteger)r.h)
mipmapLevel:0
withBytes:tex->GetPixelsAt(r.x, r.y)
bytesPerRow:(NSUInteger)tex->Width * 4];
}
tex->SetStatus(ImTextureStatus_OK);
}
else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
{
ImGui_ImplMetal4_DestroyTexture(tex);
}
}
bool ImGui_ImplMetal4_CreateDeviceObjects(id<MTLDevice> device)
{
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
MTLResidencySetDescriptor* residencySetDescriptor = [[MTLResidencySetDescriptor alloc] init];
residencySetDescriptor.initialCapacity = 1000;
NSError* error = nil;
bd->SharedMetalContext.residencySet = [device newResidencySetWithDescriptor:residencySetDescriptor error:&error];
IM_ASSERT(bd->SharedMetalContext.residencySet != nil && error == nil);
[bd->SharedMetalContext.commandQueue addResidencySet:bd->SharedMetalContext.residencySet];
MTLDepthStencilDescriptor* depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
depthStencilDescriptor.depthWriteEnabled = NO;
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways;
bd->SharedMetalContext.depthStencilState = [device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
samplerDescriptor.supportArgumentBuffers = YES;
samplerDescriptor.minFilter = MTLSamplerMinMagFilterLinear;
samplerDescriptor.magFilter = MTLSamplerMinMagFilterLinear;
samplerDescriptor.mipFilter = MTLSamplerMipFilterLinear;
bd->SharedMetalContext.samplerStateLinear = [device newSamplerStateWithDescriptor:samplerDescriptor];
samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest;
samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
samplerDescriptor.mipFilter = MTLSamplerMipFilterNearest;
bd->SharedMetalContext.samplerStateNearest = [device newSamplerStateWithDescriptor:samplerDescriptor];
NSMutableArray<id<MTLBuffer>>* constantBuffers = [NSMutableArray array];
ImGui_Metal4_ConstantData** constantBufferContentsArray = (ImGui_Metal4_ConstantData**)malloc(sizeof(ImGui_Metal4_ConstantData*) * bd->SharedMetalContext.framesInFlight);
for (NSUInteger i = 0; i < bd->SharedMetalContext.framesInFlight; i++)
{
id<MTLBuffer> constantBuffer = [device newBufferWithLength:sizeof(ImGui_Metal4_ConstantData) options:MTLResourceStorageModeShared];
[constantBuffers addObject:constantBuffer];
constantBufferContentsArray[i] = (ImGui_Metal4_ConstantData*)constantBuffer.contents;
[bd->SharedMetalContext.residencySet addAllocation:constantBuffer];
}
bd->SharedMetalContext.constantBuffers = constantBuffers;
bd->SharedMetalContext.constantBufferContentsArray = constantBufferContentsArray;
MTL4ArgumentTableDescriptor* argumentTableDescriptor = [[MTL4ArgumentTableDescriptor alloc] init];
argumentTableDescriptor.maxBufferBindCount = 8;
argumentTableDescriptor.maxTextureBindCount = 8;
argumentTableDescriptor.maxSamplerStateBindCount = 8;
argumentTableDescriptor.supportAttributeStrides = YES; // required: vertex buffer is bound via setAddress:stride:atIndex: for stage_in fetch
bd->SharedMetalContext.argumentTable = [device newArgumentTableWithDescriptor:argumentTableDescriptor error:&error];
IM_ASSERT(bd->SharedMetalContext.argumentTable != nil && error == nil);
return true;
}
void ImGui_ImplMetal4_DestroyDeviceObjects()
{
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
// Destroy all textures
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
if (tex->RefCount == 1)
ImGui_ImplMetal4_DestroyTexture(tex);
[bd->SharedMetalContext.renderPipelineStateCache removeAllObjects];
bd->SharedMetalContext.samplerStateLinear = nil;
bd->SharedMetalContext.samplerStateNearest = nil;
}
bool ImGui_ImplMetal4_Init(id<MTLDevice> device, id<MTL4CommandQueue> commandQueue, int framesInFlight)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
IM_ASSERT(framesInFlight > 0 && "framesInFlight must be at least 1!");
ImGui_ImplMetal4_Data* bd = IM_NEW(ImGui_ImplMetal4_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_metal4";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplMetal4_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplMetal4_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplMetal4_DrawCallback_SetSamplerNearest;
bd->SharedMetalContext = [[MetalContext alloc] init];
bd->SharedMetalContext.device = device;
bd->SharedMetalContext.commandQueue = commandQueue;
bd->SharedMetalContext.framesInFlight = (NSUInteger)framesInFlight;
NSMutableArray<NSMutableArray<MetalBuffer*>*>* bufferCaches = [NSMutableArray array];
for (NSUInteger i = 0; i < framesInFlight; i++)
[bufferCaches addObject:[NSMutableArray array]];
bd->SharedMetalContext.bufferCaches = bufferCaches;
return true;
}
void ImGui_ImplMetal4_Shutdown()
{
ImGui_ImplMetal4_Data* bd = ImGui_ImplMetal4_GetBackendData();
IM_UNUSED(bd);
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplMetal4_DestroyDeviceObjects();
ImGui_ImplMetal4_DestroyBackendData();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
}
@implementation MetalBuffer
- (instancetype)initWithBuffer:(id<MTLBuffer>)buffer
{
if ((self = [super init]))
{
_buffer = buffer;
_lastReuseTime = GetMachAbsoluteTimeInSeconds();
}
return self;
}
@end
#pragma mark - FramebufferDescriptor implementation
@implementation FramebufferDescriptor
- (instancetype)initWithRenderPassDescriptor:(MTL4RenderPassDescriptor*)renderPassDescriptor
{
if ((self = [super init]))
{
_sampleCount = renderPassDescriptor.colorAttachments[0].texture.sampleCount;
_colorPixelFormat = renderPassDescriptor.colorAttachments[0].texture.pixelFormat;
_depthPixelFormat = renderPassDescriptor.depthAttachment.texture.pixelFormat;
_stencilPixelFormat = renderPassDescriptor.stencilAttachment.texture.pixelFormat;
}
return self;
}
- (nonnull id)copyWithZone:(nullable NSZone*)zone
{
FramebufferDescriptor* copy = [[FramebufferDescriptor allocWithZone:zone] init];
copy.sampleCount = self.sampleCount;
copy.colorPixelFormat = self.colorPixelFormat;
copy.depthPixelFormat = self.depthPixelFormat;
copy.stencilPixelFormat = self.stencilPixelFormat;
return copy;
}
- (NSUInteger)hash
{
NSUInteger sc = _sampleCount & 0x3;
NSUInteger cf = _colorPixelFormat & 0x3FF;
NSUInteger df = _depthPixelFormat & 0x3FF;
NSUInteger sf = _stencilPixelFormat & 0x3FF;
NSUInteger hash = (sf << 22) | (df << 12) | (cf << 2) | sc;
return hash;
}
- (BOOL)isEqual:(id)object
{
FramebufferDescriptor* other = object;
if (![other isKindOfClass:[FramebufferDescriptor class]])
return NO;
return other.sampleCount == self.sampleCount &&
other.colorPixelFormat == self.colorPixelFormat &&
other.depthPixelFormat == self.depthPixelFormat &&
other.stencilPixelFormat == self.stencilPixelFormat;
}
@end
#pragma mark - MetalTexture implementation
@implementation MetalTexture
- (instancetype)initWithTexture:(id<MTLTexture>)metalTexture
{
if ((self = [super init]))
self.metalTexture = metalTexture;
return self;
}
@end
#pragma mark - MetalContext implementation
@implementation MetalContext
- (instancetype)init
{
if ((self = [super init]))
{
self.renderPipelineStateCache = [NSMutableDictionary dictionary];
self.bufferCacheLock = [[NSObject alloc] init];
_lastBufferCachePurge = GetMachAbsoluteTimeInSeconds();
}
return self;
}
- (void)dealloc
{
free(_constantBufferContentsArray);
}
- (id<MTLBuffer>)currentConstantBuffer
{
return self.constantBuffers[self.currentFrameSlot];
}
- (ImGui_Metal4_ConstantData*)currentConstantBufferContents
{
return self.constantBufferContentsArray[self.currentFrameSlot];
}
- (MetalBuffer*)dequeueReusableBufferOfLength:(NSUInteger)length device:(id<MTLDevice>)device
{
double now = GetMachAbsoluteTimeInSeconds();
NSMutableArray<MetalBuffer*>* slotCache = self.bufferCaches[self.currentFrameSlot];
@synchronized(self.bufferCacheLock)
{
// Purge old buffers that haven't been useful for a while
if (now - self.lastBufferCachePurge > 1.0)
{
for (NSMutableArray<MetalBuffer*>* cache in self.bufferCaches)
{
NSMutableArray* survivors = [NSMutableArray array];
for (MetalBuffer* candidate in cache)
if (candidate.lastReuseTime > self.lastBufferCachePurge)
[survivors addObject:candidate];
[cache setArray:survivors];
}
self.lastBufferCachePurge = now;
}
// See if we have a buffer we can reuse, from this frame-in-flight slot's own cache
MetalBuffer* bestCandidate = nil;
for (MetalBuffer* candidate in slotCache)
if (candidate.buffer.length >= length && (bestCandidate == nil || bestCandidate.lastReuseTime > candidate.lastReuseTime))
bestCandidate = candidate;
if (bestCandidate != nil)
{
[slotCache removeObject:bestCandidate];
bestCandidate.lastReuseTime = now;
return bestCandidate;
}
}
// No luck; make a new buffer
id<MTLBuffer> backing = [device newBufferWithLength:length options:MTLResourceStorageModeShared];
[self.residencySet addAllocation:backing];
return [[MetalBuffer alloc] initWithBuffer:backing];
}
const char* shaderCode = R"(
#include <metal_stdlib>
using namespace metal;
struct Uniforms {
float4x4 projectionMatrix;
};
struct VertexIn {
float2 position [[attribute(0)]];
float2 texCoords [[attribute(1)]];
uchar4 color [[attribute(2)]];
};
struct VertexOut {
float4 position [[position]];
float2 texCoords;
float4 color;
};
vertex VertexOut vertex_main(VertexIn in [[stage_in]],
constant Uniforms &uniforms [[buffer(1)]])
{
VertexOut out;
out.position = uniforms.projectionMatrix * float4(in.position, 0, 1);
out.texCoords = in.texCoords;
out.color = float4(in.color) / float4(255.0);
return out;
}
fragment half4 fragment_main(VertexOut in [[stage_in]],
texture2d<half, access::sample> texture [[texture(0)]],
sampler textureSampler [[sampler(0)]])
{
half4 texColor = texture.sample(textureSampler, in.texCoords);
return half4(in.color) * texColor;
}
)";
- (id<MTLRenderPipelineState>)renderPipelineStateForFramebufferDescriptor:(FramebufferDescriptor*)descriptor device:(id<MTLDevice>)device
{
NSError* error = nil;
id<MTLLibrary> library = [device newLibraryWithSource:[NSString stringWithUTF8String:shaderCode] options:nil error:&error];
if (library == nil)
{
NSLog(@"Error: failed to create Metal library: %@", error);
return nil;
}
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
if (vertexFunction == nil || fragmentFunction == nil)
{
NSLog(@"Error: failed to find Metal shader functions in library: %@", error);
return nil;
}
MTLVertexDescriptor* vertexDescriptor = [MTLVertexDescriptor vertexDescriptor];
vertexDescriptor.attributes[0].offset = offsetof(ImDrawVert, pos);
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2; // position
vertexDescriptor.attributes[0].bufferIndex = 0;
vertexDescriptor.attributes[1].offset = offsetof(ImDrawVert, uv);
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2; // texCoords
vertexDescriptor.attributes[1].bufferIndex = 0;
vertexDescriptor.attributes[2].offset = offsetof(ImDrawVert, col);
vertexDescriptor.attributes[2].format = MTLVertexFormatUChar4; // color
vertexDescriptor.attributes[2].bufferIndex = 0;
vertexDescriptor.layouts[0].stepRate = 1;
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
vertexDescriptor.layouts[0].stride = sizeof(ImDrawVert);
MTLRenderPipelineDescriptor* pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipelineDescriptor.vertexFunction = vertexFunction;
pipelineDescriptor.fragmentFunction = fragmentFunction;
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
pipelineDescriptor.rasterSampleCount = self.framebufferDescriptor.sampleCount;
pipelineDescriptor.colorAttachments[0].pixelFormat = self.framebufferDescriptor.colorPixelFormat;
pipelineDescriptor.colorAttachments[0].blendingEnabled = YES;
pipelineDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
pipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
pipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
pipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
pipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
pipelineDescriptor.depthAttachmentPixelFormat = self.framebufferDescriptor.depthPixelFormat;
pipelineDescriptor.stencilAttachmentPixelFormat = self.framebufferDescriptor.stencilPixelFormat;
id<MTLRenderPipelineState> renderPipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
if (error != nil)
NSLog(@"Error: failed to create Metal pipeline state: %@", error);
return renderPipelineState;
}
@end
//-----------------------------------------------------------------------------
#endif // #ifndef IMGUI_DISABLE

View file

@ -6,6 +6,7 @@
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// Missing features or Issues:
// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -25,6 +26,10 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-17: OpenGL: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378)
// 2026-09-07: OpenGL: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473)
// 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802)
@ -86,6 +91,9 @@
// OpenGL data
struct ImGui_ImplOpenGL2_Data
{
bool UseTexParameterToSetSampler;
GLuint NextSampler;
ImGui_ImplOpenGL2_Data() { memset((void*)this, 0, sizeof(*this)); }
};
@ -97,37 +105,6 @@ static ImGui_ImplOpenGL2_Data* ImGui_ImplOpenGL2_GetBackendData()
}
// Functions
bool ImGui_ImplOpenGL2_Init()
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl2";
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
return true;
}
void ImGui_ImplOpenGL2_Shutdown()
{
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplOpenGL2_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
void ImGui_ImplOpenGL2_NewFrame()
{
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
@ -138,6 +115,7 @@ void ImGui_ImplOpenGL2_NewFrame()
static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers, polygon fill.
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // In order to composite our output buffer we need to preserve alpha
@ -156,6 +134,9 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid
glShadeModel(GL_SMOOTH);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
bd->UseTexParameterToSetSampler = false;
bd->NextSampler = GL_LINEAR;
// If you are using this code with non-legacy OpenGL header/contexts (which you should not, prefer using imgui_impl_opengl3.cpp!!),
// you may need to backup/reset/restore other state, e.g. for current shader using the commented lines below.
// (DO NOT MODIFY THIS FILE! Add the code in your calling function)
@ -179,14 +160,24 @@ static void ImGui_ImplOpenGL2_SetupRenderState(ImDrawData* draw_data, int fb_wid
glLoadIdentity();
}
// Draw callbacks
// - IMPORTANT: Using DrawCallback_SetSamplerLinear/DrawCallback_SetSamplerNearest will trash glTexParameteri() values for the texture!!
// We cannot decently backup/restore that state because glGetTexParameteriv() is slow on many setups.
// - Using DrawCallback_SetSamplerFromTex will basically instruct the backend to use existing glTexParameteri() values without modifying anything, which is the initial state.
static void ImGui_ImplOpenGL2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_LINEAR; }
static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = true; bd->NextSampler = GL_NEAREST; }
static void ImGui_ImplOpenGL2_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); bd->UseTexParameterToSetSampler = false; }
// OpenGL2 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width == 0 || fb_height == 0)
return;
@ -228,8 +219,7 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplOpenGL2_DrawCallback_ResetRenderState)
ImGui_ImplOpenGL2_SetupRenderState(draw_data, fb_width, fb_height);
else
pcmd->UserCallback(draw_list, pcmd);
@ -246,7 +236,17 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
GLuint pcmd_texture = (GLuint)(intptr_t)pcmd->GetTexID();
glBindTexture(GL_TEXTURE_2D, pcmd_texture);
// Emulate sampler change (even though it is technically part of texture data)
// As a sort of hack/workaround, we only start writing using glTextParameter() if sampler is ever changed explicitly.
if (bd->UseTexParameterToSetSampler)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, bd->NextSampler);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, bd->NextSampler);
}
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset);
}
}
@ -271,6 +271,10 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex)
{
// Backup GL_UNPACK state that we modify, restore on exit.
GLint last_unpack_row_length = 0; GL_CALL(glGetIntegerv(GL_UNPACK_ROW_LENGTH, &last_unpack_row_length));
GLint last_unpack_alignment = 0; GL_CALL(glGetIntegerv(GL_UNPACK_ALIGNMENT, &last_unpack_alignment));
if (tex->Status == ImTextureStatus_WantCreate)
{
// Create and upload new texture to graphics system
@ -280,8 +284,7 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex)
const void* pixels = tex->GetPixels();
GLuint gl_texture_id = 0;
// Upload texture to graphics system
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Upload texture to graphics system (bilinear sampling is required).
GLint last_texture;
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
GL_CALL(glGenTextures(1, &gl_texture_id));
@ -327,6 +330,10 @@ void ImGui_ImplOpenGL2_UpdateTexture(ImTextureData* tex)
tex->SetTexID(ImTextureID_Invalid);
tex->SetStatus(ImTextureStatus_Destroyed);
}
// Restore GL_UNPACK state
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, last_unpack_row_length));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, last_unpack_alignment));
}
bool ImGui_ImplOpenGL2_CreateDeviceObjects()
@ -344,6 +351,43 @@ void ImGui_ImplOpenGL2_DestroyDeviceObjects()
}
}
bool ImGui_ImplOpenGL2_Init()
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplOpenGL2_Data* bd = IM_NEW(ImGui_ImplOpenGL2_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl2";
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL2_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL2_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL2_DrawCallback_SetSamplerNearest;
platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplOpenGL2_DrawCallback_SetSamplerFromTex;
return true;
}
void ImGui_ImplOpenGL2_Shutdown()
{
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplOpenGL2_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
//-----------------------------------------------------------------------------
#if defined(__clang__)

View file

@ -6,6 +6,7 @@
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// Missing features or Issues:
// [ ] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [ ] Renderer: Use of DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest is emulated by poking to glTexParameter(), as legacy OpenGL doesn't have glBindSampler().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.

View file

@ -7,6 +7,7 @@
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplOpenGL3_GetRenderState().
// About WebGL/ES:
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
@ -23,6 +24,13 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-17: OpenGL: Added support for platform_io.DrawCallback_SetSamplerFromTex. (#9378)
// 2026-09-07: OpenGL: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-07-15: OpenGL: Backup and restore GL_UNPACK_ROW_LENGTH and GL_UNPACK_ALIGNMENT in UpdateTexture() to avoid corrupting caller GL state. (#8802, #9473)
// 2026-06-17: OpenGL: Expose selected render state in ImGui_ImplOpenGL3_RenderState, Allowing to dynamically select between use of glBindSampler() and glTexParameter(). You can access in 'void* platform_io.Renderer_RenderState' during rendering.
// 2026-06-03: OpenGL: GLSL version detection assume GLSL 410 when GL context is 4.1. Fixes an issue running on macOS with Wine. (#9427, #6577)
// 2026-04-23: OpenGL: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// (Breaking): this change prioritize using glBindSampler() when available, which would override glTexParameter() settings you may have set on custom textures.
// 2026-03-12: OpenGL: Fixed invalid assert in ImGui_ImplOpenGL3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
// 2025-12-11: OpenGL: Fixed embedded loader multiple init/shutdown cycles broken on some platforms. (#8792, #9112)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
@ -252,6 +260,10 @@ struct ImGui_ImplOpenGL3_Data
bool HasBindSampler;
bool HasClipOrigin;
bool UseBufferSubData;
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
GLuint TexSamplers[2]; // Used if HasBindSimpler. (0=linear, 1=nearest)
#endif
ImVector<char> TempBuffer;
ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
@ -264,6 +276,11 @@ static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState()
{
return (ImGui_ImplOpenGL3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
struct ImGui_ImplOpenGL3_VtxAttribState
@ -312,139 +329,6 @@ static void ImGui_ImplOpenGL3_ShutdownLoader()
}
// Functions
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Initialize loader
if (!ImGui_ImplOpenGL3_InitLoader())
return false;
// Setup backend capabilities flags
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl3";
// Query for GL version (e.g. 320 for GL 3.2)
const char* gl_version_str = (const char*)glGetString(GL_VERSION);
#if defined(IMGUI_IMPL_OPENGL_ES2)
// GLES 2
bd->GlVersion = 200;
bd->GlProfileIsES2 = true;
IM_UNUSED(gl_version_str);
#else
// Desktop or GLES 3
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0)
sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &bd->MaxTextureSize);
#if defined(IMGUI_IMPL_OPENGL_ES3)
bd->GlProfileIsES3 = true;
#else
if (strncmp(gl_version_str, "OpenGL ES 3", 11) == 0)
bd->GlProfileIsES3 = true;
#endif
#if defined(GL_CONTEXT_PROFILE_MASK)
if (!bd->GlProfileIsES3 && bd->GlVersion >= 320)
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
#endif
bd->UseBufferSubData = false;
/*
// Query vendor to enable glBufferSubData kludge
#ifdef _WIN32
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
if (strncmp(vendor, "Intel", 5) == 0)
bd->UseBufferSubData = true;
#endif
*/
#endif
#ifdef IMGUI_IMPL_OPENGL_DEBUG
printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2/IsEs3 = %d/%d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
#endif
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize;
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
if (glsl_version == nullptr)
{
#if defined(IMGUI_IMPL_OPENGL_ES2)
glsl_version = "#version 100";
#elif defined(IMGUI_IMPL_OPENGL_ES3)
glsl_version = "#version 300 es";
#elif defined(__APPLE__)
glsl_version = "#version 150";
#else
glsl_version = "#version 130";
#endif
}
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_COUNTOF(bd->GlslVersionString));
strcpy(bd->GlslVersionString, glsl_version);
strcat(bd->GlslVersionString, "\n");
// Make an arbitrary GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
// Detect extensions we support
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3);
#endif
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
bd->HasBindSampler = (bd->GlVersion >= 330 || bd->GlProfileIsES3);
#endif
bd->HasClipOrigin = (bd->GlVersion >= 450);
#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS
GLint num_extensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
for (GLint i = 0; i < num_extensions; i++)
{
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
bd->HasClipOrigin = true;
}
#endif
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplOpenGL3_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
ImGui_ImplOpenGL3_ShutdownLoader();
}
void ImGui_ImplOpenGL3_NewFrame()
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
@ -456,7 +340,7 @@ void ImGui_ImplOpenGL3_NewFrame()
IM_ASSERT(0 && "ImGui_ImplOpenGL3_CreateDeviceObjects() failed!");
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplOpenGL3_RenderState* render_state, int fb_width, int fb_height, GLuint vertex_array_object)
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
@ -509,9 +393,16 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
glUniform1i(bd->AttribLocationTex, 0);
glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
render_state->UseBindSampler = bd->HasBindSampler;
render_state->UseTexParameterFilter = false;
render_state->CurrentSampler = 0;
render_state->CurrentTexParameterFilter = 0;
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (bd->HasBindSampler)
glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
if (bd->HasBindSampler && render_state->UseBindSampler)
{
render_state->CurrentSampler = bd->TexSamplers[0];
glBindSampler(0, render_state->CurrentSampler); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
}
#endif
(void)vertex_array_object;
@ -530,14 +421,56 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)));
}
static void ImGui_ImplOpenGL3_DrawCallback_SetSampler(unsigned int sampler_idx, unsigned int tex_parameter_filter)
{
ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState();
IM_UNUSED(sampler_idx);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->HasBindSampler && render_state->UseBindSampler)
{
render_state->CurrentSampler = bd->TexSamplers[sampler_idx];
render_state->UseTexParameterFilter = false;
glBindSampler(0, render_state->CurrentSampler);
}
else
#endif
{
render_state->UseTexParameterFilter = true;
render_state->CurrentTexParameterFilter = tex_parameter_filter;
}
}
// Draw callbacks
// - IMPORTANT: Using DrawCallback_SetSamplerLinear/DrawCallback_SetSamplerNearest will trash glTexParameteri() values for the texture if used on a GL context not supporting glBindSampler()!!
// We cannot decently backup/restore that state because glGetTexParameteriv() is slow on many setups.
// - Using DrawCallback_SetSamplerFromTex will basically instruct the backend to use existing glTexParameteri() values without modifying anything.
static void ImGui_ImplOpenGL3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_DrawCallback_SetSampler(0, GL_LINEAR); }
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplOpenGL3_DrawCallback_SetSampler(1, GL_NEAREST); }
static void ImGui_ImplOpenGL3_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*)
{
ImGui_ImplOpenGL3_RenderState* render_state = ImGui_ImplOpenGL3_GetRenderState();
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
if (bd->HasBindSampler)
{
render_state->CurrentSampler = 0;
glBindSampler(0, 0);
}
#endif
render_state->UseBindSampler = false;
render_state->UseTexParameterFilter = false;
}
// OpenGL3 Render function.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0)
return;
@ -598,7 +531,13 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
GL_CALL(glGenVertexArrays(1, &vertex_array_object));
#endif
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
// Setup render state structure (for callbacks and custom texture bindings)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplOpenGL3_RenderState render_state = {};
platform_io.Renderer_RenderState = &render_state;
ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
@ -644,9 +583,8 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
if (pcmd->UserCallback == ImGui_ImplOpenGL3_DrawCallback_ResetRenderState)
ImGui_ImplOpenGL3_SetupRenderState(draw_data, &render_state, fb_width, fb_height, vertex_array_object);
else
pcmd->UserCallback(draw_list, pcmd);
}
@ -663,6 +601,15 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Bind texture, Draw
GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
// Emulate sampler change (even though it is technically part of texture data)
// As a sort of hack/workaround, we only start writing using glTexParameter() if sampler is ever changed explicitly.
if (render_state.UseTexParameterFilter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, render_state.CurrentTexParameterFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, render_state.CurrentTexParameterFilter);
}
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320)
GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset));
@ -672,6 +619,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
}
}
}
platform_io.Renderer_RenderState = nullptr;
// Destroy the temporary VAO
#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
@ -730,13 +678,15 @@ static void ImGui_ImplOpenGL3_DestroyTexture(ImTextureData* tex)
void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
{
// FIXME: Consider backing up and restoring
if (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates)
// Backup GL_UNPACK state that we modify, restore on exit.
GLint last_unpack_row_length = 0; (void)last_unpack_row_length;
GLint last_unpack_alignment = 0; (void)last_unpack_alignment;
const bool last_unpack_state_save_and_restore = (tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates);
if (last_unpack_state_save_and_restore)
{
#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
#endif
#ifdef GL_UNPACK_ALIGNMENT
GL_CALL(glGetIntegerv(GL_UNPACK_ROW_LENGTH, &last_unpack_row_length));
GL_CALL(glGetIntegerv(GL_UNPACK_ALIGNMENT, &last_unpack_alignment));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
#endif
}
@ -750,8 +700,7 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
const void* pixels = tex->GetPixels();
GLuint gl_texture_id = 0;
// Upload texture to graphics system
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Upload texture to graphics system (bilinear sampling is required).
GLint last_texture;
GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
GL_CALL(glGenTextures(1, &gl_texture_id));
@ -760,6 +709,9 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
#if GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
#endif
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->Width, tex->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
// Store identifiers
@ -782,7 +734,6 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, tex->Width));
for (ImTextureRect& r : tex->Updates)
GL_CALL(glTexSubImage2D(GL_TEXTURE_2D, 0, r.x, r.y, r.w, r.h, GL_RGBA, GL_UNSIGNED_BYTE, tex->GetPixelsAt(r.x, r.y)));
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
#else
// GL ES doesn't have GL_UNPACK_ROW_LENGTH, so we need to (A) copy to a contiguous buffer or (B) upload line by line.
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
@ -802,6 +753,15 @@ void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex)
}
else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0)
ImGui_ImplOpenGL3_DestroyTexture(tex);
// Restore GL_UNPACK state
if (last_unpack_state_save_and_restore)
{
#ifdef GL_UNPACK_ROW_LENGTH
GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, last_unpack_row_length));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, last_unpack_alignment));
#endif
}
}
// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
@ -1028,6 +988,20 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
glGenBuffers(1, &bd->VboHandle);
glGenBuffers(1, &bd->ElementsHandle);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (bd->HasBindSampler)
{
glGenSamplers(2, &bd->TexSamplers[0]);
for (int sampler_n = 0; sampler_n < 2; sampler_n++)
{
GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_MIN_FILTER, (sampler_n == 0) ? GL_LINEAR : GL_NEAREST));
GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_MAG_FILTER, (sampler_n == 0) ? GL_LINEAR : GL_NEAREST));
GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL_CALL(glSamplerParameteri(bd->TexSamplers[sampler_n], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
}
}
#endif
// Restore modified GL state
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
@ -1045,6 +1019,9 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
{
ImGui_ImplOpenGL3_InitLoader();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
if (bd->TexSamplers[0]) { glDeleteSamplers(2, &bd->TexSamplers[0]); bd->TexSamplers[0] = bd->TexSamplers[1] = 0; }
#endif
if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
@ -1055,6 +1032,146 @@ void ImGui_ImplOpenGL3_DestroyDeviceObjects()
ImGui_ImplOpenGL3_DestroyTexture(tex);
}
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
// Initialize loader
if (!ImGui_ImplOpenGL3_InitLoader())
return false;
// Setup backend capabilities flags
ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_opengl3";
// Query for GL version (e.g. 320 for GL 3.2)
const char* gl_version_str = (const char*)glGetString(GL_VERSION);
#if defined(IMGUI_IMPL_OPENGL_ES2)
// GLES 2
bd->GlVersion = 200;
bd->GlProfileIsES2 = true;
IM_UNUSED(gl_version_str);
#else
// Desktop or GLES 3
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0)
sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
bd->GlVersion = (GLuint)(major * 100 + minor * 10);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &bd->MaxTextureSize);
#if defined(IMGUI_IMPL_OPENGL_ES3)
bd->GlProfileIsES3 = true;
#else
if (strncmp(gl_version_str, "OpenGL ES 3", 11) == 0)
bd->GlProfileIsES3 = true;
#endif
#if defined(GL_CONTEXT_PROFILE_MASK)
if (!bd->GlProfileIsES3 && bd->GlVersion >= 320)
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
#endif
bd->UseBufferSubData = false;
/*
// Query vendor to enable glBufferSubData kludge
#ifdef _WIN32
if (const char* vendor = (const char*)glGetString(GL_VENDOR))
if (strncmp(vendor, "Intel", 5) == 0)
bd->UseBufferSubData = true;
#endif
*/
#endif
#ifdef IMGUI_IMPL_OPENGL_DEBUG
printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2/IsEs3 = %d/%d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
#endif
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
#endif
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.Renderer_TextureMaxWidth = platform_io.Renderer_TextureMaxHeight = (int)bd->MaxTextureSize;
platform_io.DrawCallback_ResetRenderState = ImGui_ImplOpenGL3_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest;
platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplOpenGL3_DrawCallback_SetSamplerFromTex;
// Store GLSL version string so we can refer to it later in case we recreate shaders.
// Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
if (glsl_version == nullptr)
{
#if defined(IMGUI_IMPL_OPENGL_ES2)
glsl_version = "#version 100";
#elif defined(IMGUI_IMPL_OPENGL_ES3)
glsl_version = "#version 300 es";
#elif defined(__APPLE__)
glsl_version = "#version 150";
#else
if (bd->GlVersion >= 410)
glsl_version = "#version 410";
else
glsl_version = "#version 130";
#endif
}
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_COUNTOF(bd->GlslVersionString));
strcpy(bd->GlslVersionString, glsl_version);
strcat(bd->GlslVersionString, "\n");
// Make an arbitrary GL call (we don't actually need the result)
// IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
GLint current_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
// Detect extensions we support
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3);
#endif
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
bd->HasBindSampler = (bd->GlVersion >= 330 || bd->GlProfileIsES3);
#endif
bd->HasClipOrigin = (bd->GlVersion >= 450);
#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS
GLint num_extensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
for (GLint i = 0; i < num_extensions; i++)
{
const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
bd->HasClipOrigin = true;
}
#endif
return true;
}
void ImGui_ImplOpenGL3_Shutdown()
{
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplOpenGL3_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
ImGui_ImplOpenGL3_ShutdownLoader();
}
//-----------------------------------------------------------------------------
#if defined(__GNUC__)

View file

@ -7,6 +7,7 @@
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [x] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset) [Desktop OpenGL only!]
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplOpenGL3_GetRenderState().
// About WebGL/ES:
// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
@ -65,4 +66,16 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_UpdateTexture(ImTextureData* tex);
#endif
// [BETA] Selected render state data shared with callbacks.
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplOpenGL3_RenderDrawData() call.
// (Please open an issue if you feel you need access to more data)
struct ImGui_ImplOpenGL3_RenderState
{
bool UseBindSampler;
bool UseTexParameterFilter;
unsigned int CurrentSampler; // (GLuint) Used if UseBindSampler == true (and are available), otherwise always 0
unsigned int CurrentTexParameterFilter; // (GLuint) Used if UseTexParameterFilter == true
};
IMGUI_IMPL_API ImGui_ImplOpenGL3_RenderState* ImGui_ImplOpenGL3_GetRenderState();
#endif // #ifndef IMGUI_DISABLE

View file

@ -114,7 +114,7 @@ extern "C" {
#define GLAPI extern
#endif
/* glcorearb.h is for use with OpenGL core profile implementations.
** It should should be placed in the same directory as gl.h and
** It should be placed in the same directory as gl.h and
** included as <GL/glcorearb.h>.
**
** glcorearb.h includes only APIs in the latest OpenGL core profile

759
backends/imgui_impl_qnx.cpp Normal file
View file

@ -0,0 +1,759 @@
// dear imgui: Platform Backend for QNX Screen
// This needs to be used along with a Renderer Backend (e.g. OpenGL3, Vulkan).
// Implemented features:
// [X] Platform: Keyboard support. Uses io.AddKeyEvent() and native QNX key symbols.
// [X] Platform: Mouse support. Handles position, three buttons and horizontal/vertical wheels.
// [X] Platform: Touch support. Maps the first active touch contact to the primary mouse button.
// [X] Platform: Focus and window-size updates.
// Missing features or Issues:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support.
// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors).
// [ ] Platform: Multi-viewport support.
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-08-04: Initial QNX Screen backend. (#9492)
#include "imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_qnx.h"
#include <float.h>
#include <stdint.h>
#include <string.h>
#include <sys/keycodes.h>
#include <time.h>
static unsigned int ImGui_ImplQNX_KeySymToUnicode(unsigned int keysym);
struct ImGui_ImplQNX_Data
{
screen_context_t Context;
screen_window_t Window;
uint64_t TimeNanoseconds;
int MouseButtons;
int ActiveTouchId;
bool LeftSuper;
bool RightSuper;
ImGui_ImplQNX_Data()
{
memset(this, 0, sizeof(*this));
ActiveTouchId = -1;
}
};
static ImGui_ImplQNX_Data* ImGui_ImplQNX_GetBackendData()
{
return ImGui::GetCurrentContext() != nullptr ? (ImGui_ImplQNX_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
}
static uint64_t ImGui_ImplQNX_GetTimeNanoseconds()
{
struct timespec timestamp = {};
if (clock_gettime(CLOCK_MONOTONIC, &timestamp) != 0)
{
return 0;
}
return (uint64_t)timestamp.tv_sec * UINT64_C(1000000000) + (uint64_t)timestamp.tv_nsec;
}
static ImGuiKey ImGui_ImplQNX_KeyCodeToImGuiKey(int key_code)
{
switch (key_code)
{
case KEYCODE_TAB: return ImGuiKey_Tab;
case KEYCODE_LEFT: return ImGuiKey_LeftArrow;
case KEYCODE_RIGHT: return ImGuiKey_RightArrow;
case KEYCODE_UP: return ImGuiKey_UpArrow;
case KEYCODE_DOWN: return ImGuiKey_DownArrow;
case KEYCODE_PG_UP: return ImGuiKey_PageUp;
case KEYCODE_PG_DOWN: return ImGuiKey_PageDown;
case KEYCODE_HOME: return ImGuiKey_Home;
case KEYCODE_END: return ImGuiKey_End;
case KEYCODE_INSERT: return ImGuiKey_Insert;
case KEYCODE_DELETE: return ImGuiKey_Delete;
case KEYCODE_BACKSPACE: return ImGuiKey_Backspace;
case KEYCODE_SPACE: return ImGuiKey_Space;
case KEYCODE_RETURN: return ImGuiKey_Enter;
case KEYCODE_ESCAPE: return ImGuiKey_Escape;
case KEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
case KEYCODE_COMMA: return ImGuiKey_Comma;
case KEYCODE_MINUS: return ImGuiKey_Minus;
case KEYCODE_PERIOD: return ImGuiKey_Period;
case KEYCODE_SLASH: return ImGuiKey_Slash;
case KEYCODE_SEMICOLON: return ImGuiKey_Semicolon;
case KEYCODE_EQUAL: return ImGuiKey_Equal;
case KEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
case KEYCODE_BACK_SLASH: return ImGuiKey_Backslash;
case KEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
case KEYCODE_GRAVE: return ImGuiKey_GraveAccent;
case KEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
case KEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
case KEYCODE_NUM_LOCK: return ImGuiKey_NumLock;
case KEYCODE_PRINT: return ImGuiKey_PrintScreen;
case KEYCODE_PAUSE: return ImGuiKey_Pause;
case KEYCODE_KP_DIVIDE: return ImGuiKey_KeypadDivide;
case KEYCODE_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
case KEYCODE_KP_MINUS: return ImGuiKey_KeypadSubtract;
case KEYCODE_KP_PLUS: return ImGuiKey_KeypadAdd;
case KEYCODE_KP_ENTER: return ImGuiKey_KeypadEnter;
// QNX reports keypad digits by their navigation key-cap names.
case KEYCODE_KP_INSERT: return ImGuiKey_Keypad0;
case KEYCODE_KP_END: return ImGuiKey_Keypad1;
case KEYCODE_KP_DOWN: return ImGuiKey_Keypad2;
case KEYCODE_KP_PG_DOWN: return ImGuiKey_Keypad3;
case KEYCODE_KP_LEFT: return ImGuiKey_Keypad4;
case KEYCODE_KP_FIVE: return ImGuiKey_Keypad5;
case KEYCODE_KP_RIGHT: return ImGuiKey_Keypad6;
case KEYCODE_KP_HOME: return ImGuiKey_Keypad7;
case KEYCODE_KP_UP: return ImGuiKey_Keypad8;
case KEYCODE_KP_PG_UP: return ImGuiKey_Keypad9;
case KEYCODE_KP_DELETE: return ImGuiKey_KeypadDecimal;
case KEYCODE_LEFT_CTRL: return ImGuiKey_LeftCtrl;
case KEYCODE_LEFT_SHIFT: return ImGuiKey_LeftShift;
case KEYCODE_LEFT_ALT: return ImGuiKey_LeftAlt;
case KEYCODE_RIGHT_CTRL: return ImGuiKey_RightCtrl;
case KEYCODE_RIGHT_SHIFT: return ImGuiKey_RightShift;
case KEYCODE_RIGHT_ALT: return ImGuiKey_RightAlt;
case KEYCODE_LEFT_HYPER: return ImGuiKey_LeftSuper;
case KEYCODE_RIGHT_HYPER: return ImGuiKey_RightSuper;
case KEYCODE_MENU: return ImGuiKey_Menu;
case KEYCODE_ZERO: return ImGuiKey_0;
case KEYCODE_ONE: return ImGuiKey_1;
case KEYCODE_TWO: return ImGuiKey_2;
case KEYCODE_THREE: return ImGuiKey_3;
case KEYCODE_FOUR: return ImGuiKey_4;
case KEYCODE_FIVE: return ImGuiKey_5;
case KEYCODE_SIX: return ImGuiKey_6;
case KEYCODE_SEVEN: return ImGuiKey_7;
case KEYCODE_EIGHT: return ImGuiKey_8;
case KEYCODE_NINE: return ImGuiKey_9;
case KEYCODE_A: return ImGuiKey_A;
case KEYCODE_B: return ImGuiKey_B;
case KEYCODE_C: return ImGuiKey_C;
case KEYCODE_D: return ImGuiKey_D;
case KEYCODE_E: return ImGuiKey_E;
case KEYCODE_F: return ImGuiKey_F;
case KEYCODE_G: return ImGuiKey_G;
case KEYCODE_H: return ImGuiKey_H;
case KEYCODE_I: return ImGuiKey_I;
case KEYCODE_J: return ImGuiKey_J;
case KEYCODE_K: return ImGuiKey_K;
case KEYCODE_L: return ImGuiKey_L;
case KEYCODE_M: return ImGuiKey_M;
case KEYCODE_N: return ImGuiKey_N;
case KEYCODE_O: return ImGuiKey_O;
case KEYCODE_P: return ImGuiKey_P;
case KEYCODE_Q: return ImGuiKey_Q;
case KEYCODE_R: return ImGuiKey_R;
case KEYCODE_S: return ImGuiKey_S;
case KEYCODE_T: return ImGuiKey_T;
case KEYCODE_U: return ImGuiKey_U;
case KEYCODE_V: return ImGuiKey_V;
case KEYCODE_W: return ImGuiKey_W;
case KEYCODE_X: return ImGuiKey_X;
case KEYCODE_Y: return ImGuiKey_Y;
case KEYCODE_Z: return ImGuiKey_Z;
case KEYCODE_F1: return ImGuiKey_F1;
case KEYCODE_F2: return ImGuiKey_F2;
case KEYCODE_F3: return ImGuiKey_F3;
case KEYCODE_F4: return ImGuiKey_F4;
case KEYCODE_F5: return ImGuiKey_F5;
case KEYCODE_F6: return ImGuiKey_F6;
case KEYCODE_F7: return ImGuiKey_F7;
case KEYCODE_F8: return ImGuiKey_F8;
case KEYCODE_F9: return ImGuiKey_F9;
case KEYCODE_F10: return ImGuiKey_F10;
case KEYCODE_F11: return ImGuiKey_F11;
case KEYCODE_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
static void ImGui_ImplQNX_UpdateKeyModifiers(ImGuiIO& io, ImGui_ImplQNX_Data* bd, int modifiers, ImGuiKey key, bool down)
{
// SCREEN_PROPERTY_MODIFIERS is the authoritative state for Shift/Ctrl/Alt.
// Tracking those keys locally loses sticky modifiers and can become stale if
// a key transition is consumed elsewhere. qterm uses this same Screen state.
if (key == ImGuiKey_LeftSuper)
{
bd->LeftSuper = down;
}
else if (key == ImGuiKey_RightSuper)
{
bd->RightSuper = down;
}
io.AddKeyEvent(ImGuiMod_Ctrl, (modifiers & KEYMOD_CTRL) != 0);
io.AddKeyEvent(ImGuiMod_Shift, (modifiers & KEYMOD_SHIFT) != 0);
io.AddKeyEvent(ImGuiMod_Alt, (modifiers & KEYMOD_ALT) != 0);
io.AddKeyEvent(ImGuiMod_Super, bd->LeftSuper || bd->RightSuper);
}
static void ImGui_ImplQNX_ClearModifierState(ImGuiIO& io, ImGui_ImplQNX_Data* bd)
{
bd->LeftSuper = false;
bd->RightSuper = false;
io.AddKeyEvent(ImGuiMod_Ctrl, false);
io.AddKeyEvent(ImGuiMod_Shift, false);
io.AddKeyEvent(ImGuiMod_Alt, false);
io.AddKeyEvent(ImGuiMod_Super, false);
}
static bool ImGui_ImplQNX_IsTextCodePoint(unsigned int code_point)
{
// At this point the QNX keysym has already been converted to Unicode.
// Do not reject Unicode private-use characters: a user keymap may emit one.
const bool surrogate = code_point >= 0xd800u && code_point <= 0xdfffu;
const bool control = code_point < 0x20u || (code_point >= 0x7fu && code_point <= 0x9fu);
return code_point <= IM_UNICODE_CODEPOINT_MAX && !surrogate && !control;
}
static bool ImGui_ImplQNX_ProcessKeyboardEvent(ImGui_ImplQNX_Data* bd, screen_event_t event)
{
int flags = 0;
int modifiers = 0;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_FLAGS, &flags) != 0 ||
screen_get_event_property_iv(event, SCREEN_PROPERTY_MODIFIERS, &modifiers) != 0)
{
return false;
}
// KEY_CAP is the unmodified key identity used for ImGuiKey events. SYM is
// the layout/modifier-translated QNX keysym used for text input.
int key_cap = 0;
int key_sym = 0;
int scan_code = 0;
const bool cap_valid = (flags & SCREEN_FLAG_CAP_VALID) != 0;
const bool sym_valid = (flags & SCREEN_FLAG_SYM_VALID) != 0;
const bool scan_valid = (flags & SCREEN_FLAG_SCAN_VALID) != 0;
const bool down = (flags & (SCREEN_FLAG_KEY_DOWN | SCREEN_FLAG_KEY_REPEAT)) != 0;
if (cap_valid && screen_get_event_property_iv(event, SCREEN_PROPERTY_KEY_CAP, &key_cap) != 0)
{
return false;
}
if (sym_valid && screen_get_event_property_iv(event, SCREEN_PROPERTY_SYM, &key_sym) != 0)
{
return false;
}
if (scan_valid && screen_get_event_property_iv(event, SCREEN_PROPERTY_SCAN, &scan_code) != 0)
{
scan_code = 0;
}
const ImGuiKey key = cap_valid ? ImGui_ImplQNX_KeyCodeToImGuiKey(key_cap) : ImGuiKey_None;
ImGuiIO& io = ImGui::GetIO();
// Modifier events must precede the ordinary key event in Dear ImGui's queue.
// Unlike qterm, we still submit the individual modifier key because ImGui
// exposes Left/Right Ctrl, Shift, Alt and Super as named keys.
ImGui_ImplQNX_UpdateKeyModifiers(io, bd, modifiers, key, down);
if (key != ImGuiKey_None)
{
io.AddKeyEvent(key, down);
io.SetKeyEventNativeData(key, key_cap, scan_code);
}
bool text_added = false;
if (down && sym_valid && key_sym >= 0)
{
const unsigned int keysym = (unsigned int)key_sym;
// QNX special/function symbols begin at KEYCODE_PC_KEYS. Printable
// symbols below that boundary use X11 keysym encoding. Also accept the
// standard directly encoded UCS keysym form (0x01000000 | codepoint).
if (keysym < (unsigned int)KEYCODE_PC_KEYS || (keysym & 0xff000000u) == 0x01000000u)
{
const unsigned int code_point = ImGui_ImplQNX_KeySymToUnicode(keysym);
if (ImGui_ImplQNX_IsTextCodePoint(code_point))
{
io.AddInputCharacter(code_point);
text_added = true;
}
}
}
return key != ImGuiKey_None || text_added || cap_valid || sym_valid;
}
static bool ImGui_ImplQNX_ProcessPointerEvent(ImGui_ImplQNX_Data* bd, screen_event_t event)
{
int position[2] = {};
int buttons = 0;
int wheel_vertical = 0;
int wheel_horizontal = 0;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, position) != 0 &&
screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, position) != 0)
{
return false;
}
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_BUTTONS, &buttons) != 0)
{
buttons = bd->MouseButtons;
}
ImGuiIO& io = ImGui::GetIO();
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
io.AddMousePosEvent((float)position[0], (float)position[1]);
const int changed_buttons = buttons ^ bd->MouseButtons;
if ((changed_buttons & SCREEN_LEFT_MOUSE_BUTTON) != 0)
{
io.AddMouseButtonEvent(0, (buttons & SCREEN_LEFT_MOUSE_BUTTON) != 0);
}
if ((changed_buttons & SCREEN_RIGHT_MOUSE_BUTTON) != 0)
{
io.AddMouseButtonEvent(1, (buttons & SCREEN_RIGHT_MOUSE_BUTTON) != 0);
}
if ((changed_buttons & SCREEN_MIDDLE_MOUSE_BUTTON) != 0)
{
io.AddMouseButtonEvent(2, (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) != 0);
}
bd->MouseButtons = buttons;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel_vertical) != 0)
{
wheel_vertical = 0;
}
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_MOUSE_HORIZONTAL_WHEEL, &wheel_horizontal) != 0)
{
wheel_horizontal = 0;
}
if (wheel_vertical != 0 || wheel_horizontal != 0)
{
// Screen: up/left are negative. Dear ImGui: up/left are positive.
io.AddMouseWheelEvent((float)-wheel_horizontal, (float)-wheel_vertical);
}
return true;
}
static bool ImGui_ImplQNX_ProcessTouchEvent(ImGui_ImplQNX_Data* bd, screen_event_t event, int event_type)
{
int touch_id = -1;
int position[2] = {};
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TOUCH_ID, &touch_id) != 0)
{
return false;
}
const bool is_release = event_type == SCREEN_EVENT_MTOUCH_RELEASE;
if (bd->ActiveTouchId != -1 && touch_id != bd->ActiveTouchId)
{
return false;
}
ImGuiIO& io = ImGui::GetIO();
io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
if (!is_release)
{
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_SOURCE_POSITION, position) != 0 &&
screen_get_event_property_iv(event, SCREEN_PROPERTY_POSITION, position) != 0)
{
return false;
}
io.AddMousePosEvent((float)position[0], (float)position[1]);
}
if (event_type == SCREEN_EVENT_MTOUCH_TOUCH)
{
bd->ActiveTouchId = touch_id;
io.AddMouseButtonEvent(0, true);
}
else if (is_release)
{
io.AddMouseButtonEvent(0, false);
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
bd->ActiveTouchId = -1;
}
return true;
}
bool ImGui_ImplQNX_ProcessEvent(screen_event_t event)
{
ImGui_ImplQNX_Data* bd = ImGui_ImplQNX_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplQNX_Init()?");
if (bd == nullptr || event == nullptr)
{
return false;
}
int event_type = SCREEN_EVENT_NONE;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_TYPE, &event_type) != 0 || event_type == SCREEN_EVENT_NONE)
{
return false;
}
switch (event_type)
{
case SCREEN_EVENT_KEYBOARD:
return ImGui_ImplQNX_ProcessKeyboardEvent(bd, event);
case SCREEN_EVENT_POINTER:
return ImGui_ImplQNX_ProcessPointerEvent(bd, event);
case SCREEN_EVENT_MTOUCH_TOUCH:
case SCREEN_EVENT_MTOUCH_MOVE:
case SCREEN_EVENT_MTOUCH_RELEASE:
return ImGui_ImplQNX_ProcessTouchEvent(bd, event, event_type);
case SCREEN_EVENT_PROPERTY:
{
int property = 0;
if (screen_get_event_property_iv(event, SCREEN_PROPERTY_NAME, &property) != 0)
{
return false;
}
if (property == SCREEN_PROPERTY_FOCUS)
{
int focused = 0;
if (screen_get_window_property_iv(bd->Window, SCREEN_PROPERTY_FOCUS, &focused) == 0)
{
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(focused != 0);
if (focused == 0)
{
ImGui_ImplQNX_ClearModifierState(io, bd);
}
}
return true;
}
if (property == SCREEN_PROPERTY_SIZE || property == SCREEN_PROPERTY_BUFFER_SIZE || property == SCREEN_PROPERTY_VISIBLE)
{
return true;
}
return false;
}
case SCREEN_EVENT_CLOSE:
{
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(false);
ImGui_ImplQNX_ClearModifierState(io, bd);
return true;
}
default:
return false;
}
}
bool ImGui_ImplQNX_Init(screen_context_t context, screen_window_t window)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
IM_ASSERT(context != nullptr && window != nullptr);
if (context == nullptr || window == nullptr)
{
return false;
}
ImGui_ImplQNX_Data* bd = IM_NEW(ImGui_ImplQNX_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_qnx";
bd->Context = context;
bd->Window = window;
bd->TimeNanoseconds = ImGui_ImplQNX_GetTimeNanoseconds();
int focused = 0;
if (screen_get_window_property_iv(window, SCREEN_PROPERTY_FOCUS, &focused) == 0)
{
io.AddFocusEvent(focused != 0);
}
return true;
}
void ImGui_ImplQNX_Shutdown()
{
ImGui_ImplQNX_Data* bd = ImGui_ImplQNX_GetBackendData();
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
if (bd == nullptr)
{
return;
}
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = nullptr;
io.BackendPlatformUserData = nullptr;
IM_DELETE(bd);
}
void ImGui_ImplQNX_NewFrame()
{
ImGui_ImplQNX_Data* bd = ImGui_ImplQNX_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplQNX_Init()?");
if (bd == nullptr)
{
return;
}
ImGuiIO& io = ImGui::GetIO();
int size[2] = {};
if (screen_get_window_property_iv(bd->Window, SCREEN_PROPERTY_BUFFER_SIZE, size) != 0 ||
size[0] <= 0 || size[1] <= 0)
{
size[0] = 0;
size[1] = 0;
(void)screen_get_window_property_iv(bd->Window, SCREEN_PROPERTY_SIZE, size);
}
if (size[0] > 0 && size[1] > 0)
{
io.DisplaySize = ImVec2((float)size[0], (float)size[1]);
io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
}
const uint64_t current_time = ImGui_ImplQNX_GetTimeNanoseconds();
if (current_time > bd->TimeNanoseconds && bd->TimeNanoseconds != 0)
{
io.DeltaTime = (float)((double)(current_time - bd->TimeNanoseconds) / 1000000000.0);
}
else
{
io.DeltaTime = 1.0f / 60.0f;
}
bd->TimeNanoseconds = current_time;
}
// Generated by Markus Kuhn's public-domain unicode/convmap.pl from X11 keysymdef.h and UnicodeData.
// Original source: https://www.cl.cam.ac.uk/~mgk25/ucs/keysym2ucs.c
// The table must remain sorted by keysym for the binary search below.
struct ImGui_ImplQNX_KeySymPair
{
uint16_t KeySym;
uint16_t Unicode;
};
static const ImGui_ImplQNX_KeySymPair ImGui_ImplQNX_KeySymTable[] =
{
{ 0x01a1, 0x0104 }, { 0x01a2, 0x02d8 }, { 0x01a3, 0x0141 }, { 0x01a5, 0x013d },
{ 0x01a6, 0x015a }, { 0x01a9, 0x0160 }, { 0x01aa, 0x015e }, { 0x01ab, 0x0164 },
{ 0x01ac, 0x0179 }, { 0x01ae, 0x017d }, { 0x01af, 0x017b }, { 0x01b1, 0x0105 },
{ 0x01b2, 0x02db }, { 0x01b3, 0x0142 }, { 0x01b5, 0x013e }, { 0x01b6, 0x015b },
{ 0x01b7, 0x02c7 }, { 0x01b9, 0x0161 }, { 0x01ba, 0x015f }, { 0x01bb, 0x0165 },
{ 0x01bc, 0x017a }, { 0x01bd, 0x02dd }, { 0x01be, 0x017e }, { 0x01bf, 0x017c },
{ 0x01c0, 0x0154 }, { 0x01c3, 0x0102 }, { 0x01c5, 0x0139 }, { 0x01c6, 0x0106 },
{ 0x01c8, 0x010c }, { 0x01ca, 0x0118 }, { 0x01cc, 0x011a }, { 0x01cf, 0x010e },
{ 0x01d0, 0x0110 }, { 0x01d1, 0x0143 }, { 0x01d2, 0x0147 }, { 0x01d5, 0x0150 },
{ 0x01d8, 0x0158 }, { 0x01d9, 0x016e }, { 0x01db, 0x0170 }, { 0x01de, 0x0162 },
{ 0x01e0, 0x0155 }, { 0x01e3, 0x0103 }, { 0x01e5, 0x013a }, { 0x01e6, 0x0107 },
{ 0x01e8, 0x010d }, { 0x01ea, 0x0119 }, { 0x01ec, 0x011b }, { 0x01ef, 0x010f },
{ 0x01f0, 0x0111 }, { 0x01f1, 0x0144 }, { 0x01f2, 0x0148 }, { 0x01f5, 0x0151 },
{ 0x01f8, 0x0159 }, { 0x01f9, 0x016f }, { 0x01fb, 0x0171 }, { 0x01fe, 0x0163 },
{ 0x01ff, 0x02d9 }, { 0x02a1, 0x0126 }, { 0x02a6, 0x0124 }, { 0x02a9, 0x0130 },
{ 0x02ab, 0x011e }, { 0x02ac, 0x0134 }, { 0x02b1, 0x0127 }, { 0x02b6, 0x0125 },
{ 0x02b9, 0x0131 }, { 0x02bb, 0x011f }, { 0x02bc, 0x0135 }, { 0x02c5, 0x010a },
{ 0x02c6, 0x0108 }, { 0x02d5, 0x0120 }, { 0x02d8, 0x011c }, { 0x02dd, 0x016c },
{ 0x02de, 0x015c }, { 0x02e5, 0x010b }, { 0x02e6, 0x0109 }, { 0x02f5, 0x0121 },
{ 0x02f8, 0x011d }, { 0x02fd, 0x016d }, { 0x02fe, 0x015d }, { 0x03a2, 0x0138 },
{ 0x03a3, 0x0156 }, { 0x03a5, 0x0128 }, { 0x03a6, 0x013b }, { 0x03aa, 0x0112 },
{ 0x03ab, 0x0122 }, { 0x03ac, 0x0166 }, { 0x03b3, 0x0157 }, { 0x03b5, 0x0129 },
{ 0x03b6, 0x013c }, { 0x03ba, 0x0113 }, { 0x03bb, 0x0123 }, { 0x03bc, 0x0167 },
{ 0x03bd, 0x014a }, { 0x03bf, 0x014b }, { 0x03c0, 0x0100 }, { 0x03c7, 0x012e },
{ 0x03cc, 0x0116 }, { 0x03cf, 0x012a }, { 0x03d1, 0x0145 }, { 0x03d2, 0x014c },
{ 0x03d3, 0x0136 }, { 0x03d9, 0x0172 }, { 0x03dd, 0x0168 }, { 0x03de, 0x016a },
{ 0x03e0, 0x0101 }, { 0x03e7, 0x012f }, { 0x03ec, 0x0117 }, { 0x03ef, 0x012b },
{ 0x03f1, 0x0146 }, { 0x03f2, 0x014d }, { 0x03f3, 0x0137 }, { 0x03f9, 0x0173 },
{ 0x03fd, 0x0169 }, { 0x03fe, 0x016b }, { 0x047e, 0x203e }, { 0x04a1, 0x3002 },
{ 0x04a2, 0x300c }, { 0x04a3, 0x300d }, { 0x04a4, 0x3001 }, { 0x04a5, 0x30fb },
{ 0x04a6, 0x30f2 }, { 0x04a7, 0x30a1 }, { 0x04a8, 0x30a3 }, { 0x04a9, 0x30a5 },
{ 0x04aa, 0x30a7 }, { 0x04ab, 0x30a9 }, { 0x04ac, 0x30e3 }, { 0x04ad, 0x30e5 },
{ 0x04ae, 0x30e7 }, { 0x04af, 0x30c3 }, { 0x04b0, 0x30fc }, { 0x04b1, 0x30a2 },
{ 0x04b2, 0x30a4 }, { 0x04b3, 0x30a6 }, { 0x04b4, 0x30a8 }, { 0x04b5, 0x30aa },
{ 0x04b6, 0x30ab }, { 0x04b7, 0x30ad }, { 0x04b8, 0x30af }, { 0x04b9, 0x30b1 },
{ 0x04ba, 0x30b3 }, { 0x04bb, 0x30b5 }, { 0x04bc, 0x30b7 }, { 0x04bd, 0x30b9 },
{ 0x04be, 0x30bb }, { 0x04bf, 0x30bd }, { 0x04c0, 0x30bf }, { 0x04c1, 0x30c1 },
{ 0x04c2, 0x30c4 }, { 0x04c3, 0x30c6 }, { 0x04c4, 0x30c8 }, { 0x04c5, 0x30ca },
{ 0x04c6, 0x30cb }, { 0x04c7, 0x30cc }, { 0x04c8, 0x30cd }, { 0x04c9, 0x30ce },
{ 0x04ca, 0x30cf }, { 0x04cb, 0x30d2 }, { 0x04cc, 0x30d5 }, { 0x04cd, 0x30d8 },
{ 0x04ce, 0x30db }, { 0x04cf, 0x30de }, { 0x04d0, 0x30df }, { 0x04d1, 0x30e0 },
{ 0x04d2, 0x30e1 }, { 0x04d3, 0x30e2 }, { 0x04d4, 0x30e4 }, { 0x04d5, 0x30e6 },
{ 0x04d6, 0x30e8 }, { 0x04d7, 0x30e9 }, { 0x04d8, 0x30ea }, { 0x04d9, 0x30eb },
{ 0x04da, 0x30ec }, { 0x04db, 0x30ed }, { 0x04dc, 0x30ef }, { 0x04dd, 0x30f3 },
{ 0x04de, 0x309b }, { 0x04df, 0x309c }, { 0x05ac, 0x060c }, { 0x05bb, 0x061b },
{ 0x05bf, 0x061f }, { 0x05c1, 0x0621 }, { 0x05c2, 0x0622 }, { 0x05c3, 0x0623 },
{ 0x05c4, 0x0624 }, { 0x05c5, 0x0625 }, { 0x05c6, 0x0626 }, { 0x05c7, 0x0627 },
{ 0x05c8, 0x0628 }, { 0x05c9, 0x0629 }, { 0x05ca, 0x062a }, { 0x05cb, 0x062b },
{ 0x05cc, 0x062c }, { 0x05cd, 0x062d }, { 0x05ce, 0x062e }, { 0x05cf, 0x062f },
{ 0x05d0, 0x0630 }, { 0x05d1, 0x0631 }, { 0x05d2, 0x0632 }, { 0x05d3, 0x0633 },
{ 0x05d4, 0x0634 }, { 0x05d5, 0x0635 }, { 0x05d6, 0x0636 }, { 0x05d7, 0x0637 },
{ 0x05d8, 0x0638 }, { 0x05d9, 0x0639 }, { 0x05da, 0x063a }, { 0x05e0, 0x0640 },
{ 0x05e1, 0x0641 }, { 0x05e2, 0x0642 }, { 0x05e3, 0x0643 }, { 0x05e4, 0x0644 },
{ 0x05e5, 0x0645 }, { 0x05e6, 0x0646 }, { 0x05e7, 0x0647 }, { 0x05e8, 0x0648 },
{ 0x05e9, 0x0649 }, { 0x05ea, 0x064a }, { 0x05eb, 0x064b }, { 0x05ec, 0x064c },
{ 0x05ed, 0x064d }, { 0x05ee, 0x064e }, { 0x05ef, 0x064f }, { 0x05f0, 0x0650 },
{ 0x05f1, 0x0651 }, { 0x05f2, 0x0652 }, { 0x06a1, 0x0452 }, { 0x06a2, 0x0453 },
{ 0x06a3, 0x0451 }, { 0x06a4, 0x0454 }, { 0x06a5, 0x0455 }, { 0x06a6, 0x0456 },
{ 0x06a7, 0x0457 }, { 0x06a8, 0x0458 }, { 0x06a9, 0x0459 }, { 0x06aa, 0x045a },
{ 0x06ab, 0x045b }, { 0x06ac, 0x045c }, { 0x06ae, 0x045e }, { 0x06af, 0x045f },
{ 0x06b0, 0x2116 }, { 0x06b1, 0x0402 }, { 0x06b2, 0x0403 }, { 0x06b3, 0x0401 },
{ 0x06b4, 0x0404 }, { 0x06b5, 0x0405 }, { 0x06b6, 0x0406 }, { 0x06b7, 0x0407 },
{ 0x06b8, 0x0408 }, { 0x06b9, 0x0409 }, { 0x06ba, 0x040a }, { 0x06bb, 0x040b },
{ 0x06bc, 0x040c }, { 0x06be, 0x040e }, { 0x06bf, 0x040f }, { 0x06c0, 0x044e },
{ 0x06c1, 0x0430 }, { 0x06c2, 0x0431 }, { 0x06c3, 0x0446 }, { 0x06c4, 0x0434 },
{ 0x06c5, 0x0435 }, { 0x06c6, 0x0444 }, { 0x06c7, 0x0433 }, { 0x06c8, 0x0445 },
{ 0x06c9, 0x0438 }, { 0x06ca, 0x0439 }, { 0x06cb, 0x043a }, { 0x06cc, 0x043b },
{ 0x06cd, 0x043c }, { 0x06ce, 0x043d }, { 0x06cf, 0x043e }, { 0x06d0, 0x043f },
{ 0x06d1, 0x044f }, { 0x06d2, 0x0440 }, { 0x06d3, 0x0441 }, { 0x06d4, 0x0442 },
{ 0x06d5, 0x0443 }, { 0x06d6, 0x0436 }, { 0x06d7, 0x0432 }, { 0x06d8, 0x044c },
{ 0x06d9, 0x044b }, { 0x06da, 0x0437 }, { 0x06db, 0x0448 }, { 0x06dc, 0x044d },
{ 0x06dd, 0x0449 }, { 0x06de, 0x0447 }, { 0x06df, 0x044a }, { 0x06e0, 0x042e },
{ 0x06e1, 0x0410 }, { 0x06e2, 0x0411 }, { 0x06e3, 0x0426 }, { 0x06e4, 0x0414 },
{ 0x06e5, 0x0415 }, { 0x06e6, 0x0424 }, { 0x06e7, 0x0413 }, { 0x06e8, 0x0425 },
{ 0x06e9, 0x0418 }, { 0x06ea, 0x0419 }, { 0x06eb, 0x041a }, { 0x06ec, 0x041b },
{ 0x06ed, 0x041c }, { 0x06ee, 0x041d }, { 0x06ef, 0x041e }, { 0x06f0, 0x041f },
{ 0x06f1, 0x042f }, { 0x06f2, 0x0420 }, { 0x06f3, 0x0421 }, { 0x06f4, 0x0422 },
{ 0x06f5, 0x0423 }, { 0x06f6, 0x0416 }, { 0x06f7, 0x0412 }, { 0x06f8, 0x042c },
{ 0x06f9, 0x042b }, { 0x06fa, 0x0417 }, { 0x06fb, 0x0428 }, { 0x06fc, 0x042d },
{ 0x06fd, 0x0429 }, { 0x06fe, 0x0427 }, { 0x06ff, 0x042a }, { 0x07a1, 0x0386 },
{ 0x07a2, 0x0388 }, { 0x07a3, 0x0389 }, { 0x07a4, 0x038a }, { 0x07a5, 0x03aa },
{ 0x07a7, 0x038c }, { 0x07a8, 0x038e }, { 0x07a9, 0x03ab }, { 0x07ab, 0x038f },
{ 0x07ae, 0x0385 }, { 0x07af, 0x2015 }, { 0x07b1, 0x03ac }, { 0x07b2, 0x03ad },
{ 0x07b3, 0x03ae }, { 0x07b4, 0x03af }, { 0x07b5, 0x03ca }, { 0x07b6, 0x0390 },
{ 0x07b7, 0x03cc }, { 0x07b8, 0x03cd }, { 0x07b9, 0x03cb }, { 0x07ba, 0x03b0 },
{ 0x07bb, 0x03ce }, { 0x07c1, 0x0391 }, { 0x07c2, 0x0392 }, { 0x07c3, 0x0393 },
{ 0x07c4, 0x0394 }, { 0x07c5, 0x0395 }, { 0x07c6, 0x0396 }, { 0x07c7, 0x0397 },
{ 0x07c8, 0x0398 }, { 0x07c9, 0x0399 }, { 0x07ca, 0x039a }, { 0x07cb, 0x039b },
{ 0x07cc, 0x039c }, { 0x07cd, 0x039d }, { 0x07ce, 0x039e }, { 0x07cf, 0x039f },
{ 0x07d0, 0x03a0 }, { 0x07d1, 0x03a1 }, { 0x07d2, 0x03a3 }, { 0x07d4, 0x03a4 },
{ 0x07d5, 0x03a5 }, { 0x07d6, 0x03a6 }, { 0x07d7, 0x03a7 }, { 0x07d8, 0x03a8 },
{ 0x07d9, 0x03a9 }, { 0x07e1, 0x03b1 }, { 0x07e2, 0x03b2 }, { 0x07e3, 0x03b3 },
{ 0x07e4, 0x03b4 }, { 0x07e5, 0x03b5 }, { 0x07e6, 0x03b6 }, { 0x07e7, 0x03b7 },
{ 0x07e8, 0x03b8 }, { 0x07e9, 0x03b9 }, { 0x07ea, 0x03ba }, { 0x07eb, 0x03bb },
{ 0x07ec, 0x03bc }, { 0x07ed, 0x03bd }, { 0x07ee, 0x03be }, { 0x07ef, 0x03bf },
{ 0x07f0, 0x03c0 }, { 0x07f1, 0x03c1 }, { 0x07f2, 0x03c3 }, { 0x07f3, 0x03c2 },
{ 0x07f4, 0x03c4 }, { 0x07f5, 0x03c5 }, { 0x07f6, 0x03c6 }, { 0x07f7, 0x03c7 },
{ 0x07f8, 0x03c8 }, { 0x07f9, 0x03c9 }, { 0x08a1, 0x23b7 }, { 0x08a2, 0x250c },
{ 0x08a3, 0x2500 }, { 0x08a4, 0x2320 }, { 0x08a5, 0x2321 }, { 0x08a6, 0x2502 },
{ 0x08a7, 0x23a1 }, { 0x08a8, 0x23a3 }, { 0x08a9, 0x23a4 }, { 0x08aa, 0x23a6 },
{ 0x08ab, 0x239b }, { 0x08ac, 0x239d }, { 0x08ad, 0x239e }, { 0x08ae, 0x23a0 },
{ 0x08af, 0x23a8 }, { 0x08b0, 0x23ac }, { 0x08bc, 0x2264 }, { 0x08bd, 0x2260 },
{ 0x08be, 0x2265 }, { 0x08bf, 0x222b }, { 0x08c0, 0x2234 }, { 0x08c1, 0x221d },
{ 0x08c2, 0x221e }, { 0x08c5, 0x2207 }, { 0x08c8, 0x223c }, { 0x08c9, 0x2243 },
{ 0x08cd, 0x21d4 }, { 0x08ce, 0x21d2 }, { 0x08cf, 0x2261 }, { 0x08d6, 0x221a },
{ 0x08da, 0x2282 }, { 0x08db, 0x2283 }, { 0x08dc, 0x2229 }, { 0x08dd, 0x222a },
{ 0x08de, 0x2227 }, { 0x08df, 0x2228 }, { 0x08ef, 0x2202 }, { 0x08f6, 0x0192 },
{ 0x08fb, 0x2190 }, { 0x08fc, 0x2191 }, { 0x08fd, 0x2192 }, { 0x08fe, 0x2193 },
{ 0x09e0, 0x25c6 }, { 0x09e1, 0x2592 }, { 0x09e2, 0x2409 }, { 0x09e3, 0x240c },
{ 0x09e4, 0x240d }, { 0x09e5, 0x240a }, { 0x09e8, 0x2424 }, { 0x09e9, 0x240b },
{ 0x09ea, 0x2518 }, { 0x09eb, 0x2510 }, { 0x09ec, 0x250c }, { 0x09ed, 0x2514 },
{ 0x09ee, 0x253c }, { 0x09ef, 0x23ba }, { 0x09f0, 0x23bb }, { 0x09f1, 0x2500 },
{ 0x09f2, 0x23bc }, { 0x09f3, 0x23bd }, { 0x09f4, 0x251c }, { 0x09f5, 0x2524 },
{ 0x09f6, 0x2534 }, { 0x09f7, 0x252c }, { 0x09f8, 0x2502 }, { 0x0aa1, 0x2003 },
{ 0x0aa2, 0x2002 }, { 0x0aa3, 0x2004 }, { 0x0aa4, 0x2005 }, { 0x0aa5, 0x2007 },
{ 0x0aa6, 0x2008 }, { 0x0aa7, 0x2009 }, { 0x0aa8, 0x200a }, { 0x0aa9, 0x2014 },
{ 0x0aaa, 0x2013 }, { 0x0aae, 0x2026 }, { 0x0aaf, 0x2025 }, { 0x0ab0, 0x2153 },
{ 0x0ab1, 0x2154 }, { 0x0ab2, 0x2155 }, { 0x0ab3, 0x2156 }, { 0x0ab4, 0x2157 },
{ 0x0ab5, 0x2158 }, { 0x0ab6, 0x2159 }, { 0x0ab7, 0x215a }, { 0x0ab8, 0x2105 },
{ 0x0abb, 0x2012 }, { 0x0abc, 0x2329 }, { 0x0abe, 0x232a }, { 0x0ac3, 0x215b },
{ 0x0ac4, 0x215c }, { 0x0ac5, 0x215d }, { 0x0ac6, 0x215e }, { 0x0ac9, 0x2122 },
{ 0x0aca, 0x2613 }, { 0x0acc, 0x25c1 }, { 0x0acd, 0x25b7 }, { 0x0ace, 0x25cb },
{ 0x0acf, 0x25af }, { 0x0ad0, 0x2018 }, { 0x0ad1, 0x2019 }, { 0x0ad2, 0x201c },
{ 0x0ad3, 0x201d }, { 0x0ad4, 0x211e }, { 0x0ad6, 0x2032 }, { 0x0ad7, 0x2033 },
{ 0x0ad9, 0x271d }, { 0x0adb, 0x25ac }, { 0x0adc, 0x25c0 }, { 0x0add, 0x25b6 },
{ 0x0ade, 0x25cf }, { 0x0adf, 0x25ae }, { 0x0ae0, 0x25e6 }, { 0x0ae1, 0x25ab },
{ 0x0ae2, 0x25ad }, { 0x0ae3, 0x25b3 }, { 0x0ae4, 0x25bd }, { 0x0ae5, 0x2606 },
{ 0x0ae6, 0x2022 }, { 0x0ae7, 0x25aa }, { 0x0ae8, 0x25b2 }, { 0x0ae9, 0x25bc },
{ 0x0aea, 0x261c }, { 0x0aeb, 0x261e }, { 0x0aec, 0x2663 }, { 0x0aed, 0x2666 },
{ 0x0aee, 0x2665 }, { 0x0af0, 0x2720 }, { 0x0af1, 0x2020 }, { 0x0af2, 0x2021 },
{ 0x0af3, 0x2713 }, { 0x0af4, 0x2717 }, { 0x0af5, 0x266f }, { 0x0af6, 0x266d },
{ 0x0af7, 0x2642 }, { 0x0af8, 0x2640 }, { 0x0af9, 0x260e }, { 0x0afa, 0x2315 },
{ 0x0afb, 0x2117 }, { 0x0afc, 0x2038 }, { 0x0afd, 0x201a }, { 0x0afe, 0x201e },
{ 0x0ba3, 0x003c }, { 0x0ba6, 0x003e }, { 0x0ba8, 0x2228 }, { 0x0ba9, 0x2227 },
{ 0x0bc0, 0x00af }, { 0x0bc2, 0x22a5 }, { 0x0bc3, 0x2229 }, { 0x0bc4, 0x230a },
{ 0x0bc6, 0x005f }, { 0x0bca, 0x2218 }, { 0x0bcc, 0x2395 }, { 0x0bce, 0x22a4 },
{ 0x0bcf, 0x25cb }, { 0x0bd3, 0x2308 }, { 0x0bd6, 0x222a }, { 0x0bd8, 0x2283 },
{ 0x0bda, 0x2282 }, { 0x0bdc, 0x22a2 }, { 0x0bfc, 0x22a3 }, { 0x0cdf, 0x2017 },
{ 0x0ce0, 0x05d0 }, { 0x0ce1, 0x05d1 }, { 0x0ce2, 0x05d2 }, { 0x0ce3, 0x05d3 },
{ 0x0ce4, 0x05d4 }, { 0x0ce5, 0x05d5 }, { 0x0ce6, 0x05d6 }, { 0x0ce7, 0x05d7 },
{ 0x0ce8, 0x05d8 }, { 0x0ce9, 0x05d9 }, { 0x0cea, 0x05da }, { 0x0ceb, 0x05db },
{ 0x0cec, 0x05dc }, { 0x0ced, 0x05dd }, { 0x0cee, 0x05de }, { 0x0cef, 0x05df },
{ 0x0cf0, 0x05e0 }, { 0x0cf1, 0x05e1 }, { 0x0cf2, 0x05e2 }, { 0x0cf3, 0x05e3 },
{ 0x0cf4, 0x05e4 }, { 0x0cf5, 0x05e5 }, { 0x0cf6, 0x05e6 }, { 0x0cf7, 0x05e7 },
{ 0x0cf8, 0x05e8 }, { 0x0cf9, 0x05e9 }, { 0x0cfa, 0x05ea }, { 0x0da1, 0x0e01 },
{ 0x0da2, 0x0e02 }, { 0x0da3, 0x0e03 }, { 0x0da4, 0x0e04 }, { 0x0da5, 0x0e05 },
{ 0x0da6, 0x0e06 }, { 0x0da7, 0x0e07 }, { 0x0da8, 0x0e08 }, { 0x0da9, 0x0e09 },
{ 0x0daa, 0x0e0a }, { 0x0dab, 0x0e0b }, { 0x0dac, 0x0e0c }, { 0x0dad, 0x0e0d },
{ 0x0dae, 0x0e0e }, { 0x0daf, 0x0e0f }, { 0x0db0, 0x0e10 }, { 0x0db1, 0x0e11 },
{ 0x0db2, 0x0e12 }, { 0x0db3, 0x0e13 }, { 0x0db4, 0x0e14 }, { 0x0db5, 0x0e15 },
{ 0x0db6, 0x0e16 }, { 0x0db7, 0x0e17 }, { 0x0db8, 0x0e18 }, { 0x0db9, 0x0e19 },
{ 0x0dba, 0x0e1a }, { 0x0dbb, 0x0e1b }, { 0x0dbc, 0x0e1c }, { 0x0dbd, 0x0e1d },
{ 0x0dbe, 0x0e1e }, { 0x0dbf, 0x0e1f }, { 0x0dc0, 0x0e20 }, { 0x0dc1, 0x0e21 },
{ 0x0dc2, 0x0e22 }, { 0x0dc3, 0x0e23 }, { 0x0dc4, 0x0e24 }, { 0x0dc5, 0x0e25 },
{ 0x0dc6, 0x0e26 }, { 0x0dc7, 0x0e27 }, { 0x0dc8, 0x0e28 }, { 0x0dc9, 0x0e29 },
{ 0x0dca, 0x0e2a }, { 0x0dcb, 0x0e2b }, { 0x0dcc, 0x0e2c }, { 0x0dcd, 0x0e2d },
{ 0x0dce, 0x0e2e }, { 0x0dcf, 0x0e2f }, { 0x0dd0, 0x0e30 }, { 0x0dd1, 0x0e31 },
{ 0x0dd2, 0x0e32 }, { 0x0dd3, 0x0e33 }, { 0x0dd4, 0x0e34 }, { 0x0dd5, 0x0e35 },
{ 0x0dd6, 0x0e36 }, { 0x0dd7, 0x0e37 }, { 0x0dd8, 0x0e38 }, { 0x0dd9, 0x0e39 },
{ 0x0dda, 0x0e3a }, { 0x0ddf, 0x0e3f }, { 0x0de0, 0x0e40 }, { 0x0de1, 0x0e41 },
{ 0x0de2, 0x0e42 }, { 0x0de3, 0x0e43 }, { 0x0de4, 0x0e44 }, { 0x0de5, 0x0e45 },
{ 0x0de6, 0x0e46 }, { 0x0de7, 0x0e47 }, { 0x0de8, 0x0e48 }, { 0x0de9, 0x0e49 },
{ 0x0dea, 0x0e4a }, { 0x0deb, 0x0e4b }, { 0x0dec, 0x0e4c }, { 0x0ded, 0x0e4d },
{ 0x0df0, 0x0e50 }, { 0x0df1, 0x0e51 }, { 0x0df2, 0x0e52 }, { 0x0df3, 0x0e53 },
{ 0x0df4, 0x0e54 }, { 0x0df5, 0x0e55 }, { 0x0df6, 0x0e56 }, { 0x0df7, 0x0e57 },
{ 0x0df8, 0x0e58 }, { 0x0df9, 0x0e59 }, { 0x0ea1, 0x3131 }, { 0x0ea2, 0x3132 },
{ 0x0ea3, 0x3133 }, { 0x0ea4, 0x3134 }, { 0x0ea5, 0x3135 }, { 0x0ea6, 0x3136 },
{ 0x0ea7, 0x3137 }, { 0x0ea8, 0x3138 }, { 0x0ea9, 0x3139 }, { 0x0eaa, 0x313a },
{ 0x0eab, 0x313b }, { 0x0eac, 0x313c }, { 0x0ead, 0x313d }, { 0x0eae, 0x313e },
{ 0x0eaf, 0x313f }, { 0x0eb0, 0x3140 }, { 0x0eb1, 0x3141 }, { 0x0eb2, 0x3142 },
{ 0x0eb3, 0x3143 }, { 0x0eb4, 0x3144 }, { 0x0eb5, 0x3145 }, { 0x0eb6, 0x3146 },
{ 0x0eb7, 0x3147 }, { 0x0eb8, 0x3148 }, { 0x0eb9, 0x3149 }, { 0x0eba, 0x314a },
{ 0x0ebb, 0x314b }, { 0x0ebc, 0x314c }, { 0x0ebd, 0x314d }, { 0x0ebe, 0x314e },
{ 0x0ebf, 0x314f }, { 0x0ec0, 0x3150 }, { 0x0ec1, 0x3151 }, { 0x0ec2, 0x3152 },
{ 0x0ec3, 0x3153 }, { 0x0ec4, 0x3154 }, { 0x0ec5, 0x3155 }, { 0x0ec6, 0x3156 },
{ 0x0ec7, 0x3157 }, { 0x0ec8, 0x3158 }, { 0x0ec9, 0x3159 }, { 0x0eca, 0x315a },
{ 0x0ecb, 0x315b }, { 0x0ecc, 0x315c }, { 0x0ecd, 0x315d }, { 0x0ece, 0x315e },
{ 0x0ecf, 0x315f }, { 0x0ed0, 0x3160 }, { 0x0ed1, 0x3161 }, { 0x0ed2, 0x3162 },
{ 0x0ed3, 0x3163 }, { 0x0ed4, 0x11a8 }, { 0x0ed5, 0x11a9 }, { 0x0ed6, 0x11aa },
{ 0x0ed7, 0x11ab }, { 0x0ed8, 0x11ac }, { 0x0ed9, 0x11ad }, { 0x0eda, 0x11ae },
{ 0x0edb, 0x11af }, { 0x0edc, 0x11b0 }, { 0x0edd, 0x11b1 }, { 0x0ede, 0x11b2 },
{ 0x0edf, 0x11b3 }, { 0x0ee0, 0x11b4 }, { 0x0ee1, 0x11b5 }, { 0x0ee2, 0x11b6 },
{ 0x0ee3, 0x11b7 }, { 0x0ee4, 0x11b8 }, { 0x0ee5, 0x11b9 }, { 0x0ee6, 0x11ba },
{ 0x0ee7, 0x11bb }, { 0x0ee8, 0x11bc }, { 0x0ee9, 0x11bd }, { 0x0eea, 0x11be },
{ 0x0eeb, 0x11bf }, { 0x0eec, 0x11c0 }, { 0x0eed, 0x11c1 }, { 0x0eee, 0x11c2 },
{ 0x0eef, 0x316d }, { 0x0ef0, 0x3171 }, { 0x0ef1, 0x3178 }, { 0x0ef2, 0x317f },
{ 0x0ef3, 0x3181 }, { 0x0ef4, 0x3184 }, { 0x0ef5, 0x3186 }, { 0x0ef6, 0x318d },
{ 0x0ef7, 0x318e }, { 0x0ef8, 0x11eb }, { 0x0ef9, 0x11f0 }, { 0x0efa, 0x11f9 },
{ 0x0eff, 0x20a9 }, { 0x13a4, 0x20ac }, { 0x13bc, 0x0152 }, { 0x13bd, 0x0153 },
{ 0x13be, 0x0178 }, { 0x20ac, 0x20ac },
};
static unsigned int ImGui_ImplQNX_KeySymToUnicode(unsigned int keysym)
{
// Latin-1 keysyms map directly to Unicode.
if ((keysym >= 0x0020u && keysym <= 0x007eu) ||
(keysym >= 0x00a0u && keysym <= 0x00ffu))
{
return keysym;
}
// X11-style directly encoded UCS keysyms use 0x01000000 | codepoint.
if ((keysym & 0xff000000u) == 0x01000000u)
{
const unsigned int codepoint = keysym & 0x00ffffffu;
return codepoint <= IM_UNICODE_CODEPOINT_MAX ? codepoint : 0u;
}
int min = 0;
int max = (int)(sizeof(ImGui_ImplQNX_KeySymTable) / sizeof(ImGui_ImplQNX_KeySymTable[0])) - 1;
while (max >= min)
{
const int mid = min + (max - min) / 2;
if (ImGui_ImplQNX_KeySymTable[mid].KeySym < keysym)
{
min = mid + 1;
}
else if (ImGui_ImplQNX_KeySymTable[mid].KeySym > keysym)
{
max = mid - 1;
}
else
{
return ImGui_ImplQNX_KeySymTable[mid].Unicode;
}
}
return 0u;
}
#endif // #ifndef IMGUI_DISABLE

35
backends/imgui_impl_qnx.h Normal file
View file

@ -0,0 +1,35 @@
// dear imgui: Platform Backend for QNX Screen
// This needs to be used along with a Renderer Backend (e.g. OpenGL3, Vulkan).
// Implemented features:
// [X] Platform: Keyboard support. Uses io.AddKeyEvent() and native QNX key symbols.
// [X] Platform: Mouse support. Handles position, three buttons and horizontal/vertical wheels.
// [X] Platform: Touch support. Maps the first active touch contact to the primary mouse button.
// [X] Platform: Focus and window-size updates.
// Missing features or Issues:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support.
// [ ] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors).
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
#include <screen/screen.h>
// 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);
#endif // #ifndef IMGUI_DISABLE

View file

@ -21,6 +21,9 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-08-06: Fixed querying framebuffer scale when using Metal. (#5592)
// 2026-07-15: Inputs: restore SDL_StartTextInput()/SDL_StopTextInput() in IME handler for on-screen keyboard support on Android/mobile. (#7636, #9474)
// 2026-04-16: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value and this breaks scaling border size. (#9369)
// 2026-02-13: Inputs: systems other than X11 are back to starting mouse capture on mouse down (reverts 2025-02-26 change). Only X11 requires waiting for a drag by default (not ideal, but a better default for X11 users). Added ImGui_ImplSDL2_SetMouseCaptureMode() for X11 debugger users. (#3650, #6410, #9235)
// 2026-01-15: Changed GetClipboardText() handler to return nullptr on error aka clipboard contents is not text. Consistent with other backends. (#9168)
// 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_MOUSEMOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786)
@ -133,10 +136,18 @@
#endif
#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
#if defined(__APPLE__)
#define SDL_HAS_METAL SDL_VERSION_ATLEAST(2,0,14)
#else
#define SDL_HAS_METAL 0
#endif
#define SDL_HAS_OPEN_URL SDL_VERSION_ATLEAST(2,0,14)
#if SDL_HAS_VULKAN
#include <SDL_vulkan.h>
#endif
#if SDL_HAS_METAL
#include <SDL_metal.h>
#endif
// SDL Data
struct ImGui_ImplSDL2_Data
@ -146,7 +157,8 @@ struct ImGui_ImplSDL2_Data
SDL_Renderer* Renderer;
Uint64 Time;
char* ClipboardTextData;
char BackendPlatformName[48];
char BackendPlatformName[64];
bool IsWayland;
// Mouse handling
Uint32 MouseWindowID;
@ -203,6 +215,18 @@ static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImG
r.w = 1;
r.h = (int)data->InputLineHeight;
SDL_SetTextInputRect(&r);
#ifdef __ANDROID__
// SDL_StartTextInput() is needed on Android (and some other platforms) to show the on-screen keyboard. (#7636, #9474, #6306)
// It was removed in a7703fe6 due to concerns about its relation to desktop IME, but is required on mobile.
SDL_StartTextInput();
#endif
}
else
{
#ifdef __ANDROID__
SDL_StopTextInput();
#endif
}
}
@ -498,11 +522,12 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
SDL_version ver_runtime;
SDL_VERSION(&ver_compiled);
SDL_GetVersion(&ver_runtime);
const char* sdl_video_driver = SDL_GetCurrentVideoDriver();
// Setup backend capabilities flags
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl2 (%u.%u.%u, %u.%u.%u)",
ver_compiled.major, ver_compiled.minor, ver_compiled.patch, ver_runtime.major, ver_runtime.minor, ver_runtime.patch);
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl2 (%u.%u.%u, %u.%u.%u) (%s)",
ver_compiled.major, ver_compiled.minor, ver_compiled.patch, ver_runtime.major, ver_runtime.minor, ver_runtime.patch, sdl_video_driver);
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = bd->BackendPlatformName;
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
@ -511,16 +536,16 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
bd->Window = window;
bd->WindowID = SDL_GetWindowID(window);
bd->Renderer = renderer;
bd->IsWayland = strcmp(sdl_video_driver, "Wayland") == 0;
// Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse()
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bd->MouseCanUseGlobalState = false;
bd->MouseCaptureMode = ImGui_ImplSDL2_MouseCaptureMode_Disabled;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char* sdl_backend = SDL_GetCurrentVideoDriver();
const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
for (const char* item : capture_and_global_state_whitelist)
if (strncmp(sdl_backend, item, strlen(item)) == 0)
if (strncmp(sdl_video_driver, item, strlen(item)) == 0)
{
bd->MouseCanUseGlobalState = true;
bd->MouseCaptureMode = (strcmp(item, "x11") == 0) ? ImGui_ImplSDL2_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL2_MouseCaptureMode_Enabled;
@ -748,6 +773,7 @@ float ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window)
return ImGui_ImplSDL2_GetContentScaleForDisplay(SDL_GetWindowDisplayIndex(window));
}
// SDL_GetDisplayDPI() seems rather unreliable on Linux.
float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index)
{
const char* sdl_driver = SDL_GetCurrentVideoDriver();
@ -757,7 +783,11 @@ float ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index)
#if !defined(__APPLE__) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__)
float dpi = 0.0f;
if (SDL_GetDisplayDPI(display_index, &dpi, nullptr, nullptr) == 0)
{
if (dpi < 96.0f)
dpi = 96.0f;
return dpi / 96.0f;
}
#endif
#endif
IM_UNUSED(display_index);
@ -878,13 +908,17 @@ static void ImGui_ImplSDL2_GetWindowSizeAndFramebufferScale(SDL_Window* window,
#if SDL_HAS_VULKAN
else if (SDL_GetWindowFlags(window) & SDL_WINDOW_VULKAN)
SDL_Vulkan_GetDrawableSize(window, &display_w, &display_h);
#endif
#if SDL_HAS_METAL
else if (SDL_GetWindowFlags(window) & SDL_WINDOW_METAL)
SDL_Metal_GetDrawableSize(window, &display_w, &display_h);
#endif
else
SDL_GL_GetDrawableSize(window, &display_w, &display_h);
if (out_size != nullptr)
*out_size = ImVec2((float)w, (float)h);
if (out_framebuffer_scale != nullptr)
*out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / w, (float)display_h / h) : ImVec2(1.0f, 1.0f);
*out_framebuffer_scale = (w > 0 && h > 0) ? ImVec2((float)display_w / (float)w, (float)display_h / (float)h) : ImVec2(1.0f, 1.0f);
}
void ImGui_ImplSDL2_NewFrame()
@ -902,7 +936,7 @@ void ImGui_ImplSDL2_NewFrame()
Uint64 current_time = SDL_GetPerformanceCounter();
if (current_time <= bd->Time)
current_time = bd->Time + 1;
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / (double)frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
if (bd->MouseLastLeaveFrame && bd->MouseLastLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)

View file

@ -111,7 +111,8 @@ struct ImGui_ImplSDL3_Data
SDL_Renderer* Renderer;
Uint64 Time;
char* ClipboardTextData;
char BackendPlatformName[48];
char BackendPlatformName[64];
bool IsWayland;
// IME handling
SDL_Window* ImeWindow;
@ -502,11 +503,13 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
//SDL_SetHint(SDL_HINT_EVENT_LOGGING, "2");
const int ver_linked = SDL_GetVersion();
const char* sdl_video_driver = SDL_GetCurrentVideoDriver();
// Setup backend capabilities flags
ImGui_ImplSDL3_Data* bd = IM_NEW(ImGui_ImplSDL3_Data)();
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl3 (%d.%d.%d; %d.%d.%d)",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, SDL_VERSIONNUM_MAJOR(ver_linked), SDL_VERSIONNUM_MINOR(ver_linked), SDL_VERSIONNUM_MICRO(ver_linked));
snprintf(bd->BackendPlatformName, sizeof(bd->BackendPlatformName), "imgui_impl_sdl3 (%d.%d.%d; %d.%d.%d) (%s)",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_MICRO_VERSION, SDL_VERSIONNUM_MAJOR(ver_linked), SDL_VERSIONNUM_MINOR(ver_linked), SDL_VERSIONNUM_MICRO(ver_linked),
sdl_video_driver);
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = bd->BackendPlatformName;
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
@ -515,16 +518,16 @@ static bool ImGui_ImplSDL3_Init(SDL_Window* window, SDL_Renderer* renderer, void
bd->Window = window;
bd->WindowID = SDL_GetWindowID(window);
bd->Renderer = renderer;
bd->IsWayland = strcmp(sdl_video_driver, "wayland") == 0;
// Check and store if we are on a SDL backend that supports SDL_GetGlobalMouseState() and SDL_CaptureMouse()
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bd->MouseCanUseGlobalState = false;
bd->MouseCaptureMode = ImGui_ImplSDL3_MouseCaptureMode_Disabled;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char* sdl_backend = SDL_GetCurrentVideoDriver();
const char* capture_and_global_state_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
for (const char* item : capture_and_global_state_whitelist)
if (strncmp(sdl_backend, item, strlen(item)) == 0)
if (strncmp(sdl_video_driver, item, strlen(item)) == 0)
{
bd->MouseCanUseGlobalState = true;
bd->MouseCaptureMode = (strcmp(item, "x11") == 0) ? ImGui_ImplSDL3_MouseCaptureMode_EnabledAfterDrag : ImGui_ImplSDL3_MouseCaptureMode_Enabled;
@ -686,8 +689,8 @@ static void ImGui_ImplSDL3_UpdateMouseData()
int window_x, window_y;
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
mouse_x -= window_x;
mouse_y -= window_y;
mouse_x -= (float)window_x;
mouse_y -= (float)window_y;
io.AddMousePosEvent(mouse_x, mouse_y);
}
}
@ -860,7 +863,7 @@ void ImGui_ImplSDL3_NewFrame()
Uint64 current_time = SDL_GetPerformanceCounter();
if (current_time <= bd->Time)
current_time = bd->Time + 1;
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / (double)frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
if (bd->MousePendingLeaveFrame && bd->MousePendingLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)

View file

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLGPU3_GetRenderState().
// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@ -22,6 +23,8 @@
// Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info.
// CHANGELOG
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. Obsoleting samplers from ImGui_ImplSDLGPU3_RenderState. (#9378)
// 2026-03-19: Fixed issue in ImGui_ImplSDLGPU3_DestroyTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
// 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262)
// 2025-11-26: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL.
@ -59,6 +62,10 @@ struct ImGui_ImplSDLGPU3_Data
{
ImGui_ImplSDLGPU3_InitInfo InitInfo;
// Render state
ImGui_ImplSDLGPU3_RenderState* RenderState = nullptr; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering.
SDL_GPUSampler* CurrentSampler = nullptr;
// Graphics pipeline & shaders
SDL_GPUShader* VertexShader = nullptr;
SDL_GPUShader* FragmentShader = nullptr;
@ -87,10 +94,15 @@ static ImGui_ImplSDLGPU3_Data* ImGui_ImplSDLGPU3_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLGPU3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, ImGui_ImplSDLGPU3_RenderState* render_state, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height)
ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState()
{
return (ImGui_ImplSDLGPU3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
static void ImGui_ImplSDLGPU3_SetupRenderState(ImDrawData* draw_data, SDL_GPUGraphicsPipeline* pipeline, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, ImGui_ImplSDLGPU3_FrameData* fd, uint32_t fb_width, uint32_t fb_height)
{
ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData();
render_state->SamplerCurrent = bd->TexSamplerLinear;
bd->CurrentSampler = bd->TexSamplerLinear;
// Bind graphics pipeline
SDL_BindGPUGraphicsPipeline(render_pass, pipeline);
@ -158,8 +170,8 @@ static void CreateOrResizeBuffers(SDL_GPUBuffer** buffer, SDL_GPUTransferBuffer*
void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount <= 0)
return;
@ -174,8 +186,8 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff
ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo;
ImGui_ImplSDLGPU3_FrameData* fd = &bd->MainWindowFrameData;
uint32_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert);
uint32_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
uint32_t vertex_size = (uint32_t)draw_data->TotalVtxCount * sizeof(ImDrawVert);
uint32_t index_size = (uint32_t)draw_data->TotalIdxCount * sizeof(ImDrawIdx);
if (fd->VertexBuffer == nullptr || fd->VertexBufferSize < vertex_size)
CreateOrResizeBuffers(&fd->VertexBuffer, &fd->VertexTransferBuffer, &fd->VertexBufferSize, vertex_size, SDL_GPU_BUFFERUSAGE_VERTEX);
if (fd->IndexBuffer == nullptr || fd->IndexBufferSize < index_size)
@ -216,11 +228,16 @@ void ImGui_ImplSDLGPU3_PrepareDrawData(ImDrawData* draw_data, SDL_GPUCommandBuff
SDL_EndGPUCopyPass(copy_pass);
}
// Draw callbacks
static void ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = bd->TexSamplerLinear; }
static void ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); bd->CurrentSampler = bd->TexSamplerNearest; }
void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffer* command_buffer, SDL_GPURenderPass* render_pass, SDL_GPUGraphicsPipeline* pipeline)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0)
return;
@ -238,11 +255,9 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLGPU3_RenderState render_state;
render_state.Device = bd->InitInfo.Device;
render_state.SamplerLinear = render_state.SamplerCurrent = bd->TexSamplerLinear;
render_state.SamplerNearest = bd->TexSamplerNearest;
platform_io.Renderer_RenderState = &render_state;
platform_io.Renderer_RenderState = bd->RenderState = &render_state;
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
@ -256,9 +271,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, &render_state, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
if (pcmd->UserCallback == ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState)
ImGui_ImplSDLGPU3_SetupRenderState(draw_data, pipeline, command_buffer, render_pass, fd, fb_width, fb_height);
else
pcmd->UserCallback(draw_list, pcmd);
}
@ -271,8 +285,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
// Clamp to viewport as SDL_SetGPUScissor() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
@ -287,7 +301,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
// Bind DescriptorSet with font or user texture
SDL_GPUTextureSamplerBinding texture_sampler_binding;
texture_sampler_binding.texture = (SDL_GPUTexture*)(intptr_t)pcmd->GetTexID();
texture_sampler_binding.sampler = render_state.SamplerCurrent;
texture_sampler_binding.sampler = bd->CurrentSampler;
SDL_BindGPUFragmentSamplers(render_pass, 0, &texture_sampler_binding, 1);
// Draw
@ -306,6 +320,8 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe
// We perform a call to SDL_SetGPUScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644)
SDL_Rect scissor_rect { 0, 0, fb_width, fb_height };
SDL_SetGPUScissor(render_pass, &scissor_rect);
platform_io.Renderer_RenderState = bd->RenderState = nullptr;
}
static void ImGui_ImplSDLGPU3_DestroyTexture(ImTextureData* tex)
@ -582,7 +598,7 @@ void ImGui_ImplSDLGPU3_CreateDeviceObjects()
if (bd->TexSamplerLinear == nullptr)
{
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
// Bilinear sampling is required.
SDL_GPUSamplerCreateInfo sampler_info = {};
sampler_info.min_filter = SDL_GPU_FILTER_LINEAR;
sampler_info.mag_filter = SDL_GPU_FILTER_LINEAR;
@ -656,6 +672,11 @@ bool ImGui_ImplSDLGPU3_Init(ImGui_ImplSDLGPU3_InitInfo* info)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLGPU3_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLGPU3_DrawCallback_SetSamplerNearest;
IM_ASSERT(info->Device != nullptr);
IM_ASSERT(info->ColorTargetFormat != SDL_GPU_TEXTUREFORMAT_INVALID);

View file

@ -5,6 +5,7 @@
// [X] Renderer: User texture binding. Use 'SDL_GPUTexture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef! **IMPORTANT** Before 2025/08/08, ImTextureID was a reference to a SDL_GPUTextureSamplerBinding struct.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLGPU3_GetRenderState().
// The aim of imgui_impl_sdlgpu3.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@ -57,9 +58,7 @@ IMGUI_IMPL_API void ImGui_ImplSDLGPU3_UpdateTexture(ImTextureData* tex);
struct ImGui_ImplSDLGPU3_RenderState
{
SDL_GPUDevice* Device;
SDL_GPUSampler* SamplerLinear; // Bilinear filtering sampler
SDL_GPUSampler* SamplerNearest; // Nearest/point filtering sampler
SDL_GPUSampler* SamplerCurrent; // Current sampler (may be changed by callback)
};
IMGUI_IMPL_API ImGui_ImplSDLGPU3_RenderState* ImGui_ImplSDLGPU3_GetRenderState();
#endif // #ifndef IMGUI_DISABLE

View file

@ -14,8 +14,10 @@
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// Missing features or Issues:
// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering.
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
@ -24,6 +26,8 @@
// - Introduction, links and more at the top of imgui.cpp
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported). (#9378)
// 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer2_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer2_CreateFontsTexture() and ImGui_ImplSDLRenderer2_DestroyFontsTexture().
@ -51,7 +55,8 @@
#endif
// SDL
#include <SDL.h>
#include <SDL_render.h>
#include <SDL_version.h>
#if !SDL_VERSION_ATLEAST(2,0,17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif
@ -71,42 +76,12 @@ static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState()
{
return (ImGui_ImplSDLRenderer2_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
// Functions
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
// Setup backend capabilities flags
ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_sdlrenderer2";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
bd->Renderer = renderer;
return true;
}
void ImGui_ImplSDLRenderer2_Shutdown()
{
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer)
{
// Clear out any viewports and cliprect set by the user
@ -122,6 +97,9 @@ void ImGui_ImplSDLRenderer2_NewFrame()
IM_UNUSED(bd);
}
// Draw callbacks
static void ImGui_ImplSDLRenderer2_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
{
// If there's a scale factor set by the user, use that instead
@ -184,8 +162,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplSDLRenderer2_DrawCallback_ResetRenderState)
ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
else
pcmd->UserCallback(draw_list, pcmd);
@ -242,8 +219,7 @@ void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex)
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
// Create texture
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Create texture (bilinear sampling is required)
SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height);
IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!");
SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch());
@ -293,6 +269,44 @@ void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
}
}
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
// Setup backend capabilities flags
ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_sdlrenderer2";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLRenderer2_DrawCallback_ResetRenderState;
bd->Renderer = renderer;
return true;
}
void ImGui_ImplSDLRenderer2_Shutdown()
{
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
//-----------------------------------------------------------------------------
#if defined(__clang__)

View file

@ -14,6 +14,8 @@
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// Missing features or Issues:
// [ ] Renderer: Missing support for DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest callbacks: SDLRenderer2 does not support changing SDL_SCALE_MODE while rendering.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -49,5 +51,6 @@ struct ImGui_ImplSDLRenderer2_RenderState
{
SDL_Renderer* Renderer;
};
IMGUI_IMPL_API ImGui_ImplSDLRenderer2_RenderState* ImGui_ImplSDLRenderer2_GetRenderState();
#endif // #ifndef IMGUI_DISABLE

View file

@ -13,9 +13,9 @@
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLRenderer3_GetRenderState().
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
@ -24,6 +24,10 @@
// - Introduction, links and more at the top of imgui.cpp
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-17: Restore modified texture scale modes at the end of RenderDrawData(). Added DrawCallback_SetSamplerFromTex support. Added CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState (#9543, #9378)
// 2026-07-15: Fixed default sampler state to be linear (broken 2026-04-23). (#9470, #9378)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer3_CreateFontsTexture() and ImGui_ImplSDLRenderer3_DestroyFontsTexture().
@ -48,16 +52,24 @@
#endif
// SDL
#include <SDL3/SDL.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_version.h>
#if !SDL_VERSION_ATLEAST(3,0,0)
#error This backend requires SDL 3.0.0+
#endif
// SDL_Renderer data
struct ImGui_ImplSDLRenderer3_TexScaleModeEntry
{
SDL_Texture* Texture;
SDL_ScaleMode ScaleModeBackup;
};
struct ImGui_ImplSDLRenderer3_Data
{
SDL_Renderer* Renderer; // Main viewport's renderer
ImVector<SDL_FColor> ColorBuffer;
ImVector<ImGui_ImplSDLRenderer3_TexScaleModeEntry> TexScaleModeBackups; // Backup of texture scale modes
ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); }
};
@ -69,48 +81,21 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplSDLRenderer3_RenderState* ImGui_ImplSDLRenderer3_GetRenderState()
{
return (ImGui_ImplSDLRenderer3_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
// Functions
bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
// Setup backend capabilities flags
ImGui_ImplSDLRenderer3_Data* bd = IM_NEW(ImGui_ImplSDLRenderer3_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_sdlrenderer3";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
bd->Renderer = renderer;
return true;
}
void ImGui_ImplSDLRenderer3_Shutdown()
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState();
// Clear out any viewports and cliprect set by the user
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
SDL_SetRenderViewport(renderer, nullptr);
SDL_SetRenderClipRect(renderer, nullptr);
render_state->CurrentScaleMode = SDL_SCALEMODE_LINEAR;
}
void ImGui_ImplSDLRenderer3_NewFrame()
@ -138,6 +123,64 @@ static int SDL_RenderGeometryRaw8BitColor(SDL_Renderer* renderer, ImVector<SDL_F
return SDL_RenderGeometryRaw(renderer, texture, xy, xy_stride, color3, sizeof(*color3), uv, uv_stride, num_vertices, indices, num_indices, size_indices);
}
// Draw callbacks
static void ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_LINEAR; }
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_NEAREST; }
static void ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerFromTex(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplSDLRenderer3_RenderState* render_state = ImGui_ImplSDLRenderer3_GetRenderState(); render_state->CurrentScaleMode = SDL_SCALEMODE_INVALID; } // SDL_SCALEMODE_INVALID = use/keep value in texture.
// SDLRenderer has various design issues which makes it hard to do it compared to regular graphics API.
// - scale/filtering mode is tied to a texture.
// - scale/filtering mode is not queued as part of the SDL_RenderGeometryXXX commands, so a change in one texture requires a flush.
static void ImGui_ImplSDLRenderer3_TexScaleModeUpdate(SDL_Renderer* renderer, SDL_Texture* tex, SDL_ScaleMode desired_scale_mode)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
if (desired_scale_mode != SDL_SCALEMODE_INVALID)
{
// Enforce a scale mode
SDL_ScaleMode tex_scale_mode = desired_scale_mode;
if (!SDL_GetTextureScaleMode(tex, &tex_scale_mode) || tex_scale_mode == desired_scale_mode)
return;
SDL_FlushRenderer(renderer);
SDL_SetTextureScaleMode(tex, desired_scale_mode);
// Store backup of old scale mode (FIXME-OPT)
for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups)
if (entry.Texture == tex)
{
if (entry.ScaleModeBackup == SDL_SCALEMODE_INVALID)
entry.ScaleModeBackup = tex_scale_mode;
return;
}
ImGui_ImplSDLRenderer3_TexScaleModeEntry entry = { tex, tex_scale_mode };
bd->TexScaleModeBackups.push_back(entry);
}
else
{
// Use scale mode that was set in texture by user. If there is an entry, restore it and clear the entry.
for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups)
if (entry.Texture == tex && entry.ScaleModeBackup != SDL_SCALEMODE_INVALID)
{
SDL_FlushRenderer(renderer);
SDL_SetTextureScaleMode(tex, entry.ScaleModeBackup);
entry.ScaleModeBackup = SDL_SCALEMODE_INVALID;
return;
}
}
}
static void ImGui_ImplSDLRenderer3_TexScaleModeRestoreBackups(SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
if (bd->TexScaleModeBackups.Size == 0)
return;
SDL_FlushRenderer(renderer);
for (ImGui_ImplSDLRenderer3_TexScaleModeEntry& entry : bd->TexScaleModeBackups)
if (entry.ScaleModeBackup != SDL_SCALEMODE_INVALID)
SDL_SetTextureScaleMode(entry.Texture, entry.ScaleModeBackup);
bd->TexScaleModeBackups.resize(0);
}
void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
@ -179,15 +222,16 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
SDL_GetRenderViewport(renderer, &old.Viewport);
SDL_GetRenderClipRect(renderer, &old.ClipRect);
// Setup desired state
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
// Setup render state structure (for callbacks and custom texture bindings)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLRenderer3_RenderState render_state;
render_state.Renderer = renderer;
platform_io.Renderer_RenderState = &render_state;
// Setup desired state
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
IM_ASSERT(bd->TexScaleModeBackups.Size == 0);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = render_scale;
@ -204,8 +248,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState)
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
else
pcmd->UserCallback(draw_list, pcmd);
@ -221,16 +264,17 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
SDL_SetRenderClipRect(renderer, &r);
// Setup texture scale/filtering mode
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
ImGui_ImplSDLRenderer3_TexScaleModeUpdate(renderer, tex, render_state.CurrentScaleMode);
// Draw
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+
// Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col));
SDL_RenderGeometryRaw8BitColor(renderer, bd->ColorBuffer, tex,
xy, (int)sizeof(ImDrawVert),
color, (int)sizeof(ImDrawVert),
@ -245,6 +289,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
// Restore modified SDL_Renderer state
SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr);
SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
ImGui_ImplSDLRenderer3_TexScaleModeRestoreBackups(renderer);
}
void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex)
@ -258,8 +303,7 @@ void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex)
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
// Create texture
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Create texture (bilinear sampling is required)
SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height);
IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!");
SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch());
@ -309,6 +353,47 @@ void ImGui_ImplSDLRenderer3_DestroyDeviceObjects()
}
}
bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
{
ImGuiIO& io = ImGui::GetIO();
IMGUI_CHECKVERSION();
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");
// Setup backend capabilities flags
ImGui_ImplSDLRenderer3_Data* bd = IM_NEW(ImGui_ImplSDLRenderer3_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_sdlrenderer3";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplSDLRenderer3_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerNearest;
platform_io.DrawCallback_SetSamplerFromTex = ImGui_ImplSDLRenderer3_DrawCallback_SetSamplerFromTex;
bd->Renderer = renderer;
return true;
}
void ImGui_ImplSDLRenderer3_Shutdown()
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
io.BackendRendererName = nullptr;
io.BackendRendererUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
platform_io.ClearRendererHandlers();
IM_DELETE(bd);
}
//-----------------------------------------------------------------------------
#if defined(__clang__)

View file

@ -13,9 +13,9 @@
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplSDLRenderer3_GetRenderState().
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
@ -27,7 +27,8 @@
#include "imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct SDL_Renderer;
// For SDL_ScaleMode which cannot be forward declared.
#include <SDL3/SDL_render.h>
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer);
@ -48,6 +49,8 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex)
struct ImGui_ImplSDLRenderer3_RenderState
{
SDL_Renderer* Renderer;
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();
#endif // #ifndef IMGUI_DISABLE

View file

@ -2,10 +2,10 @@
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplVulkan_GetRenderState().
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@ -27,6 +27,18 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-09-03: Added for support for multiple Vulkan contexts with custom loaders. (#6616)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends.
// - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler.
// - Before: ImGui_ImplVulkan_AddTexture(VkSampler, VkImageView, VkImageLayout)
// - After: ImGui_ImplVulkan_AddTexture(VkImageView, VkImageLayout)
// - Kept inline redirection function that ignores the sampler.
// - When creating your own descriptor pool (instead of letting backend creates its own):
// - Before: need at least IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER.
// - After: need at least IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE.
// + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE descriptors of type VK_DESCRIPTOR_TYPE_SAMPLER.
// 2026-03-11: Vulkan: Added ImGui_ImplVulkan_PipelineInfo::ExtraDynamicStates[] to allow specifying extra dynamic states to add when creating the VkPipeline. (#9211)
// 2025-09-26: [Helpers] *BREAKING CHANGE*: Vulkan: Helper ImGui_ImplVulkanH_DestroyWindow() does not call vkDestroySurfaceKHR(): as surface is created by caller of ImGui_ImplVulkanH_CreateOrResizeWindow(), it is more consistent that we don't destroy it. (#9163)
// 2026-01-05: [Helpers] *BREAKING CHANGE*: Vulkan: Helper for creating render pass uses ImGui_ImplVulkanH_Window::AttachmentDesc to create render pass. Removed ClearEnabled. (#9152)
@ -220,10 +232,28 @@ static bool g_FunctionsLoaded = true;
IMGUI_VULKAN_FUNC_MAP_MACRO(vkUpdateDescriptorSets) \
IMGUI_VULKAN_FUNC_MAP_MACRO(vkWaitForFences)
struct ImGui_ImplVulkan_Functions
{
// Define function pointers
#define IMGUI_VULKAN_FUNC_DEF(func) static PFN_##func func;
#define IMGUI_VULKAN_FUNC_DEF(func) PFN_##func pfn_##func;
IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_DEF)
#undef IMGUI_VULKAN_FUNC_DEF
};
// Globally available function pointers used for initialization of the backend data
static ImGui_ImplVulkan_Functions ImGuiImplVulkanFuncs;
// Multi Vulkan contexts support: wrap each Vulkan function pointer to properly dispatch it using the current backend data
static ImGui_ImplVulkan_Functions& ImGui_ImplVulkan_GetFunctions();
#define IMGUI_VULKAN_FUNC_WRAPPER(func) \
template<typename... Args> \
auto func(Args&&... args) -> decltype(ImGui_ImplVulkan_GetFunctions().pfn_##func(args...)) \
{ \
return ImGui_ImplVulkan_GetFunctions().pfn_##func(args...); \
}
IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_WRAPPER)
#undef IMGUI_VULKAN_FUNC_WRAPPER
#endif // IMGUI_IMPL_VULKAN_USE_LOADER
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
@ -266,10 +296,12 @@ struct ImGui_ImplVulkan_Texture
struct ImGui_ImplVulkan_Data
{
ImGui_ImplVulkan_InitInfo VulkanInitInfo;
ImGui_ImplVulkan_RenderState* RenderState; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering.
VkDeviceSize BufferMemoryAlignment;
VkDeviceSize NonCoherentAtomSize;
VkPipelineCreateFlags PipelineCreateFlags;
VkDescriptorSetLayout DescriptorSetLayout;
VkDescriptorSetLayout DescriptorSetLayoutTexture;
VkDescriptorSetLayout DescriptorSetLayoutSampler;
VkPipelineLayout PipelineLayout;
VkPipeline Pipeline; // pipeline for main render pass (created by app)
VkShaderModule ShaderModuleVert;
@ -278,13 +310,21 @@ struct ImGui_ImplVulkan_Data
ImVector<VkFormat> PipelineRenderingCreateInfoColorAttachmentFormats; // Deep copy of format array
// Texture management
VkSampler TexSamplerLinear;
VkSampler SamplerLinear;
VkSampler SamplerNearest;
VkDescriptorSet SamplerLinearDS;
VkDescriptorSet SamplerNearestDS;
VkCommandPool TexCommandPool;
VkCommandBuffer TexCommandBuffer;
// Render buffers for main window
ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers;
// Vulkan function pointers loaded for this context
#ifdef IMGUI_IMPL_VULKAN_USE_LOADER
ImGui_ImplVulkan_Functions Functions;
#endif
ImGui_ImplVulkan_Data()
{
memset((void*)this, 0, sizeof(*this));
@ -318,7 +358,7 @@ void main()
*/
static uint32_t __glsl_shader_vert_spv[] =
{
0x07230203,0x00010000,0x00080001,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,
0x07230203,0x00010000,0x0008000b,0x0000002e,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x000a000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000b,0x0000000f,0x00000015,
0x0000001b,0x0000001c,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
@ -331,10 +371,10 @@ static uint32_t __glsl_shader_vert_spv[] =
0x00050006,0x0000001e,0x00000000,0x61635375,0x0000656c,0x00060006,0x0000001e,0x00000001,
0x61725475,0x616c736e,0x00006574,0x00030005,0x00000020,0x00006370,0x00040047,0x0000000b,
0x0000001e,0x00000000,0x00040047,0x0000000f,0x0000001e,0x00000002,0x00040047,0x00000015,
0x0000001e,0x00000001,0x00050048,0x00000019,0x00000000,0x0000000b,0x00000000,0x00030047,
0x00000019,0x00000002,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00050048,0x0000001e,
0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,0x00000001,0x00000023,0x00000008,
0x00030047,0x0000001e,0x00000002,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,
0x0000001e,0x00000001,0x00030047,0x00000019,0x00000002,0x00050048,0x00000019,0x00000000,
0x0000000b,0x00000000,0x00040047,0x0000001c,0x0000001e,0x00000000,0x00030047,0x0000001e,
0x00000002,0x00050048,0x0000001e,0x00000000,0x00000023,0x00000000,0x00050048,0x0000001e,
0x00000001,0x00000023,0x00000008,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,
0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040017,
0x00000008,0x00000006,0x00000002,0x0004001e,0x00000009,0x00000007,0x00000008,0x00040020,
0x0000000a,0x00000003,0x00000009,0x0004003b,0x0000000a,0x0000000b,0x00000003,0x00040015,
@ -366,39 +406,44 @@ static uint32_t __glsl_shader_vert_spv[] =
/*
#version 450 core
layout(location = 0) out vec4 fColor;
layout(set=0, binding=0) uniform sampler2D sTexture;
layout(set=0, binding=0) uniform texture2D _Texture;
layout(set=1, binding=0) uniform sampler _Sampler;
layout(location = 0) in struct { vec4 Color; vec2 UV; } In;
void main()
{
fColor = In.Color * texture(sTexture, In.UV.st);
fColor = In.Color * texture(sampler2D(_Texture, _Sampler), In.UV.st);
}
*/
static uint32_t __glsl_shader_frag_spv[] =
{
0x07230203,0x00010000,0x00080001,0x0000001e,0x00000000,0x00020011,0x00000001,0x0006000b,
0x07230203,0x00010000,0x0008000b,0x00000023,0x00000000,0x00020011,0x00000001,0x0006000b,
0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000009,0x0000000d,0x00030010,
0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,0x0000000b,0x00000000,
0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,0x0000000b,0x00000001,
0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000016,0x78655473,0x65727574,
0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,
0x00000000,0x00040047,0x00000016,0x00000022,0x00000000,0x00040047,0x00000016,0x00000021,
0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,
0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,
0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006,
0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001,
0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020,
0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001,
0x00000007,0x00090019,0x00000013,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,
0x00000001,0x00000000,0x0003001b,0x00000014,0x00000013,0x00040020,0x00000015,0x00000000,
0x00000014,0x0004003b,0x00000015,0x00000016,0x00000000,0x0004002b,0x0000000e,0x00000018,
0x00000001,0x00040020,0x00000019,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,
0x00000000,0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,
0x0000000f,0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000014,0x00000017,
0x00000016,0x00050041,0x00000019,0x0000001a,0x0000000d,0x00000018,0x0004003d,0x0000000a,
0x0000001b,0x0000001a,0x00050057,0x00000007,0x0000001c,0x00000017,0x0000001b,0x00050085,
0x00000007,0x0000001d,0x00000012,0x0000001c,0x0003003e,0x00000009,0x0000001d,0x000100fd,
0x00005655,0x00030005,0x0000000d,0x00006e49,0x00050005,0x00000015,0x7865545f,0x65727574,
0x00000000,0x00050005,0x00000019,0x6d61535f,0x72656c70,0x00000000,0x00040047,0x00000009,
0x0000001e,0x00000000,0x00040047,0x0000000d,0x0000001e,0x00000000,0x00040047,0x00000015,
0x00000021,0x00000000,0x00040047,0x00000015,0x00000022,0x00000000,0x00040047,0x00000019,
0x00000021,0x00000000,0x00040047,0x00000019,0x00000022,0x00000001,0x00020013,0x00000002,
0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,
0x00000006,0x00000004,0x00040020,0x00000008,0x00000003,0x00000007,0x0004003b,0x00000008,
0x00000009,0x00000003,0x00040017,0x0000000a,0x00000006,0x00000002,0x0004001e,0x0000000b,
0x00000007,0x0000000a,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,
0x0000000d,0x00000001,0x00040015,0x0000000e,0x00000020,0x00000001,0x0004002b,0x0000000e,
0x0000000f,0x00000000,0x00040020,0x00000010,0x00000001,0x00000007,0x00090019,0x00000013,
0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00040020,
0x00000014,0x00000000,0x00000013,0x0004003b,0x00000014,0x00000015,0x00000000,0x0002001a,
0x00000017,0x00040020,0x00000018,0x00000000,0x00000017,0x0004003b,0x00000018,0x00000019,
0x00000000,0x0003001b,0x0000001b,0x00000013,0x0004002b,0x0000000e,0x0000001d,0x00000001,
0x00040020,0x0000001e,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,0x00000000,
0x00000003,0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,0x0000000f,
0x0004003d,0x00000007,0x00000012,0x00000011,0x0004003d,0x00000013,0x00000016,0x00000015,
0x0004003d,0x00000017,0x0000001a,0x00000019,0x00050056,0x0000001b,0x0000001c,0x00000016,
0x0000001a,0x00050041,0x0000001e,0x0000001f,0x0000000d,0x0000001d,0x0004003d,0x0000000a,
0x00000020,0x0000001f,0x00050057,0x00000007,0x00000021,0x0000001c,0x00000020,0x00050085,
0x00000007,0x00000022,0x00000012,0x00000021,0x0003003e,0x00000009,0x00000022,0x000100fd,
0x00010038
};
@ -414,6 +459,21 @@ static ImGui_ImplVulkan_Data* ImGui_ImplVulkan_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplVulkan_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState()
{
return (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
#ifdef IMGUI_IMPL_VULKAN_USE_LOADER
// Get the Vulkan function pointers used by the current backend.
// If no backend is available, return the currently loaded global function pointers (ImGuiImplVulkanFuncs).
static ImGui_ImplVulkan_Functions& ImGui_ImplVulkan_GetFunctions()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
return bd ? bd->Functions : ImGuiImplVulkanFuncs;
}
#endif
static uint32_t ImGui_ImplVulkan_MemoryType(VkMemoryPropertyFlags properties, uint32_t type_bits)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
@ -481,9 +541,7 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
// Bind pipeline:
{
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
}
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
// Bind Vertex And Index Buffer:
if (draw_data->TotalVtxCount > 0)
@ -495,35 +553,48 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
}
// Setup viewport:
{
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = (float)fb_width;
viewport.height = (float)fb_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
}
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.width = (float)fb_width;
viewport.height = (float)fb_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
// Setup scale and translation:
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
{
float constants[4];
constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale
constants[1] = 2.0f / draw_data->DisplaySize.y;
constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate
constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1];
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants);
}
float constants[4];
constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale
constants[1] = 2.0f / draw_data->DisplaySize.y;
constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate
constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1];
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, (uint32_t)sizeof(float) * 4, constants);
// Setup sampler
vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr);
}
// Draw callbacks
static void ImGui_ImplVulkan_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); }
static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); }
// If you want to use your own sampler, you can create your own callback, access ImGui_ImplVulkan_RenderState for command-buffer and pipeline layout, e.g.
/*
void ImGui_ImplVulkan_DrawCallback_SetSamplerCustom(const ImDrawList*, const ImDrawCmd* cmd)
{
ImGui_ImplVulkan_RenderState* render_state = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
vkCmdBindDescriptorSets(render_state->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, render_state->PipelineLayout, 1, 1, (VkDescriptorSet*)cmd->UserCallbackData, 0, nullptr);
}
*/
// Render function
void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline)
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0)
return;
@ -589,16 +660,16 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
vkUnmapMemory(v->Device, rb->IndexBufferMemory);
}
// Setup desired Vulkan state
ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height);
// Setup render state structure (for callbacks and custom texture bindings)
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGui_ImplVulkan_RenderState render_state;
render_state.CommandBuffer = command_buffer;
render_state.Pipeline = pipeline;
render_state.PipelineLayout = bd->PipelineLayout;
platform_io.Renderer_RenderState = &render_state;
platform_io.Renderer_RenderState = bd->RenderState = &render_state;
// Setup desired Vulkan state
ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
@ -606,7 +677,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
VkDescriptorSet last_desc_set = VK_NULL_HANDLE;
VkDescriptorSet last_image_view = VK_NULL_HANDLE;
int global_vtx_offset = 0;
int global_idx_offset = 0;
for (const ImDrawList* draw_list : draw_data->CmdLists)
@ -617,12 +688,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplVulkan_DrawCallback_ResetRenderState)
{
ImGui_ImplVulkan_SetupRenderState(draw_data, pipeline, command_buffer, rb, fb_width, fb_height);
last_image_view = VK_NULL_HANDLE;
}
else
pcmd->UserCallback(draw_list, pcmd);
last_desc_set = VK_NULL_HANDLE;
}
else
{
@ -633,8 +705,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
@ -646,11 +718,11 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y);
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
// Bind DescriptorSet with font or user texture
VkDescriptorSet desc_set = (VkDescriptorSet)pcmd->GetTexID();
if (desc_set != last_desc_set)
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &desc_set, 0, nullptr);
last_desc_set = desc_set;
// Bind DescriptorSets for image view (font or user texture) and samplers
VkDescriptorSet image_view = (VkDescriptorSet)pcmd->GetTexID();
if (image_view != last_image_view)
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &image_view, 0, nullptr);
last_image_view = image_view;
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
@ -659,7 +731,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
global_idx_offset += draw_list->IdxBuffer.Size;
global_vtx_offset += draw_list->VtxBuffer.Size;
}
platform_io.Renderer_RenderState = nullptr;
platform_io.Renderer_RenderState = bd->RenderState = nullptr;
// Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called.
// Our last values will leak into user/application rendering IF:
@ -753,7 +825,7 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex)
}
// Create the Descriptor Set
backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(bd->TexSamplerLinear, backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Store identifiers
tex->SetTexID((ImTextureID)backend_tex->DescriptorSet);
@ -1048,15 +1120,82 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc
return pipeline;
}
static void ImGui_ImplVulkan_CreateDescriptorSetLayout(VkDescriptorSetLayout* p_layout, VkDescriptorType descriptor_type)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkDescriptorSetLayoutBinding binding[1] = {};
binding[0].descriptorType = descriptor_type;
binding[0].descriptorCount = 1;
binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
VkResult err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, p_layout);
check_vk_result(err);
}
static VkDescriptorSet ImGui_ImplVulkan_CreateSamplerDS(VkSampler sampler)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkDescriptorSet descriptor_set;
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayoutSampler;
VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set);
check_vk_result(err);
VkDescriptorImageInfo desc_image = {};
desc_image.sampler = sampler;
VkWriteDescriptorSet sampler_write_desc = {};
sampler_write_desc.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
sampler_write_desc.dstSet = descriptor_set;
sampler_write_desc.descriptorCount = 1;
sampler_write_desc.dstBinding = 0;
sampler_write_desc.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
sampler_write_desc.pImageInfo = &desc_image;
vkUpdateDescriptorSets(v->Device, 1, &sampler_write_desc, 0, nullptr);
return descriptor_set;
}
bool ImGui_ImplVulkan_CreateDeviceObjects()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
VkResult err;
if (!bd->TexSamplerLinear)
if (!bd->DescriptorSetLayoutTexture)
ImGui_ImplVulkan_CreateDescriptorSetLayout(&bd->DescriptorSetLayoutTexture, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
if (!bd->DescriptorSetLayoutSampler)
ImGui_ImplVulkan_CreateDescriptorSetLayout(&bd->DescriptorSetLayoutSampler, VK_DESCRIPTOR_TYPE_SAMPLER);
if (v->DescriptorPoolSize != 0)
{
IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE);
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, v->DescriptorPoolSize },
{ VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE },
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = v->DescriptorPoolSize + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE;
pool_info.poolSizeCount = (uint32_t)IM_COUNTOF(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool);
check_vk_result(err);
}
// Create samplers (bilinear sampling is required)
if (!bd->SamplerLinear || !bd->SamplerNearest)
{
// Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling.
VkSamplerCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
info.magFilter = VK_FILTER_LINEAR;
@ -1068,37 +1207,16 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
info.minLod = -1000;
info.maxLod = 1000;
info.maxAnisotropy = 1.0f;
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->TexSamplerLinear);
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerLinear);
check_vk_result(err);
}
bd->SamplerLinearDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerLinear);
if (!bd->DescriptorSetLayout)
{
VkDescriptorSetLayoutBinding binding[1] = {};
binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
binding[0].descriptorCount = 1;
binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.bindingCount = 1;
info.pBindings = binding;
err = vkCreateDescriptorSetLayout(v->Device, &info, v->Allocator, &bd->DescriptorSetLayout);
check_vk_result(err);
}
if (v->DescriptorPoolSize != 0)
{
IM_ASSERT(v->DescriptorPoolSize >= IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE);
VkDescriptorPoolSize pool_size = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, v->DescriptorPoolSize };
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = v->DescriptorPoolSize;
pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &pool_size;
err = vkCreateDescriptorPool(v->Device, &pool_info, v->Allocator, &bd->DescriptorPool);
info.magFilter = VK_FILTER_NEAREST;
info.minFilter = VK_FILTER_NEAREST;
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerNearest);
check_vk_result(err);
bd->SamplerNearestDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerNearest);
}
if (!bd->PipelineLayout)
@ -1108,10 +1226,10 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
push_constants[0].offset = sizeof(float) * 0;
push_constants[0].size = sizeof(float) * 4;
VkDescriptorSetLayout set_layout[1] = { bd->DescriptorSetLayout };
VkDescriptorSetLayout set_layout[2] = { bd->DescriptorSetLayoutTexture, bd->DescriptorSetLayoutSampler };
VkPipelineLayoutCreateInfo layout_info = {};
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layout_info.setLayoutCount = 1;
layout_info.setLayoutCount = 2;
layout_info.pSetLayouts = set_layout;
layout_info.pushConstantRangeCount = 1;
layout_info.pPushConstantRanges = push_constants;
@ -1191,10 +1309,12 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
if (bd->TexCommandBuffer) { vkFreeCommandBuffers(v->Device, bd->TexCommandPool, 1, &bd->TexCommandBuffer); bd->TexCommandBuffer = VK_NULL_HANDLE; }
if (bd->TexCommandPool) { vkDestroyCommandPool(v->Device, bd->TexCommandPool, v->Allocator); bd->TexCommandPool = VK_NULL_HANDLE; }
if (bd->TexSamplerLinear) { vkDestroySampler(v->Device, bd->TexSamplerLinear, v->Allocator); bd->TexSamplerLinear = VK_NULL_HANDLE; }
if (bd->SamplerLinear) { vkDestroySampler(v->Device, bd->SamplerLinear, v->Allocator); bd->SamplerLinear = VK_NULL_HANDLE; }
if (bd->SamplerNearest) { vkDestroySampler(v->Device, bd->SamplerNearest, v->Allocator); bd->SamplerNearest = VK_NULL_HANDLE; }
if (bd->ShaderModuleVert) { vkDestroyShaderModule(v->Device, bd->ShaderModuleVert, v->Allocator); bd->ShaderModuleVert = VK_NULL_HANDLE; }
if (bd->ShaderModuleFrag) { vkDestroyShaderModule(v->Device, bd->ShaderModuleFrag, v->Allocator); bd->ShaderModuleFrag = VK_NULL_HANDLE; }
if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
if (bd->DescriptorSetLayoutTexture) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutTexture, v->Allocator); bd->DescriptorSetLayoutTexture = VK_NULL_HANDLE; }
if (bd->DescriptorSetLayoutSampler) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayoutSampler, v->Allocator); bd->DescriptorSetLayoutSampler = VK_NULL_HANDLE; }
if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; }
@ -1241,8 +1361,8 @@ bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction(
#ifdef IMGUI_IMPL_VULKAN_USE_LOADER
#define IMGUI_VULKAN_FUNC_LOAD(func) \
func = reinterpret_cast<decltype(func)>(loader_func(#func, user_data)); \
if (func == nullptr) \
ImGuiImplVulkanFuncs.pfn_##func = reinterpret_cast<PFN_##func>(loader_func(#func, user_data)); \
if (ImGuiImplVulkanFuncs.pfn_##func == nullptr) \
return false;
IMGUI_VULKAN_FUNC_MAP(IMGUI_VULKAN_FUNC_LOAD)
#undef IMGUI_VULKAN_FUNC_LOAD
@ -1290,6 +1410,11 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplVulkan_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplVulkan_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplVulkan_DrawCallback_SetSamplerNearest;
// Sanity checks
IM_ASSERT(info->Instance != VK_NULL_HANDLE);
IM_ASSERT(info->PhysicalDevice != VK_NULL_HANDLE);
@ -1305,6 +1430,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
IM_ASSERT(info->PipelineInfoMain.RenderPass == VK_NULL_HANDLE);
bd->VulkanInitInfo = *info;
#ifdef IMGUI_IMPL_VULKAN_USE_LOADER
bd->Functions = ImGuiImplVulkanFuncs;
#endif
VkPhysicalDeviceProperties properties;
vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties);
@ -1355,7 +1483,7 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
// Register a texture by creating a descriptor
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayout image_layout)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
@ -1368,7 +1496,7 @@ VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = pool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
alloc_info.pSetLayouts = &bd->DescriptorSetLayoutTexture;
VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set);
check_vk_result(err);
}
@ -1377,20 +1505,27 @@ VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image
if (descriptor_set != VK_NULL_HANDLE)
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = sampler;
desc_image[0].imageView = image_view;
desc_image[0].imageLayout = image_layout;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = descriptor_set;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, nullptr);
}
return descriptor_set;
}
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
{
IM_UNUSED(sampler);
return ImGui_ImplVulkan_AddTexture(image_view, image_layout);
}
#endif
void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();

View file

@ -2,10 +2,10 @@
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features:
// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplVulkan_GetRenderState().
// The aim of imgui_impl_vulkan.h/.cpp is to be usable in your engine without any modification.
// IF YOU FEEL YOU NEED TO MAKE ANY CHANGE TO THIS CODE, please share them and your feedback at https://github.com/ocornut/imgui/
@ -78,7 +78,8 @@
#endif
// Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture().
#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (8) // Minimum per atlas
#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
// Specify settings to create pipeline and swapchain
struct ImGui_ImplVulkan_PipelineInfo
@ -109,7 +110,7 @@ struct ImGui_ImplVulkan_InitInfo
uint32_t QueueFamily;
VkQueue Queue;
VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0
uint32_t DescriptorPoolSize; // Optional: set to create internal descriptor pool automatically instead of using DescriptorPool.
uint32_t DescriptorPoolSize; // Optional: set to create internal ImageView descriptor pool automatically instead of using DescriptorPool.
uint32_t MinImageCount; // >= 2
uint32_t ImageCount; // >= MinImageCount
VkPipelineCache PipelineCache; // Optional
@ -152,18 +153,21 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_
// (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_ImplVulkan_UpdateTexture(ImTextureData* tex);
// Register a texture (VkDescriptorSet == ImTextureID)
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem
// Please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
// Register a texture (VkDescriptorSet for a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE == ImTextureID)
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayout image_layout);
IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout); // Ignore VkSampler
#endif
// Optional: load Vulkan functions with a custom function loader
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = nullptr);
// [BETA] Selected render state data shared with callbacks.
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplVulkan_RenderDrawData() call.
// ImGui_ImplVulkan_RenderState* render_state = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
// (Please open an issue if you feel you need access to more data)
struct ImGui_ImplVulkan_RenderState
{
@ -171,6 +175,7 @@ struct ImGui_ImplVulkan_RenderState
VkPipeline Pipeline;
VkPipelineLayout PipelineLayout;
};
IMGUI_IMPL_API ImGui_ImplVulkan_RenderState* ImGui_ImplVulkan_GetRenderState();
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
@ -254,7 +259,7 @@ struct ImGui_ImplVulkanH_Window
memset((void*)this, 0, sizeof(*this));
// Parameters to create SwapChain
PresentMode = (VkPresentModeKHR)~0; // Ensure we get an error if user doesn't set this.
PresentMode = VK_PRESENT_MODE_MAX_ENUM_KHR; // Ensure we get an error if user doesn't set this.
// Parameters to create RenderPass
AttachmentDesc.format = VK_FORMAT_UNDEFINED; // Will automatically use wd->SurfaceFormat.format.

View file

@ -5,8 +5,8 @@
// Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplWGPU_GetRenderState().
// Read imgui_impl_wgpu.h about how to use the IMGUI_IMPL_WEBGPU_BACKEND_WGPU or IMGUI_IMPL_WEBGPU_BACKEND_DAWN flags.
@ -20,6 +20,10 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-09-07: Round framebuffer dimensions to the nearest integer instead of truncating them. (#9538, 9515, #8628)
// 2026-08-31: Update to compile with wgpu-native 29.0. (#9377, #9532, #9530)
// 2026-08-18: Fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport() when FramebufferScale is >1.0f. (#9515, #8628)
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
// 2026-03-25: Added support for WGVK native backend via IMGUI_IMPL_WEBGPU_BACKEND_WGVK define, with SPIRV shaders if WGSL is not available. (#9316, #9246, #9257)
// 2026-03-09: Removed support for Emscripten < 4.0.10. (#9281)
// 2025-10-16: Update to compile with Dawn and Emscripten's 4.0.10+ '--use-port=emdawnwebgpu' ports. (#8381, #8898)
@ -64,12 +68,6 @@
#error Emscripten <4.0.10 with '-sUSE_WEBGPU=1' is not supported anymore.
#endif
#if defined IMGUI_IMPL_WEBGPU_BACKEND_DAWN || defined IMGUI_IMPL_WEBGPU_BACKEND_WGVK
// Dawn renamed WGPUProgrammableStageDescriptor to WGPUComputeState (see: https://github.com/webgpu-native/webgpu-headers/pull/413)
// Using type alias until WGPU adopts the same naming convention (#8369)
using WGPUProgrammableStageDescriptor = WGPUComputeState;
#endif
// Dear ImGui prototypes from imgui_internal.h
extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed);
#define MEMALIGN(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) // Memory align (copied from IM_ALIGN() macro).
@ -83,11 +81,13 @@ struct ImGui_ImplWGPU_Texture
struct RenderResources
{
WGPUSampler Sampler = nullptr; // Sampler for textures
WGPUBuffer Uniforms = nullptr; // Shader uniforms
WGPUBindGroup CommonBindGroup = nullptr; // Resources bind-group to bind the common resources to pipeline
ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map)
WGPUBindGroupLayout ImageBindGroupLayout = nullptr; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM
WGPUSampler SamplerLinear = nullptr; // Bilinear sampler
WGPUSampler SamplerNearest = nullptr; // Nearest/point sampler
WGPUBuffer Uniforms = nullptr; // Shader uniforms
WGPUBindGroup CommonBindGroupLinear = nullptr; // Common bind-group bound to group 0 (uniforms + SamplerLinear)
WGPUBindGroup CommonBindGroupNearest = nullptr; // Common bind-group bound to group 0 (uniforms + SamplerNearest)
ImGuiStorage ImageBindGroups; // Resources bind-group to bind the font/image resources to pipeline (this is a key->value map)
WGPUBindGroupLayout ImageBindGroupLayout = nullptr; // Cache layout used for the image bind group. Avoids allocating unnecessary JS objects when working with WebASM
};
struct FrameResources
@ -114,6 +114,7 @@ struct ImGui_ImplWGPU_Data
WGPUTextureFormat renderTargetFormat = WGPUTextureFormat_Undefined;
WGPUTextureFormat depthStencilFormat = WGPUTextureFormat_Undefined;
WGPURenderPipeline pipelineState = nullptr;
ImGui_ImplWGPU_RenderState* RenderState = nullptr; // == ImGui::GetPlatformIO().Renderer_RenderState during rendering.
RenderResources renderResources;
FrameResources* pFrameResources = nullptr;
@ -128,6 +129,11 @@ static ImGui_ImplWGPU_Data* ImGui_ImplWGPU_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplWGPU_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState()
{
return (ImGui_ImplWGPU_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState;
}
//-----------------------------------------------------------------------------
// SHADERS
//-----------------------------------------------------------------------------
@ -296,9 +302,11 @@ static void SafeRelease(WGPUShaderModule& res)
}
static void SafeRelease(RenderResources& res)
{
SafeRelease(res.Sampler);
SafeRelease(res.SamplerLinear);
SafeRelease(res.SamplerNearest);
SafeRelease(res.Uniforms);
SafeRelease(res.CommonBindGroup);
SafeRelease(res.CommonBindGroupLinear);
SafeRelease(res.CommonBindGroupNearest);
SafeRelease(res.ImageBindGroupLayout);
};
@ -310,9 +318,10 @@ static void SafeRelease(FrameResources& res)
SafeRelease(res.VertexBufferHost);
}
static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(const char* wgsl_source)
static WGPUComputeState ImGui_ImplWGPU_CreateShaderModuleWGSL(const char* wgsl_source)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
IM_UNUSED(bd);
WGPUShaderSourceWGSL wgsl_desc = {};
wgsl_desc.chain.sType = WGPUSType_ShaderSourceWGSL;
@ -321,14 +330,35 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleWGSL(con
WGPUShaderModuleDescriptor desc = {};
desc.nextInChain = (WGPUChainedStruct*)&wgsl_desc;
WGPUProgrammableStageDescriptor stage_desc = {};
stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc);
// Detect shader compilation errors by using an error scope.
// Flag to be passed into the validation callback `userdata1` pointer.
int validation_error = 0;
wgpuDevicePushErrorScope(bd->wgpuDevice, WGPUErrorFilter_Validation);
WGPUShaderModule module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc);
WGPUPopErrorScopeCallbackInfo pop_cb = {};
pop_cb.mode = WGPUCallbackMode_AllowSpontaneous;
pop_cb.callback = [](WGPUPopErrorScopeStatus, WGPUErrorType type, WGPUStringView, void* userdata1, void*)
{
if (type == WGPUErrorType_Validation)
*static_cast<int*>(userdata1) = 1;
};
pop_cb.userdata1 = &validation_error;
wgpuDevicePopErrorScope(bd->wgpuDevice, pop_cb);
stage_desc.entryPoint = { "main", WGPU_STRLEN };
WGPUComputeState stage_desc = {};
if (module && !validation_error)
{
stage_desc.module = module;
stage_desc.entryPoint = { "main", WGPU_STRLEN };
}
else if (module)
{
wgpuShaderModuleRelease(module);
}
return stage_desc;
}
static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleSPIRV(const void* spirv_binary, size_t spirv_length)
static WGPUComputeState ImGui_ImplWGPU_CreateShaderModuleSPIRV(const void* spirv_binary, size_t spirv_length)
{
ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData();
@ -340,7 +370,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModuleSPIRV(co
WGPUShaderModuleDescriptor desc = {};
desc.nextInChain = (WGPUChainedStruct*)&spirv_desc;
WGPUProgrammableStageDescriptor stage_desc = {};
WGPUComputeState stage_desc = {};
stage_desc.module = wgpuDeviceCreateShaderModule(bd->wgpuDevice, &desc);
stage_desc.entryPoint = { "main", WGPU_STRLEN };
@ -412,26 +442,32 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas
}
// Setup viewport
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, (float)fb_width, (float)fb_height, 0, 1);
// Bind shader and vertex buffers
wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize * sizeof(ImDrawVert));
wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize * sizeof(ImDrawIdx));
wgpuRenderPassEncoderSetPipeline(ctx, bd->pipelineState);
wgpuRenderPassEncoderSetBindGroup(ctx, 0, bd->renderResources.CommonBindGroup, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(ctx, 0, bd->renderResources.CommonBindGroupLinear, 0, nullptr);
// Setup blend factor
WGPUColor blend_color = { 0.f, 0.f, 0.f, 0.f };
WGPUColor blend_color = { 0.0f, 0.0f, 0.0f, 0.0f };
wgpuRenderPassEncoderSetBlendConstant(ctx, &blend_color);
}
// Draw callbacks
static void ImGui_ImplWGPU_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
static void ImGui_ImplWGPU_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); wgpuRenderPassEncoderSetBindGroup(bd->RenderState->RenderPassEncoder, 0, bd->renderResources.CommonBindGroupLinear, 0, nullptr); }
static void ImGui_ImplWGPU_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); wgpuRenderPassEncoderSetBindGroup(bd->RenderState->RenderPassEncoder, 0, bd->renderResources.CommonBindGroupNearest, 0, nullptr); }
// Render function
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder pass_encoder)
{
// Avoid rendering when minimized
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
if (fb_width <= 0 || fb_height <= 0 || draw_data->CmdLists.Size == 0)
return;
@ -521,7 +557,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
ImGui_ImplWGPU_RenderState render_state;
render_state.Device = bd->wgpuDevice;
render_state.RenderPassEncoder = pass_encoder;
platform_io.Renderer_RenderState = &render_state;
platform_io.Renderer_RenderState = bd->RenderState = &render_state;
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
@ -537,8 +573,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
if (pcmd->UserCallback != nullptr)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
if (pcmd->UserCallback == ImGui_ImplWGPU_DrawCallback_ResetRenderState)
ImGui_ImplWGPU_SetupRenderState(draw_data, pass_encoder, fr);
else
pcmd->UserCallback(draw_list, pcmd);
@ -549,12 +584,11 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
ImTextureID tex_id = pcmd->GetTexID();
ImGuiID tex_id_hash = ImHashData(&tex_id, sizeof(tex_id), 0);
WGPUBindGroup bind_group = (WGPUBindGroup)bd->renderResources.ImageBindGroups.GetVoidPtr(tex_id_hash);
if (!bind_group)
{
bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bd->renderResources.ImageBindGroupLayout, (WGPUTextureView)tex_id);
bd->renderResources.ImageBindGroups.SetVoidPtr(tex_id_hash, bind_group);
}
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, nullptr);
if (!bind_group && tex_id != 0)
if ((bind_group = ImGui_ImplWGPU_CreateImageBindGroup(bd->renderResources.ImageBindGroupLayout, (WGPUTextureView)tex_id)) != 0)
bd->renderResources.ImageBindGroups.SetVoidPtr(tex_id_hash, bind_group);
if (bind_group)
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, (WGPUBindGroup)bind_group, 0, nullptr);
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
@ -563,8 +597,8 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
// Clamp to viewport as wgpuRenderPassEncoderSetScissorRect() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
@ -586,7 +620,7 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
}
image_bind_groups.Data.resize(0);
platform_io.Renderer_RenderState = nullptr;
platform_io.Renderer_RenderState = bd->RenderState = nullptr;
}
static void ImGui_ImplWGPU_DestroyTexture(ImTextureData* tex)
@ -739,7 +773,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
graphics_pipeline_desc.layout = wgpuDeviceCreatePipelineLayout(bd->wgpuDevice, &layout_desc);
// Create the vertex shader
WGPUProgrammableStageDescriptor vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_vert_wgsl);
WGPUComputeState vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_vert_wgsl);
if (!vertex_shader_desc.module) vertex_shader_desc = ImGui_ImplWGPU_CreateShaderModuleSPIRV(__shader_vert_spirv, sizeof(__shader_vert_spirv));
graphics_pipeline_desc.vertex.module = vertex_shader_desc.module;
graphics_pipeline_desc.vertex.entryPoint = vertex_shader_desc.entryPoint;
@ -747,15 +781,9 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
// Vertex input configuration
WGPUVertexAttribute attribute_desc[] =
{
#if defined IMGUI_IMPL_WEBGPU_BACKEND_DAWN || defined IMGUI_IMPL_WEBGPU_BACKEND_WGVK
{ nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 },
{ nullptr, WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 },
{ nullptr, WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 },
#else
{ WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, pos), 0 },
{ WGPUVertexFormat_Float32x2, (uint64_t)offsetof(ImDrawVert, uv), 1 },
{ WGPUVertexFormat_Unorm8x4, (uint64_t)offsetof(ImDrawVert, col), 2 },
#endif
};
WGPUVertexBufferLayout buffer_layouts[1];
@ -768,7 +796,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
graphics_pipeline_desc.vertex.buffers = buffer_layouts;
// Create the pixel shader
WGPUProgrammableStageDescriptor pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_frag_wgsl);
WGPUComputeState pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleWGSL(__shader_frag_wgsl);
if (!pixel_shader_desc.module) pixel_shader_desc = ImGui_ImplWGPU_CreateShaderModuleSPIRV(__shader_frag_spirv, sizeof(__shader_frag_spirv));
// Create the blending setup
@ -814,29 +842,34 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
ImGui_ImplWGPU_CreateUniformBuffer();
// Create sampler
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// Create samplers (Linear/Nearest) (bilinear sampling is required)
WGPUSamplerDescriptor sampler_desc = {};
sampler_desc.minFilter = WGPUFilterMode_Linear;
sampler_desc.magFilter = WGPUFilterMode_Linear;
sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge;
sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge;
sampler_desc.addressModeW = WGPUAddressMode_ClampToEdge;
sampler_desc.maxAnisotropy = 1;
bd->renderResources.Sampler = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc);
sampler_desc.minFilter = WGPUFilterMode_Linear;
sampler_desc.magFilter = WGPUFilterMode_Linear;
sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
bd->renderResources.SamplerLinear = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc);
sampler_desc.minFilter = WGPUFilterMode_Nearest;
sampler_desc.magFilter = WGPUFilterMode_Nearest;
sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
bd->renderResources.SamplerNearest = wgpuDeviceCreateSampler(bd->wgpuDevice, &sampler_desc);
// Create resource bind group
// Create resource bind groups (one per sampler, otherwise identical)
WGPUBindGroupEntry common_bg_entries[] =
{
{ nullptr, 0, bd->renderResources.Uniforms, 0, MEMALIGN(sizeof(Uniforms), 16), 0, 0 },
{ nullptr, 1, 0, 0, 0, bd->renderResources.Sampler, 0 },
{ nullptr, 1, 0, 0, 0, bd->renderResources.SamplerLinear, 0 },
};
WGPUBindGroupDescriptor common_bg_descriptor = {};
common_bg_descriptor.layout = bg_layouts[0];
common_bg_descriptor.entryCount = sizeof(common_bg_entries) / sizeof(WGPUBindGroupEntry);
common_bg_descriptor.entries = common_bg_entries;
bd->renderResources.CommonBindGroup = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor);
bd->renderResources.CommonBindGroupLinear = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor);
common_bg_entries[1].sampler = bd->renderResources.SamplerNearest;
bd->renderResources.CommonBindGroupNearest = wgpuDeviceCreateBindGroup(bd->wgpuDevice, &common_bg_descriptor);
bd->renderResources.ImageBindGroupLayout = bg_layouts[1];
SafeRelease(vertex_shader_desc.module);
@ -888,6 +921,11 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
platform_io.DrawCallback_ResetRenderState = ImGui_ImplWGPU_DrawCallback_ResetRenderState;
platform_io.DrawCallback_SetSamplerLinear = ImGui_ImplWGPU_DrawCallback_SetSamplerLinear;
platform_io.DrawCallback_SetSamplerNearest = ImGui_ImplWGPU_DrawCallback_SetSamplerNearest;
bd->initInfo = *init_info;
bd->wgpuDevice = init_info->Device;
bd->defaultQueue = wgpuDeviceGetQueue(bd->wgpuDevice);
@ -896,11 +934,7 @@ bool ImGui_ImplWGPU_Init(ImGui_ImplWGPU_InitInfo* init_info)
bd->numFramesInFlight = init_info->NumFramesInFlight;
bd->frameIndex = UINT_MAX;
bd->renderResources.Sampler = nullptr;
bd->renderResources.Uniforms = nullptr;
bd->renderResources.CommonBindGroup = nullptr;
bd->renderResources.ImageBindGroups.Data.reserve(100);
bd->renderResources.ImageBindGroupLayout = nullptr;
// Create buffers with a default size (they will later be grown as needed)
bd->pFrameResources = new FrameResources[bd->numFramesInFlight];
@ -955,11 +989,7 @@ void ImGui_ImplWGPU_NewFrame()
bool ImGui_ImplWGPU_IsSurfaceStatusError(WGPUSurfaceGetCurrentTextureStatus status)
{
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
return (status == WGPUSurfaceGetCurrentTextureStatus_Error);
#else
return (status == WGPUSurfaceGetCurrentTextureStatus_OutOfMemory || status == WGPUSurfaceGetCurrentTextureStatus_DeviceLost);
#endif
}
bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextureStatus status)
@ -972,7 +1002,6 @@ bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextureStatus
}
// Helpers to obtain a string
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN) || defined(IMGUI_IMPL_WEBGPU_BACKEND_WGVK)
const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type)
{
switch (type)
@ -995,7 +1024,7 @@ const char* ImGui_ImplWGPU_GetDeviceLostReasonName(WGPUDeviceLostReason type)
default: return "Unknown";
}
}
#elif !defined(__EMSCRIPTEN__)
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__)
const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level)
{
switch (level)

View file

@ -17,8 +17,8 @@
// Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID/ImTextureRef!
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
// [X] Renderer: Expose selected render state for draw callbacks to use. Access with ImGui_ImplWGPU_GetRenderState().
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -81,6 +81,7 @@ struct ImGui_ImplWGPU_RenderState
WGPUDevice Device;
WGPURenderPassEncoder RenderPassEncoder;
};
IMGUI_IMPL_API ImGui_ImplWGPU_RenderState* ImGui_ImplWGPU_GetRenderState();
//-------------------------------------------------------------------------
// Internal Helpers
@ -95,10 +96,9 @@ bool ImGui_ImplWGPU_IsSurfaceStatusSubOptimal(WGPUSurfaceGetCurrentTextur
void ImGui_ImplWGPU_DebugPrintAdapterInfo(const WGPUAdapter& adapter);
const char* ImGui_ImplWGPU_GetBackendTypeName(WGPUBackendType type);
const char* ImGui_ImplWGPU_GetAdapterTypeName(WGPUAdapterType type);
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_DAWN)
const char* ImGui_ImplWGPU_GetDeviceLostReasonName(WGPUDeviceLostReason type);
const char* ImGui_ImplWGPU_GetErrorTypeName(WGPUErrorType type);
#elif defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU) && !defined(__EMSCRIPTEN__)
const char* ImGui_ImplWGPU_GetLogLevelName(WGPULogLevel level);
#endif

View file

@ -21,6 +21,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2026-05-19: DPI: ImGui_ImplWin32_EnableDpiAwareness() helper uses SetProcessDpiAwarenessContext() instead of SetThreadDpiAwarenessContext(), fixes DPI scaling issues with e.g. OpenGL. (#9403)
// 2026-01-28: Inputs: Minor optimization not submitting gamepad input if packet number has not changed (reworked from 2025-09-23 attempt). (#9202, #8556)
// 2025-12-03: Inputs: handle WM_IME_CHAR/WM_IME_COMPOSITION messages to support Unicode inputs on MBCS (non-Unicode) Windows. (#9099, #3653, #5961)
// 2025-10-19: Inputs: Revert previous change to allow for io.ClearInputKeys() on focus-out not losing gamepad state.
@ -412,7 +413,7 @@ void ImGui_ImplWin32_NewFrame()
// Setup time step
INT64 current_time = 0;
::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
io.DeltaTime = (float)(current_time - bd->Time) / bd->TicksPerSecond;
io.DeltaTime = (float)((double)(current_time - bd->Time) / (double)bd->TicksPerSecond);
bd->Time = current_time;
// Update OS mouse position
@ -886,6 +887,7 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
typedef HRESULT(WINAPI* PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); // Shcore.lib + dll, Windows 8.1+
typedef HRESULT(WINAPI* PFN_GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); // Shcore.lib + dll, Windows 8.1+
typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1607+ (Creators Update)
typedef BOOL(WINAPI* PFN_SetProcessDpiAwarenessContext)(DPI_AWARENESS_CONTEXT); // User32.lib + dll, Windows 10 v1703+ (Creators Update)
// Helper function to enable DPI awareness without setting up a manifest
void ImGui_ImplWin32_EnableDpiAwareness()
@ -893,7 +895,12 @@ void ImGui_ImplWin32_EnableDpiAwareness()
if (_IsWindows10OrGreater())
{
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
if (PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContextFn = (PFN_SetProcessDpiAwarenessContext)::GetProcAddress(user32_dll, "SetProcessDpiAwarenessContext")) // Windows 10 v1703+
{
SetProcessDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
return;
}
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) // Windows 10 v1607+
{
SetThreadDpiAwarenessContextFn(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
return;
@ -930,7 +937,7 @@ float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
{
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
return xdpi / 96.0f;
return (float)xdpi / 96.0f;
}
}
#ifndef NOGDI
@ -940,7 +947,7 @@ float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
::ReleaseDC(nullptr, dc);
#endif
return xdpi / 96.0f;
return (float)xdpi / 96.0f;
}
float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)

View file

@ -1,7 +1,8 @@
#version 450 core
layout(location = 0) out vec4 fColor;
layout(set=0, binding=0) uniform sampler2D sTexture;
layout(set=0, binding=0) uniform texture2D _Texture;
layout(set=1, binding=0) uniform sampler _Sampler;
layout(location = 0) in struct {
vec4 Color;
@ -10,5 +11,5 @@ layout(location = 0) in struct {
void main()
{
fColor = In.Color * texture(sTexture, In.UV.st);
fColor = In.Color * texture(sampler2D(_Texture, _Sampler), In.UV.st);
}

View file

@ -72,13 +72,14 @@ For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree
In the [backends/](https://github.com/ocornut/imgui/blob/master/backends) folder:
List of Platforms Backends:
List of Platform Backends:
imgui_impl_android.cpp ; Android native app API
imgui_impl_glfw.cpp ; GLFW (Windows, macOS, Linux, etc.) http://www.glfw.org/
imgui_impl_osx.mm ; macOS native API (not as feature complete as glfw/sdl backends)
imgui_impl_sdl2.cpp ; SDL2 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org
imgui_impl_sdl3.cpp ; SDL3 (Windows, macOS, Linux, iOS, Android) https://www.libsdl.org
imgui_impl_qnx.cpp ; QNX Screen
imgui_impl_win32.cpp ; Win32 native API (Windows)
imgui_impl_glut.cpp ; GLUT/FreeGLUT (this is prehistoric software and absolutely not recommended today!)
@ -89,6 +90,7 @@ List of Renderer Backends:
imgui_impl_dx11.cpp ; DirectX11
imgui_impl_dx12.cpp ; DirectX12
imgui_impl_metal.mm ; Metal (ObjC or C++)
imgui_impl_metal4.mm ; Metal 4 (ObjC or C++)
imgui_impl_opengl2.cpp ; OpenGL 2 (legacy fixed pipeline. Don't use with modern OpenGL code!)
imgui_impl_opengl3.cpp ; OpenGL 3/4, OpenGL ES 2/3, WebGL
imgui_impl_sdlgpu3.cpp ; SDL_GPU (portable 3D graphics API of SDL3)
@ -116,7 +118,7 @@ If you are not sure which backend to use, the recommended platform/frameworks fo
| GLFW | https://github.com/glfw/glfw | imgui_impl_glfw.cpp | |
| Sokol | https://github.com/floooh/sokol | [util/sokol_imgui.h](https://github.com/floooh/sokol/blob/master/util/sokol_imgui.h) | Lower-level than GLFW/SDL |
If your application runs on Windows or if you are using multi-viewport, the win32 backend handles some details a little better than other backends.
If your application runs on Windows or if you are using multi-viewports, the imgui_impl_win32 backend handles some details better than other backends.
## Using third-party Backends
@ -233,9 +235,7 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data)
// - Scissor enabled
MyEngineSetupenderState();
// TODO: Setup texture sampling state
// - Sample with bilinear filtering (NOT point/nearest filtering).
// - Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering.
// TODO: Setup texture sampler to bilinear (NOT point/nearest filtering).
// TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
@ -255,8 +255,8 @@ void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data)
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
MyEngineSetupenderState();
if (pcmd->UserCallback == platform_io.DrawCallback_ResetRenderState)
MyEngineSetupSenderState();
else
pcmd->UserCallback(cmd_list, pcmd);
}

View file

@ -35,6 +35,563 @@ HOW TO UPDATE?
and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users.
- Please report any issue!
-----------------------------------------------------------------------
VERSION 1.93.0 WIP (In Progress)
-----------------------------------------------------------------------
Breaking Changes:
- Style: obsoleted `style.CurveTessellationTol (default 1.25)` which was in Pixels² unit in
favor of `style.CurveTessellationMaxError` (default 1.12)` which is in Pixels unit. It is
easier to tweak + this allows us to easily scale error threshold on high density screens.
- style.CurveTessellationMaxError == sqrf(style.CurveTessellationTol).
- ImGuiTextFilter: removed `float width` parameter of `Draw(const char* filter, float width)`:
prefer using `SetNextItemWidth(float)` which is standard. Kept inline redirection function.
- Backends:
- DirectX12: Removed support for legacy `ImGui_ImplDX12_Init()` signature, which was
obsoleted in 1.91.6 (December 2014), because it needed to forcefully disable support
for `ImGuiBackendFlags_RendererHasTextures`. Use the new signature! (#9487)
Other Changes:
- Drags, Sliders:
- Fixed an overflow using `ImGuiSliderFlags_Logarithmic` with S32/S64 types which
leads to clamped interactions. (#9526, #3361, #1823, #1316, #642) [@lailoken]
- Ongoing drags may be cancelled using Right-Click, Escape or Gamepad Triangle.
Cancelling reverts to the initial value. (#8564, #9534)
- TreeNode:
- Fixed issues/asserts with 32+ deep trees when using ImGuiTreeNodeFlags_DrawLinesXXX
features or other features requiring stack storage. (#9509) [@lasrod]
- TabBar:
- Improved scroll target when clicking a Tab that is larger than the scrolling
section width.
- Using <> scrolling buttons while the selected Tab is at either end of the
section mid-section but not fully visible always makes it fully visible
(before eventually selecting a Tab in the leading/trailing section)
- Tables:
- Fixed a bug restoring correct .ini columns order when table use is Sortable
but had no user changes. (regression from 1.92.9). (#9519, #9108)
- InpuText:
- Fixed a crash in some cases when using Home key in a WordWrap+ReadOnly field. (#9561)
- Selectable:
- Fixed `ImGuiSelectableFlags_SelectOnNav` triggering during NavInit.
- Fonts:
- Reworked `AddFontDefault()` to use `io.DisplayFrameBufferScale` as part of the heuristic
to select `AddFontDefaultVector()` by default, effectively using ProggyForever instead of
ProggyClean on most Apple/Retina setups by default.
- imgui_freetype: Fixed blurryness rendering `AddFontDefaultVector()`. Caused by a
non-pixel aligned offset caused by `ExtraSizeScale`. (#9348, #9233) [@redpartizan, @RDMCz]
- ColorEdit:
- ColorButton, ColorEdit, ColorPicker: cancel-out alpha caused by BeginDisabled() so
disabled color buttons have the same color as non-disabled oness. (#9511)
- ColorButton: fixed issues/inconsistencies with checkerboard rendering when combining
color alpha and global style alpha. (#9511) [@enjmiah, @ocornut]
- Popups:
- Amended context menu right-click opening code to check that the right-click
hasn't been owned by another items. This is more correct and also necessary
to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534)
- Reworked `GetMousePosOnOpeningCurrentPopup()` to be legal to call within the
BeginPopup/EndPopup scope of a popup which was just closed. (#9551) [@jkunstwald]
- ImGuiTextFilter:
- Added support for space as an "and" filter, which is the standard. (#2435, #30)
e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data.
- Added support for double-quoted "xxx" blocks to e.g. match words sequences. (#2435)
e.g. w/ filter "hello world" the exact sequence needs to be in input data.
- Fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude"
match always filters out. (#2435) [@kudaba, @ocornut]
- Added `DrawWithHint()` function. (#6206, #6395, #6447)
- Added a "incl -excl" hint by default when the search field is empty. (#6206, #6395, #6447)
- Style:
- Inverted `ImGuiCol_TitleBgXXX` colors for `StyleColorsLight()` so that the selected
window title bar appears brighter.
- Misc:
- Added `ImGuiItemFlags_MixedValue` flag for representing mixed/indeterminate values.
Supported by: Checkbox(), RadioButton(), DragXXX(), SliderXXX(), InputXXX(), ColorXXX()
and Combo() functions.
The scoped flag is designed for usage by advanced property editors. (#5518, #5677, #6865)
- Fixed `GetBackgroundDrawList()`/`GetForegroundDrawList()` not being properly reset
every frame when cumulated session time is very large (e.g. a few days). [@lailoken]
- Added `IM_NODEBUGSTEP` helper to tag functions with `__declspec(non_user_code)` (MSVC)
or `[[gnu::artificial]]` (Clang/GCC) in order to provide a hint to debuggers to skip
trivial functions when stepping into.
- Tagged various trivial functions using `IM_NODEBUGSTEP`: `ImVec2()`, `ImVec4()` etc.
and various operators.
- Fixed strict aliasing violation in `ImHashData()` affecting Clang 23 + SSE 4.2 + -flto.
Could manifest as `ImFontAtlasBakedGetId()` computation omitting font size from
the hashed data. (#9557, #9560) [@sthalik]
- IO: restore default clipboard/ime/shell platform handlers on ClearPlatformHandlers(), fixing
issues switching backends mid-session to one relying on default. (#9537, #8945, #2769) [@lstalmir]
- DrawList:
- Per-viewport FramebufferScale for Apple/Retina screen is applied to draw lists:
- AA Fringe is scaled accordingly.
- Circle and Curves tessellation error are scaled accordingly.
- Reworked assert in PushTexture() to allow convenience grace period of using a
texture that was queue for destroy during the frame. Make it safe to stick to
an existing texture during the frame. (#9528, #8465)
- Added optional `platform_io.DrawCallback_SetSamplerFromTex` standard backend-agnostic
draw callback for requesting to use the sampler associated already associated to a texture.
Currently only supported by the OpenGL2/3 and SDLRenderer3 backend. (#9378)
- Fixed dangling ImDrawList::_OwnerName when using animated label. (#9552) [@ubi-dcastonguay]
- Demo:
- Added `Widgets->Mixed Values` section. (#5518, #5677, #6865)
- Style Editor: fixed style/colors combo box applying style when opening Combo.
- Backends:
- QNX: added QNX Screen backend. (#9492) [@mgorchak-blackberry]
- OpenGL2, OpenGL3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw
callback to request using the sampler associated already associated to a texture. (#9378)
- OpenGL2, OpenGL3: fixed `DrawCallback_ResetRenderState` handler not reseting all states
in the glTexParameter() path. (#9378)
- SDL2: fixed querying framebuffer scale/density when using Metal without
going through a SDL_Renderer. (#5592) [@lailoken]
- SDLRenderer3: restore any temporarily modified texture scale modes at the of `RenderDrawData()`. (#9378)
- SDLRenderer3: expose CurrentScaleMode in ImGui_ImplSDLRenderer3_RenderState. (#9543, #9378) [@Clownacy]
- SDLRenderer3: added support for `platform_io.DrawCallback_SetSamplerFromTex` draw callback to request
using the sampler associated already associated to a texture via `SDL_SetTextureScaleMode()`. (#9378)
It is equivalent to setting `render_state->CurrentScaleMode = SDL_SCALEMODE_INVALID`.
Note: this callback is only supported by selected rendering backends: most other graphics API
don't have the equivalent of `SDL_SetTextureScaleMode()` and the callback won't work with them.
- Vulkan: added for support for multiple Vulkan contexts with custom loaders. (#6616) [@lstalmir]
- WebGPU: fixed passing non-integer sizes to `wgpuRenderPassEncoderSetViewport()`
when `FramebufferScale` is >1.0f. (#9515, #8628) [@WayU]
- WebGPU: update to build with wgpu-native 29.0+. (#9377, #9532, #9530) [@lucascompython, @ivan-enzhaev]
- Examples:
- MSVC: disabled /JMC in Visual Studio projects (unnecessary overhead).
- GLFW/SDL2/SDL3+WebGPU: fixed running with wgpu-native missing `wgpuInstanceWaitAny()`. (#9377)
- SDL2+Metal: create Metal context without using a `SDL_Renderer`.
- QNX+OpenGL3, QNX+Vulkan: added QNX Screen examples. (#9492) [@mgorchak-blackberry]
- OSX+OpenGL3: added example_apple_opengl3/ (OSX/Cocoa + OpenGL 3.2 Core profile).
-----------------------------------------------------------------------
VERSION 1.92.9b (Released 2026-07-31)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.9b
Changes:
- DragXXX, SliderXXX: fixed a regression in 1.92.9 where clicking a previously
Ctrl+Clicked field would flick it to text edit mode for a frame. (#9476, #701)
- Tables:
- Fixed Y2 position of lower horizontal border (ImGuiTableFlags_BordersOuterH)
being off by one pixel when vertical ones are not also enabled. [@thedmd]
- Fixed X position of angled borders being off by half a pixel. [@thedmd]
- ImDrawData: fixed a regression in 1.92.9 where legacy `ImDrawData::CmdListsCount` was always 0.
Prefer using `ImDrawData::CmdList.Size` anyway.
-----------------------------------------------------------------------
VERSION 1.92.9 (Released 2026-07-25)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.9
Breaking Changes:
- DragXXX, SliderXXX, InputScalar: with `ImGuiItemFlags_LiveEditOnInputScalar` now
defaulting to being disabled: inputting a value with the keyboard doesn't write
intermediate values to the backing variable. (#9476)
Before: DragFloat() with user typing "123" --> write back 1, then 12, then 123.
After: DragFloat() with user typing "123" --> write back 123 when validated/unfocused.
You can enable the flag back for a given scope if needed by specific widget/behavior.
Read below for details.
- TreeNode: commented out legacy name `ImGuiTreeNodeFlags_SpanTextWidth` which
was obsoleted in 1.90.7 (May 2024). Use `ImGuiTreeNodeFlags_SpanLabelWidth`.
- ColorEdit: obsoleted SetColorEditOptions() function added in 1.51 (June 2017) in favor
of directly poking to io.ConfigColorEditFlags. More consistent and easier to discover.
- Drag and Drop: commented out legacy name `ImGuiDragDropFlags_SourceAutoExpirePayload`
which obsoleted in 1.90.9 (July 2024). Use `ImGuiDragDropFlags_PayloadAutoExpire`.
- ImDrawData: marked `CmdListsCount` as obsolete (technically was obsoleted in 1.89.8).
Before: `draw_data->CmdListsCount`, After: `draw_data->CmdLists.Size`.
Other Changes:
- LiveEdit on/off: added `ImGuiItemFlags_LiveEditOnInputText` and `ImGuiItemFlags_LiveEditOnInputScalar`
flags to configure the timing of applying edits of backing variables when typing
values using a keyboard.
(#9476, #701, #3936, #3946, #5904, #6284, #8149, #8065, #8665, #9117, #9299, #700, #1351,
#1875, #2060, #2215, #2380, #2550, #3083, #3338, #3556, #4373, #4714, #4885, #5184,
#5777, #6707, #6766, #8004, #8303, #8915, #9308)
- ImGuiItemFlags_LiveEditOnInputText is enabled by default (same as before):
- The expectation is that for strings/text, enabling LiveEdit is a better default.
- ImGuiItemFlags_LiveEditOnInputScalar is disabled by default (new behavior):
- The expectation is that for numeric/scalars values, disabling LiveEdit is a better default.
- Until now:
- Edits where always applied immediately to backing variable, which is equivalent
to the `ImGuiItemFlags_LiveEditXXX` flags being enabled.
- Typing '123' in an integer field would output successively 1, 12 then 123.
- Most uses of `IsItemDeactivatedAfterEdit()` or `ImGuiInputTextFlags_EnterReturnsTrue`
were actually workarounds for this issue. Advanced applications would typically
use `IsItemDeactivatedAfterEdit()` to distinguish transactions.
Workarounds often required a backing store for scalar values, and there were
also a few niggles related to `IsItemDeactivatedAfterEdit()` when using +/-
buttons of an `InputInt()` widgets.
- Many of those situations can now be naturally simplified when disabling
`ImGuiItemFlags_LiveEditOnInputScalar` is disabled.
- The new flags allows disabling this behavior selectively for strings fields
such as `InputText()` vs scalar fields: `SliderInt()`, `InputFloat()`, etc.
- When LiveEdit is disabled, edits are applied when pressing enter, tabbing out,
clearing a field or deactivating due to a focus loss.
- The flag may be altered programmatically, e.g. for the entire frame scope:
NewFrame();
PushItemFlag(ImGuiItemFlags_LiveEditOnInputScalar, true); // Enable for scalars for the whole frame
....
PopItemFlag();
EndFrame();
Or for a specific widget:
PushItemFlag(ImGuiItemFlags_LiveEditOnInput, true); // Enable for one widget
SliderInt(...);
PopItemFlag();
- We intentionally are not adding `io.ConfigLiveEditXXX` fields to dictate the
default value of each `ImGuiItemFlags_LiveEditXXX`, because this is not expected
to be a user preference but a programmer/widget preferences.
And we strive to make the toolkit consistent.
- Windows:
- Clicking on a window's empty-space to move/focus a window checks
for lack of mouse button ownership. This gives an additional opportunity
for user code to bypass it without using a clickable item. (#9382)
- Clicking on a window's empty-space to move/focus a window checks
for lack of queued focus request. (#9382)
- Fixed double-click collapse toggle not owning the mouse button. If a
`SetNextWindowPos()` with pivot was queued in the same frame, the second
click could trigger another item in the same window. (#9439) [@Cleroth]
- Popups:
- Added bool return value to `OpenPopup()`, `OpenPopupOnItemClick()` functions
to notify when the popup was just opened. (#9429)
- InputText:
- Added `style.InputTextCursorSize` to configure cursor/caret thickness. (#7031, #9409)
It is automatically scaled by `style.ScaleAllSizes()`.
- Reworked `io.ConfigInputTextEnterKeepActive` mode so that pressing
Ctrl+Enter or Shift+Enter still allows to deactivate. (#9239)
- Tables:
- Redesigned/rewrote code to reconcile columns and settings on topology changes. (#9108)
- When a column label is passed to TableSetupColumn(), the underlying identifier
is used to match live columns data and .ini settings data when changing.
This makes it possible to add/remove columns from a table without losing
neither live data neither .ini settings data.
- PS: Note that this is distinct from toggling column visibility or reordering
columns, which was always possible. The new matching makes it easier to create
tables that are entirely customized by user or code, without losing state.
- Columns without identifiers or with duplicate identifiers are matched
sequentially, matching old behavior.
- Column ID are stored in .ini file.
- Code is being tested both for live topology changes and for loading .ini
data with mismatched topology.
- Context Menu: added a "Reset" sub-menu with a "Reset Visibility" option.
(which is greyed out when using default settings)
- Headers: fixed label being clipped early to reserve space for a sort marker
even when no sort marker is displayed. Auto-fitting a column still accounts
for the possible marker, so that sorting after an auto-fit doesn't clip the label.
- Multi-Select:
- Reworked `ImGuiMultiSelectFlags_NoAutoSelect` as it carried side-effects that
were hardcoded/designed to use multi-selection on checkboxes. (#9391)
Specifically removed those undocumented behaviors from `_NoAutoSelect`:
- Clicking a selected/checked item always unselect/uncheck.
- Shift+Click inverts targets value and copy to range.
- Shift+Keyboard copy selection source value to range.
Those behaviors are still happening on checkboxes used within multi-selection.
- Fonts:
- Added `IMGUI_DISABLE_DEFAULT_FONT_BITMAP`/`IMGUI_DISABLE_DEFAULT_FONT_VECTOR` to
disable embedding either fonts separately. (#9407)
- Tweak `CalcTextSize()` awkward width rounding/ceiling code to reduce floating-point
precision issues altering the result by 1 even at relatively small width. (#791)
- Better document the fact that `ImFontAtlas::Clear()`/`ClearFonts()` functions are
unlikely to be useful nowadays. Better recover to an edge case of mistakenly
calling `ClearFonts()` during rendering.
- Fixed an issue where passing a manually created ImFontAtlas to CreateContext() would
incorrectly destroy it in `DestroyContext()` when ref-count gets back to zero. (#9426)
- Destroying an ImGui context using a `ImFontAtlas` checks that the later has no references.
- Nav:
- Fixed context menu activation with gamepad erroneously testing for _NavEnableKeyboard
instead of _NavEnableGamepad. (#9454, #8803, #9270) [@Clownacy]
- TreeNode:
- Fixed nav cursor rendering with rounding even though tree nodes don't have it. (#7589)
- Inputs:
- Added `GetItemClickedCountWithSingleClickDelay()` helper for easy disambiguation
between single-click and double-click for actions that needs single-click to do
something other than selection. (#8337)
- Returns 1 on single-click but delayed by io.MouseSingleClickDelay.
- Returns 2 on double-click, and 2+ on subsequent repeated clicks.
- Added `io.MouseSingleClickDelay` to configure default delayed single click delay when
using `GetItemClickedCountWithSingleClickDelay()` or `IsMouseReleasedWithDelay()`. (#8337)
Note that `io.MouseSingleClickDelay` is always `> io.MouseDoubleClickTime`.
- ColorEdit:
- Added `io.ConfigColorEditFlags` to read/modify current color edit/picker settings.
- ColorPicker: added `ImGuiColorEditFlags_PickerNoRotate` to disable rotation of the
S/V triangle when in `ImGuiColorEditFlags_PickerHueWheel` mode. (#9337) [@SeanTheBuilder1]
Likely best passed to `style.ColorEditFlags` to setup globally and once.
- ColorButton: small rendering tweak/optimization for the alpha checkerboard.
- Style:
- Added style.MenuItemRounding, ImGuiStyleVar_MenuItemRounding. (#7589, #9375, #9453)
- Added style.SelectableRounding, ImGuiStyleVar_SelectableRounding. (#7589, #9375, #9453)
The use of this is discouraged because it can easily create problems rendering e.g.
contiguous selection.
- Scale the NavCursor border thickness when using large values with `ScallAllSizes()`.
- Settings:
- Windows/Tables settings entries can now record the last used date in YYYYMMDD format,
allowing tools to run to e.g. delete entries that haven't been used in X months. (#9460)
- Added `bool io.ConfigIniSettingsSaveLastUsedDate` to disable saving that info. (#9460)
- Added `int io.ConfigIniSettingsAutoDiscardMonths` to enable a mode where unused settings
are automatically discard after xx months. (#9460)
- Added a trimming tool under Metrics->Settings, along with a yet-unexposed function.
- The current system date is fed through `ImGuiPlatformIO::Platform_SessionDate`,
which is automatically set by a call to time() done during context creation. (#9460)
- Added `IMGUI_DISABLE_TIME_FUNCTIONS` to disable setting platform_io.Platform_SessionDate.
A custom backend may still set it manually. (#9460)
- DrawList:
- Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091)
- Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText()
coordinates for a given scope. (#3437, #9417, #2291)
- Demo:
- Extract 'Widgets->Tree Nodes->Selectable Nodes' out of the 'Advanced'
demo for clarity (manual reimplementation of basic selection).
- Debug Tools:
- Added `IM_DEBUG_BREAK()` handler for GCC+AArch64/ARM64. [@tom-seddon]
- Backends:
- Android:
- Clear mouse position on touch release (`AMOTION_EVENT_ACTION_UP`) to prevent
items from staying in hovered state. (#6627, #9474) [@Turtle-PB]
- Metal4:
- Added new Metal 4 backend (forked from Metal 3 backend). (#9458, #9451) [@AmelieHeinrich]
- Added Metal-cpp support enabled with `IMGUI_IMPL_METAL_CPP` define. (#9461) [@MERL10N]
- OpenGL2:
- Backup and restore `GL_UNPACK_ROW_LENGTH` and `GL_UNPACK_ALIGNMENT` when updating texture
to avoid altering caller GL state. (#8802, #9473) [@Turtle-PB]
- OpenGL3:
- GLSL version detection assume GLSL 410 when GL context is 4.1.
Fixes an issue running on macOS with Wine. [#9427, #6577) [@perminovVS]
- Expose selected render state in `ImGui_ImplOpenGL3_RenderState`, allowing to
dynamically select between use of `glBindSampler()` and `glTexParameter()`. (#9378)
- Backup and restore `GL_UNPACK_ROW_LENGTH` and `GL_UNPACK_ALIGNMENT` when updating texture
to avoid altering caller GL state. (#8802, #9473) [@Turtle-PB]
- SDL2:
- Restore SDL_StartTextInput()/SDL_StopTextInput() in IME handler for on-screen keyboard
support on Android. (#7636, #9474) [@Turtle-PB]
- SDLRenderer3:
- Fixed sampler change which didn't work on all graphics backends. (#7616, #9470, #9378)
- Fixed default sampler not being Linear. Regression in 1.92.8. (#7616, #9470, #9378) [@ShiroKSH]
- Win32:
- Uses `SetProcessDpiAwarenessContext()` instead of `SetThreadDpiAwarenessContext()`
when available, fixing OpenGL DPI scaling issues as e.g. NVIDIA drivers tends
to spawn multiple-thread to manage OpenGL. (#9403)
- Examples:
- Android: update to AGP 9.2.0 to support Gradle 9.6.0.
- Apple+Metal4: added new example. (#9465, #9451) [@hoffstadt]
- OpenGL3+GLFW/SDL2/SDL3: allow Wine compatibility by passing empty GLSL version
string to ImGui_ImplOpenGL3_Init() to let backend decide of a GLSL version based
on actual GL version obtained. (#9427, #6577) [@perminovVS]
- OpenGL3+Win32: rework context creation to allow Wine compatibility. (#9427, #6577) [@perminovVS]
- SDL2/SDL3: use `SDL_GetWindowSizeInPixels()` to create frame-buffers. Fixes issues
with non-fractional framebuffer size on Wayland. (#8761, #9124) [@billtran1632001]
- SDL3+Metal4: added new example. (#9458, #9451) [@AmelieHeinrich]
-----------------------------------------------------------------------
VERSION 1.92.8 (Released 2026-05-12)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.92.8
Breaking Changes:
- DrawList: swapped the last two arguments of `AddRect()`, `AddPolyline()`, `PathStroke()`.
- Before: `void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, ImDrawFlags flags = 0, float thickness = 1.0f);`
- After: `void ImDrawList::AddRect(ImVec2 p_min, ImVec2 p_max, ImU32 col, float rounding = 0.0f, float thickness = 1.0f, ImDrawFlags flags = 0);`
- Before: `void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, ImDrawFlags flags, float thickness);`
- After: `void ImDrawList::AddPolyline(const ImVec2* points, int num_points, ImU32 col, float thickness, ImDrawFlags flags = 0);`
- Before: `void ImDrawList::PathStroke(ImU32 col, ImDrawFlags flags = 0, float thickness = 1.0f);`
- After: `void ImDrawList::PathStroke(ImU32 col, float thickness = 1.0f, ImDrawFlags flags = 0);`
Added inline redirection functions when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is off.
Marked the old functions are =delete when IMGUI_DISABLE_OBSOLETE_FUNCTIONS is on, to allow for better type-checking.
Effectively the typical call site is changing from:
- Before: `window->DrawList->AddRect(p_min, p_max, color, rounding, ImDrawFlags_None, border_size);`
- After: `window->DrawList->AddRect(p_min, p_max, color, rounding, border_size);`
Notes:
- Users of C++ and other languages with type-checking will be notified at compile-time of any mistakes.
- Users of high-level bindings or languages with no type-checking will be notified at runtime via an assert for invalid flags value.
If you are a binding maintainer consider doing something to facilitate transition or error detection.
- This is perhaps the worst breaking change in our history :( but it makes ImDrawList function signatures consistent.
As we are aiming to add flags and features to variety of ImDrawList functions, that consistency becomes more important.
The new order is also more convenient as `flags` are less frequently used than `thickness` in real code.
- As a general policy in Dear ImGui, all our flags default to 0 so ImDrawFlags_None was likely written 0 in some call sites.
- Consider adding `#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS` in your imconfig.h, even temporarily, to clean up legacy code.
- Reminder: you do NOT need to specify `ImDrawFlags_RoundCornersAll` for rounding, it is already the default!
- DrawList: obsoleted `ImDrawCallback_ResetRenderState` in favor of using `ImGui::GetPlatformIO().DrawCallback_ResetRenderState`,
which is part of our new standard draw callbacks. (#9378)
Redirecting the earlier value into the later one when set, so both old and new code should work.
- DrawList: changed value of `ImDrawFlags_Closed`. It was previously advertised as "always == 1" when introduced
in 1.82 (2021/02), in order to facilitate backward compatibility with the legacy `bool closed` flag. This
guarantee has been removed. The bit is reserved, and `AddPolyline()`, `PathStroke()` will assert when it is used.
- Backends:
- Vulkan: redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. (#914)
This change allows us to facilitate changing samplers, in line with other backends. [@yaz0r, @ocornut]
- When creating your own descriptor pool (instead of letting backend creates its own):
- Before: need at least `IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER`.
- After: need at least `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`.
+ `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLER`.
- When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler.
- Before: `ImGui_ImplVulkan_AddTexture(VkSampler, VkImageView, VkImageLayout)`
- After: `ImGui_ImplVulkan_AddTexture(VkImageView, VkImageLayout)`
- Kept inline redirection function that ignores the sampler (will obsolete).
- DirectX10, DirectX11, SDLGPU3, Vulkan: removed samplers from `ImGui_ImplXXXX_RenderState`.
Prefer to use backend-agnostic DrawCallback_SetSamplerLinear which works everywhere! (#9378)
If there is a legit need/request for them or any render state we can always add them back.
- OpenGL3: the new sampler support system prioritize using glBindSampler() when available,
which would override glTexParameter() settings you may have set on custom textures. (#9378)
Other Changes:
- DrawList:
- Added room in `ImGuiPlatformIO` for standard backend-agnostic draw callbacks. Those callbacks
are setup/provided by the backend and available in most of our standard backends.
They allow backend-agnostic code from e.g. switching to a Nearest/Point sampler without
messing with custom Renderer-specific callbacks.
platform_io.DrawCallback_ResetRenderState; // Request to reset the graphics/render state.
platform_io.DrawCallback_SetSamplerLinear; // Request to set current texture sampling to Linear
platform_io.DrawCallback_SetSamplerNearest; // Request to set current texture sampling to Nearest/Point
Note that some backends might not support all callbacks.
(#9378, #9371, #3590, #8926, #2973, #7485, #7468, #6969, #5118, #7616, #9173, #8322, #7230,
#5999, #6452, #5156, #7342, #7592, #7511)
- Made `AddCallback()` user data default to Null for convenience.
- Added `AddLineH()`, `AddLineV()` helpers to draw horizontal and vertical lines. [@memononen]
The new functions are more optimal and will be part of a larger effort in 1.93 to fix
inconsistencies and improve the DrawList API. In the current API, `AddLine()` adds a "magic" +0.5f
offset and then center the line, whereas AddLineH()/AddLineV() use the right side of the line to expand.
For thickness=1.0f lines this is equivalent:
`AddLine({10,3}, {20,3}, ...)` --> `AddLineH(x1=10, x2=20, y=3, ...)`.
`AddLine({3,10}, {3,20}, ...)` --> `AddLineV(x=3, y1=10, y2=20, ...)`.
For larger integer thickness, AddLine() will center but may be blurry, AddLineH()/AddLineV()
will expand "inside" (to the right side) and will always be sharp.
A subsequent release will expand on those concepts and add new options.
- InputText:
- InputTextMultiline: fixed an issue processing deactivation logic when an active
multi-line edit is clipped due to being out of view.
- Fixed a crash when toggling ReadOnly while active. (#9354)
- `CharFilter` callback event sets CursorPos/SelectionStart/SelectionEnd. (#816)
- Tables:
- Fixed issues reporting ideal size to parent window/container: (#9352, #7651)
- When both scrollbars are visible but only one of ScrollX/ScrollY was explicitly requested.
- When vertical scrollbar was not at the top, the computation was often incorrect.
- Windows:
- Fixed a single-axis auto-resizing feedback loop issue with nested containers
and varying scrollbar visibility. (#9352)
- Detect and report error when calling End() instead of EndPopup() on a popup. (#9351)
- Child windows with only `ImGuiChildFlags_AutoResizeY` flag keep using the proportional
default `ItemWidth`. (#9355)
- Using mouse wheel to scroll takes and keeps ownership of the corresponding keys
(e.g. `ImGuiKey_MouseWheelY`) while a wheeling window is locked. (#2604, #3795)
- InputInt, InputFloat, InputScalar:
- Reinstated `ImGuiInputTextFlags_EnterReturnsTrue` support which was removed in 1.91.4.
(#8665, #9299, #8065, #3946, #6284, #9117)
- Fixed the fact that it didn't return true when validating same value.
- Fixed losing value when tabbing out or losing focus.
- Made it that pressing +/- step buttons also return true, which is in line
with 1.91.4 behavior.
- In a majority of cases you should use `IsItemDeactivatedAfterEdit()` instead,
but it still has a few edge cases flaws (to be addressed soon).
- Allow passing a format string that does not display the scalar value.
Parsing input with default format for the type. (#9385) [@FireFox2000000]
- Multi-Select:
- Fixed an issue using Multi-Select within a Table causing column width measurement to
be invalid when trailing column contents is not submitted in the last row. (#9341, #8250)
- Fixed an issue using Multi-Select within a Table with the right-most column visible,
which could lead to an extra vertical offset in the Header row. (#8250)
- Multi-Select + Box-Select:
- Fixed an issue using `ImGuiMultiSelectFlags_BoxSelect1d` mode while scrolling.
Notably, using mouse wheel while holding a box-selection could lead items close to windows
edges from not being correctly unselected. (#7994, #8250, #7821, #7850, #7970)
- Improved dirty/unclip rectangle logic for `ImGuiMultiSelectFlags_BoxSelect2d`.
- Fixed an issue using `ImGuiMultiSelectFlags_BoxSelect2d` mode, where
items out of view wouldn't be properly selected while scrolling while mouse cursor
is hovering outside of selection scope. (#7994, #1861, #6518)
- Fixed an issue where items out of horizontal view would sometimes lead
to incorrect merging of sequential selection requests while also scrolling fast
enough to overlap multiple rows during a frame. (#7994, #1861, #6518)
- Fixed an issue using `ImGuiMultiSelectFlags_BoxSelect2d` mode in a Table
while relying on the `TableNextColumn()` return value to perform coarse clipping. (#7994)
- Disabled merging consecutive selection requests as we have no reliable
way of detecting if user has submitted all consecutive items without clipping gaps,
and `ImGuiSelectionUserData` is technically opaque storage. (#7994, #1861)
(we will probably bring this back as a minor optimization if we have a way to for
user to tell us `ImGuiSelectionUserData` are indices)
- Fixes for using across nested child windows. (#8364)
- Box-Select + Clipper: fixed an issue selecting items while scrolling while a clipper
active. (#7994, #8250, #7821, #7850, #7970)
- Box-Select + Tables: fixed an issue using box-selection in a tables with
items straying out of columns boundaries. (#7994, #2221)
- Box-Select + Tables: fixed an issue when calling `BeginMultiSelect()` in a table
before layout has been locked (first row or headers row submitted). (#8250)
- Menus:
- BeginMenu()/MenuItem(): fixed accidental triggering of child menu items when
opening a menu inside a small host window forcing the child menu window to be
repositioned under the mouse cursor. (#8233, #9394)
Done by reworking `BeginMenu()`/`MenuItem()`: they previously avoiding taking
ActiveID + key/click ownership (in order to allow releasing button on another item).
Now they take them and release them once the mouse is moved outside item boundaries.
- Inputs:
- SetItemKeyOwner(): return true if ownership has been requested, which typically
needs to to checked for gating further tests. This is important as the function
may fail. (#456, #2637, #2620, #2891, #3370, #3724, #4828, #5108, #5242, #5641)
- SetItemKeyOwner(): does not set ownership is key is already taken. Effectively
this makes using `SetItemKeyOwner(ImGuiKey_MouseWheelY)` over an item work as
expected while not having item react if a scroll wheel is actively in progress.
May be subject to further redesign, e.g. conditional flags. Feedback welcome!
- Style:
- Checkbox: added `ImGuiCol_CheckboxSelectedBg` to change or accentuate the
background color of checked/mixed checkboxes. (#9392)
- Added `ImGuiStyleVar_DragDropTargetRounding`. (#9056)
- Fixed vertical scrollbar top coordinates when using thick borders on windows
with no title bar and no menu bar. (#9366)
- Fonts:
- imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details.
- Assert when using MergeMode with an explicit size over a target font with an implicit
size, as scale factor are likely erroneous. (#9361)
- Clipper:
- Improved error reporting when misusing the clipper inside a table (prioritize
reporting the common clipper error over a table sanity check assert). (#9350)
- Tweaked assert triggering when first item height measurement fails, and made it
a better recoverable error. (#9350)
- Misc:
- Minor optimization: reduce redundant label scanning in common widgets.
- Added missing Test Engine hooks for `PlotLines()`, `PlotHistogram()`, `VSliderXXX()`
and `TableHeader()` functions.
- Demo:
- Added simple demo for a scrollable/zoomable image viewer with a grid.
Available in `Examples->Image Viewer` and `Widgets->Images`.
- Backends:
- Added support for new standardized draw callbacks in most backends: (#9378)
- Allegro5: Reset n/a n/a
- DX9: Reset SetSamplerLinear SetSamplerNearest
- DX10: Reset SetSamplerLinear SetSamplerNearest
- DX11: Reset SetSamplerLinear SetSamplerNearest
- DX12: Reset SetSamplerLinear SetSamplerNearest
- Metal: Reset SetSamplerLinear SetSamplerNearest
- OpenGL2: Reset SetSamplerLinear SetSamplerNearest
- OpenGL3+: Reset SetSamplerLinear SetSamplerNearest
- SDLGPU3: Reset SetSamplerLinear SetSamplerNearest
- SDLRenderer2: Reset n/a n/a
- SDLRenderer3: Reset SetSamplerLinear SetSamplerNearest
- Vulkan: Reset SetSamplerLinear SetSamplerNearest
- WebGPU: Reset SetSamplerLinear SetSamplerNearest
(Vulkan backend by @yaz0r, Metal by @ssh4net, others by @ocornut)
- GLFW: added a Win32-specific implementation of `ImGui_ImplGlfw_GetContentScaleXXXX`
functions for legacy GLFW 3.2. (#9003)
- Metal: avoid redundant vertex buffer bind in `SetupRenderState()`, which leads
to validation issue. (#9343) [@Hunam6]
- Metal: use a dedicated `bufferCacheLock` to avoid crashing when `bufferCache` is
replaced by a new object while being used for `@synchronize()`. (#9367) [@andygrundman]
- SDL2: made `ImGui_ImplSDL2_GetContentScaleForWindow()`/`ImGui_ImplSDL2_GetContentScaleForDisplay()`
helpers return a minimum of 1.0f, as some Linux setup seems to report <1.0f value
and this breaks scaling border size. (#9369)
- WebGPU: rework choice/detection of using WGSL/SPIR-V shader on WGVK. (#9316, #9246, #9257, #9387)
- Examples:
- Update VS toolset in all .vcxproj from VS2015 (v140) to VS2017 (v141). The later is the
first that supports vcpkg. Onward we will likely stop testing building the library with VS2015.
- GLFW+Vulkan, SDL2+Vulkan, SDL3+Vulkan, Win32+Vulkan: reworked to create a descriptor pool with:
- `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE`.
- `IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE` descriptors of type `VK_DESCRIPTOR_TYPE_SAMPLER`.
-----------------------------------------------------------------------
VERSION 1.92.7 (Released 2026-04-02)
-----------------------------------------------------------------------
@ -694,7 +1251,7 @@ Other Changes:
not available. (#5924, #5562)
- SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82]
- Win32+DirectX12: Rework synchronization logic. (#8961) [@RT2Code]
- Made examples's main.cpp consistent with returning 1 on error.
- Made examples' main.cpp consistent with returning 1 on error.
-----------------------------------------------------------------------
@ -1205,7 +1762,7 @@ Non-breaking Fonts/Textures related changes:
- Fonts: ImFontAtlas::AddFontXXX() can fail more gracefully if error handling is configured
to not assert (this will be better exposed via future font flags).
- Fonts: added style.FontScaleBase scaling factor (previously called io.FontGlobalScale).
- Fonts: added style.FontScaleDpi scaling factor. This is designed to be be changed on
- Fonts: added style.FontScaleDpi scaling factor. This is designed to be changed on
per-monitor/per-viewport basis, which `io.ConfigDpiScaleFonts` does automatically.
(which is why it is separate from FontScaleBase).
- Fonts: added optional font_size parameter to ImGui::PushFont() function.
@ -2360,7 +2917,7 @@ Other changes:
- Backends: Vulkan: Remove Volk/ from volk.h #include directives. (#7722, #6582, #4854)
[@martin-ejdestig]
- Examples: SDL3: Remove use of SDL_HINT_IME_NATIVE_UI since new SDL_HINT_IME_IMPLEMENTED_UI
values has a more suitable default for our case case.
values has a more suitable default for our case.
- Examples: GLFW+Vulkan, SDL+Vulkan: handle swap chain resize even without Vulkan
returning VK_SUBOPTIMAL_KHR, which doesn't seem to happen on Wayland. (#7671)
[@AndreiNego, @ocornut]
@ -3136,8 +3693,10 @@ Breaking changes:
input queue. This is automatically cleared by io.ClearInputKeys(). (#4921)
- ImDrawData: CmdLists[] array is now owned, changed from 'ImDrawList**' to
'ImVector<ImDrawList*>'. Majority of users shouldn't be affected, but you
cannot compare to NULL nor reassign manually anymore.
Instead use AddDrawList(). Allocation count are identical. (#6406, #4879, #1878)
cannot compare to NULL nor reassign manually anymore. (#6406, #4879, #1878)
- Allocation count are identical.
- Use `draw_data->CmdLists.Size` instead of `draw_list->CmdListsCount`!
- Use `AddDrawList()` to add to a `ImDrawData`.
Other changes:
@ -4311,7 +4870,7 @@ Other Changes:
- ColorPicker4: Fixed picker being unable to select exact 1.0f color when dragging toward the edges
of the SV square (previously picked 0.999989986f). (#3517) [@rokups]
- Menus: Fixed vertical alignments of MenuItem() calls within a menu bar (broken in 1.84). (#4538)
- Menus: Improve closing logic when moving diagonally in empty between between parent and child menus to
- Menus: Improve closing logic when moving diagonally in empty space between parent and child menus to
accommodate for varying font size and dpi.
- Menus: Fixed crash when navigating left inside a child window inside a sub-menu. (#4510).
- Menus: Fixed an assertion happening in some situations when closing nested menus (broken in 1.83). (#4640)

View file

@ -3,7 +3,7 @@
## Index
- [Getting Started & General Advice](#getting-started--general-advice)
- [Issues vs Discussions](#issues-vs-discussions)
- [Using "Issues" for almost everything!](using-issues-for-almost-everything)
- [How to open an Issue](#how-to-open-an-issue)
- [How to open a Pull Request](#how-to-open-a-pull-request)
- [Copyright / Contributor License Agreement](#copyright--contributor-license-agreement)
@ -23,18 +23,20 @@
- If you get a crash or assert, use a debugger to locate the line triggering it and read the comments around.
- Please don't be a [Help Vampire](https://slash7.com/2006/12/22/vampires/).
## 'Issues' vs 'Discussions'
## Using "Issues" for almost everything!
We are happy to use 'Issues' for many type of open-ended questions. We are encouraging 'Issues' becoming an enormous, centralized and cross-referenced database of Dear ImGui contents.
We are happy to use 'Issues' for many type of open-ended questions.
We are encouraging 'Issues' becoming an enormous, centralized and cross-referenced database of Dear ImGui contents.
Only if you:
- Need help using the API? Open an Issue!
- Want to suggest a feature? Open an Issue!
- etc.
ONLY IN THOSE CASE you can use the [Discussions forums](https://github.com/ocornut/imgui/discussions)
- Cannot BUILD or LINK examples.
- Cannot BUILD, or LINK, or RUN Dear ImGui in your application or custom engine.
- Cannot LOAD a font.
Then please [use the Discussions forums](https://github.com/ocornut/imgui/discussions) instead of opening an issue.
If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new issue.
If Dear ImGui is successfully showing in your app and you have used Dear ImGui before, you can open an Issue. Any form of discussions is welcome as a new Issue.
## How to open an issue

View file

@ -60,16 +60,20 @@ Android + OpenGL3 (ES) example. <BR>
[example_apple_metal/](https://github.com/ocornut/imgui/tree/master/examples/example_apple_metal/) <BR>
OSX & iOS + Metal example. <BR>
= main.m + imgui_impl_osx.mm + imgui_impl_metal.mm <BR>
= main.mm + imgui_impl_osx.mm + imgui_impl_metal.mm <BR>
It is based on the "cross-platform" game template provided with Xcode as of Xcode 9.
(NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends.
You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.)
[example_apple_metal4/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_metal4/) <BR>
OSX & iOS + Metal4 example, Mac only. <BR>
= main.mm + imgui_impl_osx.mm + imgui_impl_metal4.mm <BR>
[example_apple_opengl2/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_opengl2/) <BR>
OSX + OpenGL2 example. <BR>
= main.mm + imgui_impl_osx.mm + imgui_impl_opengl2.cpp <BR>
(NB: imgui_impl_osx.mm is currently not as feature complete as other platforms backends.
You may prefer to use the GLFW Or SDL backends, which will also support Windows and Linux.)
[example_apple_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_apple_opengl3/) <BR>
OSX + OpenGL3 example. <BR>
= main.mm + imgui_impl_osx.mm + imgui_impl_opengl3.cpp <BR>
[example_glfw_wgpu/](https://github.com/ocornut/imgui/blob/master/examples/example_glfw_wgpu/) <BR>
GLFW + WebGPU example. Supports Emscripten (web), Dawn (native), WGPU (native). <BR>
@ -115,6 +119,16 @@ Because this application doesn't create a window nor a graphic context, there's
Please note that imgui_impl_null itself is a rather empty backend. We provide it for consistency but
it is similarly easy to create a skeleton application without the null backend.
[example_qnx_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_qnx_opengl3/) <BR>
QNX Screen + OpenGL ES 3 example. <BR>
= main.cpp + imgui_impl_qnx.cpp + imgui_impl_opengl3.cpp <BR>
Uses the QNX recursive make build system and compiles the OpenGL3 renderer with `IMGUI_IMPL_OPENGL_ES3`.
[example_qnx_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_qnx_vulkan/) <BR>
QNX Screen + Vulkan example using `VK_QNX_screen_surface`. <BR>
= main.cpp + imgui_impl_qnx.cpp + imgui_impl_vulkan.cpp <BR>
Uses the QNX recursive make build system and the Vulkan backend's example helper structures.
[example_sdl2_directx11/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_directx11/) <BR>
SDL2 + DirectX11 example, Windows only. <BR>
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_dx11.cpp <BR>
@ -164,6 +178,10 @@ SDL3 + DirectX11 examples, Windows only. <BR>
SDL3 + Metal example, Mac only. <BR>
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_metal.mm <BR>
[example_sdl3_metal4/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_metal/) <BR>
SDL3 + Metal4 example, Mac only. <BR>
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_metal4.mm <BR>
[example_sdl3_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_opengl3/) <BR>
SDL3 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example. <BR>
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_opengl3.cpp <BR>

View file

@ -9,42 +9,58 @@ or view this file with any Markdown viewer.
## Index
| **Q&A: Basics** |
:---------------------------------------------------------- |
| [Where is the documentation?](#q-where-is-the-documentation) |
| [What is this library called?](#q-what-is-this-library-called) |
| [What is the difference between Dear ImGui and traditional UI toolkits?](#q-what-is-the-difference-between-dear-imgui-and-traditional-ui-toolkits) |
| [Which version should I get?](#q-which-version-should-i-get) |
| **Q&A: Integration** |
| **[How to get started?](#q-how-to-get-started)** |
| **[How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?](#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear-imgui-or-my-application)** |
| [How can I enable keyboard or gamepad controls?](#q-how-can-i-enable-keyboard-or-gamepad-controls) |
| [How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)](#q-how-can-i-use-this-on-a-machine-without-mouse-keyboard-or-screen-input-share-remote-display) |
| [How can I create my own backend?](#q-how-can-i-create-my-own-backend)
| [I integrated Dear ImGui in my engine and little squares are showing instead of text...](#q-i-integrated-dear-imgui-in-my-engine-and-little-squares-are-showing-instead-of-text) |
| [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) |
| [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) |
| **Q&A: Usage** |
| **[About the ID Stack system...](#q-about-the-id-stack-system)**<br>**[How can I have multiple widgets with the same label?](#q-how-can-i-have-multiple-widgets-with-the-same-label) (using `##` or `PushID()`)**<br>**[How can I have widgets with an empty label?](#q-how-can-i-have-widgets-with-an-empty-label) (using `##`)**<br>**[How can I animate the label of an existing widget?](#q-how-can-i-change-the-label-of-an-existing-widget) (using `###`)**<br>**[General description of the label and ID Stack system.](#general-description-of-the-label-and-id-stack-system)** |
| [How can I display an image?](#q-how-can-i-display-an-image)<br>[What are ImTextureID/ImTextureRef?](#q-what-are-imtextureidimtextureref)|
| [How can I use maths operators with ImVec2?](#q-how-can-i-use-maths-operators-with-imvec2) |
| [How can I use my own maths types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-maths-types-instead-of-imvec2imvec4) |
| [How can I interact with standard C++ types (such as std::string and std::vector)?](#q-how-can-i-interact-with-standard-c-types-such-as-stdstring-and-stdvector) |
| [How can I display custom shapes? (using low-level ImDrawList API)](#q-how-can-i-display-custom-shapes-using-low-level-imdrawlist-api) |
| **Q&A: Fonts, Text** |
| [How should I handle DPI in my application?](#q-how-should-i-handle-dpi-in-my-application) |
| [How can I load a different font than the default?](#q-how-can-i-load-a-different-font-than-the-default) |
| [How can I easily use icons in my application?](#q-how-can-i-easily-use-icons-in-my-application) |
| [How can I load multiple fonts?](#q-how-can-i-load-multiple-fonts) |
| [How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?](#q-how-can-i-display-and-input-non-latin-characters-such-as-chinese-japanese-korean-cyrillic) |
| **Q&A: Concerns** |
| [Who uses Dear ImGui?](#q-who-uses-dear-imgui) |
| [Can you create elaborate/serious tools with Dear ImGui?](#q-can-you-create-elaborateserious-tools-with-dear-imgui) |
| [Can you reskin the look of Dear ImGui?](#q-can-you-reskin-the-look-of-dear-imgui) |
| [Why using C++ (as opposed to C)?](#q-why-using-c-as-opposed-to-c) |
| **Q&A: Community** |
| [How can I help?](#q-how-can-i-help) |
### Basics
- [Where is the documentation?](#q-where-is-the-documentation)
- [What is this library called?](#q-what-is-this-library-called)
- [What is the difference between Dear ImGui and traditional UI toolkits?](#q-what-is-the-difference-between-dear-imgui-and-traditional-ui-toolkits)
- [Which version should I get?](#q-which-version-should-i-get)
### Integration
- **[How to get started?](#q-how-to-get-started)**
- **[How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?](#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear-imgui-or-my-application)**
- [How can I enable keyboard or gamepad controls?](#q-how-can-i-enable-keyboard-or-gamepad-controls)
- [How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)](#q-how-can-i-use-this-on-a-machine-without-mouse-keyboard-or-screen-input-share-remote-display)
- [How can I create my own backend?](#q-how-can-i-create-my-own-backend)
- [I integrated Dear ImGui in my engine and little squares are showing instead of text...](#q-i-integrated-dear-imgui-in-my-engine-and-little-squares-are-showing-instead-of-text)
- [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around)
- [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries)
### Usage
- **[About the ID Stack system...](#q-about-the-id-stack-system)**
- **[How can I have multiple widgets with the same label?](#q-how-can-i-have-multiple-widgets-with-the-same-label) (using `##` or `PushID()`)**
- **[How can I have widgets with an empty label?](#q-how-can-i-have-widgets-with-an-empty-label) (using `##`)**
- **[How can I make a label dynamic?](#q-how-can-i-make-a-label-dynamic) (using `###`)**
- **[General description of the label and ID Stack system.](#general-description-of-the-label-and-id-stack-system)**
- [How can I display an image?](#q-how-can-i-display-an-image), [What are ImTextureID/ImTextureRef?](#q-what-are-imtextureidimtextureref)
- [How can I use maths operators with ImVec2?](#q-how-can-i-use-maths-operators-with-imvec2)
- [How can I use my own maths types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-maths-types-instead-of-imvec2imvec4)
- [How can I interact with standard C++ types (such as std::string and std::vector)?](#q-how-can-i-interact-with-standard-c-types-such-as-stdstring-and-stdvector)
- [How can I display custom shapes? (using low-level ImDrawList API)](#q-how-can-i-display-custom-shapes-using-low-level-imdrawlist-api)
- [About Multi-Threading](#about-multi-threading)
### Fonts, Text
- [How should I handle DPI in my application?](#q-how-should-i-handle-dpi-in-my-application)
- [How can I load a different font than the default?](#q-how-can-i-load-a-different-font-than-the-default)
- [How can I easily use icons in my application?](#q-how-can-i-easily-use-icons-in-my-application)
- [How can I load multiple fonts?](#q-how-can-i-load-multiple-fonts)
- [How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?](#q-how-can-i-display-and-input-non-latin-characters-such-as-chinese-japanese-korean-cyrillic)
### Concerns
- [Who uses Dear ImGui?](#q-who-uses-dear-imgui)
- [Can you create elaborate/serious tools with Dear ImGui?](#q-can-you-create-elaborateserious-tools-with-dear-imgui)
- [Can you reskin the look of Dear ImGui?](#q-can-you-reskin-the-look-of-dear-imgui)
- [Why using C++ (as opposed to C)?](#q-why-using-c-as-opposed-to-c)
### Community
- [How can I help?](#q-how-can-i-help)
--------
# Q&A: Basics
@ -85,16 +101,17 @@ Here's a very simplified comparison between the approach taken by Dear ImGui vs
|--------------------------|--------------------------|
| UI fully issued on every update. | UI issued once then later modified. |
| UI layout is fully dynamic and can change at any time.<BR>UI is generally emitted programmatically, which empowers reflecting a dynamic set of data. | UI layout is mostly static.<BR>UI may be emitted programmatically or from data created by offline tools. UI need extra code to evolve, which is often tedious and error-prone if it needs to be reflecting dynamic data and systems. |
| Application can submit UI based on arbitrary logic and then forget about it. | Application needs more bookkeeping of UI elements. |
| UI system is optimized for the worst case and designed to be optimal even under frequent changes. | UI system is optimized for the case where nothing changes. Performances tends to degrade when anything changes. |
| Application can submit UI based on arbitrary logic without bookkeeping all aspects of that logic. | Application needs more bookkeeping of UI elements. |
| UI library stores minimal amounts of data. At one point in time, it typically doesn't know or remember which other widgets are displayed and which widgets are coming next. As a result, certain layout features (alignment, resizing) are not as easy to implement or require ad-hoc code. | UI library stores entire widgets tree and state. UI library can use this retained data to easily layout things. |
| UI code may be added anywhere.<BR>You can even create UI to edit a local variable! | UI code needs to be added in dedicated spots. |
| UI layout/logic/action/data bindings are all nearby in the code. | UI layout/logic/action/data bindings in distinct functions, files or formats. |
| Data is naturally always synchronized. | Use callback/signal/slot for synchronizing data (error-prone). |
| API is simple and easy to learn. In particular, doing basic things is very easy. | API is more complex and specialized. |
| API is low-level (raw language types). | API are higher-level (more abstractions, advanced language features). |
| Less fancy look and feel. | Standard look and feel. |
| API is simple and easy to learn. In particular, doing basic things is very easy.<BR>Attractive to more programmers. | API is more complex and specialized.<BR>Tends to require specialized programmers. |
| API is low-level. Few abstractions, uses raw language types and your existing data. | API are higher-level. More abstractions, advanced language features. |
| Less fancy look and feel. But keeps improving :) | Standard look and feel. |
| Compile yourself. Easy to debug, hack, modify, study. | Mostly use precompiled libraries. Compiling, modifying or studying is daunting if not impossible. |
| Run on every platform. | Run on limited desktop platforms. |
| Run on every platform (incl. web, consoles, mobiles, legacy systems). | Run on major desktop platforms. |
Idiomatic Dear ImGui code:
```cpp
@ -553,8 +570,8 @@ typedef ImU64 ImTextureID; // Default: store up to 64-bits (any pointer or inte
// Store a ImTextureID _or_ a ImTextureData*.
struct ImTextureRef
{
ImTextureRef() { _TexData = NULL; _TexID = ImTextureID_Invalid; }
ImTextureRef(ImTextureID tex_id) { _TexData = NULL; _TexID = tex_id; }
ImTextureRef() { _TexData = nullptr; _TexID = ImTextureID_Invalid; }
ImTextureRef(ImTextureID tex_id) { _TexData = nullptr; _TexID = tex_id; }
inline ImTextureID GetTexID() const { return _TexData ? _TexData->TexID : _TexID; }
// Members (either are set, never both!)
@ -572,7 +589,7 @@ struct ImTextureRef
We intentionally do not provide an `ImTextureRef` constructor for this: we don't expect this to be frequently useful to the end-user, and it would be erroneously called by many legacy code.
- There is no constructor to create a `ImTextureRef` from a `ImTextureData*` as we don't expect this to be useful to the end-user, and it would be erroneously called by many legacy code.
- If you want to bind the current atlas when using custom rectangles, you can use `io.Fonts->TexRef`.
- Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = NULL, .TexID = tex_id }; return tex_ref; }`
- Binding generators for languages such as C (which don't have constructors), should provide a helper, e.g. `inline ImTextureRef ImTextureRefFromID(ImTextureID tex_id) { ImTextureRef tex_ref = { ._TexData = nullptr, .TexID = tex_id }; return tex_ref; }`
**Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.**
@ -666,6 +683,7 @@ This way you will be able to use your own types everywhere, e.g. passing `MyVect
---
### Q: How can I interact with standard C++ types (such as std::string and std::vector)?
- Being highly portable (backends/bindings for several languages, frameworks, programming styles, obscure or older platforms/compilers), and aiming for compatibility & performance suitable for every modern real-time game engine, Dear ImGui does not use any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases.
- To use ImGui::InputText() with a std::string or any resizable string class, see [misc/cpp/imgui_stdlib.h](https://github.com/ocornut/imgui/blob/master/misc/cpp/imgui_stdlib.h).
- To use combo boxes and list boxes with `std::vector` or any other data structure: the `BeginCombo()/EndCombo()` API
@ -685,6 +703,10 @@ One possible implementation of a helper to facilitate printf-style building of s
This is a small helper where you can instance strings with configurable local buffers length. Many game engines will
provide similar or better string helpers.
Using string views:
- String view types such as `std::string_view` may be used with the [feature/string_view](https://github.com/ocornut/imgui/tree/features/string_view) branch. This branch is actively maintained and supported. Please provide feedback if you use it. We are waiting for a good moment to merge it.
##### [Return to Index](#index)
---
@ -725,6 +747,20 @@ ImGui::End();
---
### About Multi-Threading
A same Dear ImGui context may be not used from multiple threads in parallel.
If you want to use a same context within parallel tasks for occasional debug purpose, consider using a lock.
If you want to submit contents from a main/update thread but render Dear ImGui output in a dedicated render thread, you'll need to stage `ImDrawData` and texture requests. See the `ImDrawDataSnapshot` and `ImTextureQueue` helpers in [imgui_threaded_rendering](https://github.com/ocornut/imgui_club#imgui_threaded_rendering). Also see topics with [label: multi-threading](https://github.com/ocornut/imgui/issues?q=label%3Amulti-threading).
If you use multiple Dear ImGui contexts and want to use them from multiple threads, you need to `#define GImGui` to become a TLS variable (see details near the definition of `GImGui`. If you need to display multiple contexts simultaneously, consider using [imgui_multicontext_compositor](https://github.com/ocornut/imgui_club#imgui_multicontext_compositor). Also see topics with [label: multi-contexts](https://github.com/ocornut/imgui/issues?q=label%3Amulti-contexts).
There is a script/patch to make the API take an explicit context pointer: [#5856](https://github.com/ocornut/imgui/pull/5856). It is presently unmaintained and likely to easy to update. It has been decided that the change is not currently worth applying to main-line but maybe will be in a future version.
---
# Q&A: Fonts, Text
### Q: How should I handle DPI in my application?
@ -744,7 +780,7 @@ style.FontScaleDpi = 2.0f;
To change font size:
```cpp
ImGui::PushFont(NULL, 42.0f); // This will be multiplied by style.FontScaleDpi
ImGui::PushFont(nullptr, 42.0f); // This will be multiplied by style.FontScaleDpi
```
To change font and font size:
```cpp

View file

@ -77,6 +77,17 @@ Some solutions:
You can use the `ImFontGlyphRangesBuilder` for this purpose and rebuilding your atlas between frames when new characters are needed. This will be the biggest win!
- Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two.
### (5) Reduce texture resizes/copy on startup
🆕 Since 1.92, the ImFontAtlas is initially created using a 512x128 texture, then grows as glyphs and fonts are used. Atlas growth leads to alloc+copy, and both the old and new sized textures are present in memory for a short time (typically one frame). If you use known fonts and want to reduce initial growth, you may set `TexMinWidth` and `TexMinHeight` during initializaton.
```cpp
ImFontAtlas* atlas = io.Fonts;
atlas->TexMinWidth = 1024;
atlas->TexMinHeight = 1024;
atlas->AddFont(...);
```
##### [Return to Index](#index)
---------------------------------------
@ -85,7 +96,7 @@ Some solutions:
v1.92 introduces a newer, dynamic font system. It requires backend to support the `ImGuiBackendFlags_HasTextures` feature:
- Users of icons, Asian and non-English languages do not need to pre-build all glyphs ahead of time. Saving on loading time, memory, and also reducing issues with missing glyphs. Specifying glyph ranges is not needed anymore.
- `PushFont(NULL, new_size)` may be used anytime to change font size.
- `PushFont(nullptr, new_size)` may be used anytime to change font size.
- Packing custom rectangles is more convenient as pixels may be written to immediately.
- Any update to fonts previously required backend specific calls to re-upload the texture, and said calls were not portable across backends. It is now possible to scale fonts etc. in a way that doesn't require you to make backend-specific calls.
- It is possible to plug a custom loader/backend to any font source.

View file

@ -43,7 +43,7 @@ Dear ImGui is particularly suited to integration in game engines (for tooling),
**Backends for a variety of graphics API and rendering platforms** are provided in the [backends/](https://github.com/ocornut/imgui/tree/master/backends) folder, along with example applications in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder. You may also create your own backend. Anywhere where you can render textured triangles, you can render Dear ImGui.
C++20 users wishing to use a module may the use [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension.
C++20 users wishing to use a module may use the [stripe2933/imgui-module](https://github.com/stripe2933/imgui-module) third-party extension.
See the [Getting Started & Integration](#getting-started--integration) section of this document for more details.
@ -141,7 +141,7 @@ Integrating Dear ImGui within your custom engine is a matter of mainly 1) wiring
- Generally, **make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!**
Officially maintained backends (in repository):
- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU.
- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal 3/4, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU.
- Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android.
- Frameworks: Allegro5, Emscripten.

17
docs/SECURITY.md Normal file
View file

@ -0,0 +1,17 @@
# Security Policy
Dear ImGui is primarily designed for developer tools and technical applications running trusted code and trusted data.
Given that the library was not designed as a hardened security boundary against hostile or intentionally malformed inputs:
consider not using it in a context where a crash (through e.g. intentionally malformed inputs) could lead to privilege elevation.
E.g. running in a privileged process and interacting with non-privileged clients feeding code or data to Dear ImGui.
Dear ImGui development efforts are focused on improving developer experience, usability, correctness, and robustness in real-world applications.
We will do our best to reduce e.g. crashes caused by common programmer mistakes.
However, the project does not specifically focus on adversarial fuzzing scenarios, allocation-failure hardening, or highly artificial edge cases that are unlikely to occur in normal usage.
## Reporting a Vulnerability
Considering the above policy, most things may be reported in GitHub Issues.
If you have a reason to disclose privately, please reach out to the contact address listed in README.

View file

@ -2,12 +2,14 @@ dear imgui
ISSUES & TODO LIST
Issue numbers (#) refer to GitHub issues listed at https://github.com/ocornut/imgui/issues/XXXX
THIS LIST IS NOT WELL MAINTAINED. MOST OF THE WORK HAPPENS ON GITHUB NOWADAYS.
The list below consist mostly of ideas noted down before they are requested/discussed by users (at which point they usually exist on the github issue tracker).
It's mostly a bunch of personal notes, probably incomplete. Feel free to query if you have any questions.
- doc: add a proper documentation system (maybe relying on automation? #435)
- doc: checklist app to verify backends/integration of imgui (test inputs, rendering, callback, etc.).
- doc: add a proper documentation system (maybe relying on automation? #435)
- doc/tips: tips of the day: website? applet in imgui_club?
- window: preserve/restore relative focus ordering (persistent or not), and e.g. of multiple reappearing windows (#2304) -> also see docking reference to same #.
@ -29,9 +31,9 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- window/clipping: some form of clipping when DisplaySize (or corresponding viewport) is zero.
- window/tabbing: add a way to signify that a window or docked window requires attention (e.g. blinking title bar, trying to click behind a modal).
- window/id_stack: add e.g. window->GetIDFromPath() with support for leading / and ../ (#1390, #331) -> model from test engine.
! scrolling: exposing horizontal scrolling with Shift+Wheel even when scrollbar is disabled expose lots of issues (#2424, #1463)
! scrolling: exposing horizontal scrolling with Shift+Wheel even when scrollbar is disabled expose various issues (#2424, #1463)
- scrolling: while holding down a scrollbar, try to keep the same contents visible (at least while not moving mouse)
- scrolling: allow immediately effective change of scroll after Begin() if we haven't appended items yet.
- scrolling: forward mouse wheel scrolling to parent window when at the edge of scrolling limits? (useful for listbox,tables?)
- scrolling/style: shadows on scrollable areas to denote that there is more contents (see e.g. DaVinci Resolve ui)
@ -51,38 +53,32 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc. (#395)
- widgets: clean up widgets internal toward exposing everything and stabilizing imgui_internals.h.
- widgets: add always-allow-overlap mode. This should perhaps be the default? one problem is that highlight after mouse-wheel scrolling gets deferred, makes scrolling more flickery.
- widgets: start exposing PushItemFlag() and ImGuiItemFlags
- widgets: alignment options in style (e.g. center Selectable, Right-Align within Button, etc.) #1260
- widgets: activate by identifier (trigger button, focus given id)
- widgets: custom glyph/shapes replacements for stock shapes. (also #6090 #2431 #2235 #6517)
- widgets: coloredit: keep reporting as active when picker is on?
- widgets: group/scalarn functions: expose more per-component information. e.g. store NextItemData.ComponentIdx set by scalarn function, groups can expose them back somehow.
- widgets: group/ScalarN functions: expose more per-component information. e.g. store NextItemData.ComponentIdx set by scalarn function, groups can expose them back somehow.
- selectable: using (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported.
- selectable: generic BeginSelectable()/EndSelectable() mechanism. (work out alongside range-select branch)
- selectable: a way to visualize partial/mixed selection (e.g. parent tree node has children with mixed selection)
- input text: flag to disable live update of the user buffer (also applies to float/int text input) (#701)
- input text: preserve scrolling when unfocused?
- input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541)
- input text: expose CursorPos in char filter event (#816)
- input text: try usage idiom of using InputText with data only exposed through get/set accessors, without extraneous copy/alloc. (#3009)
- input text: access public fields via a non-callback API e.g. InputTextGetState("xxx") that may return nullptr if not active (available in internals)
- input text: flag to disable live update of the user buffer (also applies to float/int text input) (#701)
- input text: hover tooltip could show unclamped text
- input text: support for INSERT key to toggle overwrite mode. currently disabled because stb_textedit behavior is unsatisfactory on multi-line. (#2863)
- input text: option to Tab after an Enter validation.
- input text: add ImGuiInputTextFlags_EnterToApply? (off #218)
- input text: easier ways to update buffer (from source char*) while owned. preserve some sort of cursor position for multi-line text.
- input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725)
- input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it.
- input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position.
- input text: decorrelate display layout from inputs with custom template - e.g. what's the easiest way to implement a nice IP/Mac address input editor?
- input text: global callback system so user can plug in an expression evaluator easily. (#1691)
- input text: callback system (global) so user can plug in an expression evaluator easily. (#1691)
- input text: force scroll to end or scroll to a given line/contents (so user can implement a log or a search feature)
- input text: a way to preview completion (e.g. disabled text completing from the cursor)
- input text: a side bar that could e.g. preview where errors are. probably left to the user to draw but we'd need to give them the info there.
- input text: a way for the user to provide syntax coloring.
- input text: Shift+TAB with ImGuiInputTextFlags_AllowTabInput could eat preceding blanks, up to tab_count.
- input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc).
- input text multi-line: support for copy/cut without selection (copy/cut current line?)
- input text multi-line: line numbers? status bar? (follow up on #200)
- input text multi-line: behave better when user changes input buffer while editing is active (even though it is illegal behavior). namely, the change of buffer can create a scrollbar glitch (#725)
@ -111,11 +107,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
!- color: the color conversion helpers/types are a mess and needs sorting out.
- color: (api breaking) ImGui::ColorConvertXXX functions should be loose ImColorConvertXX to match imgui_internals.h
- plot: full featured plot/graph api w/ scrolling, zooming etc. --> promote using ImPlot
- (plot: deleted all other todo lines on 2023-06-28)
- clipper: ability to disable the clipping through a simple flag/bool.
- clipper: ability to run without knowing full count in advance.
- clipper: horizontal clipping support. (#2580)
- separator: expose flags (#759)
@ -141,22 +133,19 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- knob: rotating knob widget (#942)
- drag float: support for reversed drags (min > max) (removed is_locked, also see fdc526e)
- drag float: up/down axis
- drag float: power != 0.0f with current value being outside the range keeps the value stuck.
- drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits)
- combo: a way/helper to customize the combo preview (#1658) -> experimental BeginComboPreview()
- combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203)
- listbox: multiple selection (WIP range-select branch)
- listbox: unselect option (#1208)
- listbox: make it easier/more natural to implement range-select (need some sort of info/ref about the last clicked/focused item that user can translate to an index?) (WIP range-select branch)
- listbox: user may want to initial scroll to focus on the one selected value?
- listbox: disable capturing mouse wheel if the listbox has no scrolling. (#1681)
- listbox: scrolling should track modified selection.
- listbox: future api should allow to enable horizontal scrolling (#2510)
!- popups/menus: clarify usage of popups id, how MenuItem/Selectable closing parent popups affects the ID, etc. this is quite fishy needs improvement! (#331, #402)
- modals: make modal title bar blink when trying to click outside the modal
- modals: technically speaking, we could make Begin() with ImGuiWindowFlags_Modal work without involving popup. May help untangle a few things, as modals are more like regular windows than popups.
- modals: make modal title bar blink when trying to click outside the modal.
- modals: technically speaking, we could make Begin() with ImGuiWindowFlags_Modal work without involving popup. May help untangle a few things, as modals are more like regular windows than popups. (#402)
- popups: if the popup functions took explicit ImGuiID it would allow the user to manage the scope of those ID. (#331)
- popups: clicking outside (to close popup) and holding shouldn't drag window below.
- popups: add variant using global identifier similar to Begin/End (#402)
@ -198,7 +187,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- style: FramePadding could be different for up vs down (#584)
- style: WindowPadding needs to be EVEN as the 0.5 multiplier used on this value probably have a subtle effect on clip rectangle
- style: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438, #707, #1223)
- style: gradients fill (#1223) ~ 2 bg colors for each fill? tricky with rounded shapes and using textures for corners.
- style: gradients fill (#4722, #1223) ~ 2 bg colors for each fill? tricky with rounded shapes and using textures for corners.
- style editor: color child window height expressed in multiple of line height.
- log: improve logging of ArrowButton, ListBox, TabItem
@ -214,7 +203,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- filters: fuzzy matches (may use code at blog.forrestthewoods.com/4cffeed33fdb)
- drag and drop: focus drag target window on hold (even without open)
- drag and drop: releasing a drop shows the "..." tooltip for one frame - since e13e598 (#1725)
- drag and drop: drag source on a group object (would need e.g. an invisible button covering group in EndGroup) https://twitter.com/paniq/status/1121446364909535233
- drag and drop: have some way to know when a drag begin from BeginDragDropSource() pov. (see 2018/01/11 post in #143)
- drag and drop: allow preview tooltip to be submitted from a different place than the drag source. (#1725)
@ -247,7 +235,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- font: make it easier to submit own bitmap font (same texture, another texture?). (#2127, #2575)
- font: MemoryTTF taking ownership confusing/not obvious, maybe default should be opposite?
- font: storing MinAdvanceX per font would allow us to skip calculating line width (under a threshold of character count) in loops looking for block width
- font/demo: demonstrate use of ImFontGlyphRangesBuilder.
- font/draw: vertical and/or rotated text renderer (#705) - vertical is easier clipping wise
- font/draw: need to be able to specify wrap start position.
- font/draw: better reserve policy for large horizontal block of text (shouldn't reserve for all clipped lines). also see #3349.
@ -273,12 +260,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- nav: NavFlattened: ESC on a flattened child should select something.
- nav: NavFlattened: broken: in typical usage scenario, the items of a fully clipped child are currently not considered to enter into a NavFlattened child.
- nav: NavFlattened: cannot access menu-bar of a flattened child window with Alt/menu key (not a very common use case..).
- nav: simulate right-click or context activation? (SHIFT+F10, keyboard Menu key?)
- nav/popup: esc/enter default behavior for popups, e.g. be able to mark an "ok" or "cancel" button that would get triggered by those keys, default validation button, etc.
- nav/treenode: left within a tree node block as a fallback (ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default?)
- nav/menus: pressing left-right on a vertically clipped menu bar tends to jump to the collapse/close buttons.
- nav/menus: allow pressing Menu to leave a sub-menu.
- nav/menus: a way to access the main menu bar with Alt? (currently needs CTRL+TAB) or last focused window menu bar?
! nav/menus: a way to access the main menu bar with Alt? (currently needs CTRL+TAB) or last focused window menu bar?
- nav/menus: when using the main menu bar, even though we restore focus after, the underlying window loses its title bar highlight during menu manipulation. could we prevent it?
- nav/menus: main menu bar currently cannot restore a nullptr focus. Could save NavWindow at the time of being focused, similarly to what popup do?
- nav/menus: Alt,Up could open the first menu (e.g. "File") currently it tends to nav into the window/collapse menu. Do do that we would need custom transition?
@ -297,7 +283,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- misc: no way to run a root-most GetID() with ImGui:: api since there's always a Debug window in the stack. (mentioned in #2960)
- misc: make the ImGuiCond values linear (non-power-of-two). internal storage for ImGuiWindow can use integers to combine into flags (Why?)
- misc: PushItemFlag(): add a flag to disable keyboard capture when used with mouse? (#1682)
- misc: use more size_t in public api?
- misc: support for string view/range instead of char* would e.g. facilitate usage with Rust (#683, #3038, WIP string_view branch)
- demo: demonstrate using PushStyleVar() in more details.
@ -315,8 +300,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- backends: opengl: could use a single vertex buffer and glBufferSubData for uploads?
- backends: opengl: explicitly disable GL_STENCIL_TEST in bindings.
- backends: vulkan: viewport: support for synchronized swapping of multiple swap chains.
- backends: bgfx: https://gist.github.com/RichardGale/6e2b74bc42b3005e08397236e4be0fd0
- backends: emscripten: with refactored examples, we could provide a direct imgui_impl_emscripten platform layer (see eg. https://github.com/floooh/sokol-samples/blob/master/html5/imgui-emsc.cc#L42)
- backends: emscripten: dedicated backend? (#8178, #9120, eg. https://github.com/floooh/sokol-samples/blob/master/html5/imgui-emsc.cc#L42)
- bindings: ways to use clang ast dump to generate bindings or helpers for bindings? (e.g. clang++ -Xclang -ast-dump=json imgui.h) (--> use https://github.com/dearimgui/dear_bindings)

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -92,6 +92,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -107,6 +108,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -1,6 +1,5 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
@ -25,9 +24,6 @@ android {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
externalNativeBuild {
cmake {
path file('../../CMakeLists.txt')

View file

@ -1,6 +1,6 @@
[versions]
agp = "8.12.0"
kotlin = "2.0.21"
agp = "9.2.0"
kotlin = "2.3.21"
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }

View file

@ -0,0 +1,21 @@
# Makefile for example_apple_metal4, for macOS only (**not iOS**)
CXX = clang++
EXE = example_apple_metal4
IMGUI_DIR = ../../
SOURCES = main.mm
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_metal4.mm
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
FRAMEWORKS = -framework AppKit -framework Metal -framework MetalKit -framework QuartzCore -framework GameController
all: $(EXE)
$(EXE): $(SOURCES)
$(CXX) $(CXXFLAGS) $^ $(FRAMEWORKS) -o $@
run: all
./$(EXE)
clean:
rm -f $(EXE) *.o

View file

@ -0,0 +1,10 @@
# iOS / OSX Metal4 example
## Introduction
This example shows how to integrate Dear ImGui with Metal4. It is based on the "cross-platform" game template provided with Xcode as of Xcode 9.
Consider basing your work off the example_glfw_metal/ or example_sdl2_metal/ examples. They are better supported and will be portable unlike this one.

View file

@ -0,0 +1,535 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 050450AC276863B000AB6805 /* QuartzCore.framework */; };
05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; };
05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A275432773BEA20084EF39 /* QuartzCore.framework */; };
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8309BD8E253CCAAA0045E2A1 /* UIKit.framework */; };
8309BDA5253CCC070045E2A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDA0253CCBC10045E2A1 /* main.mm */; };
8309BDA8253CCC080045E2A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDA0253CCBC10045E2A1 /* main.mm */; };
8309BDBB253CCCAD0045E2A1 /* imgui_impl_metal4.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal4.mm */; };
8309BDBE253CCCB60045E2A1 /* imgui_impl_metal4.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal4.mm */; };
8309BDBF253CCCB60045E2A1 /* imgui_impl_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8309BDB6253CCC9D0045E2A1 /* imgui_impl_osx.mm */; };
8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8309BDC5253CCCFE0045E2A1 /* AppKit.framework */; };
8309BDFC253CDAB30045E2A1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8309BDF7253CDAAE0045E2A1 /* LaunchScreen.storyboard */; };
8309BE04253CDAB60045E2A1 /* MainMenu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8309BDFA253CDAAE0045E2A1 /* MainMenu.storyboard */; };
83BBE9E520EB46B900295997 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9E420EB46B900295997 /* Metal.framework */; };
83BBE9E720EB46BD00295997 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9E620EB46BD00295997 /* MetalKit.framework */; };
83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9EA20EB471700295997 /* MetalKit.framework */; };
83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 83BBE9EB20EB471700295997 /* Metal.framework */; };
83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0120EB54E700295997 /* imgui_draw.cpp */; };
83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0120EB54E700295997 /* imgui_draw.cpp */; };
83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0220EB54E700295997 /* imgui_demo.cpp */; };
83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0220EB54E700295997 /* imgui_demo.cpp */; };
83BBEA0920EB54E700295997 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0320EB54E700295997 /* imgui.cpp */; };
83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 83BBEA0320EB54E700295997 /* imgui.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
050450AC276863B000AB6805 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
05A2754027728F5B0084EF39 /* imgui_impl_metal4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_metal4.h; path = ../../backends/imgui_impl_metal4.h; sourceTree = "<group>"; };
05A2754127728F5B0084EF39 /* imgui_impl_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_osx.h; path = ../../backends/imgui_impl_osx.h; sourceTree = "<group>"; };
05A275432773BEA20084EF39 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS15.2.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; };
07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; };
8307E7C420E9F9C900473790 /* example_apple_metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_apple_metal.app; sourceTree = BUILT_PRODUCTS_DIR; };
8307E7DA20E9F9C900473790 /* example_apple_metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example_apple_metal.app; sourceTree = BUILT_PRODUCTS_DIR; };
8309BD8E253CCAAA0045E2A1 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
8309BDA0253CCBC10045E2A1 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal4.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = imgui_impl_metal4.mm; path = ../../backends/imgui_impl_metal4.mm; sourceTree = "<group>"; };
8309BDB6253CCC9D0045E2A1 /* imgui_impl_osx.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = imgui_impl_osx.mm; path = ../../backends/imgui_impl_osx.mm; sourceTree = "<group>"; };
8309BDC5253CCCFE0045E2A1 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
8309BDF7253CDAAE0045E2A1 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
8309BDF8253CDAAE0045E2A1 /* Info-iOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = "<group>"; };
8309BDFA253CDAAE0045E2A1 /* MainMenu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainMenu.storyboard; sourceTree = "<group>"; };
8309BDFB253CDAAE0045E2A1 /* Info-macOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Info-macOS.plist"; sourceTree = "<group>"; };
83BBE9E420EB46B900295997 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/Metal.framework; sourceTree = DEVELOPER_DIR; };
83BBE9E620EB46BD00295997 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/MetalKit.framework; sourceTree = DEVELOPER_DIR; };
83BBE9E820EB46C100295997 /* ModelIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModelIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.4.sdk/System/Library/Frameworks/ModelIO.framework; sourceTree = DEVELOPER_DIR; };
83BBE9EA20EB471700295997 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
83BBE9EB20EB471700295997 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
83BBE9EE20EB471C00295997 /* ModelIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModelIO.framework; path = System/Library/Frameworks/ModelIO.framework; sourceTree = SDKROOT; };
83BBEA0020EB54E700295997 /* imgui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = ../../imgui.h; sourceTree = "<group>"; };
83BBEA0120EB54E700295997 /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = ../../imgui_draw.cpp; sourceTree = "<group>"; };
83BBEA0220EB54E700295997 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../imgui_demo.cpp; sourceTree = "<group>"; };
83BBEA0320EB54E700295997 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../../imgui.cpp; sourceTree = "<group>"; };
83BBEA0420EB54E700295997 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8307E7C120E9F9C900473790 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
05A275442773BEA20084EF39 /* QuartzCore.framework in Frameworks */,
8309BD8F253CCAAA0045E2A1 /* UIKit.framework in Frameworks */,
83BBE9E720EB46BD00295997 /* MetalKit.framework in Frameworks */,
83BBE9E520EB46B900295997 /* Metal.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8307E7D720E9F9C900473790 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
050450AD276863B000AB6805 /* QuartzCore.framework in Frameworks */,
8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */,
83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */,
05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */,
83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
8307E7B520E9F9C700473790 = {
isa = PBXGroup;
children = (
83BBE9F020EB544400295997 /* imgui */,
8309BD9E253CCBA70045E2A1 /* example */,
8307E7C520E9F9C900473790 /* Products */,
83BBE9E320EB46B800295997 /* Frameworks */,
);
sourceTree = "<group>";
};
8307E7C520E9F9C900473790 /* Products */ = {
isa = PBXGroup;
children = (
8307E7C420E9F9C900473790 /* example_apple_metal.app */,
8307E7DA20E9F9C900473790 /* example_apple_metal.app */,
);
name = Products;
sourceTree = "<group>";
};
8309BD9E253CCBA70045E2A1 /* example */ = {
isa = PBXGroup;
children = (
8309BDF6253CDAAE0045E2A1 /* iOS */,
8309BDF9253CDAAE0045E2A1 /* macOS */,
8309BDA0253CCBC10045E2A1 /* main.mm */,
);
name = example;
sourceTree = "<group>";
};
8309BDF6253CDAAE0045E2A1 /* iOS */ = {
isa = PBXGroup;
children = (
8309BDF7253CDAAE0045E2A1 /* LaunchScreen.storyboard */,
8309BDF8253CDAAE0045E2A1 /* Info-iOS.plist */,
);
path = iOS;
sourceTree = "<group>";
};
8309BDF9253CDAAE0045E2A1 /* macOS */ = {
isa = PBXGroup;
children = (
8309BDFA253CDAAE0045E2A1 /* MainMenu.storyboard */,
8309BDFB253CDAAE0045E2A1 /* Info-macOS.plist */,
);
path = macOS;
sourceTree = "<group>";
};
83BBE9E320EB46B800295997 /* Frameworks */ = {
isa = PBXGroup;
children = (
050450AC276863B000AB6805 /* QuartzCore.framework */,
05A275432773BEA20084EF39 /* QuartzCore.framework */,
05318E0E274C397200A8DE2E /* GameController.framework */,
8309BDC5253CCCFE0045E2A1 /* AppKit.framework */,
8309BD8E253CCAAA0045E2A1 /* UIKit.framework */,
83BBE9EE20EB471C00295997 /* ModelIO.framework */,
83BBE9EB20EB471700295997 /* Metal.framework */,
83BBE9EA20EB471700295997 /* MetalKit.framework */,
83BBE9E820EB46C100295997 /* ModelIO.framework */,
83BBE9E620EB46BD00295997 /* MetalKit.framework */,
83BBE9E420EB46B900295997 /* Metal.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
83BBE9F020EB544400295997 /* imgui */ = {
isa = PBXGroup;
children = (
5079822D257677DB0038A28D /* imgui_tables.cpp */,
05A2754027728F5B0084EF39 /* imgui_impl_metal4.h */,
8309BDB5253CCC9D0045E2A1 /* imgui_impl_metal4.mm */,
05A2754127728F5B0084EF39 /* imgui_impl_osx.h */,
8309BDB6253CCC9D0045E2A1 /* imgui_impl_osx.mm */,
83BBEA0420EB54E700295997 /* imconfig.h */,
83BBEA0320EB54E700295997 /* imgui.cpp */,
83BBEA0020EB54E700295997 /* imgui.h */,
83BBEA0220EB54E700295997 /* imgui_demo.cpp */,
83BBEA0120EB54E700295997 /* imgui_draw.cpp */,
07A82ED62139413C0078D120 /* imgui_internal.h */,
07A82ED72139413C0078D120 /* imgui_widgets.cpp */,
);
name = imgui;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8307E7C320E9F9C900473790 /* example_apple_metal_ios */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8307E7F020E9F9C900473790 /* Build configuration list for PBXNativeTarget "example_apple_metal_ios" */;
buildPhases = (
8307E7C020E9F9C900473790 /* Sources */,
8307E7C120E9F9C900473790 /* Frameworks */,
8307E7C220E9F9C900473790 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = example_apple_metal_ios;
productName = "imguiex iOS";
productReference = 8307E7C420E9F9C900473790 /* example_apple_metal.app */;
productType = "com.apple.product-type.application";
};
8307E7D920E9F9C900473790 /* example_apple_metal_macos */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8307E7F320E9F9C900473790 /* Build configuration list for PBXNativeTarget "example_apple_metal_macos" */;
buildPhases = (
8307E7D620E9F9C900473790 /* Sources */,
8307E7D720E9F9C900473790 /* Frameworks */,
8307E7D820E9F9C900473790 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = example_apple_metal_macos;
productName = "imguiex macOS";
productReference = 8307E7DA20E9F9C900473790 /* example_apple_metal.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
8307E7B620E9F9C700473790 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1530;
ORGANIZATIONNAME = "Warren Moore";
TargetAttributes = {
8307E7C320E9F9C900473790 = {
CreatedOnToolsVersion = 9.4.1;
ProvisioningStyle = Automatic;
};
8307E7D920E9F9C900473790 = {
CreatedOnToolsVersion = 9.4.1;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 8307E7B920E9F9C700473790 /* Build configuration list for PBXProject "example_apple_metal" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 8307E7B520E9F9C700473790;
productRefGroup = 8307E7C520E9F9C900473790 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
8307E7C320E9F9C900473790 /* example_apple_metal_ios */,
8307E7D920E9F9C900473790 /* example_apple_metal_macos */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8307E7C220E9F9C900473790 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8309BDFC253CDAB30045E2A1 /* LaunchScreen.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8307E7D820E9F9C900473790 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8309BE04253CDAB60045E2A1 /* MainMenu.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8307E7C020E9F9C900473790 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8309BDBB253CCCAD0045E2A1 /* imgui_impl_metal4.mm in Sources */,
83BBEA0920EB54E700295997 /* imgui.cpp in Sources */,
83BBEA0720EB54E700295997 /* imgui_demo.cpp in Sources */,
83BBEA0520EB54E700295997 /* imgui_draw.cpp in Sources */,
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */,
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */,
8309BDA5253CCC070045E2A1 /* main.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
8307E7D620E9F9C900473790 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8309BDBE253CCCB60045E2A1 /* imgui_impl_metal4.mm in Sources */,
8309BDBF253CCCB60045E2A1 /* imgui_impl_osx.mm in Sources */,
83BBEA0A20EB54E700295997 /* imgui.cpp in Sources */,
83BBEA0820EB54E700295997 /* imgui_demo.cpp in Sources */,
83BBEA0620EB54E700295997 /* imgui_draw.cpp in Sources */,
050450AB2768052600AB6805 /* imgui_tables.cpp in Sources */,
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */,
8309BDA8253CCC080045E2A1 /* main.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
8307E7EE20E9F9C900473790 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
};
name = Debug;
};
8307E7EF20E9F9C900473790 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MTL_ENABLE_DEBUG_INFO = NO;
};
name = Release;
};
8307E7F120E9F9C900473790 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios";
PRODUCT_NAME = example_apple_metal;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../**";
};
name = Debug;
};
8307E7F220E9F9C900473790 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/iOS/Info-iOS.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-ios";
PRODUCT_NAME = example_apple_metal;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../**";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
8307E7F420E9F9C900473790 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 26.0;
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos";
PRODUCT_NAME = example_apple_metal;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../**";
};
name = Debug;
};
8307E7F520E9F9C900473790 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/macOS/Info-macOS.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 26.0;
PRODUCT_BUNDLE_IDENTIFIER = "org.imgui.example.apple-metal-macos";
PRODUCT_NAME = example_apple_metal;
SDKROOT = macosx;
USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../**";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
8307E7B920E9F9C700473790 /* Build configuration list for PBXProject "example_apple_metal" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8307E7EE20E9F9C900473790 /* Debug */,
8307E7EF20E9F9C900473790 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8307E7F020E9F9C900473790 /* Build configuration list for PBXNativeTarget "example_apple_metal_ios" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8307E7F120E9F9C900473790 /* Debug */,
8307E7F220E9F9C900473790 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8307E7F320E9F9C900473790 /* Build configuration list for PBXNativeTarget "example_apple_metal_macos" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8307E7F420E9F9C900473790 /* Debug */,
8307E7F520E9F9C900473790 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 8307E7B620E9F9C700473790 /* Project object */;
}

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>imgui</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
<string>metal</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17125"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
<color key="backgroundColor" red="0.27843137254901962" green="0.36078431372549019" blue="0.50196078431372548" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>imgui</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSMainStoryboardFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>

View file

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="17156" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17156"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="ImGui" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="ImGui" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
<connections>
<action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="R4o-n2-Eq4">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-362" y="-38"/>
</scene>
</scenes>
</document>

View file

@ -0,0 +1,366 @@
// Dear ImGui: standalone example application for OSX + Metal.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#import <Foundation/Foundation.h>
#if TARGET_OS_OSX
#import <Cocoa/Cocoa.h>
#else
#import <UIKit/UIKit.h>
#endif
#import <Metal/Metal.h>
#import <MetalKit/MetalKit.h>
#include "imgui.h"
#include "imgui_impl_metal4.h"
#if TARGET_OS_OSX
#include "imgui_impl_osx.h"
@interface AppViewController : NSViewController<NSWindowDelegate>
@end
#else
@interface AppViewController : UIViewController
@end
#endif
@interface AppViewController () <MTKViewDelegate>
@property (nonatomic, readonly) MTKView *mtkView;
@property (nonatomic, strong) id <MTLDevice> device;
@property (nonatomic, strong) id <MTL4CommandQueue> commandQueue;
@property (nonatomic, strong) id <MTL4CommandAllocator> commandAllocator;
@end
#define FRAMES_IN_FLIGHT 2
//-----------------------------------------------------------------------------------
// AppViewController
//-----------------------------------------------------------------------------------
@implementation AppViewController
-(instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
_device = MTLCreateSystemDefaultDevice();
_commandQueue = [_device newMTL4CommandQueue];
_commandAllocator = [_device newCommandAllocator];
if (!self.device)
{
NSLog(@"Metal is not supported");
abort();
}
// Setup Dear ImGui context
// FIXME: This example doesn't have proper cleanup...
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
// Setup Renderer backend
ImGui_ImplMetal4_Init(_device, _commandQueue, FRAMES_IN_FLIGHT);
// Load Fonts
// - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
// This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
// - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
// - Read 'docs/FONTS.md' for more instructions and details.
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//style.FontSizeBase = 20.0f;
//io.Fonts->AddFontDefaultVector();
//io.Fonts->AddFontDefaultBitmap();
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
//IM_ASSERT(font != nullptr);
return self;
}
-(MTKView *)mtkView
{
return (MTKView *)self.view;
}
-(void)loadView
{
self.view = [[MTKView alloc] initWithFrame:CGRectMake(0, 0, 1200, 800)];
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.mtkView.device = self.device;
self.mtkView.delegate = self;
#if TARGET_OS_OSX
ImGui_ImplOSX_Init(self.view);
[NSApp activateIgnoringOtherApps:YES];
#endif
}
-(void)drawInMTKView:(MTKView*)view
{
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = view.bounds.size.width;
io.DisplaySize.y = view.bounds.size.height;
#if TARGET_OS_OSX
CGFloat framebufferScale = view.window.screen.backingScaleFactor ?: NSScreen.mainScreen.backingScaleFactor;
#else
CGFloat framebufferScale = view.window.screen.scale ?: UIScreen.mainScreen.scale;
#endif
io.DisplayFramebufferScale = ImVec2(framebufferScale, framebufferScale);
[self.commandAllocator reset];
id<MTL4CommandBuffer> commandBuffer = [self.device newCommandBuffer];
[commandBuffer beginCommandBufferWithAllocator:self.commandAllocator];
MTL4RenderPassDescriptor* renderPassDescriptor = view.currentMTL4RenderPassDescriptor;
if (renderPassDescriptor == nil)
{
[commandBuffer endCommandBuffer];
[self.commandQueue commit:&commandBuffer count:1];
return;
}
// Start the Dear ImGui frame
static int frameIndex = 0;
ImGui_ImplMetal4_NewFrame(renderPassDescriptor, frameIndex);
frameIndex++;
frameIndex = (frameIndex + 1) % FRAMES_IN_FLIGHT;
#if TARGET_OS_OSX
ImGui_ImplOSX_NewFrame(view);
#endif
ImGui::NewFrame();
// Our state (make them static = more or less global) as a convenience to keep the example terse.
static bool show_demo_window = true;
static bool show_another_window = false;
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
id <MTL4RenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
[renderEncoder pushDebugGroup:@"Dear ImGui rendering"];
ImGui_ImplMetal4_RenderDrawData(draw_data, commandBuffer, renderEncoder);
[renderEncoder popDebugGroup];
[renderEncoder endEncoding];
// Present
[commandBuffer endCommandBuffer];
[self.commandQueue waitForDrawable:view.currentDrawable];
[self.commandQueue commit:&commandBuffer count:1];
[self.commandQueue signalDrawable:view.currentDrawable];
[view.currentDrawable present];
}
-(void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size
{
}
//-----------------------------------------------------------------------------------
// Input processing
//-----------------------------------------------------------------------------------
#if TARGET_OS_OSX
- (void)viewWillAppear
{
[super viewWillAppear];
self.view.window.delegate = self;
}
- (void)windowWillClose:(NSNotification *)notification
{
ImGui_ImplMetal4_Shutdown();
ImGui_ImplOSX_Shutdown();
ImGui::DestroyContext();
}
#else
// This touch mapping is super cheesy/hacky. We treat any touch on the screen
// as if it were a depressed left mouse button, and we don't bother handling
// multitouch correctly at all. This causes the "cursor" to behave very erratically
// when there are multiple active touches. But for demo purposes, single-touch
// interaction actually works surprisingly well.
-(void)updateIOWithTouchEvent:(UIEvent *)event
{
UITouch *anyTouch = event.allTouches.anyObject;
CGPoint touchLocation = [anyTouch locationInView:self.view];
ImGuiIO &io = ImGui::GetIO();
io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
io.AddMousePosEvent(touchLocation.x, touchLocation.y);
BOOL hasActiveTouch = NO;
for (UITouch *touch in event.allTouches)
{
if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled)
{
hasActiveTouch = YES;
break;
}
}
io.AddMouseButtonEvent(0, hasActiveTouch);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; }
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; }
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; }
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; }
#endif
@end
//-----------------------------------------------------------------------------------
// AppDelegate
//-----------------------------------------------------------------------------------
#if TARGET_OS_OSX
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (nonatomic, strong) NSWindow *window;
@end
@implementation AppDelegate
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
-(instancetype)init
{
if (self = [super init])
{
NSViewController *rootViewController = [[AppViewController alloc] initWithNibName:nil bundle:nil];
self.window = [[NSWindow alloc] initWithContentRect:NSZeroRect
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable | NSWindowStyleMaskMiniaturizable
backing:NSBackingStoreBuffered
defer:NO];
self.window.contentViewController = rootViewController;
[self.window center];
[self.window makeKeyAndOrderFront:self];
}
return self;
}
@end
#else
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@implementation AppDelegate
-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey,id> *)launchOptions
{
UIViewController *rootViewController = [[AppViewController alloc] init];
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
#endif
//-----------------------------------------------------------------------------------
// Application main() function
//-----------------------------------------------------------------------------------
#if TARGET_OS_OSX
int main(int, const char**)
{
@autoreleasepool
{
[NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
AppDelegate *appDelegate = [[AppDelegate alloc] init]; // creates window
[NSApp setDelegate:appDelegate];
[NSApp activateIgnoringOtherApps:YES];
[NSApp run];
}
return 0;
}
#else
int main(int argc, char * argv[])
{
@autoreleasepool
{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
#endif

View file

@ -6,6 +6,7 @@
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#define GL_SILENCE_DEPRECATION
#import <Cocoa/Cocoa.h>
#import <OpenGL/gl.h>
#import <OpenGL/glu.h>
@ -32,7 +33,7 @@
#ifndef DEBUG
GLint swapInterval = 1;
[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval];
if (swapInterval == 0)
NSLog(@"Error: Cannot set swap interval.");
#endif
@ -130,8 +131,8 @@
ImDrawData* draw_data = ImGui::GetDrawData();
[[self openGLContext] makeCurrentContext];
GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
glViewport(0, 0, width, height);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);

View file

@ -0,0 +1,21 @@
# Makefile for example_apple_opengl3, for macOS only (**not iOS**)
CXX = clang++
EXE = example_apple_opengl3
IMGUI_DIR = ../../
SOURCES = main.mm
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_osx.mm $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
CXXFLAGS = -std=c++11 -ObjC++ -fobjc-arc -Wall -Wextra -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
FRAMEWORKS = -framework Cocoa -framework OpenGL -framework GameController
all: $(EXE)
$(EXE): $(SOURCES)
$(CXX) $(CXXFLAGS) $(SOURCES) -o $(EXE) $(FRAMEWORKS)
run: all
./$(EXE)
clean:
rm -f $(EXE) *.o

View file

@ -0,0 +1,334 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {
/* Begin PBXBuildFile section */
05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05E31B57274EF0360083FCB6 /* GameController.framework */; };
07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82EDA213941D00078D120 /* imgui_widgets.cpp */; };
4080A99820B02D340036BA46 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A98A20B02CD90036BA46 /* main.mm */; };
4080A9A220B034280036BA46 /* imgui_impl_opengl3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99E20B034280036BA46 /* imgui_impl_opengl3.cpp */; };
4080A9AD20B0343C0036BA46 /* imgui_demo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A9A620B0343C0036BA46 /* imgui_demo.cpp */; };
4080A9AE20B0343C0036BA46 /* imgui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A9A720B0343C0036BA46 /* imgui.cpp */; };
4080A9AF20B0343C0036BA46 /* imgui_draw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A9AA20B0343C0036BA46 /* imgui_draw.cpp */; };
4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99F20B034280036BA46 /* imgui_impl_osx.mm */; };
4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B220B034E40036BA46 /* Cocoa.framework */; };
4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080A9B420B034EA0036BA46 /* OpenGL.framework */; };
50798230257677FD0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822F257677FC0038A28D /* imgui_tables.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
4080A96920B029B00036BA46 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
05E31B57274EF0360083FCB6 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
07A82EDA213941D00078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
4080A96B20B029B00036BA46 /* example_osx_opengl3 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = example_osx_opengl3; sourceTree = BUILT_PRODUCTS_DIR; };
4080A98A20B02CD90036BA46 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = SOURCE_ROOT; };
4080A99E20B034280036BA46 /* imgui_impl_opengl3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_impl_opengl3.cpp; path = ../../backends/imgui_impl_opengl3.cpp; sourceTree = "<group>"; };
4080A99F20B034280036BA46 /* imgui_impl_osx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = imgui_impl_osx.mm; path = ../../backends/imgui_impl_osx.mm; sourceTree = "<group>"; };
4080A9A020B034280036BA46 /* imgui_impl_opengl3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_opengl3.h; path = ../../backends/imgui_impl_opengl3.h; sourceTree = "<group>"; };
4080A9A120B034280036BA46 /* imgui_impl_osx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_osx.h; path = ../../backends/imgui_impl_osx.h; sourceTree = "<group>"; };
4080A9A320B034280036BA46 /* imgui_impl_opengl3_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_impl_opengl3_loader.h; path = ../../backends/imgui_impl_opengl3_loader.h; sourceTree = "<group>"; };
4080A9A520B0343C0036BA46 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; };
4080A9A620B0343C0036BA46 /* imgui_demo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_demo.cpp; path = ../../imgui_demo.cpp; sourceTree = "<group>"; };
4080A9A720B0343C0036BA46 /* imgui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui.cpp; path = ../../imgui.cpp; sourceTree = "<group>"; };
4080A9A820B0343C0036BA46 /* imgui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui.h; path = ../../imgui.h; sourceTree = "<group>"; };
4080A9AA20B0343C0036BA46 /* imgui_draw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_draw.cpp; path = ../../imgui_draw.cpp; sourceTree = "<group>"; };
4080A9AC20B0343C0036BA46 /* imconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imconfig.h; path = ../../imconfig.h; sourceTree = "<group>"; };
4080A9B220B034E40036BA46 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
4080A9B420B034EA0036BA46 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
5079822F257677FC0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
4080A96820B029B00036BA46 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */,
4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */,
05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
4080A96220B029B00036BA46 = {
isa = PBXGroup;
children = (
5079822F257677FC0038A28D /* imgui_tables.cpp */,
4080A9AC20B0343C0036BA46 /* imconfig.h */,
4080A9A720B0343C0036BA46 /* imgui.cpp */,
4080A9A820B0343C0036BA46 /* imgui.h */,
07A82EDA213941D00078D120 /* imgui_widgets.cpp */,
4080A9A620B0343C0036BA46 /* imgui_demo.cpp */,
4080A9AA20B0343C0036BA46 /* imgui_draw.cpp */,
4080A9A520B0343C0036BA46 /* imgui_internal.h */,
4080A99E20B034280036BA46 /* imgui_impl_opengl3.cpp */,
4080A9A020B034280036BA46 /* imgui_impl_opengl3.h */,
4080A9A320B034280036BA46 /* imgui_impl_opengl3_loader.h */,
4080A9A120B034280036BA46 /* imgui_impl_osx.h */,
4080A99F20B034280036BA46 /* imgui_impl_osx.mm */,
4080A98A20B02CD90036BA46 /* main.mm */,
4080A96C20B029B00036BA46 /* Products */,
4080A9B120B034E40036BA46 /* Frameworks */,
);
sourceTree = "<group>";
};
4080A96C20B029B00036BA46 /* Products */ = {
isa = PBXGroup;
children = (
4080A96B20B029B00036BA46 /* example_osx_opengl3 */,
);
name = Products;
sourceTree = "<group>";
};
4080A9B120B034E40036BA46 /* Frameworks */ = {
isa = PBXGroup;
children = (
05E31B57274EF0360083FCB6 /* GameController.framework */,
4080A9B420B034EA0036BA46 /* OpenGL.framework */,
4080A9B220B034E40036BA46 /* Cocoa.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
4080A96A20B029B00036BA46 /* example_osx_opengl3 */ = {
isa = PBXNativeTarget;
buildConfigurationList = 4080A97220B029B00036BA46 /* Build configuration list for PBXNativeTarget "example_osx_opengl3" */;
buildPhases = (
4080A96720B029B00036BA46 /* Sources */,
4080A96820B029B00036BA46 /* Frameworks */,
4080A96920B029B00036BA46 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = example_osx_opengl3;
productName = example_osx_opengl3;
productReference = 4080A96B20B029B00036BA46 /* example_osx_opengl3 */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
4080A96320B029B00036BA46 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = ImGui;
TargetAttributes = {
4080A96A20B029B00036BA46 = {
CreatedOnToolsVersion = 9.3.1;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 4080A96620B029B00036BA46 /* Build configuration list for PBXProject "example_apple_opengl3" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 4080A96220B029B00036BA46;
productRefGroup = 4080A96C20B029B00036BA46 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
4080A96A20B029B00036BA46 /* example_osx_opengl3 */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
4080A96720B029B00036BA46 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4080A99820B02D340036BA46 /* main.mm in Sources */,
4080A9AD20B0343C0036BA46 /* imgui_demo.cpp in Sources */,
4080A9AF20B0343C0036BA46 /* imgui_draw.cpp in Sources */,
4080A9A220B034280036BA46 /* imgui_impl_opengl3.cpp in Sources */,
4080A9B020B0347A0036BA46 /* imgui_impl_osx.mm in Sources */,
4080A9AE20B0343C0036BA46 /* imgui.cpp in Sources */,
50798230257677FD0038A28D /* imgui_tables.cpp in Sources */,
07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
4080A97020B029B00036BA46 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
4080A97120B029B00036BA46 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};
name = Release;
};
4080A97320B029B00036BA46 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = ../..;
};
name = Debug;
};
4080A97420B029B00036BA46 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
MACOSX_DEPLOYMENT_TARGET = 10.13;
PRODUCT_NAME = "$(TARGET_NAME)";
USER_HEADER_SEARCH_PATHS = ../..;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
4080A96620B029B00036BA46 /* Build configuration list for PBXProject "example_apple_opengl3" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4080A97020B029B00036BA46 /* Debug */,
4080A97120B029B00036BA46 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
4080A97220B029B00036BA46 /* Build configuration list for PBXNativeTarget "example_osx_opengl3" */ = {
isa = XCConfigurationList;
buildConfigurations = (
4080A97320B029B00036BA46 /* Debug */,
4080A97420B029B00036BA46 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 4080A96320B029B00036BA46 /* Project object */;
}

View file

@ -0,0 +1,260 @@
// Dear ImGui: standalone example application for OSX + OpenGL3
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#define GL_SILENCE_DEPRECATION
#import <Cocoa/Cocoa.h>
#import <OpenGL/gl3.h>
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_osx.h"
//-----------------------------------------------------------------------------------
// AppView
//-----------------------------------------------------------------------------------
@interface AppView : NSOpenGLView
{
NSTimer* animationTimer;
}
@end
@implementation AppView
-(void)prepareOpenGL
{
[super prepareOpenGL];
#ifndef DEBUG
GLint swapInterval = 1;
[[self openGLContext] setValues:&swapInterval forParameter:NSOpenGLContextParameterSwapInterval];
if (swapInterval == 0)
NSLog(@"Error: Cannot set swap interval.");
#endif
}
-(void)initialize
{
// Setup Dear ImGui context
// FIXME: This example doesn't have proper cleanup...
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
[[self openGLContext] makeCurrentContext]; // ImGui_ImplOpenGL3_Init() requires a current GL context.
ImGui_ImplOSX_Init(self);
ImGui_ImplOpenGL3_Init();
// Load Fonts
// - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
// This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
// - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
// - Read 'docs/FONTS.md' for more instructions and details.
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//style.FontSizeBase = 20.0f;
//io.Fonts->AddFontDefaultVector();
//io.Fonts->AddFontDefaultBitmap();
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
//IM_ASSERT(font != nullptr);
}
-(void)updateAndDrawDemoView
{
// Start the Dear ImGui frame
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplOSX_NewFrame(self);
ImGui::NewFrame();
// Our state (make them static = more or less global) as a convenience to keep the example terse.
static bool show_demo_window = true;
static bool show_another_window = false;
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
[[self openGLContext] makeCurrentContext];
GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x + 0.5f);
GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y + 0.5f);
glViewport(0, 0, width, height);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(draw_data);
// Present
[[self openGLContext] flushBuffer];
if (!animationTimer)
animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES];
}
-(void)reshape { [super reshape]; [[self openGLContext] update]; [self updateAndDrawDemoView]; }
-(void)drawRect:(NSRect)bounds { [self updateAndDrawDemoView]; }
-(void)animationTimerFired:(NSTimer*)timer { [self setNeedsDisplay:YES]; }
-(void)dealloc { animationTimer = nil; }
@end
//-----------------------------------------------------------------------------------
// AppDelegate
//-----------------------------------------------------------------------------------
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (nonatomic, readonly) NSWindow* window;
@end
@implementation AppDelegate
@synthesize window = _window;
-(BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
{
return YES;
}
-(NSWindow*)window
{
if (_window != nil)
return _window;
NSRect viewRect = NSMakeRect(100.0, 100.0, 100.0 + 1280.0, 100 + 800.0);
_window = [[NSWindow alloc] initWithContentRect:viewRect styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskMiniaturizable|NSWindowStyleMaskResizable|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:YES];
[_window setTitle:@"Dear ImGui OSX+OpenGL3 Example"];
[_window setAcceptsMouseMovedEvents:YES];
[_window setOpaque:YES];
[_window makeKeyAndOrderFront:NSApp];
return _window;
}
-(void)setupMenu
{
NSMenu* mainMenuBar = [[NSMenu alloc] init];
NSMenu* appMenu;
NSMenuItem* menuItem;
appMenu = [[NSMenu alloc] initWithTitle:@"Dear ImGui OSX+OpenGL3 Example"];
menuItem = [appMenu addItemWithTitle:@"Quit Dear ImGui OSX+OpenGL3 Example" action:@selector(terminate:) keyEquivalent:@"q"];
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
menuItem = [[NSMenuItem alloc] init];
[menuItem setSubmenu:appMenu];
[mainMenuBar addItem:menuItem];
appMenu = nil;
[NSApp setMainMenu:mainMenuBar];
}
-(void)dealloc
{
_window = nil;
}
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Make the application a foreground application (else it won't receive keyboard events)
ProcessSerialNumber psn = {0, kCurrentProcess};
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
// Menu
[self setupMenu];
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 32,
0
};
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
AppView* view = [[AppView alloc] initWithFrame:self.window.frame pixelFormat:format];
format = nil;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6)
[view setWantsBestResolutionOpenGLSurface:YES];
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
[self.window setContentView:view];
if ([view openGLContext] == nil)
NSLog(@"No OpenGL Context!");
[view initialize];
}
@end
//-----------------------------------------------------------------------------------
// Application main() function
//-----------------------------------------------------------------------------------
int main(int argc, const char* argv[])
{
@autoreleasepool
{
NSApp = [NSApplication sharedApplication];
AppDelegate* delegate = [[AppDelegate alloc] init];
[[NSApplication sharedApplication] setDelegate:delegate];
[NSApp run];
}
return NSApplicationMain(argc, argv);
}

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -92,6 +92,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -107,6 +108,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -92,6 +92,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -107,6 +108,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -41,29 +41,26 @@ int main(int, char**)
if (!glfwInit())
return 1;
// Decide GL+GLSL versions
// Select GL version + let the backend select a GLSL version
const char* glsl_version = nullptr;
#if defined(IMGUI_IMPL_OPENGL_ES2)
// GL ES 2.0 + GLSL 100 (WebGL 1.0)
const char* glsl_version = "#version 100";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(IMGUI_IMPL_OPENGL_ES3)
// GL ES 3.0 + GLSL 300 es (WebGL 2.0)
const char* glsl_version = "#version 300 es";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
// GL 3.2 + GLSL 150
const char* glsl_version = "#version 150";
// GL 3.2 + generally GLSL 150
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
#else
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 130";
// GL 3.0 + generally GLSL 130
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -93,6 +93,7 @@
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -109,6 +110,7 @@
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -193,7 +193,8 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
{
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE },
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE },
{ VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE },
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;

View file

@ -1,10 +1,3 @@
# Building for desktop with Dawn:
# 1. git clone https://github.com/google/dawn dawn
# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn
# 3. cmake --build build
# The resulting binary will be found at one of the following locations:
# * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
# Building for desktop with WGPU-Native:
# 1. download WGPU-Native autogenerated binary modules for your platform/compiler from: https://github.com/gfx-rs/wgpu-native/releases
# 2. unzip the downloaded file in your_preferred_folder
@ -13,8 +6,15 @@
# The resulting binary will be found at one of the following locations:
# * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
# Building for desktop with WGVK (MUCH EASIER)
# 1. git clone https://github.com/manuel5975p/WGVK dawn
# Building for desktop with Dawn: (VERY LONG TO BUILD)
# 1. git clone https://github.com/google/dawn dawn
# 2. cmake -B build -DIMGUI_DAWN_DIR=dawn
# 3. cmake --build build
# The resulting binary will be found at one of the following locations:
# * build/example_glfw_wgpu[.exe] or build/Debug/example_glfw_wgpu[.exe]
# Building for desktop with WGVK:
# 1. git clone https://github.com/manuel5975p/WGVK wgvk
# 2. cmake -B build -DIMGUI_WGVK_DIR=wgvk
# 3. cmake --build build
# The resulting binary will be found at one of the following locations:
@ -29,7 +29,7 @@
# 4. emrun build/index.html
cmake_minimum_required(VERSION 3.22) # Dawn requires CMake >= 3.22
project(imgui_example_glfw_wgpu C CXX)
project(example_glfw_wgpu C CXX)
set(IMGUI_EXECUTABLE example_glfw_wgpu)
@ -37,7 +37,7 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE)
endif()
set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17
set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20
# Dear ImGui
set(IMGUI_DIR ../../)
@ -146,6 +146,28 @@ else() # Native/Desktop build
endif()
if(IMGUI_WGVK_DIR)
find_package(Vulkan REQUIRED)
set(WGVK_PLATFORM_LIBS)
set(WGVK_PLATFORM_DEFS)
if(WIN32)
list(APPEND WGVK_PLATFORM_DEFS SUPPORT_WIN32_SURFACE=1)
elseif(APPLE)
list(APPEND WGVK_PLATFORM_DEFS SUPPORT_METAL_SURFACE=1)
elseif(UNIX)
find_package(PkgConfig QUIET)
pkg_check_modules(WAYLAND_CLIENT QUIET wayland-client)
if(WAYLAND_CLIENT_FOUND)
list(APPEND WGVK_PLATFORM_DEFS SUPPORT_WAYLAND_SURFACE=1)
list(APPEND WGVK_PLATFORM_LIBS ${WAYLAND_CLIENT_LIBRARIES})
endif()
find_package(X11 QUIET)
if(X11_FOUND)
list(APPEND WGVK_PLATFORM_DEFS SUPPORT_XLIB_SURFACE=1)
list(APPEND WGVK_PLATFORM_LIBS X11::X11)
endif()
list(APPEND WGVK_PLATFORM_LIBS m dl pthread)
endif()
set(LIBRARIES glfw Vulkan::Vulkan ${WGVK_PLATFORM_LIBS})
endif()
endif()
@ -187,6 +209,7 @@ if(NOT EMSCRIPTEN) # WegGPU-Native settings
if(IMGUI_WGVK_DIR)
target_sources(${IMGUI_EXECUTABLE} PRIVATE ${IMGUI_WGVK_DIR}/src/wgvk.c)
target_compile_definitions(${IMGUI_EXECUTABLE} PUBLIC "IMGUI_IMPL_WEBGPU_BACKEND_WGVK")
target_compile_definitions(${IMGUI_EXECUTABLE} PRIVATE ${WGVK_PLATFORM_DEFS})
target_include_directories(${IMGUI_EXECUTABLE} PUBLIC ${IMGUI_WGVK_DIR}/include)
if (MSVC)
target_compile_options(${IMGUI_EXECUTABLE} PUBLIC /std:clatest /experimental:c11atomics)

View file

@ -344,29 +344,25 @@ static WGPUDevice RequestDevice(wgpu::Instance& instance, wgpu::Adapter& adapter
static void handle_request_adapter(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2)
{
IM_UNUSED(userdata2);
if (status == WGPURequestAdapterStatus_Success)
if (status != WGPURequestAdapterStatus_Success)
{
WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1;
*extAdapter = adapter;
}
else
{
printf("Request_adapter status=%#.8x message=%.*s\n", status, (int) message.length, message.data);
printf("Request_adapter status=%#.8x message=%.*s\n", status, (int)message.length, message.data);
return;
}
WGPUAdapter* extAdapter = (WGPUAdapter*)userdata1;
*extAdapter = adapter;
}
static void handle_request_device(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2)
{
IM_UNUSED(userdata2);
if (status == WGPURequestDeviceStatus_Success)
if (status != WGPURequestDeviceStatus_Success)
{
WGPUDevice* extDevice = (WGPUDevice*)userdata1;
*extDevice = device;
}
else
{
printf("Request_device status=%#.8x message=%.*s\n", status, (int) message.length, message.data);
printf("Request_device status=%#.8x message=%.*s\n", status, (int)message.length, message.data);
return;
}
WGPUDevice* extDevice = (WGPUDevice*)userdata1;
*extDevice = device;
}
static WGPUAdapter RequestAdapter(WGPUInstance& instance)
@ -380,8 +376,10 @@ static WGPUAdapter RequestAdapter(WGPUInstance& instance)
adapterCallbackInfo.userdata1 = &local_adapter;
WGPUFuture future = wgpuInstanceRequestAdapter(instance, &adapter_options, adapterCallbackInfo);
#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
WGPUFutureWaitInfo waitInfo = { future, false };
wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull);
#endif
IM_ASSERT(local_adapter && "Error on Adapter request");
return local_adapter;
}
@ -393,15 +391,20 @@ static WGPUDevice RequestDevice(WGPUInstance& instance, WGPUAdapter& adapter)
deviceCallbackInfo.mode = WGPUCallbackMode_WaitAnyOnly;
deviceCallbackInfo.callback = handle_request_device;
deviceCallbackInfo.userdata1 = &local_device;
WGPUFuture future = wgpuAdapterRequestDevice(adapter, nullptr, deviceCallbackInfo);
#if !defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
WGPUFutureWaitInfo waitInfo = { future, false };
wgpuInstanceWaitAny(instance, 1, &waitInfo, ~0ull);
#else
IM_UNUSED(instance);
#endif
IM_ASSERT(local_device && "Error on Device request");
return local_device;
}
#endif // IMGUI_IMPL_WEBGPU_BACKEND_WGPU
bool InitWGPU(GLFWwindow* window)
static bool InitWGPU(GLFWwindow* window)
{
WGPUTextureFormat preferred_fmt = WGPUTextureFormat_Undefined; // acquired from SurfaceCapabilities
@ -450,7 +453,7 @@ bool InitWGPU(GLFWwindow* window)
#if defined(IMGUI_IMPL_WEBGPU_BACKEND_WGPU)
wgpuSetLogCallback(
[](WGPULogLevel level, WGPUStringView msg, void* userdata) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr
[](WGPULogLevel level, WGPUStringView msg, void*) { fprintf(stderr, "%s: %.*s\n", ImGui_ImplWGPU_GetLogLevelName(level), (int)msg.length, msg.data); }, nullptr
);
wgpuSetLogLevel(WGPULogLevel_Warn);
#endif
@ -548,7 +551,7 @@ WGPUSurface CreateWGPUSurface(const WGPUInstance& instance, GLFWwindow* window)
{
create_info.System = "win32";
create_info.RawWindow = (void*)glfwGetWin32Window(window);
create_info.RawInstance = (void*)::GetModuleHandle(NULL);
create_info.RawInstance = (void*)::GetModuleHandle(nullptr);
return ImGui_ImplWGPU_CreateWGPUSurfaceHelper(&create_info);
}
#else

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -92,6 +92,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(GLUT_INCLUDE_DIR);..\..;..\..\backends;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -107,6 +108,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>$(GLUT_INCLUDE_DIR);..\..;..\..\backends;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -21,33 +21,34 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{1A0BF63C-18EF-4BAE-A8DA-055481B11F5D}</ProjectGuid>
<RootNamespace>example_win32_directx11</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -87,6 +88,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -101,6 +103,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -0,0 +1,2 @@
LIST=OS
include recurse.mk

View file

@ -0,0 +1,29 @@
# Dear ImGui QNX Screen + OpenGL ES 3 example
This example uses:
- `imgui_impl_qnx.cpp` as the QNX Screen platform backend
- `imgui_impl_opengl3.cpp` as the renderer backend
- EGL to create an OpenGL ES 3 context and Screen window surface
`imgui_impl_opengl3.cpp` supports desktop OpenGL and OpenGL ES. On QNX this
example compiles it with `IMGUI_IMPL_OPENGL_ES3` and uses `#version 300 es`.
No separate Screen/OpenGL renderer backend is required.
## Build
Load the QNX SDP environment, then run:
```sh
cd examples/example_qnx_opengl3
make
```
The QNX recursive make files build for the CPUs enabled in your SDP
configuration and install the program as `example_qnx_opengl3`.
## Input
The application polls its `screen_context_t` event queue and forwards every
non-`SCREEN_EVENT_NONE` event to `ImGui_ImplQNX_ProcessEvent()`.
Escape exits the example.

View file

@ -0,0 +1,31 @@
ifndef QCONFIG
QCONFIG=qconfig.mk
endif
include $(QCONFIG)
NAME=example_qnx_opengl3
SRCS = \
main.cpp \
imgui.cpp \
imgui_demo.cpp \
imgui_draw.cpp \
imgui_tables.cpp \
imgui_widgets.cpp \
imgui_impl_qnx.cpp \
imgui_impl_opengl3.cpp
EXTRA_SRCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends
EXTRA_INCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends
CXXFLAGS += -std=gnu++11 -DIMGUI_IMPL_OPENGL_ES3
LIBS += EGL GLESv2 screen m
INSTALLDIR=$(firstword $(INSTALLDIR_$(OS)) usr/bin)
define PINFO
PINFO DESCRIPTION=Dear ImGui QNX Screen and OpenGL ES 3 example
endef
include $(MKFILES_ROOT)/qmacros.mk
include $(MKFILES_ROOT)/qtargets.mk

View file

@ -0,0 +1,307 @@
// Dear ImGui: standalone example application for QNX Screen + OpenGL ES 3
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#include "imgui.h"
#include "imgui_impl_qnx.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h> // printf, fprintf
#include <errno.h>
#include <string.h>
#include <sys/keycodes.h>
#include <screen/screen.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#ifndef EGL_OPENGL_ES3_BIT
#ifdef EGL_OPENGL_ES3_BIT_KHR
#define EGL_OPENGL_ES3_BIT EGL_OPENGL_ES3_BIT_KHR
#else
#define EGL_OPENGL_ES3_BIT 0x0040
#endif
#endif
struct QNXWindow
{
screen_context_t Context = nullptr;
screen_window_t Window = nullptr;
screen_event_t Event = nullptr;
EGLDisplay Display = EGL_NO_DISPLAY;
EGLContext GLContext = EGL_NO_CONTEXT;
EGLSurface GLSurface = EGL_NO_SURFACE;
int Size[2] = {};
};
// Forward declarations of helper functions
bool CreateQNXWindow(QNXWindow* window);
void DestroyQNXWindow(QNXWindow* window);
bool ProcessQNXEvents(QNXWindow* window);
// Main code
int main(int, char**)
{
// Setup QNX Screen and EGL
QNXWindow window;
if (!CreateQNXWindow(&window))
{
DestroyQNXWindow(&window);
return 1;
}
// GL ES 3.0 + GLSL 300 es
const char* glsl_version = "#version 300 es";
float main_scale = 1.0f;
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup scaling
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
// Setup Platform/Renderer backends
ImGui_ImplQNX_Init(window.Context, window.Window);
ImGui_ImplOpenGL3_Init(glsl_version);
// Load Fonts
// - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
// This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
// - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
// - Read 'docs/FONTS.md' for more instructions and details.
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//style.FontSizeBase = 20.0f;
//io.Fonts->AddFontDefaultVector();
//io.Fonts->AddFontDefaultBitmap();
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
//IM_ASSERT(font != nullptr);
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
bool done = false;
while (!done)
{
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
if (!ProcessQNXEvents(&window))
done = true;
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplQNX_NewFrame();
ImGui::NewFrame();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
eglSwapBuffers(window.Display, window.GLSurface);
}
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplQNX_Shutdown();
ImGui::DestroyContext();
DestroyQNXWindow(&window);
return 0;
}
// Helper functions
bool CreateQNXWindow(QNXWindow* window)
{
if (screen_create_context(&window->Context, 0) != 0 ||
screen_create_window(&window->Window, window->Context) != 0 ||
screen_create_event(&window->Event) != 0)
{
fprintf(stderr, "QNX Screen initialization failed: %s\n", strerror(errno));
return false;
}
// A newly created QNX Screen window reports the fullscreen dimensions.
if (screen_get_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 || window->Size[0] <= 0 || window->Size[1] <= 0)
{
fprintf(stderr, "Failed to obtain QNX Screen window size: %s\n", strerror(errno));
return false;
}
const int usage = SCREEN_USAGE_OPENGL_ES2 | SCREEN_USAGE_OPENGL_ES3 | SCREEN_USAGE_NATIVE;
const int transparency = SCREEN_TRANSPARENCY_NONE;
const int swap_interval = 1;
if (screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_USAGE, &usage) != 0 ||
screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 ||
screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_TRANSPARENCY, &transparency) != 0 ||
screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_SWAP_INTERVAL, &swap_interval) != 0)
{
fprintf(stderr, "Failed to configure QNX Screen window: %s\n", strerror(errno));
return false;
}
window->Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (window->Display == EGL_NO_DISPLAY || eglInitialize(window->Display, nullptr, nullptr) != EGL_TRUE || eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE)
{
fprintf(stderr, "EGL initialization failed: 0x%04x\n", eglGetError());
return false;
}
const EGLint config_attributes[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
EGLConfig config = nullptr;
EGLint config_count = 0;
if (eglChooseConfig(window->Display, config_attributes, &config, 1, &config_count) != EGL_TRUE || config_count == 0)
{
fprintf(stderr, "eglChooseConfig() failed: 0x%04x\n", eglGetError());
return false;
}
EGLint native_visual = 0;
if (eglGetConfigAttrib(window->Display, config, EGL_NATIVE_VISUAL_ID, &native_visual) != EGL_TRUE ||
screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_FORMAT, &native_visual) != 0 ||
screen_create_window_buffers(window->Window, 2) != 0)
{
fprintf(stderr, "Failed to create QNX Screen buffers: %s\n", strerror(errno));
return false;
}
const EGLint context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE };
window->GLContext = eglCreateContext(window->Display, config, EGL_NO_CONTEXT, context_attributes);
window->GLSurface = eglCreateWindowSurface(window->Display, config, window->Window, nullptr);
if (window->GLContext == EGL_NO_CONTEXT || window->GLSurface == EGL_NO_SURFACE ||
eglMakeCurrent(window->Display, window->GLSurface, window->GLSurface, window->GLContext) != EGL_TRUE ||
eglSwapInterval(window->Display, 1) != EGL_TRUE)
{
fprintf(stderr, "EGL context creation failed: 0x%04x\n", eglGetError());
return false;
}
const int visible = 1;
if (screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_VISIBLE, &visible) != 0)
{
fprintf(stderr, "Failed to show QNX Screen window: %s\n", strerror(errno));
return false;
}
return true;
}
void DestroyQNXWindow(QNXWindow* window)
{
if (window->Display != EGL_NO_DISPLAY)
{
eglMakeCurrent(window->Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (window->GLSurface != EGL_NO_SURFACE)
eglDestroySurface(window->Display, window->GLSurface);
if (window->GLContext != EGL_NO_CONTEXT)
eglDestroyContext(window->Display, window->GLContext);
eglTerminate(window->Display);
}
if (window->Event != nullptr)
screen_destroy_event(window->Event);
if (window->Window != nullptr)
screen_destroy_window(window->Window);
if (window->Context != nullptr)
screen_destroy_context(window->Context);
}
bool ProcessQNXEvents(QNXWindow* window)
{
for (;;)
{
if (screen_get_event(window->Context, window->Event, 0) != 0)
return false;
int type = SCREEN_EVENT_NONE;
if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_TYPE, &type) != 0)
return false;
if (type == SCREEN_EVENT_NONE)
return true;
ImGui_ImplQNX_ProcessEvent(window->Event);
if (type == SCREEN_EVENT_CLOSE)
return false;
if (type == SCREEN_EVENT_KEYBOARD)
{
int flags = 0;
int key_cap = 0;
if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_FLAGS, &flags) == 0 &&
screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_KEY_CAP, &key_cap) == 0 &&
(flags & SCREEN_FLAG_KEY_DOWN) != 0 && key_cap == KEYCODE_ESCAPE)
return false;
}
}
}

View file

@ -0,0 +1,8 @@
LIST=CPU
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

View file

@ -0,0 +1,8 @@
LIST=VARIANT
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

View file

@ -0,0 +1 @@
include ../../../common.mk

View file

@ -0,0 +1,8 @@
LIST=VARIANT
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

View file

@ -0,0 +1 @@
include ../../../common.mk

View file

@ -0,0 +1,2 @@
LIST=OS
include recurse.mk

View file

@ -0,0 +1,29 @@
# Dear ImGui QNX Screen + Vulkan example
This example uses:
- `imgui_impl_qnx.cpp` as the QNX Screen platform backend
- the unmodified `imgui_impl_vulkan.cpp` renderer backend
- `vkCreateScreenSurfaceQNX()` and `VK_QNX_screen_surface`
No separate Screen/Vulkan renderer backend is required. The QNX-specific work
is limited to the Screen platform backend, native window setup, and Vulkan WSI
surface creation.
## Build
Load the QNX SDP environment, then run:
```sh
cd examples/example_qnx_vulkan
make
```
The build defines `VK_USE_PLATFORM_SCREEN_QNX` and links `libvulkan` and
`libscreen`.
## Input and resize
The application forwards Screen input events to `ImGui_ImplQNX_ProcessEvent()`.
It recreates the Vulkan swapchain when the Screen window size changes or Vulkan
reports `VK_ERROR_OUT_OF_DATE_KHR` / `VK_SUBOPTIMAL_KHR`. Escape exits.

View file

@ -0,0 +1,31 @@
ifndef QCONFIG
QCONFIG=qconfig.mk
endif
include $(QCONFIG)
NAME=example_qnx_vulkan
SRCS = \
main.cpp \
imgui.cpp \
imgui_demo.cpp \
imgui_draw.cpp \
imgui_tables.cpp \
imgui_widgets.cpp \
imgui_impl_qnx.cpp \
imgui_impl_vulkan.cpp
EXTRA_SRCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends
EXTRA_INCVPATH += $(PROJECT_ROOT)/../.. $(PROJECT_ROOT)/../../backends
CXXFLAGS += -std=gnu++11 -DVK_USE_PLATFORM_SCREEN_QNX=1
LIBS += vulkan screen m
INSTALLDIR=$(firstword $(INSTALLDIR_$(OS)) usr/bin)
define PINFO
PINFO DESCRIPTION=Dear ImGui QNX Screen and Vulkan example
endef
include $(MKFILES_ROOT)/qmacros.mk
include $(MKFILES_ROOT)/qtargets.mk

View file

@ -0,0 +1,626 @@
// Dear ImGui: standalone example application for QNX Screen + Vulkan
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// Important note to the reader who wish to integrate imgui_impl_vulkan.cpp/.h in their own engine/app.
// - Common ImGui_ImplVulkan_XXX functions and structures are used to interface with imgui_impl_vulkan.cpp/.h.
// You will use those if you want to use this rendering backend in your engine/app.
// - Helper ImGui_ImplVulkanH_XXX functions and structures are only used by this example (main.cpp) and by
// the backend itself (imgui_impl_vulkan.cpp), but should PROBABLY NOT be used by your own engine/app code.
// Read comments in imgui_impl_vulkan.h.
#ifndef VK_USE_PLATFORM_SCREEN_QNX
#define VK_USE_PLATFORM_SCREEN_QNX
#endif
#include "imgui.h"
#include "imgui_impl_qnx.h"
#include "imgui_impl_vulkan.h"
#include <stdio.h> // printf, fprintf
#include <stdlib.h> // abort
#include <errno.h>
#include <string.h>
#include <sys/keycodes.h>
#include <time.h>
#include <screen/screen.h>
// Volk headers
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
#define VOLK_IMPLEMENTATION
#include <volk.h>
#endif
//#define APP_USE_UNLIMITED_FRAME_RATE
#ifdef _DEBUG
#define APP_USE_VULKAN_DEBUG_REPORT
static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE;
#endif
// Data
static VkAllocationCallbacks* g_Allocator = nullptr;
static VkInstance g_Instance = VK_NULL_HANDLE;
static VkPhysicalDevice g_PhysicalDevice = VK_NULL_HANDLE;
static VkDevice g_Device = VK_NULL_HANDLE;
static uint32_t g_QueueFamily = (uint32_t)-1;
static VkQueue g_Queue = VK_NULL_HANDLE;
static VkPipelineCache g_PipelineCache = VK_NULL_HANDLE;
static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
static ImGui_ImplVulkanH_Window g_MainWindowData;
static uint32_t g_MinImageCount = 2;
static bool g_SwapChainRebuild = false;
static void check_vk_result(VkResult err)
{
if (err == VK_SUCCESS)
return;
fprintf(stderr, "[vulkan] Error: VkResult = %d\n", err);
if (err < 0)
abort();
}
#ifdef APP_USE_VULKAN_DEBUG_REPORT
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
{
(void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments
fprintf(stderr, "[vulkan] Debug report from ObjectType: %i\nMessage: %s\n\n", objectType, pMessage);
return VK_FALSE;
}
#endif // APP_USE_VULKAN_DEBUG_REPORT
static bool IsExtensionAvailable(const ImVector<VkExtensionProperties>& properties, const char* extension)
{
for (const VkExtensionProperties& p : properties)
if (strcmp(p.extensionName, extension) == 0)
return true;
return false;
}
static void SetupVulkan(ImVector<const char*> instance_extensions)
{
VkResult err;
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
volkInitialize();
#endif
// Create Vulkan Instance
{
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
// Enumerate available extensions
uint32_t properties_count;
ImVector<VkExtensionProperties> properties;
vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, nullptr);
properties.resize(properties_count);
err = vkEnumerateInstanceExtensionProperties(nullptr, &properties_count, properties.Data);
check_vk_result(err);
// Enable required extensions
if (IsExtensionAvailable(properties, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME))
instance_extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME))
{
instance_extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
create_info.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
}
#endif
// Enabling validation layers
#ifdef APP_USE_VULKAN_DEBUG_REPORT
const char* layers[] = { "VK_LAYER_KHRONOS_validation" };
create_info.enabledLayerCount = 1;
create_info.ppEnabledLayerNames = layers;
instance_extensions.push_back("VK_EXT_debug_report");
#endif
// Create Vulkan Instance
create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size;
create_info.ppEnabledExtensionNames = instance_extensions.Data;
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance);
check_vk_result(err);
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
volkLoadInstance(g_Instance);
#endif
// Setup the debug report callback
#ifdef APP_USE_VULKAN_DEBUG_REPORT
auto f_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkCreateDebugReportCallbackEXT");
IM_ASSERT(f_vkCreateDebugReportCallbackEXT != nullptr);
VkDebugReportCallbackCreateInfoEXT debug_report_ci = {};
debug_report_ci.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
debug_report_ci.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
debug_report_ci.pfnCallback = debug_report;
debug_report_ci.pUserData = nullptr;
err = f_vkCreateDebugReportCallbackEXT(g_Instance, &debug_report_ci, g_Allocator, &g_DebugReport);
check_vk_result(err);
#endif
}
// Select Physical Device (GPU)
g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance);
IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE);
// Select graphics queue family
g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice);
IM_ASSERT(g_QueueFamily != (uint32_t)-1);
// Create Logical Device (with 1 queue)
{
ImVector<const char*> device_extensions;
device_extensions.push_back("VK_KHR_swapchain");
// Enumerate physical device extension
uint32_t properties_count;
ImVector<VkExtensionProperties> properties;
vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, nullptr);
properties.resize(properties_count);
vkEnumerateDeviceExtensionProperties(g_PhysicalDevice, nullptr, &properties_count, properties.Data);
#ifdef VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
#endif
const float queue_priority[] = { 1.0f };
VkDeviceQueueCreateInfo queue_info[1] = {};
queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[0].queueFamilyIndex = g_QueueFamily;
queue_info[0].queueCount = 1;
queue_info[0].pQueuePriorities = queue_priority;
VkDeviceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.queueCreateInfoCount = sizeof(queue_info) / sizeof(queue_info[0]);
create_info.pQueueCreateInfos = queue_info;
create_info.enabledExtensionCount = (uint32_t)device_extensions.Size;
create_info.ppEnabledExtensionNames = device_extensions.Data;
err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device);
check_vk_result(err);
vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue);
}
// Create Descriptor Pool
// If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets.
{
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE },
{ VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE },
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
pool_info.maxSets = 0;
for (VkDescriptorPoolSize& pool_size : pool_sizes)
pool_info.maxSets += pool_size.descriptorCount;
pool_info.poolSizeCount = (uint32_t)IM_COUNTOF(pool_sizes);
pool_info.pPoolSizes = pool_sizes;
err = vkCreateDescriptorPool(g_Device, &pool_info, g_Allocator, &g_DescriptorPool);
check_vk_result(err);
}
}
// All the ImGui_ImplVulkanH_XXX structures/functions are optional helpers used by the demo.
// Your real engine/app may not use them.
static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface, int width, int height)
{
// Check for WSI support
VkBool32 res;
vkGetPhysicalDeviceSurfaceSupportKHR(g_PhysicalDevice, g_QueueFamily, surface, &res);
if (res != VK_TRUE)
{
fprintf(stderr, "Error no WSI support on physical device 0\n");
exit(-1);
}
// Select Surface Format
const VkFormat requestSurfaceImageFormat[] = { VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
const VkColorSpaceKHR requestSurfaceColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
wd->Surface = surface;
wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(g_PhysicalDevice, wd->Surface, requestSurfaceImageFormat, (size_t)IM_COUNTOF(requestSurfaceImageFormat), requestSurfaceColorSpace);
// Select Present Mode
#ifdef APP_USE_UNLIMITED_FRAME_RATE
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_FIFO_KHR };
#else
VkPresentModeKHR present_modes[] = { VK_PRESENT_MODE_FIFO_KHR };
#endif
wd->PresentMode = ImGui_ImplVulkanH_SelectPresentMode(g_PhysicalDevice, wd->Surface, &present_modes[0], IM_COUNTOF(present_modes));
//printf("[vulkan] Selected PresentMode = %d\n", wd->PresentMode);
// Create SwapChain, RenderPass, Framebuffer, etc.
IM_ASSERT(g_MinImageCount >= 2);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, width, height, g_MinImageCount, 0);
}
static void CleanupVulkan()
{
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
#ifdef APP_USE_VULKAN_DEBUG_REPORT
// Remove the debug report callback
auto f_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(g_Instance, "vkDestroyDebugReportCallbackEXT");
f_vkDestroyDebugReportCallbackEXT(g_Instance, g_DebugReport, g_Allocator);
#endif // APP_USE_VULKAN_DEBUG_REPORT
vkDestroyDevice(g_Device, g_Allocator);
vkDestroyInstance(g_Instance, g_Allocator);
}
static void CleanupVulkanWindow(ImGui_ImplVulkanH_Window* wd)
{
ImGui_ImplVulkanH_DestroyWindow(g_Instance, g_Device, wd, g_Allocator);
vkDestroySurfaceKHR(g_Instance, wd->Surface, g_Allocator);
}
static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
{
VkSemaphore image_acquired_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].ImageAcquiredSemaphore;
VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkResult err = vkAcquireNextImageKHR(g_Device, wd->Swapchain, UINT64_MAX, image_acquired_semaphore, VK_NULL_HANDLE, &wd->FrameIndex);
if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
g_SwapChainRebuild = true;
if (err == VK_ERROR_OUT_OF_DATE_KHR)
return;
if (err != VK_SUBOPTIMAL_KHR)
check_vk_result(err);
ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex];
{
err = vkWaitForFences(g_Device, 1, &fd->Fence, VK_TRUE, UINT64_MAX); // wait indefinitely instead of periodically checking
check_vk_result(err);
err = vkResetFences(g_Device, 1, &fd->Fence);
check_vk_result(err);
}
{
err = vkResetCommandPool(g_Device, fd->CommandPool, 0);
check_vk_result(err);
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
err = vkBeginCommandBuffer(fd->CommandBuffer, &info);
check_vk_result(err);
}
{
VkRenderPassBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = wd->RenderPass;
info.framebuffer = fd->Framebuffer;
info.renderArea.extent.width = wd->Width;
info.renderArea.extent.height = wd->Height;
info.clearValueCount = 1;
info.pClearValues = &wd->ClearValue;
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
// Record dear imgui primitives into command buffer
ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
// Submit command buffer
vkCmdEndRenderPass(fd->CommandBuffer);
{
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkSubmitInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &image_acquired_semaphore;
info.pWaitDstStageMask = &wait_stage;
info.commandBufferCount = 1;
info.pCommandBuffers = &fd->CommandBuffer;
info.signalSemaphoreCount = 1;
info.pSignalSemaphores = &render_complete_semaphore;
err = vkEndCommandBuffer(fd->CommandBuffer);
check_vk_result(err);
err = vkQueueSubmit(g_Queue, 1, &info, fd->Fence);
check_vk_result(err);
}
}
static void FramePresent(ImGui_ImplVulkanH_Window* wd)
{
if (g_SwapChainRebuild)
return;
VkSemaphore render_complete_semaphore = wd->FrameSemaphores[wd->SemaphoreIndex].RenderCompleteSemaphore;
VkPresentInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
info.waitSemaphoreCount = 1;
info.pWaitSemaphores = &render_complete_semaphore;
info.swapchainCount = 1;
info.pSwapchains = &wd->Swapchain;
info.pImageIndices = &wd->FrameIndex;
VkResult err = vkQueuePresentKHR(g_Queue, &info);
if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
g_SwapChainRebuild = true;
if (err == VK_ERROR_OUT_OF_DATE_KHR)
return;
if (err != VK_SUBOPTIMAL_KHR)
check_vk_result(err);
wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores
}
struct QNXWindow
{
screen_context_t Context = nullptr;
screen_window_t Window = nullptr;
screen_event_t Event = nullptr;
int Size[2] = {};
};
static bool CreateQNXWindow(QNXWindow* window)
{
if (screen_create_context(&window->Context, 0) != 0 ||
screen_create_window(&window->Window, window->Context) != 0 ||
screen_create_event(&window->Event) != 0)
{
fprintf(stderr, "QNX Screen initialization failed: %s\n", strerror(errno));
return false;
}
// A newly created QNX Screen window reports the fullscreen dimensions.
if (screen_get_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 || window->Size[0] <= 0 || window->Size[1] <= 0)
{
fprintf(stderr, "Failed to obtain QNX Screen window size: %s\n", strerror(errno));
return false;
}
const int usage = SCREEN_USAGE_VULKAN | SCREEN_USAGE_NATIVE;
const int transparency = SCREEN_TRANSPARENCY_NONE;
if (screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_USAGE, &usage) != 0 ||
screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_SIZE, window->Size) != 0 ||
screen_set_window_property_iv(window->Window, SCREEN_PROPERTY_TRANSPARENCY, &transparency) != 0)
{
fprintf(stderr, "Failed to configure QNX Screen window: %s\n", strerror(errno));
return false;
}
return true;
}
static void DestroyQNXWindow(QNXWindow* window)
{
if (window->Event != nullptr)
screen_destroy_event(window->Event);
if (window->Window != nullptr)
screen_destroy_window(window->Window);
if (window->Context != nullptr)
screen_destroy_context(window->Context);
}
static bool ProcessQNXEvents(QNXWindow* window)
{
for (;;)
{
if (screen_get_event(window->Context, window->Event, 0) != 0)
return false;
int type = SCREEN_EVENT_NONE;
if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_TYPE, &type) != 0)
return false;
if (type == SCREEN_EVENT_NONE)
return true;
ImGui_ImplQNX_ProcessEvent(window->Event);
if (type == SCREEN_EVENT_CLOSE)
return false;
if (type == SCREEN_EVENT_KEYBOARD)
{
int flags = 0;
int key_cap = 0;
if (screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_FLAGS, &flags) == 0 &&
screen_get_event_property_iv(window->Event, SCREEN_PROPERTY_KEY_CAP, &key_cap) == 0 &&
(flags & SCREEN_FLAG_KEY_DOWN) != 0 && key_cap == KEYCODE_ESCAPE)
return false;
}
}
}
static void QNXSleep(int milliseconds)
{
struct timespec request = { milliseconds / 1000, (milliseconds % 1000) * 1000000L };
nanosleep(&request, nullptr);
}
// Main code
int main(int, char**)
{
// Create window with Vulkan graphics context
QNXWindow window;
if (!CreateQNXWindow(&window))
{
DestroyQNXWindow(&window);
return 1;
}
float main_scale = 1.0f;
ImVector<const char*> extensions;
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
extensions.push_back(VK_QNX_SCREEN_SURFACE_EXTENSION_NAME);
SetupVulkan(extensions);
// Create Window Surface
VkScreenSurfaceCreateInfoQNX surface_create_info = {};
surface_create_info.sType = VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX;
surface_create_info.context = window.Context;
surface_create_info.window = window.Window;
VkSurfaceKHR surface;
VkResult err = vkCreateScreenSurfaceQNX(g_Instance, &surface_create_info, g_Allocator, &surface);
check_vk_result(err);
// Create Framebuffers
int w = window.Size[0];
int h = window.Size[1];
ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
SetupVulkanWindow(wd, surface, w, h);
const int visible = 1;
if (screen_set_window_property_iv(window.Window, SCREEN_PROPERTY_VISIBLE, &visible) != 0)
{
fprintf(stderr, "Failed to show QNX Screen window: %s\n", strerror(errno));
return 1;
}
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup scaling
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
// Setup Platform/Renderer backends
ImGui_ImplQNX_Init(window.Context, window.Window);
ImGui_ImplVulkan_InitInfo init_info = {};
//init_info.ApiVersion = VK_API_VERSION_1_3; // Pass in your value of VkApplicationInfo::apiVersion, otherwise will default to header version.
init_info.Instance = g_Instance;
init_info.PhysicalDevice = g_PhysicalDevice;
init_info.Device = g_Device;
init_info.QueueFamily = g_QueueFamily;
init_info.Queue = g_Queue;
init_info.PipelineCache = g_PipelineCache;
init_info.DescriptorPool = g_DescriptorPool;
init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.Allocator = g_Allocator;
init_info.PipelineInfoMain.RenderPass = wd->RenderPass;
init_info.PipelineInfoMain.Subpass = 0;
init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info);
// Load Fonts
// - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
// This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
// - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
// - Read 'docs/FONTS.md' for more instructions and details.
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//style.FontSizeBase = 20.0f;
//io.Fonts->AddFontDefaultVector();
//io.Fonts->AddFontDefaultBitmap();
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
//IM_ASSERT(font != nullptr);
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
bool done = false;
while (!done)
{
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
if (!ProcessQNXEvents(&window))
done = true;
// Resize swap chain?
int framebuffer_size[2] = {};
if (screen_get_window_property_iv(window.Window, SCREEN_PROPERTY_SIZE, framebuffer_size) != 0)
done = true;
int fb_width = framebuffer_size[0];
int fb_height = framebuffer_size[1];
if (fb_width <= 0 || fb_height <= 0)
{
QNXSleep(10);
continue;
}
if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
{
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);
ImGui_ImplVulkanH_CreateOrResizeWindow(g_Instance, g_PhysicalDevice, g_Device, wd, g_QueueFamily, g_Allocator, fb_width, fb_height, g_MinImageCount, 0);
g_MainWindowData.FrameIndex = 0;
g_SwapChainRebuild = false;
}
// Start the Dear ImGui frame
ImGui_ImplVulkan_NewFrame();
ImGui_ImplQNX_NewFrame();
ImGui::NewFrame();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);
if (!is_minimized)
{
wd->ClearValue.color.float32[0] = clear_color.x * clear_color.w;
wd->ClearValue.color.float32[1] = clear_color.y * clear_color.w;
wd->ClearValue.color.float32[2] = clear_color.z * clear_color.w;
wd->ClearValue.color.float32[3] = clear_color.w;
FrameRender(wd, draw_data);
FramePresent(wd);
}
}
// Cleanup
err = vkDeviceWaitIdle(g_Device);
check_vk_result(err);
ImGui_ImplVulkan_Shutdown();
ImGui_ImplQNX_Shutdown();
ImGui::DestroyContext();
CleanupVulkanWindow(&g_MainWindowData);
CleanupVulkan();
DestroyQNXWindow(&window);
return 0;
}

View file

@ -0,0 +1,8 @@
LIST=CPU
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

View file

@ -0,0 +1,8 @@
LIST=VARIANT
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

View file

@ -0,0 +1 @@
include ../../../common.mk

View file

@ -0,0 +1,8 @@
LIST=VARIANT
ifndef QRECURSE
QRECURSE=recurse.mk
ifdef QCONFIG
QRDIR=$(dir $(QCONFIG))
endif
endif
include $(QRDIR)$(QRECURSE)

View file

@ -0,0 +1 @@
include ../../../common.mk

View file

@ -29,27 +29,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -93,6 +93,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -108,6 +109,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -10,25 +10,76 @@
#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_metal.h"
#include <stdio.h>
#include <stdio.h> // printf, fprintf
#include <SDL.h>
#import <Metal/Metal.h>
#import <QuartzCore/QuartzCore.h>
// Main code
int main(int, char**)
{
// Setup SDL
// (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
// depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
{
printf("Error: SDL_Init(): %s\n", SDL_GetError());
return 1;
}
// From 2.0.18: Enable native IME.
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
// Create SDL window graphics context
float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0);
int window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(800 * main_scale), window_flags);
if (window == nullptr)
{
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
return 1;
}
// Create Metal device _before_ creating the view/layer
id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
if (!metalDevice)
{
printf("Error: failed to create Metal device.\n");
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
SDL_MetalView view = SDL_Metal_CreateView(window);
CAMetalLayer* layer = (__bridge CAMetalLayer*)SDL_Metal_GetLayer(view);
layer.device = metalDevice;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
id<MTLCommandQueue> commandQueue = [layer.device newCommandQueue];
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor new];
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup style
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup scaling
ImGuiStyle& style = ImGui::GetStyle();
style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
// Setup Platform/Renderer backends
ImGui_ImplMetal_Init(layer.device);
ImGui_ImplSDL2_InitForMetal(window);
// Load Fonts
// - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
// This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
@ -47,48 +98,10 @@ int main(int, char**)
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
//IM_ASSERT(font != nullptr);
// Setup SDL
// (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
// depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
{
printf("Error: %s\n", SDL_GetError());
return 1;
}
// Inform SDL that we will be using metal for rendering. Without this hint initialization of metal renderer may fail.
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "metal");
// Enable native IME.
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL+Metal example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 800, SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
if (window == nullptr)
{
printf("Error creating window: %s\n", SDL_GetError());
return -2;
}
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == nullptr)
{
printf("Error creating renderer: %s\n", SDL_GetError());
return -3;
}
// Setup Platform/Renderer backends
CAMetalLayer* layer = (__bridge CAMetalLayer*)SDL_RenderGetMetalLayer(renderer);
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
ImGui_ImplMetal_Init(layer.device);
ImGui_ImplSDL2_InitForMetal(window);
id<MTLCommandQueue> commandQueue = [layer.device newCommandQueue];
MTLRenderPassDescriptor* renderPassDescriptor = [MTLRenderPassDescriptor new];
// Our state
bool show_demo_window = true;
bool show_another_window = false;
float clear_color[4] = {0.45f, 0.55f, 0.60f, 1.00f};
float clear_color[4] = { 0.45f, 0.55f, 0.60f, 1.00f };
// Main loop
bool done = false;
@ -112,7 +125,8 @@ int main(int, char**)
}
int width, height;
SDL_GetRendererOutputSize(renderer, &width, &height);
SDL_GetWindowSizeInPixels(window, &width, &height);
layer.drawableSize = CGSizeMake(width, height);
id<CAMetalDrawable> drawable = [layer nextDrawable];
@ -168,7 +182,8 @@ int main(int, char**)
// Rendering
ImGui::Render();
ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), commandBuffer, renderEncoder);
ImDrawData* draw_data = ImGui::GetDrawData();
ImGui_ImplMetal_RenderDrawData(draw_data, commandBuffer, renderEncoder);
[renderEncoder popDebugGroup];
[renderEncoder endEncoding];
@ -183,7 +198,6 @@ int main(int, char**)
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -92,6 +92,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -107,6 +108,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -92,6 +92,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -107,6 +108,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View file

@ -39,31 +39,28 @@ int main(int, char**)
return 1;
}
// Decide GL+GLSL versions
// Select GL version + let the backend select a GLSL version
const char* glsl_version = nullptr;
#if defined(IMGUI_IMPL_OPENGL_ES2)
// GL ES 2.0 + GLSL 100 (WebGL 1.0)
const char* glsl_version = "#version 100";
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#elif defined(IMGUI_IMPL_OPENGL_ES3)
// GL ES 3.0 + GLSL 300 es (WebGL 2.0)
const char* glsl_version = "#version 300 es";
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#elif defined(__APPLE__)
// GL 3.2 Core + GLSL 150
const char* glsl_version = "#version 150";
// GL 3.2 Core + generally GLSL 150
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); // Always required on Mac
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
#else
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 130";
// GL 3.0 + generally GLSL 130
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);

View file

@ -29,27 +29,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -93,6 +93,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -108,6 +109,7 @@
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -184,4 +186,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -28,27 +28,27 @@
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
<PlatformToolset>v141</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -93,6 +93,7 @@
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -109,6 +110,7 @@
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<SupportJustMyCode>false</SupportJustMyCode>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -187,4 +189,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -184,7 +184,8 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
{
VkDescriptorPoolSize pool_sizes[] =
{
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE },
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE },
{ VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE },
};
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
@ -385,7 +386,7 @@ int main(int, char**)
// Create Framebuffers
int w, h;
SDL_GetWindowSize(window, &w, &h);
SDL_GetWindowSizeInPixels(window, &w, &h);
ImGui_ImplVulkanH_Window* wd = &g_MainWindowData;
SetupVulkanWindow(wd, surface, w, h);
@ -474,7 +475,7 @@ int main(int, char**)
// Resize swap chain?
int fb_width, fb_height;
SDL_GetWindowSize(window, &fb_width, &fb_height);
SDL_GetWindowSizeInPixels(window, &fb_width, &fb_height);
if (fb_width > 0 && fb_height > 0 && (g_SwapChainRebuild || g_MainWindowData.Width != fb_width || g_MainWindowData.Height != fb_height))
{
ImGui_ImplVulkan_SetMinImageCount(g_MinImageCount);

Some files were not shown because too many files have changed in this diff Show more