Closed msmshazan closed 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.
@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
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 ...
@msmshazan I noticed some immediate problems when I tried your code:
FontAtlas.GetTexDataAsXYZ
. You need to call that function and put that texture data into a GPU texture (not sure of the exact MonoGame API). This is what gives me an immediate crash.SetupBuffers
, so your VB/IB are null.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;
}
}
}`
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?
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 .
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.
I pasted the code in a gist to avoid bloating the comments section here:
https://gist.github.com/mellinoe/488bfde9139da90d3d9a8914fcc657c8
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();
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.
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
Here's the exception i get.
I think the issue is that since you have .net core installed the ImGui.Net dll works.
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.
@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.
@mellinoe Yes , the 64-bit dll was the issue. Currently trying to get it working on FNA-XNA and fixing the text rendering issue.
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.
How to integrate imgui.net into monogame any samples available?