1
0
algoru-labs/Lab4/ImguiController.cs

324 lines
12 KiB
C#

using ImGuiNET;
using Raylib_cs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace Lab4
{
public class ImguiController : IDisposable
{
IntPtr context;
Texture2D fontTexture;
Vector2 scaleFactor = Vector2.One;
public ImguiController()
{
context = ImGui.CreateContext();
ImGui.SetCurrentContext(context);
}
public void Dispose()
{
ImGui.DestroyContext(context);
Raylib.UnloadTexture(fontTexture);
}
/// <summary>
/// Creates a texture and loads the font data from ImGui.
/// </summary>
public void Load(int width, int height)
{
ImGuiIOPtr io = ImGui.GetIO();
io.Fonts.AddFontDefault();
Resize(width, height);
LoadFontTexture();
SetupInput();
ImGui.NewFrame();
}
unsafe void LoadFontTexture()
{
ImGuiIOPtr io = ImGui.GetIO();
// Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders.
// If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
io.Fonts.GetTexDataAsRGBA32(out byte* pixels, out int width, out int height);
// Upload texture to graphics system
Image image = new Image
{
data = pixels,
width = width,
height = height,
mipmaps = 1,
format = PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
};
fontTexture = Raylib.LoadTextureFromImage(image);
// Store texture id in imgui font
io.Fonts.SetTexID(new IntPtr(fontTexture.id));
// Clears font data on the CPU side
io.Fonts.ClearTexData();
}
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.KEY_TAB;
io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)KeyboardKey.KEY_LEFT;
io.KeyMap[(int)ImGuiKey.RightArrow] = (int)KeyboardKey.KEY_RIGHT;
io.KeyMap[(int)ImGuiKey.UpArrow] = (int)KeyboardKey.KEY_UP;
io.KeyMap[(int)ImGuiKey.DownArrow] = (int)KeyboardKey.KEY_DOWN;
io.KeyMap[(int)ImGuiKey.PageUp] = (int)KeyboardKey.KEY_PAGE_UP;
io.KeyMap[(int)ImGuiKey.PageDown] = (int)KeyboardKey.KEY_PAGE_DOWN;
io.KeyMap[(int)ImGuiKey.Home] = (int)KeyboardKey.KEY_HOME;
io.KeyMap[(int)ImGuiKey.End] = (int)KeyboardKey.KEY_END;
io.KeyMap[(int)ImGuiKey.Insert] = (int)KeyboardKey.KEY_INSERT;
io.KeyMap[(int)ImGuiKey.Delete] = (int)KeyboardKey.KEY_DELETE;
io.KeyMap[(int)ImGuiKey.Backspace] = (int)KeyboardKey.KEY_BACKSPACE;
io.KeyMap[(int)ImGuiKey.Space] = (int)KeyboardKey.KEY_SPACE;
io.KeyMap[(int)ImGuiKey.Enter] = (int)KeyboardKey.KEY_ENTER;
io.KeyMap[(int)ImGuiKey.Escape] = (int)KeyboardKey.KEY_ESCAPE;
io.KeyMap[(int)ImGuiKey.A] = (int)KeyboardKey.KEY_A;
io.KeyMap[(int)ImGuiKey.C] = (int)KeyboardKey.KEY_C;
io.KeyMap[(int)ImGuiKey.V] = (int)KeyboardKey.KEY_V;
io.KeyMap[(int)ImGuiKey.X] = (int)KeyboardKey.KEY_X;
io.KeyMap[(int)ImGuiKey.Y] = (int)KeyboardKey.KEY_Y;
io.KeyMap[(int)ImGuiKey.Z] = (int)KeyboardKey.KEY_Z;
}
/// <summary>
/// Update imgui internals(input, frameData)
/// </summary>
/// <param name="dt"></param>
public void Update(float dt)
{
ImGuiIOPtr io = ImGui.GetIO();
io.DisplayFramebufferScale = Vector2.One;
io.DeltaTime = dt;
UpdateKeyboard();
UpdateMouse();
if (Raylib.IsWindowResized())
{
Resize(Raylib.GetScreenWidth(), Raylib.GetScreenHeight());
}
ImGui.NewFrame();
}
/// <summary>
/// Resize imgui display
/// </summary>
public void Resize(int width, int height)
{
ImGuiIOPtr io = ImGui.GetIO();
io.DisplaySize = new Vector2(width, height) / scaleFactor;
}
void UpdateKeyboard()
{
ImGuiIOPtr io = ImGui.GetIO();
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[(int)KeyboardKey.KEY_LEFT_CONTROL] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[(int)KeyboardKey.KEY_LEFT_SHIFT] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[(int)KeyboardKey.KEY_LEFT_ALT] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_ALT];
io.KeySuper = io.KeysDown[(int)KeyboardKey.KEY_LEFT_SUPER] || io.KeysDown[(int)KeyboardKey.KEY_RIGHT_SUPER];
// Key states
for (int i = (int)KeyboardKey.KEY_SPACE; i < (int)KeyboardKey.KEY_KB_MENU + 1; i++)
{
io.KeysDown[i] = Raylib.IsKeyDown((KeyboardKey)i);
}
// Key input
int keyPressed = Raylib.GetCharPressed();
if (keyPressed != 0)
{
io.AddInputCharacter((uint)keyPressed);
}
}
void UpdateMouse()
{
ImGuiIOPtr io = ImGui.GetIO();
// Store button states
for (int i = 0; i < io.MouseDown.Count; i++)
{
io.MouseDown[i] = Raylib.IsMouseButtonDown((MouseButton)i);
}
// Mouse scroll
io.MouseWheel += Raylib.GetMouseWheelMove();
// Mouse position
Vector2 mousePosition = io.MousePos;
bool focused = Raylib.IsWindowFocused();
if (focused)
{
if (io.WantSetMousePos)
{
Raylib.SetMousePosition((int)mousePosition.X, (int)mousePosition.Y);
}
else
{
io.MousePos = Raylib.GetMousePosition();
}
}
// Mouse cursor state
if ((io.ConfigFlags & ImGuiConfigFlags.NoMouseCursorChange) == 0 || Raylib.IsCursorHidden())
{
ImGuiMouseCursor cursor = ImGui.GetMouseCursor();
if (cursor == ImGuiMouseCursor.None || io.MouseDrawCursor)
{
Raylib.HideCursor();
}
else
{
Raylib.ShowCursor();
}
}
}
/// <summary>
/// Gets the geometry as set up by ImGui and sends it to the graphics device
/// </summary>
public void Draw()
{
ImGui.Render();
RenderCommandLists(ImGui.GetDrawData());
}
// Returns a Color struct from hexadecimal value
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
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();
}
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();
}
}
}