ImGuiNET / ImGui.NET

An ImGui wrapper for .NET.
MIT License
1.89k stars 304 forks source link

Monogame / FNA integration support #11

Closed msmshazan closed 7 years ago

msmshazan commented 7 years ago

How to integrate imgui.net into monogame any samples available?

mellinoe commented 7 years ago

I don't have any samples handy, but it should be very simple to get it integrated, from what I remember of XNA / MonoGame. The sample in here uses legacy OpenGL, so it might not be a great starting point to implement a MonoGame version. It might be helpful to take a look at the ImGui renderer in my game engine: https://github.com/mellinoe/ge/blob/master/src/Engine/Graphics/ImGuiRenderer.cs. You would need to convert the graphics calls into MonoGame stuff, but I think it should be fairly straightforward.

If you do get something working, I'd be happy to take a PR with a MonoGame sample project.

msmshazan commented 7 years ago

@mellinoe I get this error while building the project. Using .Net Framework 4.6

CS0103 The name 'Unsafe' does not exist in the current context Imgui.NET c:\Users\Magic DPI\Documents\Visual Studio 2015\Projects\Imgui-FNA\Imgui.NET\TextInputBuffer.cs 49

msmshazan commented 7 years ago

Current progress....

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using ImGuiNET;

namespace Imgui_FNA { 
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        IO io;
        Texture2D Font;
        private Matrix worldMatrix, viewMatrix, projectionMatrix;

        private BasicEffect basicEffect;
        private VertexBuffer vbuff;
        private IndexBuffer ibuff;

        private Texture2D defaultWhiteTexture, fontTexture;

        private int scrollWheel = 0;
        private char[] input = new char[1024];

        private float renderTime = 0f;

