Renderer - FNA (#62)

* Workspace

* Assembly name "ImGui.NET.FNA"

* Removed directives

* FNA ImGuiRenderer cleanup

* Comments

* More comments

* Even more comments

* Removed unnecessary changes to IO.cs

* Worked in review comments

* Cleanup and readme

* Corrected minVertexIndex and numVertices

* Removed png, now generating sample image on runtime

* SampleProgram.FNA - Added cimgui.dll as content

* Added MonoGame support

* Updated readme

* Suppress warning on the DrawIndexedPrimitives method
internals
Marco van den Oever 6 years ago committed by Eric Mellino
parent d5a14169ad
commit 9690c5570a
  1. 29
      src/ImGui.NET.SampleProgram.XNA/DrawVertDeclaration.cs
  2. 26
      src/ImGui.NET.SampleProgram.XNA/ImGui.NET.SampleProgram.XNA.csproj
  3. 377
      src/ImGui.NET.SampleProgram.XNA/ImGuiRenderer.cs
  4. 10
      src/ImGui.NET.SampleProgram.XNA/Program.cs
  5. 12
      src/ImGui.NET.SampleProgram.XNA/README.md
  6. 134
      src/ImGui.NET.SampleProgram.XNA/SampleGame.cs
  7. 14
      src/ImGui.NET.sln
  8. 9
      src/ImGui.NET/IO.cs

@ -0,0 +1,29 @@
using Microsoft.Xna.Framework.Graphics;
namespace ImGuiNET.SampleProgram.XNA
{
public static class DrawVertDeclaration
{
public static readonly VertexDeclaration Declaration;
public static readonly int Size;
static DrawVertDeclaration()
{
unsafe { Size = sizeof(DrawVert); }
Declaration = new VertexDeclaration(
Size,
// Position
new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),
// UV
new VertexElement(8, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
// Color
new VertexElement(16, VertexElementFormat.Color, VertexElementUsage.Color, 0)
);
}
}
}

@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AssemblyName>ImGuiNET.SampleProgram.XNA</AssemblyName>
<RootNamespace>ImGuiNET.SampleProgram.XNA</RootNamespace>
<TargetFramework>net462</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ImGui.NET\ImGui.NET.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="$(RepositoryRootDirectory)/deps/cimgui/win-x64/cimgui.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(RepositoryRootDirectory)/deps/cimgui/osx-x64/cimgui.dylib" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(RepositoryRootDirectory)/deps/cimgui/linux-x64/cimgui.so" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.6.0.1625" />
</ItemGroup>
</Project>

@ -0,0 +1,377 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace ImGuiNET.SampleProgram.XNA
{
/// <summary>
/// ImGui renderer for use with XNA-likes (FNA & MonoGame)
/// </summary>
public class ImGuiRenderer
{
private Game _game;
// Graphics
private GraphicsDevice _graphicsDevice;
private BasicEffect _effect;
private RasterizerState _rasterizerState;
private byte[] _vertexData;
private VertexBuffer _vertexBuffer;
private int _vertexBufferSize;
private byte[] _indexData;
private IndexBuffer _indexBuffer;
private int _indexBufferSize;
// Textures
private Dictionary<IntPtr, Texture2D> _loadedTextures;
private int _textureId;
private IntPtr? _fontTextureId;
// Input
private int _scrollWheelValue;
private List<int> _keys = new List<int>();
public ImGuiRenderer(Game game)
{
_game = game ?? throw new ArgumentNullException(nameof(game));
_graphicsDevice = game.GraphicsDevice;
_loadedTextures = new Dictionary<IntPtr, Texture2D>();
_rasterizerState = new RasterizerState()
{
CullMode = CullMode.None,
DepthBias = 0,
FillMode = FillMode.Solid,
MultiSampleAntiAlias = false,
ScissorTestEnable = true,
SlopeScaleDepthBias = 0
};
SetupInput();
}
#region ImGuiRenderer
/// <summary>
/// Creates a texture and loads the font data from ImGui. Should be called when the <see cref="GraphicsDevice" /> is initialized but before any rendering is done
/// </summary>
public virtual void RebuildFontAtlas()
{
// Get font texture from ImGui
var io = ImGui.GetIO();
var texData = io.FontAtlas.GetTexDataAsRGBA32();
// Copy the data to a managed array
var pixels = new byte[texData.Width * texData.Height * texData.BytesPerPixel];
unsafe { Marshal.Copy(new IntPtr(texData.Pixels), pixels, 0, pixels.Length); }
// Create and register the texture as an XNA texture
var tex2d = new Texture2D(_graphicsDevice, texData.Width, texData.Height, false, SurfaceFormat.Color);
tex2d.SetData(pixels);
// Should a texture already have been build previously, unbind it first so it can be deallocated
if (_fontTextureId.HasValue) UnbindTexture(_fontTextureId.Value);
// Bind the new texture to an ImGui-friendly id
_fontTextureId = BindTexture(tex2d);
// Let ImGui know where to find the texture
io.FontAtlas.SetTexID(_fontTextureId.Value);
io.FontAtlas.ClearTexData(); // Clears CPU side texture data
}
/// <summary>
/// Creates a pointer to a texture, which can be passed through ImGui calls such as <see cref="ImGui.Image" />. That pointer is then used by ImGui to let us know what texture to draw
/// </summary>
public virtual IntPtr BindTexture(Texture2D texture)
{
var id = new IntPtr(_textureId++);
_loadedTextures.Add(id, texture);
return id;
}
/// <summary>
/// Removes a previously created texture pointer, releasing its reference and allowing it to be deallocated
/// </summary>
public virtual void UnbindTexture(IntPtr textureId)
{
_loadedTextures.Remove(textureId);
}
/// <summary>
/// Sets up ImGui for a new frame, should be called at frame start
/// </summary>
public virtual void BeforeLayout(GameTime gameTime)
{
ImGui.GetIO().DeltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
UpdateInput();
ImGui.NewFrame();
}
/// <summary>
/// Asks ImGui for the generated geometry data and sends it to the graphics pipeline, should be called after the UI is drawn using ImGui.** calls
/// </summary>
public virtual void AfterLayout()
{
ImGui.Render();
unsafe { RenderDrawData(ImGui.GetDrawData()); }
}
#endregion ImGuiRenderer
#region Setup & Update
/// <summary>
/// Maps ImGui keys to XNA keys. We use this later on to tell ImGui what keys were pressed
/// </summary>
protected virtual void SetupInput()
{
var io = ImGui.GetIO();
_keys.Add(io.KeyMap[GuiKey.Tab] = (int)Keys.Tab);
_keys.Add(io.KeyMap[GuiKey.LeftArrow] = (int)Keys.Left);
_keys.Add(io.KeyMap[GuiKey.RightArrow] = (int)Keys.Right);
_keys.Add(io.KeyMap[GuiKey.UpArrow] = (int)Keys.Up);
_keys.Add(io.KeyMap[GuiKey.DownArrow] = (int)Keys.Down);
_keys.Add(io.KeyMap[GuiKey.PageUp] = (int)Keys.PageUp);
_keys.Add(io.KeyMap[GuiKey.PageDown] = (int)Keys.PageDown);
_keys.Add(io.KeyMap[GuiKey.Home] = (int)Keys.Home);
_keys.Add(io.KeyMap[GuiKey.End] = (int)Keys.End);
_keys.Add(io.KeyMap[GuiKey.Delete] = (int)Keys.Delete);
_keys.Add(io.KeyMap[GuiKey.Backspace] = (int)Keys.Back);
_keys.Add(io.KeyMap[GuiKey.Enter] = (int)Keys.Enter);
_keys.Add(io.KeyMap[GuiKey.Escape] = (int)Keys.Escape);
_keys.Add(io.KeyMap[GuiKey.A] = (int)Keys.A);
_keys.Add(io.KeyMap[GuiKey.C] = (int)Keys.C);
_keys.Add(io.KeyMap[GuiKey.V] = (int)Keys.V);
_keys.Add(io.KeyMap[GuiKey.X] = (int)Keys.X);
_keys.Add(io.KeyMap[GuiKey.Y] = (int)Keys.Y);
_keys.Add(io.KeyMap[GuiKey.Z] = (int)Keys.Z);
// MonoGame-specific //////////////////////
_game.Window.TextInput += (s, a) =>
{
if (a.Character == '\t') return;
ImGui.AddInputCharacter(a.Character);
};
///////////////////////////////////////////
// FNA-specific ///////////////////////////
//TextInputEXT.TextInput += c =>
//{
// if (c == '\t') return;
// ImGui.AddInputCharacter(c);
//};
///////////////////////////////////////////
ImGui.GetIO().FontAtlas.AddDefaultFont();
}
/// <summary>
/// Updates the <see cref="Effect" /> to the current matrices and texture
/// </summary>
protected virtual Effect UpdateEffect(Texture2D texture)
{
_effect = _effect ?? new BasicEffect(_graphicsDevice);
var io = ImGui.GetIO();
// MonoGame-specific //////////////////////
var offset = .5f;
///////////////////////////////////////////
// FNA-specific ///////////////////////////
//var offset = 0f;
///////////////////////////////////////////
_effect.World = Matrix.Identity;
_effect.View = Matrix.Identity;
_effect.Projection = Matrix.CreateOrthographicOffCenter(offset, io.DisplaySize.X + offset, io.DisplaySize.Y + offset, offset, -1f, 1f);
_effect.TextureEnabled = true;
_effect.Texture = texture;
_effect.VertexColorEnabled = true;
return _effect;
}
/// <summary>
/// Sends XNA input state to ImGui
/// </summary>
protected virtual void UpdateInput()
{
var io = ImGui.GetIO();
var mouse = Mouse.GetState();
var keyboard = Keyboard.GetState();
for (int i = 0; i < _keys.Count; i++)
{
io.KeysDown[_keys[i]] = keyboard.IsKeyDown((Keys)_keys[i]);
}
io.ShiftPressed = keyboard.IsKeyDown(Keys.LeftShift) || keyboard.IsKeyDown(Keys.RightShift);
io.CtrlPressed = keyboard.IsKeyDown(Keys.LeftControl) || keyboard.IsKeyDown(Keys.RightControl);
io.AltPressed = keyboard.IsKeyDown(Keys.LeftAlt) || keyboard.IsKeyDown(Keys.RightAlt);
io.SuperPressed = keyboard.IsKeyDown(Keys.LeftWindows) || keyboard.IsKeyDown(Keys.RightWindows);
io.DisplaySize = new System.Numerics.Vector2(_graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight);
io.DisplayFramebufferScale = new System.Numerics.Vector2(1f, 1f);
io.MousePosition = new System.Numerics.Vector2(mouse.X, mouse.Y);
io.MouseDown[0] = mouse.LeftButton == ButtonState.Pressed;
io.MouseDown[1] = mouse.RightButton == ButtonState.Pressed;
io.MouseDown[2] = mouse.MiddleButton == ButtonState.Pressed;
var scrollDelta = mouse.ScrollWheelValue - _scrollWheelValue;
io.MouseWheel = scrollDelta > 0 ? 1 : scrollDelta < 0 ? -1 : 0;
_scrollWheelValue = mouse.ScrollWheelValue;
}
#endregion Setup & Update
#region Internals
/// <summary>
/// Gets the geometry as set up by ImGui and sends it to the graphics device
/// </summary>
private unsafe void RenderDrawData(DrawData* drawData)
{
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers
var lastViewport = _graphicsDevice.Viewport;
var lastScissorBox = _graphicsDevice.ScissorRectangle;
_graphicsDevice.BlendFactor = Color.White;
_graphicsDevice.BlendState = BlendState.NonPremultiplied;
_graphicsDevice.RasterizerState = _rasterizerState;
_graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
// Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays)
ImGui.ScaleClipRects(drawData, ImGui.GetIO().DisplayFramebufferScale);
// Setup projection
_graphicsDevice.Viewport = new Viewport(0, 0, _graphicsDevice.PresentationParameters.BackBufferWidth, _graphicsDevice.PresentationParameters.BackBufferHeight);
UpdateBuffers(drawData);
RenderCommandLists(drawData);
// Restore modified state
_graphicsDevice.Viewport = lastViewport;
_graphicsDevice.ScissorRectangle = lastScissorBox;
}
private unsafe void UpdateBuffers(DrawData* drawData)
{
// Expand buffers if we need more room
if (drawData->TotalVtxCount > _vertexBufferSize)
{
_vertexBuffer?.Dispose();
_vertexBufferSize = (int)(drawData->TotalVtxCount * 1.5f);
_vertexBuffer = new VertexBuffer(_graphicsDevice, DrawVertDeclaration.Declaration, _vertexBufferSize, BufferUsage.None);
_vertexData = new byte[_vertexBufferSize * DrawVertDeclaration.Size];
}
if (drawData->TotalIdxCount > _indexBufferSize)
{
_indexBuffer?.Dispose();
_indexBufferSize = (int)(drawData->TotalIdxCount * 1.5f);
_indexBuffer = new IndexBuffer(_graphicsDevice, IndexElementSize.SixteenBits, _indexBufferSize, BufferUsage.None);
_indexData = new byte[_indexBufferSize * sizeof(ushort)];
}
// Copy ImGui's vertices and indices to a set of managed byte arrays
int vtxOffset = 0;
int idxOffset = 0;
for (int n = 0; n < drawData->CmdListsCount; n++)
{
var cmdList = drawData->CmdLists[n];
fixed (void* vtxDstPtr = &_vertexData[vtxOffset * DrawVertDeclaration.Size])
fixed (void* idxDstPtr = &_indexData[idxOffset * sizeof(ushort)])
{
Buffer.MemoryCopy(cmdList->VtxBuffer.Data, vtxDstPtr, _vertexData.Length, cmdList->VtxBuffer.Size * DrawVertDeclaration.Size);
Buffer.MemoryCopy(cmdList->IdxBuffer.Data, idxDstPtr, _indexData.Length, cmdList->IdxBuffer.Size * sizeof(ushort));
}
vtxOffset += cmdList->VtxBuffer.Size;
idxOffset += cmdList->IdxBuffer.Size;
}
// Copy the managed byte arrays to the gpu vertex- and index buffers
_vertexBuffer.SetData(_vertexData, 0, drawData->TotalVtxCount * DrawVertDeclaration.Size);
_indexBuffer.SetData(_indexData, 0, drawData->TotalIdxCount * sizeof(ushort));
}
private unsafe void RenderCommandLists(DrawData* drawData)
{
_graphicsDevice.SetVertexBuffer(_vertexBuffer);
_graphicsDevice.Indices = _indexBuffer;
int vtxOffset = 0;
int idxOffset = 0;
for (int n = 0; n < drawData->CmdListsCount; n++)
{
var cmdList = drawData->CmdLists[n];
for (int cmdi = 0; cmdi < cmdList->CmdBuffer.Size; cmdi++)
{
var drawCmd = &(((DrawCmd*)cmdList->CmdBuffer.Data)[cmdi]);
if (!_loadedTextures.ContainsKey(drawCmd->TextureId)) throw new InvalidOperationException($"Could not find a texture with id '{drawCmd->TextureId}', please check your bindings");
_graphicsDevice.ScissorRectangle = new Rectangle(
(int)drawCmd->ClipRect.X,
(int)drawCmd->ClipRect.Y,
(int)(drawCmd->ClipRect.Z - drawCmd->ClipRect.X),
(int)(drawCmd->ClipRect.W - drawCmd->ClipRect.Y)
);
var effect = UpdateEffect(_loadedTextures[drawCmd->TextureId]);
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
#pragma warning disable CS0618 // // FNA does not expose an alternative method.
_graphicsDevice.DrawIndexedPrimitives(
primitiveType: PrimitiveType.TriangleList,
baseVertex: vtxOffset,
minVertexIndex: 0,
numVertices: cmdList->VtxBuffer.Size,
startIndex: idxOffset,
primitiveCount: (int)drawCmd->ElemCount / 3
);
#pragma warning restore CS0618
}
idxOffset += (int)drawCmd->ElemCount;
}
vtxOffset += cmdList->VtxBuffer.Size;
}
}
#endregion Internals
}
}

