334 lines
9.3 KiB
C#
334 lines
9.3 KiB
C#
using MoonWorks.Graphics;
|
|
using MoonWorks;
|
|
using ImGuiNET;
|
|
using System.Runtime.InteropServices;
|
|
using System.IO;
|
|
using MoonWorks.Input;
|
|
using MoonWorks.Math;
|
|
using System.Collections.Generic;
|
|
|
|
namespace MoonWorksImGuiExample
|
|
{
|
|
class MoonWorksImGuiExampleGame : Game
|
|
{
|
|
private string ContentPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Content");
|
|
|
|
private ImFontPtr DefaultFontPtr;
|
|
private int TextureID;
|
|
private System.IntPtr? FontTexturePtr;
|
|
private Dictionary<System.IntPtr, Texture> LoadedTextures = new Dictionary<System.IntPtr, Texture>();
|
|
private Dictionary<Texture, System.IntPtr> TextureHandles = new Dictionary<Texture, System.IntPtr>();
|
|
|
|
private uint VertexCount = 0;
|
|
private uint IndexCount = 0;
|
|
private Buffer ImGuiVertexBuffer = null;
|
|
private Buffer ImGuiIndexBuffer = null;
|
|
private GraphicsPipeline ImGuiPipeline;
|
|
private ShaderModule ImGuiVertexShader;
|
|
private ShaderModule ImGuiFragmentShader;
|
|
private Sampler ImGuiSampler;
|
|
|
|
private Texture WoodGrainTexture;
|
|
private System.IntPtr WoodGrainTexturePtr;
|
|
|
|
private System.Numerics.Vector3 ExampleColor;
|
|
|
|
public MoonWorksImGuiExampleGame(
|
|
WindowCreateInfo windowCreateInfo,
|
|
PresentMode presentMode,
|
|
bool debugMode
|
|
) : base(windowCreateInfo, presentMode, 60, debugMode)
|
|
{
|
|
ImGuiVertexShader = new ShaderModule(GraphicsDevice, Path.Combine(ContentPath, "ImGuiVert.spv"));
|
|
ImGuiFragmentShader = new ShaderModule(GraphicsDevice, Path.Combine(ContentPath, "ImGuiFrag.spv"));
|
|
ImGuiSampler = new Sampler(GraphicsDevice, SamplerCreateInfo.PointClamp);
|
|
|
|
ImGuiPipeline = new GraphicsPipeline(
|
|
GraphicsDevice,
|
|
new GraphicsPipelineCreateInfo
|
|
{
|
|
AttachmentInfo = new GraphicsPipelineAttachmentInfo(
|
|
new ColorAttachmentDescription(
|
|
GraphicsDevice.GetSwapchainFormat(Window),
|
|
ColorAttachmentBlendState.NonPremultiplied
|
|
)
|
|
),
|
|
DepthStencilState = DepthStencilState.Disable,
|
|
VertexShaderInfo = GraphicsShaderInfo.Create<Matrix4x4>(ImGuiVertexShader, "main", 0),
|
|
FragmentShaderInfo = GraphicsShaderInfo.Create(ImGuiFragmentShader, "main", 1),
|
|
VertexInputState = new VertexInputState(
|
|
VertexBinding.Create<VertexPositionTextureColor>(),
|
|
VertexAttribute.Create<VertexPositionTextureColor>("Position", 0),
|
|
VertexAttribute.Create<VertexPositionTextureColor>("Texture", 1),
|
|
VertexAttribute.Create<VertexPositionTextureColor>("Color", 2)
|
|
),
|
|
PrimitiveType = PrimitiveType.TriangleList,
|
|
RasterizerState = RasterizerState.CW_CullNone,
|
|
MultisampleState = MultisampleState.None
|
|
}
|
|
);
|
|
|
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
|
WoodGrainTexture = Texture.LoadPNG(GraphicsDevice, commandBuffer, Path.Combine(ContentPath, "woodgrain.png"));
|
|
GraphicsDevice.Submit(commandBuffer);
|
|
|
|
var context = ImGui.CreateContext();
|
|
ImGui.SetCurrentContext(context);
|
|
|
|
var io = ImGui.GetIO();
|
|
|
|
io.Fonts.AddFontDefault();
|
|
|
|
RebuildFontAtlas();
|
|
|
|
WoodGrainTexturePtr = BindTexture(WoodGrainTexture);
|
|
|
|
io.DisplaySize = new System.Numerics.Vector2(
|
|
windowCreateInfo.WindowWidth,
|
|
windowCreateInfo.WindowHeight
|
|
);
|
|
io.DisplayFramebufferScale = System.Numerics.Vector2.One;
|
|
}
|
|
|
|
protected override void Update(System.TimeSpan dt)
|
|
{
|
|
// Insert your game update logic here.
|
|
}
|
|
|
|
private System.IntPtr BindTexture(Texture texture)
|
|
{
|
|
var id = new System.IntPtr(TextureID);
|
|
LoadedTextures.Add(id, texture);
|
|
TextureHandles.Add(texture, id);
|
|
TextureID += 1;
|
|
return id;
|
|
}
|
|
|
|
private void UnbindTexture(System.IntPtr textureID)
|
|
{
|
|
var texture = LoadedTextures[textureID];
|
|
LoadedTextures.Remove(textureID);
|
|
TextureHandles.Remove(texture);
|
|
}
|
|
|
|
private void RebuildFontAtlas()
|
|
{
|
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
|
|
|
var io = ImGui.GetIO();
|
|
|
|
io.Fonts.GetTexDataAsRGBA32(
|
|
out System.IntPtr pixelData,
|
|
out int width,
|
|
out int height,
|
|
out int bytesPerPixel
|
|
);
|
|
|
|
var texture = Texture.CreateTexture2D(
|
|
GraphicsDevice,
|
|
(uint) width,
|
|
(uint) height,
|
|
TextureFormat.R8G8B8A8,
|
|
TextureUsageFlags.Sampler
|
|
);
|
|
|
|
commandBuffer.SetTextureData(texture, pixelData, (uint) (width * height * bytesPerPixel));
|
|
|
|
GraphicsDevice.Submit(commandBuffer);
|
|
|
|
if (FontTexturePtr.HasValue)
|
|
{
|
|
UnbindTexture(FontTexturePtr.Value);
|
|
}
|
|
|
|
FontTexturePtr = BindTexture(texture);
|
|
|
|
io.Fonts.SetTexID(FontTexturePtr.Value);
|
|
io.Fonts.ClearTexData();
|
|
}
|
|
|
|
private void UpdateImGuiBuffers(ImDrawDataPtr drawDataPtr)
|
|
{
|
|
if (drawDataPtr.TotalVtxCount == 0) { return; }
|
|
|
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
|
|
|
var vertexSize = Marshal.SizeOf<VertexPositionTextureColor>();
|
|
|
|
if (drawDataPtr.TotalVtxCount > VertexCount)
|
|
{
|
|
ImGuiVertexBuffer?.Dispose();
|
|
|
|
VertexCount = (uint) (drawDataPtr.TotalVtxCount * 1.5f);
|
|
ImGuiVertexBuffer = Buffer.Create<VertexPositionTextureColor>(
|
|
GraphicsDevice,
|
|
BufferUsageFlags.Vertex,
|
|
VertexCount
|
|
);
|
|
}
|
|
|
|
if (drawDataPtr.TotalIdxCount > IndexCount)
|
|
{
|
|
ImGuiIndexBuffer?.Dispose();
|
|
|
|
IndexCount = (uint) (drawDataPtr.TotalIdxCount * 1.5f);
|
|
ImGuiIndexBuffer = Buffer.Create<ushort>(
|
|
GraphicsDevice,
|
|
BufferUsageFlags.Index,
|
|
IndexCount
|
|
);
|
|
}
|
|
|
|
uint vertexOffset = 0;
|
|
uint indexOffset = 0;
|
|
|
|
for (var n = 0; n < drawDataPtr.CmdListsCount; n += 1)
|
|
{
|
|
var cmdList = drawDataPtr.CmdListsRange[n];
|
|
|
|
commandBuffer.SetBufferData<VertexPositionTextureColor>(
|
|
ImGuiVertexBuffer,
|
|
cmdList.VtxBuffer.Data,
|
|
vertexOffset,
|
|
(uint) cmdList.VtxBuffer.Size
|
|
);
|
|
|
|
commandBuffer.SetBufferData<ushort>(
|
|
ImGuiIndexBuffer,
|
|
cmdList.IdxBuffer.Data,
|
|
indexOffset,
|
|
(uint) cmdList.IdxBuffer.Size
|
|
);
|
|
|
|
vertexOffset += (uint) cmdList.VtxBuffer.Size;
|
|
indexOffset += (uint) cmdList.IdxBuffer.Size;
|
|
}
|
|
|
|
GraphicsDevice.Submit(commandBuffer);
|
|
}
|
|
|
|
private void RenderCommandLists(ImDrawDataPtr drawDataPtr, ImGuiIOPtr ioPtr)
|
|
{
|
|
if (ImGuiVertexBuffer == null) { return; }
|
|
|
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
|
var swapchainTexture = commandBuffer.AcquireSwapchainTexture(Window);
|
|
|
|
if (swapchainTexture != null)
|
|
{
|
|
commandBuffer.BeginRenderPass(
|
|
new ColorAttachmentInfo(swapchainTexture, Color.Transparent)
|
|
);
|
|
|
|
commandBuffer.BindGraphicsPipeline(ImGuiPipeline);
|
|
|
|
var vertexUniformOffset = commandBuffer.PushVertexShaderUniforms(
|
|
Matrix4x4.CreateOrthographicOffCenter(0, ioPtr.DisplaySize.X, ioPtr.DisplaySize.Y, 0, -1, 1)
|
|
);
|
|
|
|
commandBuffer.BindVertexBuffers(ImGuiVertexBuffer);
|
|
commandBuffer.BindIndexBuffer(ImGuiIndexBuffer, IndexElementSize.Sixteen);
|
|
|
|
uint vertexOffset = 0;
|
|
uint indexOffset = 0;
|
|
|
|
for (int n = 0; n < drawDataPtr.CmdListsCount; n += 1)
|
|
{
|
|
var cmdList = drawDataPtr.CmdListsRange[n];
|
|
|
|
for (int cmdIndex = 0; cmdIndex < cmdList.CmdBuffer.Size; cmdIndex += 1)
|
|
{
|
|
var drawCmd = cmdList.CmdBuffer[cmdIndex];
|
|
|
|
commandBuffer.BindFragmentSamplers(
|
|
new TextureSamplerBinding(LoadedTextures[drawCmd.TextureId], ImGuiSampler)
|
|
);
|
|
|
|
commandBuffer.DrawIndexedPrimitives(
|
|
vertexOffset,
|
|
indexOffset,
|
|
drawCmd.ElemCount / 3,
|
|
vertexUniformOffset,
|
|
0
|
|
);
|
|
|
|
indexOffset += drawCmd.ElemCount;
|
|
}
|
|
|
|
vertexOffset += (uint) cmdList.VtxBuffer.Size;
|
|
}
|
|
|
|
commandBuffer.EndRenderPass();
|
|
}
|
|
|
|
GraphicsDevice.Submit(commandBuffer);
|
|
}
|
|
|
|
protected override void Draw(System.TimeSpan dt, double alpha)
|
|
{
|
|
// Replace this with your own drawing code.
|
|
|
|
var io = ImGui.GetIO();
|
|
|
|
io.KeyShift = Inputs.Keyboard.IsDown(Keycode.LeftShift) || Inputs.Keyboard.IsDown(Keycode.RightShift);
|
|
io.KeyCtrl = Inputs.Keyboard.IsDown(Keycode.LeftControl) || Inputs.Keyboard.IsDown(Keycode.RightControl);
|
|
io.KeyAlt = Inputs.Keyboard.IsDown(Keycode.LeftAlt) || Inputs.Keyboard.IsDown(Keycode.RightAlt);
|
|
io.KeySuper = Inputs.Keyboard.IsDown(Keycode.LeftMeta) || Inputs.Keyboard.IsDown(Keycode.RightMeta);
|
|
io.KeyMap[(int) ImGuiKey.Backspace] = (int) Keycode.Backspace;
|
|
|
|
io.MousePos = new System.Numerics.Vector2(Inputs.Mouse.X, Inputs.Mouse.Y);
|
|
io.MouseDown[0] = Inputs.Mouse.LeftButton.IsDown;
|
|
io.MouseDown[1] = Inputs.Mouse.RightButton.IsDown;
|
|
io.MouseDown[2] = Inputs.Mouse.MiddleButton.IsDown;
|
|
io.MouseWheel = Inputs.Mouse.Wheel > 0 ? 1 : Inputs.Mouse.Wheel < 0 ? -1 : 0;
|
|
|
|
ImGui.NewFrame();
|
|
|
|
ImGui.SetNextWindowSize(new System.Numerics.Vector2(400, 200));
|
|
ImGui.Begin("Help");
|
|
ImGui.Columns(2);
|
|
|
|
ImGui.Text("F7");
|
|
ImGui.NextColumn();
|
|
ImGui.Text("Pause Action");
|
|
ImGui.NextColumn();
|
|
|
|
ImGui.Text("Ctrl-E");
|
|
ImGui.NextColumn();
|
|
ImGui.Text("Entity Search");
|
|
ImGui.NextColumn();
|
|
|
|
ImGui.Text("Left Click");
|
|
ImGui.NextColumn();
|
|
ImGui.Text("Inspect Entity");
|
|
ImGui.NextColumn();
|
|
|
|
ImGui.Text("Ctrl-H");
|
|
ImGui.NextColumn();
|
|
ImGui.Text("Help");
|
|
ImGui.NextColumn();
|
|
|
|
ImGui.End();
|
|
|
|
ImGui.Begin("Texture", ImGuiWindowFlags.AlwaysAutoResize);
|
|
ImGui.Image(WoodGrainTexturePtr, new System.Numerics.Vector2(400, 400));
|
|
ImGui.End();
|
|
|
|
ImGui.Begin("Color Picker", ImGuiWindowFlags.AlwaysAutoResize);
|
|
ImGui.ColorPicker3("Color", ref ExampleColor);
|
|
ImGui.End();
|
|
|
|
ImGui.Render();
|
|
|
|
var drawDataPtr = ImGui.GetDrawData();
|
|
UpdateImGuiBuffers(drawDataPtr);
|
|
RenderCommandLists(drawDataPtr, io);
|
|
}
|
|
|
|
protected override void OnDestroy()
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|