        private VertexDeclaration vertexDeclaration = new VertexDeclaration(
                new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),
                new VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
                new VertexElement(16, VertexElementFormat.Color, VertexElementUsage.Color, 0)
            );

        public Game()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "../../Content";
        }
        protected override void Initialize()
        {
            SetupBasicShader();
            //Font = Content.Load<Texture2D>("LiberationMono.xnb");
            // TODO: Add your initialization logic here
            io = ImGui.GetIO();
            io.FontAtlas.AddDefaultFont();
            SetupKeyMappings();
            io.DisplaySize = new System.Numerics.Vector2(GraphicsDevice.Viewport.Width,GraphicsDevice.Viewport.Height);
            base.Initialize();
        }
        void SetupBasicShader()
        {
            viewMatrix = Matrix.Identity;
            projectionMatrix = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, -1);
            worldMatrix = Matrix.Identity;

            basicEffect = new BasicEffect(GraphicsDevice);
            basicEffect.World = worldMatrix;
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix;
            basicEffect.VertexColorEnabled = true;
            basicEffect.TextureEnabled = true;
        }
        void SetupBuffers()
        {
            vbuff = new VertexBuffer(GraphicsDevice, vertexDeclaration, 4096, BufferUsage.WriteOnly);
            ibuff = new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, 4096 * 4, BufferUsage.WriteOnly);
        }
        void SetupKeyMappings()
        {

            io.KeyMap[GuiKey.Tab] = (int)Keys.Tab;
            io.KeyMap[GuiKey.LeftArrow] = (int)Keys.Left;
            io.KeyMap[GuiKey.RightArrow] = (int)Keys.Right;
            io.KeyMap[GuiKey.UpArrow] = (int)Keys.Up;
            io.KeyMap[GuiKey.DownArrow] = (int)Keys.Down;
            io.KeyMap[GuiKey.PageUp] = (int)Keys.PageUp;
            io.KeyMap[GuiKey.PageDown] = (int)Keys.PageDown;
            io.KeyMap[GuiKey.Home] = (int)Keys.Home;
            io.KeyMap[GuiKey.End] = (int)Keys.End;
            io.KeyMap[GuiKey.Delete] = (int)Keys.Delete;
            io.KeyMap[GuiKey.Backspace] = (int)Keys.Back;
            io.KeyMap[GuiKey.Enter] = (int)Keys.Enter;
            io.KeyMap[GuiKey.Escape] = (int)Keys.Escape;
            io.KeyMap[GuiKey.A] = (int)Keys.A;
            io.KeyMap[GuiKey.C] = (int)Keys.C;
            io.KeyMap[GuiKey.V] = (int)Keys.V;
            io.KeyMap[GuiKey.X] = (int)Keys.X;
            io.KeyMap[GuiKey.Y] = (int)Keys.Y;
            io.KeyMap[GuiKey.Z] = (int)Keys.Z;
        }

        //// An umanaged function that retrieves the states of each key
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
        public static extern short GetKeyState(int keyCode);

        #region Convert Key
        public static char ConvertKeyboardInput(Keys key, bool alt, bool shift, bool ctrl, bool caps)
        {
            bool upperCase = caps ^ shift;
            switch (key)
            {
                //Alphabet keys
                case Keys.A: if (upperCase) { return 'A'; } else { return 'a'; }
                case Keys.B: if (upperCase) { return 'B'; } else { return 'b'; }
                case Keys.C: if (upperCase) { return 'C'; } else { return 'c'; }
                case Keys.D: if (upperCase) { return 'D'; } else { return 'd'; }
                case Keys.E: if (upperCase) { return 'E'; } else { return 'e'; }
                case Keys.F: if (upperCase) { return 'F'; } else { return 'f'; }
                case Keys.G: if (upperCase) { return 'G'; } else { return 'g'; }
                case Keys.H: if (upperCase) { return 'H'; } else { return 'h'; }
                case Keys.I: if (upperCase) { return 'I'; } else { return 'i'; }
                case Keys.J: if (upperCase) { return 'J'; } else { return 'j'; }
                case Keys.K: if (upperCase) { return 'K'; } else { return 'k'; }
                case Keys.L: if (upperCase) { return 'L'; } else { return 'l'; }
                case Keys.M: if (upperCase) { return 'M'; } else { return 'm'; }
                case Keys.N: if (upperCase) { return 'N'; } else { return 'n'; }
                case Keys.O: if (upperCase) { return 'O'; } else { return 'o'; }
                case Keys.P: if (upperCase) { return 'P'; } else { return 'p'; }
                case Keys.Q: if (upperCase) { return 'Q'; } else { return 'q'; }
                case Keys.R: if (upperCase) { return 'R'; } else { return 'r'; }
                case Keys.S: if (upperCase) { return 'S'; } else { return 's'; }
                case Keys.T: if (upperCase) { return 'T'; } else { return 't'; }
                case Keys.U: if (upperCase) { return 'U'; } else { return 'u'; }
                case Keys.V: if (upperCase) { return 'V'; } else { return 'v'; }
                case Keys.W: if (upperCase) { return 'W'; } else { return 'w'; }
                case Keys.X: if (upperCase) { return 'X'; } else { return 'x'; }
                case Keys.Y: if (upperCase) { return 'Y'; } else { return 'y'; }
                case Keys.Z: if (upperCase) { return 'Z'; } else { return 'z'; }

                //Decimal keys
                case Keys.D0: if (shift) { return ')'; } else { return '0'; }
                case Keys.D1: if (shift) { return '!'; } else { return '1'; }
                case Keys.D2: if (shift) { return '@'; } else { return '2'; }
                case Keys.D3: if (shift) { return '#'; } else { return '3'; }
                case Keys.D4: if (shift) { return '$'; } else { return '4'; }
                case Keys.D5: if (shift) { return '%'; } else { return '5'; }
                case Keys.D6: if (shift) { return '^'; } else { return '6'; }
                case Keys.D7: if (shift) { return '&'; } else { return '7'; }
                case Keys.D8: if (shift) { return '*'; } else { return '8'; }
                case Keys.D9: if (shift) { return '('; } else { return '9'; }

                //Decimal numpad keys
                case Keys.NumPad0: return '0';
                case Keys.NumPad1: return '1';
                case Keys.NumPad2: return '2';
                case Keys.NumPad3: return '3';
                case Keys.NumPad4: return '4';
                case Keys.NumPad5: return '5';
                case Keys.NumPad6: return '6';
                case Keys.NumPad7: return '7';
                case Keys.NumPad8: return '8';
                case Keys.NumPad9: return '9';

                //Special keys
                case Keys.OemTilde: if (shift) { return '~'; } else { return '`'; }
                case Keys.OemSemicolon: if (shift) { return ':'; } else { return ';'; }
                case Keys.OemQuotes: if (shift) { return '"'; } else { return '\''; }
                case Keys.OemQuestion: if (shift) { return '?'; } else { return '/'; }
                case Keys.OemPlus: if (shift) { return '+'; } else { return '='; }
                case Keys.OemPipe: if (shift) { return '|'; } else { return '\\'; }
                case Keys.OemPeriod: if (shift) { return '>'; } else { return '.'; }
                case Keys.OemOpenBrackets: if (shift) { return '{'; } else { return '['; }
                case Keys.OemCloseBrackets: if (shift) { return '}'; } else { return ']'; }
                case Keys.OemMinus: if (shift) { return '_'; } else { return '-'; }
                case Keys.OemComma: if (shift) { return '<'; } else { return ','; }
                case Keys.Space: return ' ';
            }

            return '\0';
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            // TODO: use this.Content to load your game content here
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        protected override void Update(GameTime gameTime)
        {
            io.DeltaTime = gameTime.ElapsedGameTime.Milliseconds / 1000;
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == (ButtonState.Pressed) || Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                Exit();
            }
            if (Keyboard.GetState().IsKeyDown(Keys.F))
            {
                graphics.ToggleFullScreen();
            }
            int w = GraphicsDevice.Viewport.Width, h = GraphicsDevice.Viewport.Height;
            int display_w = GraphicsDevice.Viewport.Width, display_h = GraphicsDevice.Viewport.Height;
            //int display_w = GraphicsDevice.PresentationParameters.BackBufferWidth, display_h = GraphicsDevice.PresentationParameters.BackBufferHeight;

            KeyboardState keyboard = Keyboard.GetState();
            MouseState mouse = Mouse.GetState();

            io.DisplaySize = new System.Numerics.Vector2(w, h);
            //io.DisplayFramebufferScale = new ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
            //// 1) get low-level inputs (e.g. on Win32, GetKeyboardState(), or poll your events, etc.)
            //// TODO: fill all fields of IO structure and call NewFrame
            io.DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (IsActive)
            {
                io.MousePosition = new System.Numerics.Vector2(mouse.X, mouse.Y);
            }
            else
            {
                io.MousePosition = new System.Numerics.Vector2(-1, -1);
            }

            io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed;
            io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed;
            io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;
            io.MouseWheel = mouse.ScrollWheelValue > scrollWheel ? 1 : mouse.ScrollWheelValue < scrollWheel ? -1 : 0;
            scrollWheel = mouse.ScrollWheelValue;

            io.CtrlPressed = keyboard.IsKeyDown(Keys.LeftControl) || keyboard.IsKeyDown(Keys.RightControl);
            io.AltPressed = keyboard.IsKeyDown(Keys.LeftAlt) || keyboard.IsKeyDown(Keys.RightAlt);
            io.ShiftPressed = keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift);

            bool capslock = ((((ushort)GetKeyState(0x14)) & 0xffff) != 0);
            Keys[] keys = keyboard.GetPressedKeys();
            for (int i = 0; i < 256; i++)
                io.KeysDown[i] = false;

            for (int i=0;i<keys.Length;i++)
            {
                Keys key = keys[i];
                char ch = ConvertKeyboardInput(key, io.AltPressed, io.ShiftPressed, io.CtrlPressed, capslock);
                if (!io.AltPressed && !io.CtrlPressed && (int)key < 0x80 && ch != 0)
                {
                    io.KeysDown[ch] = true;
                    ImGui.AddInputCharacter(ch);
                }
                else
                    io.KeysDown[(int)key + 0xff] = true;
            }

            // TODO: Add your update logic here
            ImGui.NewFrame();
            bool crap = true;
            ImGuiNative.igShowTestWindow(ref crap);

            base.Update(gameTime);
        }
        private void EnsureBuffers(int vertexCount, int indexCount)
        {
            if (vertexCount >= vbuff.VertexCount)
            {
                vbuff.Dispose();
                vbuff = new VertexBuffer(this.GraphicsDevice, vertexDeclaration, vertexCount * 3 / 2, BufferUsage.WriteOnly);
            }

            if (indexCount >= ibuff.IndexCount)
            {
                ibuff.Dispose();
                ibuff = new IndexBuffer(this.GraphicsDevice, IndexElementSize.SixteenBits, indexCount * 3 / 2, BufferUsage.WriteOnly);
            }

        }
        private byte[] GetBytes(IntPtr m_pBuffer,int size)
        {
            byte[] bytes = new byte[size];
            Marshal.Copy(m_pBuffer, bytes, 0, size);
            return bytes;
        }
        unsafe protected override void Draw(GameTime gameTime)
        {
            ImGui.Text("AVG Render: "+renderTime +"");
            Stopwatch timer = Stopwatch.StartNew();

            ImGui.Render();

            DrawData* data = ImGui.GetDrawData();

            GraphicsDevice.Clear(Color.CornflowerBlue);
            for (int k = 0; k < data->CmdListsCount; k++)
            {
                DrawList* drawlist = data->CmdLists[k];
                EnsureBuffers(drawlist->VtxBuffer.Size, drawlist->IdxBuffer.Size);
                vbuff.SetData(GetBytes((IntPtr)drawlist->VtxBuffer.Data,drawlist->VtxBuffer.Size), 0, drawlist->VtxBuffer.Size);
                ibuff.SetData(GetBytes((IntPtr)drawlist->IdxBuffer.Data,drawlist->IdxBuffer.Size), 0, drawlist->IdxBuffer.Size);

                GraphicsDevice.SetVertexBuffer(vbuff);
                GraphicsDevice.Indices = ibuff;

                int idxoffset = 0;
                for (int j = 0; j < drawlist->CmdBuffer.Size; j++)
                {
                    DrawCmd * pcmd_ = &(((DrawCmd *)drawlist->CmdBuffer.Data)[j]);
                    DrawCmd pcmd = *pcmd_;
                    if (pcmd.UserCallback != null)
                    {
                        throw new NotImplementedException();
                    }
                    else
                    {
                        GraphicsDevice.ScissorRectangle = new Rectangle((int)pcmd.ClipRect.X, (int)pcmd.ClipRect.Y, (int)(pcmd.ClipRect.Z - pcmd.ClipRect.X), (int)(pcmd.ClipRect.W - pcmd.ClipRect.Y));
                        basicEffect.Texture.Equals(pcmd.TextureId);
                        for(int i=0; i< basicEffect.CurrentTechnique.Passes.Count;i++)
                        {
                            EffectPass pass = basicEffect.CurrentTechnique.Passes[i];
                            pass.Apply();
                            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList,0,0, 0, idxoffset, (int)(pcmd.ElemCount / 3));
                        }
                    }
                    idxoffset += (int)pcmd.ElemCount;
                }
            }

            base.Draw(gameTime);

            timer.Stop();
            renderTime = renderTime * 0.8f + (float)timer.Elapsed.TotalSeconds * 0.2f;
        }
    }
}