@ -0,0 +1,10 @@
namespace ImGuiNET.SampleProgram.XNA
{
public static class Program
{
public static void Main(string[] args)
{
new SampleGame().Run();
}
}
}

@ -0,0 +1,12 @@
# ImGui.NET renderer for XNA-likes (FNA & MonoGame)
To run this sample program:
## MonoGame (default, NuGet package for "DesktopGL"-version already installed)
- Download the SDL2 dll from https://www.libsdl.org/download-2.0.php and copy it to the project output directory
## FNA
- Remove the MonoGame.Framework.DesktopGL NuGet package
- Download FNA from https://github.com/FNA-XNA/FNA/releases and add a reference to it
- Download the native FNA dependencies from https://github.com/FNA-XNA/FNA/wiki/3:-Distributing-FNA-Games and copy them to the project output directory
- Replace the marked MonoGame-specific parts of the code with their commented FNA counterparts (search for "FNA-specific")

@ -0,0 +1,134 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.IO;
using Num = System.Numerics;
namespace ImGuiNET.SampleProgram.XNA
{
/// <summary>
/// Simple FNA + ImGui example
/// </summary>
public class SampleGame : Game
{
private GraphicsDeviceManager _graphics;
private ImGuiRenderer _imGuiRenderer;
private Texture2D _xnaTexture;
private IntPtr _imGuiTexture;
public SampleGame()
{
_graphics = new GraphicsDeviceManager(this);
_graphics.PreferredBackBufferWidth = 1024;
_graphics.PreferredBackBufferHeight = 768;
_graphics.PreferMultiSampling = true;
IsMouseVisible = true;
}
protected override void Initialize()
{
_imGuiRenderer = new ImGuiRenderer(this);
_imGuiRenderer.RebuildFontAtlas();
base.Initialize();
}
protected override void LoadContent()
{
// Texture loading example
// First, load the texture as a Texture2D (can also be done using the XNA/FNA content pipeline)
_xnaTexture = Texture2D.FromStream(GraphicsDevice, GenerateImage(300, 150));
// Then, bind it to an ImGui-friendly pointer, that we can use during regular ImGui.** calls (see below)
_imGuiTexture = _imGuiRenderer.BindTexture(_xnaTexture);
base.LoadContent();
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(new Color(clear_color.X, clear_color.Y, clear_color.Z));
// Call BeforeLayout first to set things up
_imGuiRenderer.BeforeLayout(gameTime);
// Draw our UI
ImGuiLayout();
// Call AfterLayout now to finish up and draw all the things
_imGuiRenderer.AfterLayout();
base.Draw(gameTime);
}
// Direct port of the example at https://github.com/ocornut/imgui/blob/master/examples/sdl_opengl2_example/main.cpp
private float f = 0.0f;
private bool show_test_window = false;
private bool show_another_window = false;
private Num.Vector3 clear_color = new Num.Vector3(114f / 255f, 144f / 255f, 154f / 255f);
private byte[] _textBuffer = new byte[100];
protected virtual void ImGuiLayout()
{
// 1. Show a simple window
// Tip: if we don't call ImGui.Begin()/ImGui.End() the widgets appears in a window automatically called "Debug"
{
ImGui.Text("Hello, world!");
ImGui.SliderFloat("float", ref f, 0.0f, 1.0f, null, 1f);
ImGui.ColorEdit3("clear color", ref clear_color);
if (ImGui.Button("Test Window")) show_test_window = !show_test_window;
if (ImGui.Button("Another Window")) show_another_window = !show_another_window;
ImGui.Text(string.Format("Application average {0:F3} ms/frame ({1:F1} FPS)", 1000f / ImGui.GetIO().Framerate, ImGui.GetIO().Framerate));
ImGui.InputText("Text input", _textBuffer, 100, InputTextFlags.Default, null);
ImGui.Text("Texture sample");
ImGui.Image(_imGuiTexture, new Num.Vector2(300, 150), Num.Vector2.Zero, Num.Vector2.One, Num.Vector4.One, Num.Vector4.One); // Here, the previously loaded texture is used
}
// 2. Show another simple window, this time using an explicit Begin/End pair
if (show_another_window)
{
ImGui.SetNextWindowSize(new Num.Vector2(200, 100), Condition.FirstUseEver);
ImGui.BeginWindow("Another Window", ref show_another_window, WindowFlags.Default);
ImGui.Text("Hello");
ImGui.EndWindow();
}
// 3. Show the ImGui test window. Most of the sample code is in ImGui.ShowTestWindow()
if (show_test_window)
{
ImGui.SetNextWindowPos(new Num.Vector2(650, 20), Condition.FirstUseEver);
ImGuiNative.igShowDemoWindow(ref show_test_window);
}
}
private static Stream GenerateImage(int width, int height)
{
var stream = new MemoryStream();
var random = new Random(42);
var bmp = new System.Drawing.Bitmap(width, height);
var graphics = System.Drawing.Graphics.FromImage(bmp);
graphics.Clear(System.Drawing.Color.Black);
for (int i = 0; i < 100; i++)
{
var size = random.Next(10, 50);
var pen = new System.Drawing.Pen(System.Drawing.Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)), random.Next(1, 4));
graphics.DrawEllipse(pen, random.Next(0, width), random.Next(0, height), size, size);
}
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Position = 0;
return stream;
}
}
}

