Init.
This commit is contained in:
320
Source/ImGuiRenderLayer.cs
Executable file
320
Source/ImGuiRenderLayer.cs
Executable file
@@ -0,0 +1,320 @@
|
||||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
using Raylib_cs;
|
||||
|
||||
using DaggerFramework.Rendering;
|
||||
|
||||
namespace DaggerFramework
|
||||
{
|
||||
public class ImGuiRenderLayer : Layer
|
||||
{
|
||||
protected override void OnDraw(ref Renderer renderer)
|
||||
{
|
||||
Layout();
|
||||
_controller.Draw(ref renderer);
|
||||
}
|
||||
|
||||
protected virtual void Layout() { }
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
_controller = new ImGuiController();
|
||||
_controller.Load(Scene.Renderer.WindowSize);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(double dt)
|
||||
{
|
||||
_controller.Update(dt, Input);
|
||||
}
|
||||
|
||||
private ImGuiController _controller;
|
||||
}
|
||||
|
||||
public class ImGuiController : IDisposable, IDrawable
|
||||
{
|
||||
public ImGuiController()
|
||||
{
|
||||
_context = ImGui.CreateContext();
|
||||
ImGui.SetCurrentContext(_context);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
ImGui.DestroyContext();
|
||||
}
|
||||
|
||||
public void Load(Vector2 size)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
io.Fonts.AddFontDefault();
|
||||
|
||||
Resize(size);
|
||||
LoadFontTexture();
|
||||
SetupInput();
|
||||
ImGui.NewFrame();
|
||||
}
|
||||
|
||||
unsafe void LoadFontTexture()
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
io.Fonts.GetTexDataAsRGBA32(out byte* pixels, out int width, out int height);
|
||||
|
||||
// TODO: use engine API instead of Raylib.
|
||||
Image image = new Image
|
||||
{
|
||||
data = pixels,
|
||||
width = width,
|
||||
height = height,
|
||||
mipmaps = 1,
|
||||
format = PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
|
||||
};
|
||||
_fontTexture = Raylib.LoadTextureFromImage(image);
|
||||
|
||||
io.Fonts.SetTexID(new IntPtr(_fontTexture.id));
|
||||
io.Fonts.ClearTexData();
|
||||
}
|
||||
|
||||
private void SetupInput()
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
|
||||
// Setup config flags
|
||||
io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard;
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
io.BackendFlags |= ImGuiBackendFlags.HasMouseCursors;
|
||||
io.BackendFlags |= ImGuiBackendFlags.HasSetMousePos;
|
||||
|
||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[(int)ImGuiKey.Tab] = (int)KeyboardKey.Tab;
|
||||
io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)KeyboardKey.Left;
|
||||
io.KeyMap[(int)ImGuiKey.RightArrow] = (int)KeyboardKey.Right;
|
||||
io.KeyMap[(int)ImGuiKey.UpArrow] = (int)KeyboardKey.Up;
|
||||
io.KeyMap[(int)ImGuiKey.DownArrow] = (int)KeyboardKey.Down;
|
||||
io.KeyMap[(int)ImGuiKey.PageUp] = (int)KeyboardKey.PageUp;
|
||||
io.KeyMap[(int)ImGuiKey.PageDown] = (int)KeyboardKey.PageDown;
|
||||
io.KeyMap[(int)ImGuiKey.Home] = (int)KeyboardKey.Home;
|
||||
io.KeyMap[(int)ImGuiKey.End] = (int)KeyboardKey.End;
|
||||
io.KeyMap[(int)ImGuiKey.Insert] = (int)KeyboardKey.Insert;
|
||||
io.KeyMap[(int)ImGuiKey.Delete] = (int)KeyboardKey.Delete;
|
||||
io.KeyMap[(int)ImGuiKey.Backspace] = (int)KeyboardKey.Backspace;
|
||||
io.KeyMap[(int)ImGuiKey.Space] = (int)KeyboardKey.Spacebar;
|
||||
io.KeyMap[(int)ImGuiKey.Enter] = (int)KeyboardKey.Enter;
|
||||
io.KeyMap[(int)ImGuiKey.Escape] = (int)KeyboardKey.Escape;
|
||||
io.KeyMap[(int)ImGuiKey.A] = (int)KeyboardKey.A;
|
||||
io.KeyMap[(int)ImGuiKey.C] = (int)KeyboardKey.C;
|
||||
io.KeyMap[(int)ImGuiKey.V] = (int)KeyboardKey.V;
|
||||
io.KeyMap[(int)ImGuiKey.X] = (int)KeyboardKey.X;
|
||||
io.KeyMap[(int)ImGuiKey.Y] = (int)KeyboardKey.Y;
|
||||
io.KeyMap[(int)ImGuiKey.Z] = (int)KeyboardKey.Z;
|
||||
}
|
||||
|
||||
public void Resize(Vector2 size)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
io.DisplaySize = size / _scaleFactor;
|
||||
}
|
||||
|
||||
public void Update(double dt, InputHandler input)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
|
||||
io.DisplayFramebufferScale = Vector2.One;
|
||||
io.DeltaTime = (float)dt;
|
||||
|
||||
UpdateKeyboard(input);
|
||||
UpdateMouse(input);
|
||||
|
||||
ImGui.NewFrame();
|
||||
}
|
||||
|
||||
private void UpdateKeyboard(InputHandler input)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
|
||||
// Modifiers are not reliable across systems
|
||||
io.KeyCtrl = io.KeysDown[(int)KeyboardKey.LeftControl] || io.KeysDown[(int)KeyboardKey.RightControl];
|
||||
io.KeyShift = io.KeysDown[(int)KeyboardKey.LeftShift] || io.KeysDown[(int)KeyboardKey.RightShift];
|
||||
io.KeyAlt = io.KeysDown[(int)KeyboardKey.LeftAlt] || io.KeysDown[(int)KeyboardKey.RightAlt];
|
||||
io.KeySuper = io.KeysDown[(int)KeyboardKey.LeftSuper] || io.KeysDown[(int)KeyboardKey.RightSuper];
|
||||
|
||||
// Key states
|
||||
for (int i = (int)KeyboardKey.Spacebar; i < (int)KeyboardKey.KBMenu + 1; i++)
|
||||
{
|
||||
io.KeysDown[i] = input.IsKeyboardKeyDown((KeyboardKey)i);
|
||||
}
|
||||
|
||||
// Key input
|
||||
int keyPressed = input.GetCharPressed();
|
||||
if (keyPressed != 0)
|
||||
{
|
||||
io.AddInputCharacter((uint)keyPressed);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMouse(InputHandler input)
|
||||
{
|
||||
ImGuiIOPtr io = ImGui.GetIO();
|
||||
|
||||
// Store button states
|
||||
for (int i = 0; i < io.MouseDown.Count; i++)
|
||||
{
|
||||
io.MouseDown[i] = input.IsMouseButtonDown((MouseButton)i);
|
||||
}
|
||||
|
||||
// Mouse scroll
|
||||
io.MouseWheel += input.GetMouseWheelMovement();
|
||||
|
||||
// Mouse position
|
||||
Vector2 mousePosition = io.MousePos;
|
||||
// TODO:
|
||||
// bool focused = Raylib.IsWindowFocused();
|
||||
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
input.SetMousePosition(mousePosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
io.MousePos = input.GetMousePosition();
|
||||
}
|
||||
|
||||
// Mouse cursor state
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags.NoMouseCursorChange) == 0 || input.IsCursorHidden())
|
||||
{
|
||||
ImGuiMouseCursor cursor = ImGui.GetMouseCursor();
|
||||
if (cursor == ImGuiMouseCursor.None || io.MouseDrawCursor)
|
||||
{
|
||||
input.HideCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
input.ShowCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
ImGui.Render();
|
||||
}
|
||||
|
||||
private void RenderCommandLists(ImDrawDataPtr data)
|
||||
{
|
||||
// Scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
int fbWidth = (int)(data.DisplaySize.X * data.FramebufferScale.X);
|
||||
int fbHeight = (int)(data.DisplaySize.Y * data.FramebufferScale.Y);
|
||||
|
||||
// Avoid rendering if display is minimized or if the command list is empty
|
||||
if (fbWidth <= 0 || fbHeight <= 0 || data.CmdListsCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Rlgl.rlDrawRenderBatchActive();
|
||||
Rlgl.rlDisableBackfaceCulling();
|
||||
Rlgl.rlEnableScissorTest();
|
||||
|
||||
data.ScaleClipRects(ImGui.GetIO().DisplayFramebufferScale);
|
||||
|
||||
for (int n = 0; n < data.CmdListsCount; n++)
|
||||
{
|
||||
int idxOffset = 0;
|
||||
ImDrawListPtr cmdList = data.CmdListsRange[n];
|
||||
|
||||
// Vertex buffer and index buffer generated by DearImGui
|
||||
ImPtrVector<ImDrawVertPtr> vtxBuffer = cmdList.VtxBuffer;
|
||||
ImVector<ushort> idxBuffer = cmdList.IdxBuffer;
|
||||
|
||||
for (int cmdi = 0; cmdi < cmdList.CmdBuffer.Size; cmdi++)
|
||||
{
|
||||
ImDrawCmdPtr pcmd = cmdList.CmdBuffer[cmdi];
|
||||
|
||||
// Scissor rect
|
||||
Vector2 pos = data.DisplayPos;
|
||||
int rectX = (int)((pcmd.ClipRect.X - pos.X) * data.FramebufferScale.X);
|
||||
int rectY = (int)((pcmd.ClipRect.Y - pos.Y) * data.FramebufferScale.Y);
|
||||
int rectW = (int)((pcmd.ClipRect.Z - rectX) * data.FramebufferScale.Y);
|
||||
int rectH = (int)((pcmd.ClipRect.W - rectY) * data.FramebufferScale.Y);
|
||||
Rlgl.rlScissor(rectX, Raylib.GetScreenHeight() - (rectY + rectH), rectW, rectH);
|
||||
|
||||
if (pcmd.UserCallback != IntPtr.Zero)
|
||||
{
|
||||
// pcmd.UserCallback(cmdList, pcmd);
|
||||
idxOffset += (int)pcmd.ElemCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTriangles(pcmd.ElemCount, idxOffset, (int)pcmd.VtxOffset, idxBuffer, vtxBuffer, pcmd.TextureId);
|
||||
idxOffset += (int)pcmd.ElemCount;
|
||||
Rlgl.rlDrawRenderBatchActive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rlgl.rlSetTexture(0);
|
||||
Rlgl.rlDisableScissorTest();
|
||||
Rlgl.rlEnableBackfaceCulling();
|
||||
}
|
||||
|
||||
private Color GetColor(uint hexValue)
|
||||
{
|
||||
Color color;
|
||||
|
||||
color.r = (byte)(hexValue & 0xFF);
|
||||
color.g = (byte)((hexValue >> 8) & 0xFF);
|
||||
color.b = (byte)((hexValue >> 16) & 0xFF);
|
||||
color.a = (byte)((hexValue >> 24) & 0xFF);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void DrawTriangleVertex(ImDrawVertPtr idxVert)
|
||||
{
|
||||
Color c = GetColor(idxVert.col);
|
||||
Rlgl.rlColor4ub(c.r, c.g, c.b, c.a);
|
||||
Rlgl.rlTexCoord2f(idxVert.uv.X, idxVert.uv.Y);
|
||||
Rlgl.rlVertex2f(idxVert.pos.X, idxVert.pos.Y);
|
||||
}
|
||||
|
||||
// Draw the imgui triangle data
|
||||
private void DrawTriangles(uint count, int idxOffset, int vtxOffset, ImVector<ushort> idxBuffer, ImPtrVector<ImDrawVertPtr> idxVert, IntPtr textureId)
|
||||
{
|
||||
ushort index = 0;
|
||||
ImDrawVertPtr vertex;
|
||||
|
||||
if (Rlgl.rlCheckRenderBatchLimit((int)count * 3))
|
||||
{
|
||||
Rlgl.rlDrawRenderBatchActive();
|
||||
}
|
||||
|
||||
Rlgl.rlBegin(DrawMode.TRIANGLES);
|
||||
Rlgl.rlSetTexture((uint)textureId);
|
||||
|
||||
for (int i = 0; i <= (count - 3); i += 3)
|
||||
{
|
||||
index = idxBuffer[idxOffset + i];
|
||||
vertex = idxVert[vtxOffset + index];
|
||||
DrawTriangleVertex(vertex);
|
||||
|
||||
index = idxBuffer[idxOffset + i + 1];
|
||||
vertex = idxVert[vtxOffset + index];
|
||||
DrawTriangleVertex(vertex);
|
||||
|
||||
index = idxBuffer[idxOffset + i + 2];
|
||||
vertex = idxVert[vtxOffset + index];
|
||||
DrawTriangleVertex(vertex);
|
||||
}
|
||||
Rlgl.rlEnd();
|
||||
}
|
||||
|
||||
public void Draw(ref Renderer renderer)
|
||||
{
|
||||
ImGui.Render();
|
||||
RenderCommandLists(ImGui.GetDrawData());
|
||||
}
|
||||
|
||||
private IntPtr _context;
|
||||
private Texture2D _fontTexture;
|
||||
private Vector2 _scaleFactor = Vector2.One;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user