diff --git a/README.md b/README.md index 276713a..1e45230 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,31 @@ # ImGui.NET -This is a wrapper for the immediate mode GUI library, Dear ImGui (https://github.com/ocornut/imgui). This utilizes the C API, provided by the cimgui project (https://github.com/Extrawurst/cimgui). ImGui.NET lets you build graphical interfaces using a simple immediate-mode style. Included is a basic sample program that shows how to use the library, which renders the ImGui output using OpenGL via OpenTK. +This is a .NET wrapper for the immediate mode GUI library, Dear ImGui (https://github.com/ocornut/imgui). ImGui.NET lets you build graphical interfaces using a simple immediate-mode style. ImGui.NET is a .NET Standard library, and can be used on all major .NET runtimes and operating systems. -[![NuGet](https://img.shields.io/nuget/v/Veldrid.svg)](https://www.nuget.org/packages/ImGui.NET) +Included is a basic sample program that shows how to use the library, and renders the UI using [Veldrid](https://github.com/mellinoe/veldrid), a portable graphics library for .NET. By itself, Dear ImGui does not care what technology you use for rendering; it simply outputs textured triangles. Examples renderers also exist for MonoGame and OpenTK (OpenGL). + +This wrapper is built on top of [cimgui](https://github.com/Extrawurst/cimgui), which exposes a plain C API for Dear ImGui. If you are using Windows, OSX, or a mainline Linux distribution, then the ImGui.NET NuGet package comes bundled with a pre-built native library. If you are using another operating system, then you may need to build the native library yourself; see the cimgui repo for build instructions. -![alt tag](http://i.imgur.com/02RGlsW.png) +[![NuGet](https://img.shields.io/nuget/v/Veldrid.svg)](https://www.nuget.org/packages/ImGui.NET) # Building ImGui.NET can be built in Visual Studio or on the command line. The .NET Core SDK is needed to build on the command line, and it can be downloaded [here](https://www.microsoft.com/net/core). Visual Studio 2017 is the minimum VS version supported for building. # Usage + ImGui.NET currently provides a raw wrapper around the ImGui native API, and also provides a very thin safe, managed API for convenience. It is currently very much like using the native library, which is very simple, flexible, and robust. The easiest way to figure out how to use the library is to read the documentation of imgui itself, mostly in the imgui.cpp, and imgui.h files, as well as the exported functions in cimgui.h. Looking at the sample program code will also give some indication about basic usage. # See Also + https://github.com/ocornut/imgui -> ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and self-contained (no external dependencies). It is based on an "immediate mode" graphical user interface paradigm which enables you to build user interfaces with ease. +> Dear ImGui is a bloat-free graphical user interface library for C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies). + +> Dear ImGui is designed to enable fast iterations and to empower programmers to create content creation tools and visualization / debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and lacks certain features normally found in more high-level libraries. + +> Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard. + +See the [official screenshot thread](https://github.com/ocornut/imgui/issues/123) for examples of many different kinds of interfaces created with Dear ImGui. https://github.com/Extrawurst/cimgui > This is a thin c-api wrapper for the excellent C++ intermediate gui imgui. This library is intended as a intermediate layer to be able to use imgui from other languages that can interface with C . diff --git a/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj b/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj index 6b1f145..bb07cc0 100644 --- a/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj +++ b/src/ImGui.NET.SampleProgram/ImGui.NET.SampleProgram.csproj @@ -1,15 +1,32 @@ - + + - netcoreapp1.0 - true - ImGui.NET.SampleProgram Exe + netcoreapp2.0 + true + - - PreserveNewest - - + + + + + + + + + + + + + + + + + + + + diff --git a/src/ImGui.NET.SampleProgram/ImGuiController.cs b/src/ImGui.NET.SampleProgram/ImGuiController.cs new file mode 100644 index 0000000..f081f03 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/ImGuiController.cs @@ -0,0 +1,538 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Reflection; +using System.IO; +using Veldrid; + +namespace ImGuiNET +{ + /// + /// A modified version of Veldrid.ImGui's ImGuiRenderer. + /// Manages input for ImGui and handles rendering ImGui's DrawLists with Veldrid. + /// + public class ImGuiController : IDisposable + { + private GraphicsDevice _gd; + private bool _frameBegun; + + // Veldrid objects + private DeviceBuffer _vertexBuffer; + private DeviceBuffer _indexBuffer; + private DeviceBuffer _projMatrixBuffer; + private Texture _fontTexture; + private TextureView _fontTextureView; + private Shader _vertexShader; + private Shader _fragmentShader; + private ResourceLayout _layout; + private ResourceLayout _textureLayout; + private Pipeline _pipeline; + private ResourceSet _mainResourceSet; + private ResourceSet _fontTextureResourceSet; + + private IntPtr _fontAtlasID = (IntPtr)1; + private bool _controlDown; + private bool _shiftDown; + private bool _altDown; + + private int _windowWidth; + private int _windowHeight; + private Vector2 _scaleFactor = Vector2.One; + + // Image trackers + private readonly Dictionary _setsByView + = new Dictionary(); + private readonly Dictionary _autoViewsByTexture + = new Dictionary(); + private readonly Dictionary _viewsById = new Dictionary(); + private readonly List _ownedResources = new List(); + private int _lastAssignedID = 100; + + /// + /// Constructs a new ImGuiRenderer. + /// + public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height) + { + _gd = gd; + _windowWidth = width; + _windowHeight = height; + + ImGui.GetIO().FontAtlas.AddDefaultFont(); + + CreateDeviceResources(gd, outputDescription); + SetOpenTKKeyMappings(); + + SetPerFrameImGuiData(1f / 60f); + + ImGui.NewFrame(); + _frameBegun = true; + } + + public void WindowResized(int width, int height) + { + _windowWidth = width; + _windowHeight = height; + } + + public void DestroyDeviceObjects() + { + Dispose(); + } + + public void CreateDeviceResources(GraphicsDevice gd, OutputDescription outputDescription) + { + _gd = gd; + ResourceFactory factory = gd.ResourceFactory; + _vertexBuffer = factory.CreateBuffer(new BufferDescription(10000, BufferUsage.VertexBuffer | BufferUsage.Dynamic)); + _vertexBuffer.Name = "ImGui.NET Vertex Buffer"; + _indexBuffer = factory.CreateBuffer(new BufferDescription(2000, BufferUsage.IndexBuffer | BufferUsage.Dynamic)); + _indexBuffer.Name = "ImGui.NET Index Buffer"; + RecreateFontDeviceTexture(gd); + + _projMatrixBuffer = factory.CreateBuffer(new BufferDescription(64, BufferUsage.UniformBuffer | BufferUsage.Dynamic)); + _projMatrixBuffer.Name = "ImGui.NET Projection Buffer"; + + byte[] vertexShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-vertex", ShaderStages.Vertex); + byte[] fragmentShaderBytes = LoadEmbeddedShaderCode(gd.ResourceFactory, "imgui-frag", ShaderStages.Fragment); + _vertexShader = factory.CreateShader(new ShaderDescription(ShaderStages.Vertex, vertexShaderBytes, "VS")); + _fragmentShader = factory.CreateShader(new ShaderDescription(ShaderStages.Fragment, fragmentShaderBytes, "FS")); + + VertexLayoutDescription[] vertexLayouts = new VertexLayoutDescription[] + { + new VertexLayoutDescription( + new VertexElementDescription("in_position", VertexElementSemantic.Position, VertexElementFormat.Float2), + new VertexElementDescription("in_texCoord", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2), + new VertexElementDescription("in_color", VertexElementSemantic.Color, VertexElementFormat.Byte4_Norm)) + }; + + _layout = factory.CreateResourceLayout(new ResourceLayoutDescription( + new ResourceLayoutElementDescription("ProjectionMatrixBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex), + new ResourceLayoutElementDescription("MainSampler", ResourceKind.Sampler, ShaderStages.Fragment))); + _textureLayout = factory.CreateResourceLayout(new ResourceLayoutDescription( + new ResourceLayoutElementDescription("MainTexture", ResourceKind.TextureReadOnly, ShaderStages.Fragment))); + + GraphicsPipelineDescription pd = new GraphicsPipelineDescription( + BlendStateDescription.SingleAlphaBlend, + new DepthStencilStateDescription(false, false, ComparisonKind.Always), + new RasterizerStateDescription(FaceCullMode.None, PolygonFillMode.Solid, FrontFace.Clockwise, false, true), + PrimitiveTopology.TriangleList, + new ShaderSetDescription(vertexLayouts, new[] { _vertexShader, _fragmentShader }), + new ResourceLayout[] { _layout, _textureLayout }, + outputDescription); + _pipeline = factory.CreateGraphicsPipeline(ref pd); + + _mainResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_layout, + _projMatrixBuffer, + gd.PointSampler)); + + _fontTextureResourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, _fontTextureView)); + } + + /// + /// Gets or creates a handle for a texture to be drawn with ImGui. + /// Pass the returned handle to Image() or ImageButton(). + /// + public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, TextureView textureView) + { + if (!_setsByView.TryGetValue(textureView, out ResourceSetInfo rsi)) + { + ResourceSet resourceSet = factory.CreateResourceSet(new ResourceSetDescription(_textureLayout, textureView)); + rsi = new ResourceSetInfo(GetNextImGuiBindingID(), resourceSet); + + _setsByView.Add(textureView, rsi); + _viewsById.Add(rsi.ImGuiBinding, rsi); + _ownedResources.Add(resourceSet); + } + + return rsi.ImGuiBinding; + } + + private IntPtr GetNextImGuiBindingID() + { + int newID = _lastAssignedID++; + return (IntPtr)newID; + } + + /// + /// Gets or creates a handle for a texture to be drawn with ImGui. + /// Pass the returned handle to Image() or ImageButton(). + /// + public IntPtr GetOrCreateImGuiBinding(ResourceFactory factory, Texture texture) + { + if (!_autoViewsByTexture.TryGetValue(texture, out TextureView textureView)) + { + textureView = factory.CreateTextureView(texture); + _autoViewsByTexture.Add(texture, textureView); + _ownedResources.Add(textureView); + } + + return GetOrCreateImGuiBinding(factory, textureView); + } + + /// + /// Retrieves the shader texture binding for the given helper handle. + /// + public ResourceSet GetImageResourceSet(IntPtr imGuiBinding) + { + if (!_viewsById.TryGetValue(imGuiBinding, out ResourceSetInfo tvi)) + { + throw new InvalidOperationException("No registered ImGui binding with id " + imGuiBinding.ToString()); + } + + return tvi.ResourceSet; + } + + public void ClearCachedImageResources() + { + foreach (IDisposable resource in _ownedResources) + { + resource.Dispose(); + } + + _ownedResources.Clear(); + _setsByView.Clear(); + _viewsById.Clear(); + _autoViewsByTexture.Clear(); + _lastAssignedID = 100; + } + + private byte[] LoadEmbeddedShaderCode(ResourceFactory factory, string name, ShaderStages stage) + { + switch (factory.BackendType) + { + case GraphicsBackend.Direct3D11: + { + string resourceName = name + ".hlsl.bytes"; + return GetEmbeddedResourceBytes(resourceName); + } + case GraphicsBackend.OpenGL: + { + string resourceName = name + ".glsl"; + return GetEmbeddedResourceBytes(resourceName); + } + case GraphicsBackend.Vulkan: + { + string resourceName = name + ".spv"; + return GetEmbeddedResourceBytes(resourceName); + } + case GraphicsBackend.Metal: + { + string resourceName = name + ".metallib"; + return GetEmbeddedResourceBytes(resourceName); + } + default: + throw new NotImplementedException(); + } + } + + private byte[] GetEmbeddedResourceBytes(string resourceName) + { + Assembly assembly = typeof(ImGuiController).Assembly; + using (Stream s = assembly.GetManifestResourceStream(resourceName)) + { + byte[] ret = new byte[s.Length]; + s.Read(ret, 0, (int)s.Length); + return ret; + } + } + + /// + /// Recreates the device texture used to render text. + /// + public unsafe void RecreateFontDeviceTexture(GraphicsDevice gd) + { + IO io = ImGui.GetIO(); + // Build + FontTextureData textureData = io.FontAtlas.GetTexDataAsRGBA32(); + + // Store our identifier + io.FontAtlas.SetTexID(_fontAtlasID); + + _fontTexture = gd.ResourceFactory.CreateTexture(TextureDescription.Texture2D( + (uint)textureData.Width, + (uint)textureData.Height, + 1, + 1, + PixelFormat.R8_G8_B8_A8_UNorm, + TextureUsage.Sampled)); + _fontTexture.Name = "ImGui.NET Font Texture"; + gd.UpdateTexture( + _fontTexture, + (IntPtr)textureData.Pixels, + (uint)(textureData.BytesPerPixel * textureData.Width * textureData.Height), + 0, + 0, + 0, + (uint)textureData.Width, + (uint)textureData.Height, + 1, + 0, + 0); + _fontTextureView = gd.ResourceFactory.CreateTextureView(_fontTexture); + + io.FontAtlas.ClearTexData(); + } + + /// + /// Renders the ImGui draw list data. + /// This method requires a because it may create new DeviceBuffers if the size of vertex + /// or index data has increased beyond the capacity of the existing buffers. + /// A is needed to submit drawing and resource update commands. + /// + public unsafe void Render(GraphicsDevice gd, CommandList cl) + { + if (_frameBegun) + { + _frameBegun = false; + ImGui.Render(); + RenderImDrawData(ImGui.GetDrawData(), gd, cl); + } + } + + /// + /// Updates ImGui input and IO configuration state. + /// + public void Update(float deltaSeconds, InputSnapshot snapshot) + { + if (_frameBegun) + { + ImGui.Render(); + } + + SetPerFrameImGuiData(deltaSeconds); + UpdateImGuiInput(snapshot); + + _frameBegun = true; + ImGui.NewFrame(); + } + + /// + /// Sets per-frame data based on the associated window. + /// This is called by Update(float). + /// + private unsafe void SetPerFrameImGuiData(float deltaSeconds) + { + IO io = ImGui.GetIO(); + io.DisplaySize = new Vector2( + _windowWidth / _scaleFactor.X, + _windowHeight / _scaleFactor.Y); + io.DisplayFramebufferScale = _scaleFactor; + io.DeltaTime = deltaSeconds; // DeltaTime is in seconds. + } + + private unsafe void UpdateImGuiInput(InputSnapshot snapshot) + { + IO io = ImGui.GetIO(); + + Vector2 mousePosition = snapshot.MousePosition; + + io.MousePosition = mousePosition; + io.MouseDown[0] = snapshot.IsMouseDown(MouseButton.Left); + io.MouseDown[1] = snapshot.IsMouseDown(MouseButton.Right); + io.MouseDown[2] = snapshot.IsMouseDown(MouseButton.Middle); + + float delta = snapshot.WheelDelta; + io.MouseWheel = delta; + + ImGui.GetIO().MouseWheel = delta; + + IReadOnlyList keyCharPresses = snapshot.KeyCharPresses; + for (int i = 0; i < keyCharPresses.Count; i++) + { + char c = keyCharPresses[i]; + ImGui.AddInputCharacter(c); + } + + IReadOnlyList keyEvents = snapshot.KeyEvents; + for (int i = 0; i < keyEvents.Count; i++) + { + KeyEvent keyEvent = keyEvents[i]; + io.KeysDown[(int)keyEvent.Key] = keyEvent.Down; + if (keyEvent.Key == Key.ControlLeft) + { + _controlDown = keyEvent.Down; + } + if (keyEvent.Key == Key.ShiftLeft) + { + _shiftDown = keyEvent.Down; + } + if (keyEvent.Key == Key.AltLeft) + { + _altDown = keyEvent.Down; + } + } + + io.CtrlPressed = _controlDown; + io.AltPressed = _altDown; + io.ShiftPressed = _shiftDown; + } + + private static unsafe void SetOpenTKKeyMappings() + { + IO io = ImGui.GetIO(); + io.KeyMap[GuiKey.Tab] = (int)Key.Tab; + io.KeyMap[GuiKey.LeftArrow] = (int)Key.Left; + io.KeyMap[GuiKey.RightArrow] = (int)Key.Right; + io.KeyMap[GuiKey.UpArrow] = (int)Key.Up; + io.KeyMap[GuiKey.DownArrow] = (int)Key.Down; + io.KeyMap[GuiKey.PageUp] = (int)Key.PageUp; + io.KeyMap[GuiKey.PageDown] = (int)Key.PageDown; + io.KeyMap[GuiKey.Home] = (int)Key.Home; + io.KeyMap[GuiKey.End] = (int)Key.End; + io.KeyMap[GuiKey.Delete] = (int)Key.Delete; + io.KeyMap[GuiKey.Backspace] = (int)Key.BackSpace; + io.KeyMap[GuiKey.Enter] = (int)Key.Enter; + io.KeyMap[GuiKey.Escape] = (int)Key.Escape; + io.KeyMap[GuiKey.A] = (int)Key.A; + io.KeyMap[GuiKey.C] = (int)Key.C; + io.KeyMap[GuiKey.V] = (int)Key.V; + io.KeyMap[GuiKey.X] = (int)Key.X; + io.KeyMap[GuiKey.Y] = (int)Key.Y; + io.KeyMap[GuiKey.Z] = (int)Key.Z; + } + + private unsafe void RenderImDrawData(DrawData* draw_data, GraphicsDevice gd, CommandList cl) + { + uint vertexOffsetInVertices = 0; + uint indexOffsetInElements = 0; + + if (draw_data->CmdListsCount == 0) + { + return; + } + + uint totalVBSize = (uint)(draw_data->TotalVtxCount * sizeof(DrawVert)); + if (totalVBSize > _vertexBuffer.SizeInBytes) + { + gd.DisposeWhenIdle(_vertexBuffer); + _vertexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalVBSize * 1.5f), BufferUsage.VertexBuffer | BufferUsage.Dynamic)); + } + + uint totalIBSize = (uint)(draw_data->TotalIdxCount * sizeof(ushort)); + if (totalIBSize > _indexBuffer.SizeInBytes) + { + gd.DisposeWhenIdle(_indexBuffer); + _indexBuffer = gd.ResourceFactory.CreateBuffer(new BufferDescription((uint)(totalIBSize * 1.5f), BufferUsage.IndexBuffer | BufferUsage.Dynamic)); + } + + for (int i = 0; i < draw_data->CmdListsCount; i++) + { + NativeDrawList* cmd_list = draw_data->CmdLists[i]; + + cl.UpdateBuffer( + _vertexBuffer, + vertexOffsetInVertices * (uint)sizeof(DrawVert), + (IntPtr)cmd_list->VtxBuffer.Data, + (uint)(cmd_list->VtxBuffer.Size * sizeof(DrawVert))); + + cl.UpdateBuffer( + _indexBuffer, + indexOffsetInElements * (uint)sizeof(ushort), + (IntPtr)cmd_list->IdxBuffer.Data, + (uint)(cmd_list->IdxBuffer.Size * sizeof(ushort))); + + vertexOffsetInVertices += (uint)cmd_list->VtxBuffer.Size; + indexOffsetInElements += (uint)cmd_list->IdxBuffer.Size; + } + + // Setup orthographic projection matrix into our constant buffer + { + IO io = ImGui.GetIO(); + + Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter( + 0f, + io.DisplaySize.X, + io.DisplaySize.Y, + 0.0f, + -1.0f, + 1.0f); + + _gd.UpdateBuffer(_projMatrixBuffer, 0, ref mvp); + } + + cl.SetVertexBuffer(0, _vertexBuffer); + cl.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16); + cl.SetPipeline(_pipeline); + cl.SetGraphicsResourceSet(0, _mainResourceSet); + + ImGui.ScaleClipRects(draw_data, ImGui.GetIO().DisplayFramebufferScale); + + // Render command lists + int vtx_offset = 0; + int idx_offset = 0; + for (int n = 0; n < draw_data->CmdListsCount; n++) + { + NativeDrawList* cmd_list = draw_data->CmdLists[n]; + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + { + DrawCmd* pcmd = &(((DrawCmd*)cmd_list->CmdBuffer.Data)[cmd_i]); + if (pcmd->UserCallback != IntPtr.Zero) + { + throw new NotImplementedException(); + } + else + { + if (pcmd->TextureId != IntPtr.Zero) + { + if (pcmd->TextureId == _fontAtlasID) + { + cl.SetGraphicsResourceSet(1, _fontTextureResourceSet); + } + else + { + cl.SetGraphicsResourceSet(1, GetImageResourceSet(pcmd->TextureId)); + } + } + + cl.SetScissorRect( + 0, + (uint)pcmd->ClipRect.X, + (uint)pcmd->ClipRect.Y, + (uint)(pcmd->ClipRect.Z - pcmd->ClipRect.X), + (uint)(pcmd->ClipRect.W - pcmd->ClipRect.Y)); + + cl.DrawIndexed(pcmd->ElemCount, 1, (uint)idx_offset, vtx_offset, 0); + } + + idx_offset += (int)pcmd->ElemCount; + } + vtx_offset += cmd_list->VtxBuffer.Size; + } + } + + /// + /// Frees all graphics resources used by the renderer. + /// + public void Dispose() + { + _vertexBuffer.Dispose(); + _indexBuffer.Dispose(); + _projMatrixBuffer.Dispose(); + _fontTexture.Dispose(); + _fontTextureView.Dispose(); + _vertexShader.Dispose(); + _fragmentShader.Dispose(); + _layout.Dispose(); + _textureLayout.Dispose(); + _pipeline.Dispose(); + _mainResourceSet.Dispose(); + + foreach (IDisposable resource in _ownedResources) + { + resource.Dispose(); + } + } + + private struct ResourceSetInfo + { + public readonly IntPtr ImGuiBinding; + public readonly ResourceSet ResourceSet; + + public ResourceSetInfo(IntPtr imGuiBinding, ResourceSet resourceSet) + { + ImGuiBinding = imGuiBinding; + ResourceSet = resourceSet; + } + } + } +} diff --git a/src/ImGui.NET.SampleProgram/MemoryEditor.cs b/src/ImGui.NET.SampleProgram/MemoryEditor.cs index 1a60cef..5522518 100644 --- a/src/ImGui.NET.SampleProgram/MemoryEditor.cs +++ b/src/ImGui.NET.SampleProgram/MemoryEditor.cs @@ -57,6 +57,7 @@ namespace ImGuiNET public unsafe void Draw(string title, byte[] mem_data, int mem_size, int base_display_addr = 0) { + ImGui.SetNextWindowSize(new Vector2(500, 350), Condition.FirstUseEver); if (!ImGui.BeginWindow(title)) { ImGui.EndWindow(); @@ -155,7 +156,7 @@ namespace ImGuiNET { int data; if (TryHexParse(DataInput, out data)) - mem_data[addr] = (byte)data; + mem_data[addr] = (byte)data; } ImGui.PopID(); } @@ -196,7 +197,7 @@ namespace ImGuiNET } ImGui.Separator(); - + ImGuiNative.igAlignTextToFramePadding(); ImGui.PushItemWidth(50); ImGuiNative.igPushAllowKeyboardFocus(false); @@ -211,7 +212,7 @@ namespace ImGuiNET ImGuiNative.igPopAllowKeyboardFocus(); ImGui.PopItemWidth(); ImGui.SameLine(); - ImGui.Text(string.Format(" Range {0}..{1} ", FixedHex(base_display_addr, addr_digits_count), + ImGui.Text(string.Format(" Range {0}..{1} ", FixedHex(base_display_addr, addr_digits_count), FixedHex(base_display_addr + mem_size - 1, addr_digits_count))); ImGui.SameLine(); ImGui.PushItemWidth(70); @@ -232,7 +233,7 @@ namespace ImGuiNET } } ImGui.PopItemWidth(); - + ImGui.EndWindow(); } } @@ -268,4 +269,4 @@ namespace ImGuiNET } } } -} +} \ No newline at end of file diff --git a/src/ImGui.NET.SampleProgram/Program.cs b/src/ImGui.NET.SampleProgram/Program.cs index 953def4..2a8c47f 100644 --- a/src/ImGui.NET.SampleProgram/Program.cs +++ b/src/ImGui.NET.SampleProgram/Program.cs @@ -1,11 +1,121 @@ +using System; +using System.Linq; +using System.Numerics; +using Veldrid; +using Veldrid.Sdl2; +using Veldrid.StartupUtilities; + namespace ImGuiNET { - public class Program + class Program { - public static unsafe void Main(string[] args) + private static Sdl2Window _window; + private static GraphicsDevice _gd; + private static CommandList _cl; + private static ImGuiController _controller; + private static MemoryEditor _memoryEditor; + + // UI state + private static float _f = 0.0f; + private static int _counter = 0; + private static Vector3 _clearColor = new Vector3(0.45f, 0.55f, 0.6f); + private static bool _showDemoWindow = true; + private static bool _showAnotherWindow = false; + private static bool _showMemoryEditor = false; + private static byte[] _memoryEditorData; + + static void Main(string[] args) { - var window = new SampleWindow(); - window.RunWindowLoop(); + // Create window, GraphicsDevice, and all resources necessary for the demo. + VeldridStartup.CreateWindowAndGraphicsDevice( + new WindowCreateInfo(50, 50, 1280, 720, WindowState.Normal, "ImGui.NET Sample Program"), + new GraphicsDeviceOptions(true, null, true), + GraphicsBackend.Vulkan, + out _window, + out _gd); + _window.Resized += () => + { + _gd.MainSwapchain.Resize((uint)_window.Width, (uint)_window.Height); + _controller.WindowResized(_window.Width, _window.Height); + }; + _cl = _gd.ResourceFactory.CreateCommandList(); + _controller = new ImGuiController(_gd, _gd.MainSwapchain.Framebuffer.OutputDescription, _window.Width, _window.Height); + _memoryEditor = new MemoryEditor(); + Random random = new Random(); + _memoryEditorData = Enumerable.Range(0, 1024).Select(i => (byte)random.Next(255)).ToArray(); + + // Main application loop + while (_window.Exists) + { + InputSnapshot snapshot = _window.PumpEvents(); + if (!_window.Exists) { break; } + _controller.Update(1f / 60f, snapshot); // Feed the input events to our ImGui controller, which passes them through to ImGui. + + SubmitUI(); + + _cl.Begin(); + _cl.SetFramebuffer(_gd.MainSwapchain.Framebuffer); + _cl.ClearColorTarget(0, new RgbaFloat(_clearColor.X, _clearColor.Y, _clearColor.Z, 1f)); + _controller.Render(_gd, _cl); + _cl.End(); + _gd.SubmitCommands(_cl); + _gd.SwapBuffers(_gd.MainSwapchain); + } + + // Clean up Veldrid resources + _gd.WaitForIdle(); + _controller.Dispose(); + _cl.Dispose(); + _gd.Dispose(); + } + + private static void SubmitUI() + { + // Demo code adapted from the official Dear ImGui demo program: + // https://github.com/ocornut/imgui/blob/master/examples/example_win32_directx11/main.cpp#L172 + + // 1. Show a simple window. + // Tip: if we don't call ImGui.BeginWindow()/ImGui.EndWindow() the widgets automatically appears in a window called "Debug". + { + ImGui.Text("Hello, world!"); // Display some text (you can use a format string too) + ImGui.SliderFloat("float", ref _f, 0, 1, _f.ToString("0.000"), 1); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui.ColorEdit3("clear color", ref _clearColor); // Edit 3 floats representing a color + + ImGui.Checkbox("Demo Window", ref _showDemoWindow); // Edit bools storing our windows open/close state + ImGui.Checkbox("Another Window", ref _showAnotherWindow); + ImGui.Checkbox("Memory Editor", ref _showMemoryEditor); + + if (ImGui.Button("Button")) // Buttons return true when clicked (NB: most widgets return true when edited/activated) + _counter++; + ImGui.SameLine(); + ImGui.Text($"counter = {_counter}"); + + ImGui.Text($"Application average {1000.0f / ImGui.GetIO().Framerate:0.##} ms/frame ({ImGui.GetIO().Framerate:0.#} FPS)"); + } + + // 2. Show another simple window. In most cases you will use an explicit Begin/End pair to name your windows. + if (_showAnotherWindow) + { + ImGui.BeginWindow("Another Window", ref _showAnotherWindow, WindowFlags.Default); + ImGui.Text("Hello from another window!"); + if (ImGui.Button("Close Me")) + _showAnotherWindow = false; + ImGui.EndWindow(); + } + + // 3. Show the ImGui demo window. Most of the sample code is in ImGui.ShowDemoWindow(). Read its code to learn more about Dear ImGui! + if (_showDemoWindow) + { + // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. + // Here we just want to make the demo initial state a bit more friendly! + ImGui.SetNextWindowPos(new Vector2(650, 20), Condition.FirstUseEver); + ImGuiNative.igShowDemoWindow(ref _showDemoWindow); + } + + if (_showMemoryEditor) + { + _memoryEditor.Draw("Memory Editor", _memoryEditorData, _memoryEditorData.Length); + } } } -} \ No newline at end of file +} diff --git a/src/ImGui.NET.SampleProgram/Properties/launchSettings.json b/src/ImGui.NET.SampleProgram/Properties/launchSettings.json deleted file mode 100644 index 43e0c99..0000000 --- a/src/ImGui.NET.SampleProgram/Properties/launchSettings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "profiles": {} -} \ No newline at end of file diff --git a/src/ImGui.NET.SampleProgram/SampleWindow.cs b/src/ImGui.NET.SampleProgram/SampleWindow.cs deleted file mode 100644 index 93fa306..0000000 --- a/src/ImGui.NET.SampleProgram/SampleWindow.cs +++ /dev/null @@ -1,442 +0,0 @@ -using OpenTK; -using OpenTK.Graphics; -using OpenTK.Graphics.OpenGL; -using OpenTK.Input; -using System; -using System.Runtime.InteropServices; -using System.Threading; - -#if NETFRAMEWORK -using System.Drawing; -#endif - -namespace ImGuiNET -{ - public class SampleWindow - { - private OpenTK.NativeWindow _nativeWindow; - private GraphicsContext _graphicsContext; - private int s_fontTexture; - private int _pressCount; - private IntPtr _textInputBuffer; - private int _textInputBufferLength; - private float _wheelPosition; - private float _sliderVal; - private System.Numerics.Vector4 _buttonColor = new System.Numerics.Vector4(55f / 255f, 155f / 255f, 1f, 1f); - private bool _mainWindowOpened; - private static double s_desiredFrameLength = 1f / 60.0f; - private DateTime _previousFrameStartTime; - private float _scaleFactor; - private System.Numerics.Vector3 _positionValue = new System.Numerics.Vector3(500); - - private MemoryEditor _memoryEditor = new MemoryEditor(); - private byte[] _memoryEditorData; - - public unsafe SampleWindow() - { - int desiredWidth = 960, desiredHeight = 540; - _nativeWindow = new OpenTK.NativeWindow(desiredWidth, desiredHeight, "ImGui.NET", GameWindowFlags.Default, OpenTK.Graphics.GraphicsMode.Default, DisplayDevice.Default); - _scaleFactor = _nativeWindow.Width / desiredWidth; - - GraphicsContextFlags flags = GraphicsContextFlags.Default; - _graphicsContext = new GraphicsContext(GraphicsMode.Default, _nativeWindow.WindowInfo, 3, 0, flags); - _graphicsContext.MakeCurrent(_nativeWindow.WindowInfo); - ((IGraphicsContextInternal)_graphicsContext).LoadAll(); // wtf is this? - GL.ClearColor(Color.Black); - _nativeWindow.Visible = true; - _nativeWindow.X = _nativeWindow.X; // Work around OpenTK bug (?) on Ubuntu. - - _nativeWindow.KeyDown += OnKeyDown; - _nativeWindow.KeyUp += OnKeyUp; - _nativeWindow.KeyPress += OnKeyPress; - - ImGui.GetIO().FontAtlas.AddDefaultFont(); - - SetOpenTKKeyMappings(); - - _textInputBufferLength = 1024; - _textInputBuffer = Marshal.AllocHGlobal(_textInputBufferLength); - long* ptr = (long*)_textInputBuffer.ToPointer(); - for (int i = 0; i < 1024 / sizeof(long); i++) - { - ptr[i] = 0; - } - - _memoryEditorData = new byte[1024]; - var rnd = new Random(); - for (int i = 0; i < _memoryEditorData.Length; i++) - { - _memoryEditorData[i] = (byte) rnd.Next(255); - } - - CreateDeviceObjects(); - } - - private void OnKeyPress(object sender, KeyPressEventArgs e) - { - Console.Write("Char typed: " + e.KeyChar); - ImGui.AddInputCharacter(e.KeyChar); - } - - private static unsafe void SetOpenTKKeyMappings() - { - IO io = ImGui.GetIO(); - io.KeyMap[GuiKey.Tab] = (int)Key.Tab; - io.KeyMap[GuiKey.LeftArrow] = (int)Key.Left; - io.KeyMap[GuiKey.RightArrow] = (int)Key.Right; - io.KeyMap[GuiKey.UpArrow] = (int)Key.Up; - io.KeyMap[GuiKey.DownArrow] = (int)Key.Down; - io.KeyMap[GuiKey.PageUp] = (int)Key.PageUp; - io.KeyMap[GuiKey.PageDown] = (int)Key.PageDown; - io.KeyMap[GuiKey.Home] = (int)Key.Home; - io.KeyMap[GuiKey.End] = (int)Key.End; - io.KeyMap[GuiKey.Delete] = (int)Key.Delete; - io.KeyMap[GuiKey.Backspace] = (int)Key.BackSpace; - io.KeyMap[GuiKey.Enter] = (int)Key.Enter; - io.KeyMap[GuiKey.Escape] = (int)Key.Escape; - io.KeyMap[GuiKey.A] = (int)Key.A; - io.KeyMap[GuiKey.C] = (int)Key.C; - io.KeyMap[GuiKey.V] = (int)Key.V; - io.KeyMap[GuiKey.X] = (int)Key.X; - io.KeyMap[GuiKey.Y] = (int)Key.Y; - io.KeyMap[GuiKey.Z] = (int)Key.Z; - } - - private unsafe void OnKeyDown(object sender, KeyboardKeyEventArgs e) - { - ImGui.GetIO().KeysDown[(int)e.Key] = true; - UpdateModifiers(e); - } - - private unsafe void OnKeyUp(object sender, KeyboardKeyEventArgs e) - { - ImGui.GetIO().KeysDown[(int)e.Key] = false; - UpdateModifiers(e); - } - - private static unsafe void UpdateModifiers(KeyboardKeyEventArgs e) - { - IO io = ImGui.GetIO(); - io.AltPressed = e.Alt; - io.CtrlPressed = e.Control; - io.ShiftPressed = e.Shift; - } - - private unsafe void CreateDeviceObjects() - { - IO io = ImGui.GetIO(); - - // Build texture atlas - FontTextureData texData = io.FontAtlas.GetTexDataAsAlpha8(); - - // Create OpenGL texture - s_fontTexture = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, s_fontTexture); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); - GL.TexImage2D( - TextureTarget.Texture2D, - 0, - PixelInternalFormat.Alpha, - texData.Width, - texData.Height, - 0, - PixelFormat.Alpha, - PixelType.UnsignedByte, - new IntPtr(texData.Pixels)); - - // Store the texture identifier in the ImFontAtlas substructure. - io.FontAtlas.SetTexID(s_fontTexture); - - // Cleanup (don't clear the input data if you want to append new fonts later) - //io.Fonts->ClearInputData(); - io.FontAtlas.ClearTexData(); - GL.BindTexture(TextureTarget.Texture2D, 0); - } - - public void RunWindowLoop() - { - _nativeWindow.Visible = true; - while (_nativeWindow.Exists) - { - _previousFrameStartTime = DateTime.UtcNow; - - RenderFrame(); - - _nativeWindow.ProcessEvents(); - - DateTime afterFrameTime = DateTime.UtcNow; - double elapsed = (afterFrameTime - _previousFrameStartTime).TotalSeconds; - double sleepTime = s_desiredFrameLength - elapsed; - if (sleepTime > 0.0) - { - DateTime finishTime = afterFrameTime + TimeSpan.FromSeconds(sleepTime); - while (DateTime.UtcNow < finishTime) - { - Thread.Sleep(0); - } - } - } - } - - private unsafe void RenderFrame() - { - IO io = ImGui.GetIO(); - io.DisplaySize = new System.Numerics.Vector2(_nativeWindow.Width, _nativeWindow.Height); - io.DisplayFramebufferScale = new System.Numerics.Vector2(_scaleFactor); - io.DeltaTime = (1f / 60f); - - UpdateImGuiInput(io); - - ImGui.NewFrame(); - - SubmitImGuiStuff(); - - ImGui.Render(); - - DrawData* data = ImGui.GetDrawData(); - RenderImDrawData(data); - } - - private unsafe void SubmitImGuiStuff() - { - ImGui.GetStyle().WindowRounding = 0; - - ImGui.SetNextWindowSize(new System.Numerics.Vector2(_nativeWindow.Width - 10, _nativeWindow.Height - 20), Condition.Always); - ImGui.SetNextWindowPos(ImGui.GetIO().DisplaySize, Condition.Always, new System.Numerics.Vector2(1f)); - ImGui.BeginWindow("ImGUI.NET Sample Program", ref _mainWindowOpened, WindowFlags.NoResize | WindowFlags.NoTitleBar | WindowFlags.NoMove); - - ImGui.BeginMainMenuBar(); - if (ImGui.BeginMenu("Help")) - { - if (ImGui.MenuItem("About", "Ctrl-Alt-A", false, true)) - { - - } - ImGui.EndMenu(); - } - ImGui.EndMainMenuBar(); - - ImGui.Text("Hello,"); - ImGui.Text("World!"); - ImGui.Text("From ImGui.NET. ...Did that work?"); - var pos = ImGui.GetIO().MousePosition; - bool leftPressed = ImGui.GetIO().MouseDown[0]; - ImGui.Text("Current mouse position: " + pos + ". Pressed=" + leftPressed); - - ImGui.ShowStyleSelector("Select style"); - - if (ImGui.Button("Increment the counter.")) - { - _pressCount += 1; - } - - ImGui.Text($"Button pressed {_pressCount} times.", new System.Numerics.Vector4(0, 1, 1, 1)); - - ImGui.InputTextMultiline("Input some text:", - _textInputBuffer, (uint)_textInputBufferLength, - new System.Numerics.Vector2(360, 240), - InputTextFlags.Default, - OnTextEdited); - - ImGui.SliderFloat("SlidableValue", ref _sliderVal, -50f, 100f, $"{_sliderVal.ToString("##0.00")}", 1.0f); - ImGui.DragVector3("Vector3", ref _positionValue, -100, 100); - - if (ImGui.TreeNode("First Item")) - { - ImGui.Text("Word!"); - ImGui.TreePop(); - } - if (ImGui.TreeNode("Second Item")) - { - ImGui.ColorButton("Color button", _buttonColor, ColorEditFlags.Default, new System.Numerics.Vector2(0, 0)); - if (ImGui.Button("Push me to change color", new System.Numerics.Vector2(0, 30))) - { - _buttonColor = new System.Numerics.Vector4(_buttonColor.Y + .25f, _buttonColor.Z, _buttonColor.X, _buttonColor.W); - if (_buttonColor.X > 1.0f) - { - _buttonColor.X -= 1.0f; - } - } - - ImGui.TreePop(); - } - - if (ImGui.Button("Press me!", new System.Numerics.Vector2(100, 30))) - { - ImGuiNative.igOpenPopup("SmallButtonPopup"); - } - - if (ImGui.BeginPopup("SmallButtonPopup")) - { - ImGui.Text("Here's a popup menu."); - ImGui.Text("With two lines."); - - ImGui.EndPopup(); - } - - if (ImGui.Button("Open Modal window")) - { - ImGui.OpenPopup("ModalPopup"); - } - if (ImGui.BeginPopupModal("ModalPopup")) - { - ImGui.Text("You can't press on anything else right now."); - ImGui.Text("You are stuck here."); - if (ImGui.Button("OK", new System.Numerics.Vector2(0, 0))) { } - ImGui.SameLine(); - ImGui.Dummy(100f, 0f); - ImGui.SameLine(); - if (ImGui.Button("Please go away", new System.Numerics.Vector2(0, 0))) { ImGui.CloseCurrentPopup(); } - - ImGui.EndPopup(); - } - - ImGui.Text("I have a context menu."); - if (ImGui.BeginPopupContextItem("ItemContextMenu")) - { - if (ImGui.Selectable("How's this for a great menu?")) { } - ImGui.Selectable("Just click somewhere to get rid of me."); - ImGui.EndPopup(); - } - - ImGui.Text("ProgressBar:"); - ImGui.ProgressBar(0.5f, new System.Numerics.Vector2(300, 20), "50%"); - - ImGui.EndWindow(); - - _memoryEditor.Draw("Memory editor", _memoryEditorData, _memoryEditorData.Length); - - if (ImGui.GetIO().AltPressed && ImGui.GetIO().KeysDown[(int)Key.F4]) - { - _nativeWindow.Close(); - } - } - - private unsafe int OnTextEdited(TextEditCallbackData* data) - { - char currentEventChar = (char)data->EventChar; - return 0; - } - - private unsafe void UpdateImGuiInput(IO io) - { - MouseState cursorState = Mouse.GetCursorState(); - MouseState mouseState = Mouse.GetState(); - - if (_nativeWindow.Focused) - { - Point windowPoint = _nativeWindow.PointToClient(new Point(cursorState.X, cursorState.Y)); - io.MousePosition = new System.Numerics.Vector2(windowPoint.X / io.DisplayFramebufferScale.X, windowPoint.Y / io.DisplayFramebufferScale.Y); - } - else - { - io.MousePosition = new System.Numerics.Vector2(-1f, -1f); - } - - io.MouseDown[0] = mouseState.LeftButton == ButtonState.Pressed; - io.MouseDown[1] = mouseState.RightButton == ButtonState.Pressed; - io.MouseDown[2] = mouseState.MiddleButton == ButtonState.Pressed; - - float newWheelPos = mouseState.WheelPrecise; - float delta = newWheelPos - _wheelPosition; - _wheelPosition = newWheelPos; - io.MouseWheel = delta; - } - - private unsafe void RenderImDrawData(DrawData* draw_data) - { - // Rendering - int display_w, display_h; - display_w = _nativeWindow.Width; - display_h = _nativeWindow.Height; - - Vector4 clear_color = new Vector4(114f / 255f, 144f / 255f, 154f / 255f, 1.0f); - GL.Viewport(0, 0, display_w, display_h); - GL.ClearColor(clear_color.X, clear_color.Y, clear_color.Z, clear_color.W); - GL.Clear(ClearBufferMask.ColorBufferBit); - - // We are using the OpenGL fixed pipeline to make the example code simpler to read! - // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, vertex/texcoord/color pointers. - int last_texture; - GL.GetInteger(GetPName.TextureBinding2D, out last_texture); - GL.PushAttrib(AttribMask.EnableBit | AttribMask.ColorBufferBit | AttribMask.TransformBit); - GL.Enable(EnableCap.Blend); - GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); - GL.Disable(EnableCap.CullFace); - GL.Disable(EnableCap.DepthTest); - GL.Enable(EnableCap.ScissorTest); - GL.EnableClientState(ArrayCap.VertexArray); - GL.EnableClientState(ArrayCap.TextureCoordArray); - GL.EnableClientState(ArrayCap.ColorArray); - GL.Enable(EnableCap.Texture2D); - - GL.UseProgram(0); - - // Handle cases of screen coordinates != from framebuffer coordinates (e.g. retina displays) - IO io = ImGui.GetIO(); - ImGui.ScaleClipRects(draw_data, io.DisplayFramebufferScale); - - // Setup orthographic projection matrix - GL.MatrixMode(MatrixMode.Projection); - GL.PushMatrix(); - GL.LoadIdentity(); - GL.Ortho( - 0.0f, - io.DisplaySize.X / io.DisplayFramebufferScale.X, - io.DisplaySize.Y / io.DisplayFramebufferScale.Y, - 0.0f, - -1.0f, - 1.0f); - GL.MatrixMode(MatrixMode.Modelview); - GL.PushMatrix(); - GL.LoadIdentity(); - - // Render command lists - - for (int n = 0; n < draw_data->CmdListsCount; n++) - { - NativeDrawList* cmd_list = draw_data->CmdLists[n]; - byte* vtx_buffer = (byte*)cmd_list->VtxBuffer.Data; - ushort* idx_buffer = (ushort*)cmd_list->IdxBuffer.Data; - - GL.VertexPointer(2, VertexPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.PosOffset)); - GL.TexCoordPointer(2, TexCoordPointerType.Float, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.UVOffset)); - GL.ColorPointer(4, ColorPointerType.UnsignedByte, sizeof(DrawVert), new IntPtr(vtx_buffer + DrawVert.ColOffset)); - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { - DrawCmd* pcmd = &(((DrawCmd*)cmd_list->CmdBuffer.Data)[cmd_i]); - if (pcmd->UserCallback != IntPtr.Zero) - { - throw new NotImplementedException(); - } - else - { - GL.BindTexture(TextureTarget.Texture2D, pcmd->TextureId.ToInt32()); - GL.Scissor( - (int)pcmd->ClipRect.X, - (int)(io.DisplaySize.Y - pcmd->ClipRect.W), - (int)(pcmd->ClipRect.Z - pcmd->ClipRect.X), - (int)(pcmd->ClipRect.W - pcmd->ClipRect.Y)); - GL.DrawElements(PrimitiveType.Triangles, (int)pcmd->ElemCount, DrawElementsType.UnsignedShort, new IntPtr(idx_buffer)); - } - idx_buffer += pcmd->ElemCount; - } - } - - // Restore modified state - GL.DisableClientState(ArrayCap.ColorArray); - GL.DisableClientState(ArrayCap.TextureCoordArray); - GL.DisableClientState(ArrayCap.VertexArray); - GL.BindTexture(TextureTarget.Texture2D, last_texture); - GL.MatrixMode(MatrixMode.Modelview); - GL.PopMatrix(); - GL.MatrixMode(MatrixMode.Projection); - GL.PopMatrix(); - GL.PopAttrib(); - - _graphicsContext.SwapBuffers(); - } - } -} diff --git a/src/ImGui.NET.SampleProgram/Shaders/GLSL/imgui-frag.glsl b/src/ImGui.NET.SampleProgram/Shaders/GLSL/imgui-frag.glsl new file mode 100644 index 0000000..85e5ee9 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/GLSL/imgui-frag.glsl @@ -0,0 +1,13 @@ +#version 330 core + +uniform sampler2D FontTexture; + +in vec4 color; +in vec2 texCoord; + +out vec4 outputColor; + +void main() +{ + outputColor = color * texture(FontTexture, texCoord); +} diff --git a/src/ImGui.NET.SampleProgram/Shaders/GLSL/imgui-vertex.glsl b/src/ImGui.NET.SampleProgram/Shaders/GLSL/imgui-vertex.glsl new file mode 100644 index 0000000..997ce0d --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/GLSL/imgui-vertex.glsl @@ -0,0 +1,20 @@ +#version 330 core + +uniform ProjectionMatrixBuffer +{ + mat4 projection_matrix; +}; + +in vec2 in_position; +in vec2 in_texCoord; +in vec4 in_color; + +out vec4 color; +out vec2 texCoord; + +void main() +{ + gl_Position = projection_matrix * vec4(in_position, 0, 1); + color = in_color; + texCoord = in_texCoord; +} diff --git a/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-frag.hlsl b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-frag.hlsl new file mode 100644 index 0000000..63d175f --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-frag.hlsl @@ -0,0 +1,15 @@ +struct PS_INPUT +{ + float4 pos : SV_POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +Texture2D FontTexture : register(t0); +sampler FontSampler : register(s0); + +float4 FS(PS_INPUT input) : SV_Target +{ + float4 out_col = input.col * FontTexture.Sample(FontSampler, input.uv); + return out_col; +} \ No newline at end of file diff --git a/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-frag.hlsl.bytes b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-frag.hlsl.bytes new file mode 100644 index 0000000..2a9fbf5 Binary files /dev/null and b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-frag.hlsl.bytes differ diff --git a/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-vertex.hlsl b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-vertex.hlsl new file mode 100644 index 0000000..55793c1 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-vertex.hlsl @@ -0,0 +1,27 @@ +cbuffer ProjectionMatrixBuffer : register(b0) +{ + float4x4 ProjectionMatrix; +}; + +struct VS_INPUT +{ + float2 pos : POSITION; + float2 uv : TEXCOORD0; + float4 col : COLOR0; +}; + +struct PS_INPUT +{ + float4 pos : SV_POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +PS_INPUT VS(VS_INPUT input) +{ + PS_INPUT output; + output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f)); + output.col = input.col; + output.uv = input.uv; + return output; +} \ No newline at end of file diff --git a/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-vertex.hlsl.bytes b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-vertex.hlsl.bytes new file mode 100644 index 0000000..572a045 Binary files /dev/null and b/src/ImGui.NET.SampleProgram/Shaders/HLSL/imgui-vertex.hlsl.bytes differ diff --git a/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-frag.metal b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-frag.metal new file mode 100644 index 0000000..ff3cbe6 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-frag.metal @@ -0,0 +1,18 @@ +#include +using namespace metal; + +struct PS_INPUT +{ + float4 pos [[ position ]]; + float4 col; + float2 uv; +}; + +fragment float4 FS( + PS_INPUT input [[ stage_in ]], + texture2d FontTexture [[ texture(0) ]], + sampler FontSampler [[ sampler(0) ]]) +{ + float4 out_col = input.col * FontTexture.sample(FontSampler, input.uv); + return out_col; +} \ No newline at end of file diff --git a/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-frag.metallib b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-frag.metallib new file mode 100644 index 0000000..18a3d73 Binary files /dev/null and b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-frag.metallib differ diff --git a/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-vertex.metal b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-vertex.metal new file mode 100644 index 0000000..73d649e --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-vertex.metal @@ -0,0 +1,27 @@ +#include +using namespace metal; + +struct VS_INPUT +{ + float2 pos [[ attribute(0) ]]; + float2 uv [[ attribute(1) ]]; + float4 col [[ attribute(2) ]]; +}; + +struct PS_INPUT +{ + float4 pos [[ position ]]; + float4 col; + float2 uv; +}; + +vertex PS_INPUT VS( + VS_INPUT input [[ stage_in ]], + constant float4x4 &ProjectionMatrix [[ buffer(1) ]]) +{ + PS_INPUT output; + output.pos = ProjectionMatrix * float4(input.pos.xy, 0.f, 1.f); + output.col = input.col; + output.uv = input.uv; + return output; +} \ No newline at end of file diff --git a/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-vertex.metallib b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-vertex.metallib new file mode 100644 index 0000000..2998b94 Binary files /dev/null and b/src/ImGui.NET.SampleProgram/Shaders/Metal/imgui-vertex.metallib differ diff --git a/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/generate-spirv.bat b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/generate-spirv.bat new file mode 100644 index 0000000..62d1d99 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/generate-spirv.bat @@ -0,0 +1,2 @@ +glslangvalidator -V imgui-vertex.glsl -o imgui-vertex.spv -S vert +glslangvalidator -V imgui-frag.glsl -o imgui-frag.spv -S frag diff --git a/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-frag.glsl b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-frag.glsl new file mode 100644 index 0000000..2d1c1d7 --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-frag.glsl @@ -0,0 +1,16 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout(set = 1, binding = 0) uniform texture2D FontTexture; +layout(set = 0, binding = 1) uniform sampler FontSampler; + +layout (location = 0) in vec4 color; +layout (location = 1) in vec2 texCoord; +layout (location = 0) out vec4 outputColor; + +void main() +{ + outputColor = color * texture(sampler2D(FontTexture, FontSampler), texCoord); +} diff --git a/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-frag.spv b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-frag.spv new file mode 100644 index 0000000..c8d71cc Binary files /dev/null and b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-frag.spv differ diff --git a/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-vertex.glsl b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-vertex.glsl new file mode 100644 index 0000000..6fdab3f --- /dev/null +++ b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-vertex.glsl @@ -0,0 +1,29 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec2 vsin_position; +layout (location = 1) in vec2 vsin_texCoord; +layout (location = 2) in vec4 vsin_color; + +layout (binding = 0) uniform Projection +{ + mat4 projection; +}; + +layout (location = 0) out vec4 vsout_color; +layout (location = 1) out vec2 vsout_texCoord; + +out gl_PerVertex +{ + vec4 gl_Position; +}; + +void main() +{ + gl_Position = projection * vec4(vsin_position, 0, 1); + vsout_color = vsin_color; + vsout_texCoord = vsin_texCoord; + gl_Position.y = -gl_Position.y; +} diff --git a/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-vertex.spv b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-vertex.spv new file mode 100644 index 0000000..795cd0e Binary files /dev/null and b/src/ImGui.NET.SampleProgram/Shaders/SPIR-V/imgui-vertex.spv differ diff --git a/src/ImGui.NET.SampleProgram/imgui.ini b/src/ImGui.NET.SampleProgram/imgui.ini deleted file mode 100644 index ee42db4..0000000 --- a/src/ImGui.NET.SampleProgram/imgui.ini +++ /dev/null @@ -1,15 +0,0 @@ -[Debug] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[ImGUI.NET Sample Program] -Pos=5,10 -Size=950,520 -Collapsed=0 - -[Memory editor] -Pos=210,80 -Size=594,403 -Collapsed=0 - diff --git a/src/ImGui.NET.sln b/src/ImGui.NET.sln index a4d7c7a..770d4ff 100644 --- a/src/ImGui.NET.sln +++ b/src/ImGui.NET.sln @@ -1,28 +1,50 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.27130.2036 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET", "ImGui.NET\ImGui.NET.csproj", "{AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET.SampleProgram", "ImGui.NET.SampleProgram\ImGui.NET.SampleProgram.csproj", "{0FBA4057-7708-4FCC-B0D2-D049E647DC5A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImGui.NET.SampleProgram", "ImGui.NET.SampleProgram\ImGui.NET.SampleProgram.csproj", "{D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|x64.ActiveCfg = Debug|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|x64.Build.0 = Debug|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|x86.ActiveCfg = Debug|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Debug|x86.Build.0 = Debug|Any CPU {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Release|Any CPU.Build.0 = Release|Any CPU - {0FBA4057-7708-4FCC-B0D2-D049E647DC5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0FBA4057-7708-4FCC-B0D2-D049E647DC5A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0FBA4057-7708-4FCC-B0D2-D049E647DC5A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0FBA4057-7708-4FCC-B0D2-D049E647DC5A}.Release|Any CPU.Build.0 = Release|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Release|x64.ActiveCfg = Release|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Release|x64.Build.0 = Release|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Release|x86.ActiveCfg = Release|Any CPU + {AD548A1D-01B2-410E-B3ED-ADAC05C3C4A3}.Release|x86.Build.0 = Release|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Debug|x64.ActiveCfg = Debug|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Debug|x64.Build.0 = Debug|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Debug|x86.ActiveCfg = Debug|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Debug|x86.Build.0 = Debug|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Release|Any CPU.Build.0 = Release|Any CPU + {D6F62D30-7A37-43A1-BD5B-BE9A3D6F964C}.Release|x64.ActiveCfg = Release|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8B446794-E0C0-469F-ACC9-6650375F8BCF} + EndGlobalSection EndGlobal diff --git a/src/ImGui.NET/IO.cs b/src/ImGui.NET/IO.cs index 4f8ba05..546ad3f 100644 --- a/src/ImGui.NET/IO.cs +++ b/src/ImGui.NET/IO.cs @@ -138,6 +138,12 @@ namespace ImGuiNET get { return _nativePtr->WantTextInput == 1; } set { _nativePtr->WantTextInput = value ? (byte)1 : (byte)0; } } + + public float Framerate + { + get { return _nativePtr->Framerate; } + set { _nativePtr->Framerate = value; } + } } public unsafe class KeyMap diff --git a/src/ImGui.NET/ImGui.cs b/src/ImGui.NET/ImGui.cs index 452d81c..605092b 100644 --- a/src/ImGui.NET/ImGui.cs +++ b/src/ImGui.NET/ImGui.cs @@ -491,6 +491,11 @@ namespace ImGuiNET ImGuiNative.igSetNextWindowFocus(); } + public static void SetNextWindowPos(Vector2 position, Condition condition) + { + ImGuiNative.igSetNextWindowPos(position, condition, Vector2.Zero); + } + public static void SetNextWindowPos(Vector2 position, Condition condition, Vector2 pivot) { ImGuiNative.igSetNextWindowPos(position, condition, pivot);