@ -6,6 +6,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET", "ImGui.NET\ImGu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET.SampleProgram", "ImGui.NET.SampleProgram\ImGui.NET.SampleProgram.csproj", "{D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET.SampleProgram.XNA", "ImGui.NET.SampleProgram.XNA\ImGui.NET.SampleProgram.XNA.csproj", "{3024336E-9A19-475F-A95D-60A60C0B1C0D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -40,6 +42,18 @@ Global
{D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Release|x64.Build.0 = Release|Any CPU
{D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Release|x86.ActiveCfg = Release|Any CPU
{D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Release|x86.Build.0 = Release|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Debug|x64.ActiveCfg = Debug|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Debug|x64.Build.0 = Debug|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Debug|x86.ActiveCfg = Debug|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Debug|x86.Build.0 = Debug|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Release|Any CPU.Build.0 = Release|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Release|x64.ActiveCfg = Release|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Release|x64.Build.0 = Release|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Release|x86.ActiveCfg = Release|Any CPU
{3024336E-9A19-475F-A95D-60A60C0B1C0D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -121,6 +121,15 @@ namespace ImGuiNET
set { _nativePtr->KeyAlt = value ? (byte)1 : (byte)0; }
}
/// <summary>
/// Keyboard modifier pressed: Cmd/Super/Windows
/// </summary>
public bool SuperPressed
{
get { return _nativePtr->KeySuper == 1; }
set { _nativePtr->KeySuper = value ? (byte)1 : (byte)0; }
}
public bool WantCaptureMouse
{
get { return _nativePtr->WantCaptureMouse == 1; }

Loading…
Cancel
Save