From db18bc22d3f7d21915901a5c3399a7250ecb17d3 Mon Sep 17 00:00:00 2001 From: Morfah Date: Wed, 4 Jun 2025 18:51:56 +0200 Subject: [PATCH 1/5] * Made ImGuiRenderer Disposable. * Enable docking support. * FNA fixes. * Minor code cleanups. --- .../ImGuiRenderer.cs | 105 +++++++++++++----- 1 file changed, 76 insertions(+), 29 deletions(-) diff --git a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs index 04cd24b9..04656048 100644 --- a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs +++ b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs @@ -10,15 +10,15 @@ namespace ImGuiNET.SampleProgram.XNA /// /// ImGui renderer for use with XNA-likes (FNA & MonoGame) /// - public class ImGuiRenderer + public class ImGuiRenderer : IDisposable { - private Game _game; + private readonly Game _game; // Graphics - private GraphicsDevice _graphicsDevice; + private readonly GraphicsDevice _graphicsDevice; private BasicEffect _effect; - private RasterizerState _rasterizerState; + private readonly RasterizerState _rasterizerState; private byte[] _vertexData; private VertexBuffer _vertexBuffer; @@ -29,7 +29,7 @@ public class ImGuiRenderer private int _indexBufferSize; // Textures - private Dictionary _loadedTextures; + private readonly Dictionary _loadedTextures; private int _textureId; private IntPtr? _fontTextureId; @@ -38,7 +38,9 @@ public class ImGuiRenderer private int _scrollWheelValue; private int _horizontalScrollWheelValue; private readonly float WHEEL_DELTA = 120; - private Keys[] _allKeys = Enum.GetValues(); + private readonly Keys[] _allKeys = Enum.GetValues(); + + private bool _disposed; public ImGuiRenderer(Game game) { @@ -63,6 +65,12 @@ public ImGuiRenderer(Game game) SetupInput(); } + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #region ImGuiRenderer /// @@ -81,6 +89,8 @@ public virtual unsafe void RebuildFontAtlas() // Create and register the texture as an XNA texture var tex2d = new Texture2D(_graphicsDevice, width, height, false, SurfaceFormat.Color); tex2d.SetData(pixels); + tex2d.Name = "ImGui font atlas"; + tex2d.Tag = "ImGui"; // Should a texture already have been build previously, unbind it first so it can be deallocated if (_fontTextureId.HasValue) UnbindTexture(_fontTextureId.Value); @@ -120,6 +130,9 @@ public virtual void BeforeLayout(GameTime gameTime) { ImGui.GetIO().DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; + // Enable docking + ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable; + UpdateInput(); ImGui.NewFrame(); @@ -144,24 +157,12 @@ public virtual void AfterLayout() /// protected virtual void SetupInput() { - var io = ImGui.GetIO(); - // MonoGame-specific ////////////////////// - _game.Window.TextInput += (s, a) => - { - if (a.Character == '\t') return; - io.AddInputCharacter(a.Character); - }; - + _game.Window.TextInput += OnTextInput; /////////////////////////////////////////// // FNA-specific /////////////////////////// - //TextInputEXT.TextInput += c => - //{ - // if (c == '\t') return; - - // ImGui.GetIO().AddInputCharacter(c); - //}; + // TextInputEXT.TextInput += OnTextInput; /////////////////////////////////////////// } @@ -170,7 +171,7 @@ protected virtual void SetupInput() /// protected virtual Effect UpdateEffect(Texture2D texture) { - _effect = _effect ?? new BasicEffect(_graphicsDevice); + _effect ??= new BasicEffect(_graphicsDevice); var io = ImGui.GetIO(); @@ -180,6 +181,8 @@ protected virtual Effect UpdateEffect(Texture2D texture) _effect.TextureEnabled = true; _effect.Texture = texture; _effect.VertexColorEnabled = true; + _effect.Name = $"{texture.Name}_effect"; + _effect.Tag = "ImGui"; return _effect; } @@ -190,7 +193,7 @@ protected virtual Effect UpdateEffect(Texture2D texture) protected virtual void UpdateInput() { if (!_game.IsActive) return; - + var io = ImGui.GetIO(); var mouse = Mouse.GetState(); @@ -202,6 +205,7 @@ protected virtual void UpdateInput() io.AddMouseButtonEvent(3, mouse.XButton1 == ButtonState.Pressed); io.AddMouseButtonEvent(4, mouse.XButton2 == ButtonState.Pressed); + // FNA-specific information. FNA does not have horizontal scroll wheel support. So you need to set 0f for horizontal scroll wheel value. io.AddMouseWheelEvent( (mouse.HorizontalScrollWheelValue - _horizontalScrollWheelValue) / WHEEL_DELTA, (mouse.ScrollWheelValue - _scrollWheelValue) / WHEEL_DELTA); @@ -220,11 +224,11 @@ protected virtual void UpdateInput() io.DisplayFramebufferScale = new System.Numerics.Vector2(1f, 1f); } - private bool TryMapKeys(Keys key, out ImGuiKey imguikey) + private static bool TryMapKeys(Keys key, out ImGuiKey imguikey) { - //Special case not handed in the switch... - //If the actual key we put in is "None", return none and true. - //otherwise, return none and false. + // Special case not handed in the switch... + // If the actual key we put in is "None", return none and true. + // otherwise, return none and false. if (key == Keys.None) { imguikey = ImGuiKey.None; @@ -390,12 +394,12 @@ private unsafe void RenderCommandLists(ImDrawDataPtr drawData) { ImDrawCmdPtr drawCmd = cmdList.CmdBuffer[cmdi]; - if (drawCmd.ElemCount == 0) + if (drawCmd.ElemCount == 0) { continue; } - if (!_loadedTextures.ContainsKey(drawCmd.TextureId)) + if (!_loadedTextures.TryGetValue(drawCmd.TextureId, out Texture2D value)) { throw new InvalidOperationException($"Could not find a texture with id '{drawCmd.TextureId}', please check your bindings"); } @@ -407,7 +411,7 @@ private unsafe void RenderCommandLists(ImDrawDataPtr drawData) (int)(drawCmd.ClipRect.W - drawCmd.ClipRect.Y) ); - var effect = UpdateEffect(_loadedTextures[drawCmd.TextureId]); + var effect = UpdateEffect(value); foreach (var pass in effect.CurrentTechnique.Passes) { @@ -431,6 +435,49 @@ private unsafe void RenderCommandLists(ImDrawDataPtr drawData) } } + // MonoGame-specific ////////////////////// + private void OnTextInput(object s, TextInputEventArgs a) + { + if (a.Character == '\t') return; + ImGui.GetIO().AddInputCharacter(a.Character); + } + /////////////////////////////////////////// + + // FNA-specific /////////////////////////// + // private void OnTextInput(char c) + // { + // if (c == '\t') return; + // ImGui.GetIO().AddInputCharacter(c); + // } + ///////////////////////////////////////// + + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; + + if (disposing) + { + _vertexBuffer?.Dispose(); + _indexBuffer?.Dispose(); + _effect?.Dispose(); + + foreach (var texture in _loadedTextures) + { + texture.Value?.Dispose(); + } + + // MonoGame-specific ////////////////////// + _game.Window.TextInput -= OnTextInput; + /////////////////////////////////////////// + + // FNA-specific /////////////////////////// + // TextInputEXT.TextInput -= OnTextInput; + ///////////////////////////////////////// + } + + _disposed = true; + } + #endregion Internals } } From bf3dec5d537031bc14a6c02a3ee023079cd8db34 Mon Sep 17 00:00:00 2001 From: Morfah Date: Wed, 4 Jun 2025 18:52:01 +0200 Subject: [PATCH 2/5] * Disable multisampling for the SampleGame, it causes discoloration because some MonoGame bug. --- src/ImGui.NET.SampleProgram.XNA/SampleGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs b/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs index 3eb4ba2e..155a1295 100644 --- a/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs +++ b/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs @@ -22,7 +22,7 @@ public SampleGame() _graphics = new GraphicsDeviceManager(this); _graphics.PreferredBackBufferWidth = 1024; _graphics.PreferredBackBufferHeight = 768; - _graphics.PreferMultiSampling = true; + _graphics.PreferMultiSampling = false; IsMouseVisible = true; } From 22f6a80a7c438169791fc4a80c14eef238211bfa Mon Sep 17 00:00:00 2001 From: Morfah Date: Wed, 4 Jun 2025 19:04:57 +0200 Subject: [PATCH 3/5] Also use the Dispose in the sample game. --- src/ImGui.NET.SampleProgram.XNA/SampleGame.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs b/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs index 155a1295..325f7edc 100644 --- a/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs +++ b/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs @@ -52,6 +52,13 @@ protected override void LoadContent() base.LoadContent(); } + protected override void UnloadContent() + { + _imGuiRenderer.Dispose(); + Content.Unload(); + base.UnloadContent(); + } + protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(new Color(clear_color.X, clear_color.Y, clear_color.Z)); From c0fe4db547bcb96dfe77348afeddcf427b16655b Mon Sep 17 00:00:00 2001 From: Morfah Date: Wed, 4 Jun 2025 22:09:07 +0200 Subject: [PATCH 4/5] Use consistent amount of slashes in the comments. --- src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs index 04656048..4ea6408c 100644 --- a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs +++ b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs @@ -449,7 +449,7 @@ private void OnTextInput(object s, TextInputEventArgs a) // if (c == '\t') return; // ImGui.GetIO().AddInputCharacter(c); // } - ///////////////////////////////////////// + /////////////////////////////////////////// protected virtual void Dispose(bool disposing) { @@ -472,7 +472,7 @@ protected virtual void Dispose(bool disposing) // FNA-specific /////////////////////////// // TextInputEXT.TextInput -= OnTextInput; - ///////////////////////////////////////// + /////////////////////////////////////////// } _disposed = true; From 78071028e655993c8dea1aed144cc1960b9bd490 Mon Sep 17 00:00:00 2001 From: Morfah Date: Thu, 5 Jun 2025 11:20:44 +0200 Subject: [PATCH 5/5] Renamed disposed field for clarity. --- src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs index 4ea6408c..a1d37a84 100644 --- a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs +++ b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs @@ -40,7 +40,7 @@ public class ImGuiRenderer : IDisposable private readonly float WHEEL_DELTA = 120; private readonly Keys[] _allKeys = Enum.GetValues(); - private bool _disposed; + private bool _isDisposed; public ImGuiRenderer(Game game) { @@ -453,7 +453,7 @@ private void OnTextInput(object s, TextInputEventArgs a) protected virtual void Dispose(bool disposing) { - if (_disposed) return; + if (_isDisposed) return; if (disposing) { @@ -475,7 +475,7 @@ protected virtual void Dispose(bool disposing) /////////////////////////////////////////// } - _disposed = true; + _isDisposed = true; } #endregion Internals