But Still crashes in FNA-XNA ...

mellinoe commented 7 years ago

@msmshazan I noticed some immediate problems when I tried your code:

msmshazan commented 7 years ago

Here's the corrected code but it crashes on Monogame.

When calling ImGui.GetIO();


using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using ImGuiNET;

namespace Game
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        IO io;
        Texture2D Font;
        private Matrix worldMatrix, viewMatrix, projectionMatrix;

        private BasicEffect basicEffect;
        private VertexBuffer vbuff;
        private IndexBuffer ibuff;

        private Texture2D defaultWhiteTexture, fontTexture;

        private int scrollWheel = 0;
        private char[] input = new char[1024];

        private float renderTime = 0f;

        private VertexDeclaration vertexDeclaration = new VertexDeclaration(
                new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),
                new VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
                new VertexElement(16, VertexElementFormat.Color, VertexElementUsage.Color, 0)
            );

        public Game()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "../../Content";
        }
        unsafe protected override void Initialize()
        {
            SetupBasicShader();

            // Application init
            io = ImGui.GetIO();

            io.DisplaySize = new System.Numerics.Vector2(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);

            SetupFontTextures();
            SetupBuffers();

            //not sure if we really need pointclamp since we add a 1px padding around each glyph
            GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
            GraphicsDevice.BlendState = BlendState.NonPremultiplied;
            GraphicsDevice.RasterizerState = new RasterizerState() { CullMode = CullMode.None, ScissorTestEnable = true };

            SetupKeyMappings();

            base.Initialize();
        }
        bool SetupFontTextures()
        {
            var io = ImGui.GetIO();

            //font texture
            var data = io.FontAtlas.GetTexDataAsAlpha8();
            data = io.FontAtlas.GetTexDataAsRGBA32();
            fontTexture = new Texture2D(GraphicsDevice, data.Width, data.Height);
            unsafe
            {
                fontTexture.SetData(GetBytes((IntPtr)data.Pixels, data.Height * data.Width * data.BytesPerPixel));
            }
            io.FontAtlas.SetTexID(fontTexture.GetHashCode());
            basicEffect.Texture = fontTexture;

            //default white texture
            defaultWhiteTexture = new Texture2D(GraphicsDevice, 1, 1);
            defaultWhiteTexture.SetData(new Color[] { Color.White });

            return true;
        }

        void SetupBasicShader()
        {
            viewMatrix = Matrix.Identity;
            projectionMatrix = Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, -1);
            worldMatrix = Matrix.Identity;

            basicEffect = new BasicEffect(GraphicsDevice);
            basicEffect.World = worldMatrix;
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix;
            basicEffect.VertexColorEnabled = true;
            basicEffect.TextureEnabled = true;
        }
        void SetupBuffers()
        {
            vbuff = new VertexBuffer(GraphicsDevice, vertexDeclaration, 4096, BufferUsage.WriteOnly);
            ibuff = new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, 4096 * 4, BufferUsage.WriteOnly);
        }
        void SetupKeyMappings()
        {

            io.KeyMap[GuiKey.Tab] = (int)Keys.Tab;
            io.KeyMap[GuiKey.LeftArrow] = (int)Keys.Left;
            io.KeyMap[GuiKey.RightArrow] = (int)Keys.Right;
            io.KeyMap[GuiKey.UpArrow] = (int)Keys.Up;
            io.KeyMap[GuiKey.DownArrow] = (int)Keys.Down;
            io.KeyMap[GuiKey.PageUp] = (int)Keys.PageUp;
            io.KeyMap[GuiKey.PageDown] = (int)Keys.PageDown;
            io.KeyMap[GuiKey.Home] = (int)Keys.Home;
            io.KeyMap[GuiKey.End] = (int)Keys.End;
            io.KeyMap[GuiKey.Delete] = (int)Keys.Delete;
            io.KeyMap[GuiKey.Backspace] = (int)Keys.Back;
            io.KeyMap[GuiKey.Enter] = (int)Keys.Enter;
            io.KeyMap[GuiKey.Escape] = (int)Keys.Escape;
            io.KeyMap[GuiKey.A] = (int)Keys.A;
            io.KeyMap[GuiKey.C] = (int)Keys.C;
            io.KeyMap[GuiKey.V] = (int)Keys.V;
            io.KeyMap[GuiKey.X] = (int)Keys.X;
            io.KeyMap[GuiKey.Y] = (int)Keys.Y;
            io.KeyMap[GuiKey.Z] = (int)Keys.Z;
        }

        //// An umanaged function that retrieves the states of each key
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
        public static extern short GetKeyState(int keyCode);

        #region Convert Key
        public static char ConvertKeyboardInput(Keys key, bool alt, bool shift, bool ctrl, bool caps)
        {
            bool upperCase = caps ^ shift;
            switch (key)
            {
                //Alphabet keys
                case Keys.A: if (upperCase) { return 'A'; } else { return 'a'; }
                case Keys.B: if (upperCase) { return 'B'; } else { return 'b'; }
                case Keys.C: if (upperCase) { return 'C'; } else { return 'c'; }
                case Keys.D: if (upperCase) { return 'D'; } else { return 'd'; }
                case Keys.E: if (upperCase) { return 'E'; } else { return 'e'; }
                case Keys.F: if (upperCase) { return 'F'; } else { return 'f'; }
                case Keys.G: if (upperCase) { return 'G'; } else { return 'g'; }
                case Keys.H: if (upperCase) { return 'H'; } else { return 'h'; }
                case Keys.I: if (upperCase) { return 'I'; } else { return 'i'; }
                case Keys.J: if (upperCase) { return 'J'; } else { return 'j'; }
                case Keys.K: if (upperCase) { return 'K'; } else { return 'k'; }
                case Keys.L: if (upperCase) { return 'L'; } else { return 'l'; }
                case Keys.M: if (upperCase) { return 'M'; } else { return 'm'; }
                case Keys.N: if (upperCase) { return 'N'; } else { return 'n'; }
                case Keys.O: if (upperCase) { return 'O'; } else { return 'o'; }
                case Keys.P: if (upperCase) { return 'P'; } else { return 'p'; }
                case Keys.Q: if (upperCase) { return 'Q'; } else { return 'q'; }
                case Keys.R: if (upperCase) { return 'R'; } else { return 'r'; }
                case Keys.S: if (upperCase) { return 'S'; } else { return 's'; }
                case Keys.T: if (upperCase) { return 'T'; } else { return 't'; }
                case Keys.U: if (upperCase) { return 'U'; } else { return 'u'; }
                case Keys.V: if (upperCase) { return 'V'; } else { return 'v'; }
                case Keys.W: if (upperCase) { return 'W'; } else { return 'w'; }
                case Keys.X: if (upperCase) { return 'X'; } else { return 'x'; }
                case Keys.Y: if (upperCase) { return 'Y'; } else { return 'y'; }
                case Keys.Z: if (upperCase) { return 'Z'; } else { return 'z'; }

                //Decimal keys
                case Keys.D0: if (shift) { return ')'; } else { return '0'; }
                case Keys.D1: if (shift) { return '!'; } else { return '1'; }
                case Keys.D2: if (shift) { return '@'; } else { return '2'; }
                case Keys.D3: if (shift) { return '#'; } else { return '3'; }
                case Keys.D4: if (shift) { return '$'; } else { return '4'; }
                case Keys.D5: if (shift) { return '%'; } else { return '5'; }
                case Keys.D6: if (shift) { return '^'; } else { return '6'; }
                case Keys.D7: if (shift) { return '&'; } else { return '7'; }
                case Keys.D8: if (shift) { return '*'; } else { return '8'; }
                case Keys.D9: if (shift) { return '('; } else { return '9'; }

                //Decimal numpad keys
                case Keys.NumPad0: return '0';
                case Keys.NumPad1: return '1';
                case Keys.NumPad2: return '2';
                case Keys.NumPad3: return '3';
                case Keys.NumPad4: return '4';
                case Keys.NumPad5: return '5';
                case Keys.NumPad6: return '6';
                case Keys.NumPad7: return '7';
                case Keys.NumPad8: return '8';
                case Keys.NumPad9: return '9';

                //Special keys
                case Keys.OemTilde: if (shift) { return '~'; } else { return '`'; }
                case Keys.OemSemicolon: if (shift) { return ':'; } else { return ';'; }
                case Keys.OemQuotes: if (shift) { return '"'; } else { return '\''; }
                case Keys.OemQuestion: if (shift) { return '?'; } else { return '/'; }
                case Keys.OemPlus: if (shift) { return '+'; } else { return '='; }
                case Keys.OemPipe: if (shift) { return '|'; } else { return '\\'; }
                case Keys.OemPeriod: if (shift) { return '>'; } else { return '.'; }
                case Keys.OemOpenBrackets: if (shift) { return '{'; } else { return '['; }
                case Keys.OemCloseBrackets: if (shift) { return '}'; } else { return ']'; }
                case Keys.OemMinus: if (shift) { return '_'; } else { return '-'; }
                case Keys.OemComma: if (shift) { return '<'; } else { return ','; }
                case Keys.Space: return ' ';
            }

            return '\0';
        }
        #endregion

        /// <summary>
        /// 
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            // TODO: use this.Content to load your game content here
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }
        protected override void Update(GameTime gameTime)
        {
            io.DeltaTime = gameTime.ElapsedGameTime.Milliseconds / 1000;
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == (ButtonState.Pressed) || Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                Exit();
            }
            if (Keyboard.GetState().IsKeyDown(Keys.F))
            {
                graphics.ToggleFullScreen();
            }
            int w = GraphicsDevice.Viewport.Width, h = GraphicsDevice.Viewport.Height;
            int display_w = GraphicsDevice.Viewport.Width, display_h = GraphicsDevice.Viewport.Height;
            //int display_w = GraphicsDevice.PresentationParameters.BackBufferWidth, display_h = GraphicsDevice.PresentationParameters.BackBufferHeight;

            KeyboardState keyboard = Keyboard.GetState();
            MouseState mouse = Mouse.GetState();

            io.DisplaySize = new System.Numerics.Vector2(w, h);
            //io.DisplayFramebufferScale = new ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
            //// 1) get low-level inputs (e.g. on Win32, GetKeyboardState(), or poll your events, etc.)
            //// TODO: fill all fields of IO structure and call NewFrame
            io.DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (IsActive)
            {
                io.MousePosition = new System.Numerics.Vector2(mouse.X, mouse.Y);
            }
            else
            {
                io.MousePosition = new System.Numerics.Vector2(-1, -1);
            }

            io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed;
            io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed;
            io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;
            io.MouseWheel = mouse.ScrollWheelValue > scrollWheel ? 1 : mouse.ScrollWheelValue < scrollWheel ? -1 : 0;
            scrollWheel = mouse.ScrollWheelValue;

            io.CtrlPressed = keyboard.IsKeyDown(Keys.LeftControl) || keyboard.IsKeyDown(Keys.RightControl);
            io.AltPressed = keyboard.IsKeyDown(Keys.LeftAlt) || keyboard.IsKeyDown(Keys.RightAlt);
            io.ShiftPressed = keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift);

            bool capslock = ((((ushort)GetKeyState(0x14)) & 0xffff) != 0);
            Keys[] keys = keyboard.GetPressedKeys();
            for (int i = 0; i < 256; i++)
                io.KeysDown[i] = false;

            for (int i = 0; i < keys.Length; i++)
            {
                Keys key = keys[i];
                char ch = ConvertKeyboardInput(key, io.AltPressed, io.ShiftPressed, io.CtrlPressed, capslock);
                if (!io.AltPressed && !io.CtrlPressed && (int)key < 0x80 && ch != 0)
                {
                    io.KeysDown[ch] = true;
                    ImGui.AddInputCharacter(ch);
                }
                else
                    io.KeysDown[(int)key + 0xff] = true;
            }

            // TODO: Add your update logic here
            ImGui.NewFrame();
            bool crap = true;
            ImGuiNative.igShowTestWindow(ref crap);

            base.Update(gameTime);
        }
        private void EnsureBuffers(int vertexCount, int indexCount)
        {
            if (vertexCount >= vbuff.VertexCount)
            {
                vbuff.Dispose();
                vbuff = new VertexBuffer(this.GraphicsDevice, vertexDeclaration, vertexCount * 3 / 2, BufferUsage.WriteOnly);
            }

            if (indexCount >= ibuff.IndexCount)
            {
                ibuff.Dispose();
                ibuff = new IndexBuffer(this.GraphicsDevice, IndexElementSize.SixteenBits, indexCount * 3 / 2, BufferUsage.WriteOnly);
            }

        }
        private byte[] GetBytes(IntPtr m_pBuffer, int size)
        {
            byte[] bytes = new byte[size];
            Marshal.Copy(m_pBuffer, bytes, 0, size);
            return bytes;
        }
        unsafe protected override void Draw(GameTime gameTime)
        {
            ImGui.Text("AVG Render: " + renderTime + "");
            Stopwatch timer = Stopwatch.StartNew();

            ImGui.Render();

            DrawData* data = ImGui.GetDrawData();

            GraphicsDevice.Clear(Color.CornflowerBlue);
            for (int k = 0; k < data->CmdListsCount; k++)
            {
                DrawList* drawlist = data->CmdLists[k];
                EnsureBuffers(drawlist->VtxBuffer.Size, drawlist->IdxBuffer.Size);
                vbuff.SetData(GetBytes((IntPtr)drawlist->VtxBuffer.Data, drawlist->VtxBuffer.Size), 0, drawlist->VtxBuffer.Size);
                ibuff.SetData(GetBytes((IntPtr)drawlist->IdxBuffer.Data, drawlist->IdxBuffer.Size), 0, drawlist->IdxBuffer.Size);

                GraphicsDevice.SetVertexBuffer(vbuff);
                GraphicsDevice.Indices = ibuff;

                int idxoffset = 0;
                for (int j = 0; j < drawlist->CmdBuffer.Size; j++)
                {
                    DrawCmd* pcmd_ = &(((DrawCmd*)drawlist->CmdBuffer.Data)[j]);
                    DrawCmd pcmd = *pcmd_;
                    if (pcmd.UserCallback != null)
                    {
                        throw new NotImplementedException();
                    }
                    else
                    {
                        GraphicsDevice.ScissorRectangle = new Rectangle((int)pcmd.ClipRect.X, (int)pcmd.ClipRect.Y, (int)(pcmd.ClipRect.Z - pcmd.ClipRect.X), (int)(pcmd.ClipRect.W - pcmd.ClipRect.Y));
                        basicEffect.Texture.Equals(pcmd.TextureId);
                        for (int i = 0; i < basicEffect.CurrentTechnique.Passes.Count; i++)
                        {
                            EffectPass pass = basicEffect.CurrentTechnique.Passes[i];
                            pass.Apply();
                            GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, idxoffset, (int)(pcmd.ElemCount / 3));
                        }
                    }
                    idxoffset += (int)pcmd.ElemCount;
                }
            }

            base.Draw(gameTime);

            timer.Stop();
            renderTime = renderTime * 0.8f + (float)timer.Elapsed.TotalSeconds * 0.2f;
        }
    }
}` 
mellinoe commented 7 years ago

Crashes in what way? I copy-pasted the code earlier today and I got much further than just calling ImGui.GetIO() (which was how I identified a couple problems).

Are you deploying cimgui.dll with the application?

msmshazan commented 7 years ago

I think the issue is that the ImGui library requires .Net Core assemblies to build. And Monogame requires .Net Framework.Therefore compatibility issues when calling .Net Core code from .Net Framework 4.6 .

mellinoe commented 7 years ago

The project file in this repository requires the .NET Core SDK to build, but that is free and easy to download. The ImGui.NET assembly itself targets .NET Standard 1.1, which means it will work just fine in a .NET Framework 4.6 project. You can use the nuget package if you don't wish to build it yourself. You could also build a version of ImGui.NET targeting .NET Framework pretty easily

I made a couple more modifications to your code and managed to get it partially working. There is still some problem with the text rendering, but I don't have a ton of time to debug through it.

image

I pasted the code in a gist to avoid bloating the comments section here:

https://gist.github.com/mellinoe/488bfde9139da90d3d9a8914fcc657c8

msmshazan commented 7 years ago

Where to include cimgui.dll is it in the exe directory or somewhere else.Tried putting in the exe directory still no use. Still crashes in ImGui.GetIO();

mellinoe commented 7 years ago

Yeah, putting it next to the .exe should be enough for the PInvokes to work. Could you paste the text of the error / exception you are seeing? It must be something with how your project is set up, because I'm not having that problem myself. All I did was create a new MonoGame project from one of the templates, add the ImGui NuGet package, and copy-paste your code in.

By the way, I debugged through this a bit more and got almost everything working. There was an additional issue with how you were copying the vertex and index data into byte[] arrays before uploading it to the device buffers. It was probably a simple typo somewhere, but I ended up just rewriting that part. As an aside, it's a bummer that XNA/MonoGame doesn't let you upload data directly from pointers. If you actually used this in a game, you would want to use persistent staging arrays rather than recreate them every frame to be GC'd.

image

There is still something wrong with the scissor rectangles (text still shows up "on the window" even when you minimize / shorten it), but other than that it seems to be working great. I updated the gist with the fixed version of the code.

https://gist.github.com/mellinoe/488bfde9139da90d3d9a8914fcc657c8

msmshazan commented 7 years ago

Here's the exception i get. capture

I think the issue is that since you have .net core installed the ImGui.Net dll works.

mellinoe commented 7 years ago

Could you show what the inner exception is? That doesn't give much info other than something went wrong in the type constructor. It's probably the DLL being missing, though. One other thing to double-check: is your game 64-bit? The DLL included in this repository is 64-bit, so you'd need to recompile it to use it in a 32-bit game.

I think the issue is that since you have .net core installed the ImGui.Net dll works.

Like I said, ImGui.NET.dll doesn't depend on .NET Core.

mellinoe commented 7 years ago

@msmshazan Have you been able to get any further with this? I was able to get it working on my end, so I'd like to know if you were able to at least get that far before I close this issue.

msmshazan commented 7 years ago

@mellinoe Yes , the 64-bit dll was the issue. Currently trying to get it working on FNA-XNA and fixing the text rendering issue.

mellinoe commented 7 years ago

Let me know if you hit any further issues blocking you. I'll close this issue out for now since I think you were on the right track.