diff --git a/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs b/src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs index 04cd24b9..a1d37a84 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 _isDisposed; 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 (_isDisposed) 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; + /////////////////////////////////////////// + } + + _isDisposed = true; + } + #endregion Internals } } diff --git a/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs b/src/ImGui.NET.SampleProgram.XNA/SampleGame.cs index 3eb4ba2e..325f7edc 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; } @@ -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));